Commit 9c560a68 authored by Frank Seidel's avatar Frank Seidel Committed by Greg Kroah-Hartman

USB: kobil_sct: trivial backport to fix libct

Backport of a patch by Alan Cox <alan@lxorguk.ukuu.org.uk> in the kernel tree
with commit 94d0f7ea

Original comments:
	USB: kobil_sct: Rework driver

	No hardware but this driver is currently totally broken so we can't make
	it much worse. Remove all tbe broken invalid termios handling and replace
	it with a proper set_termios method.

Frank's comments:
	Without this patch the userspace libct (to access the cardreader)
	segfaults.
Signed-off-by: default avatarFrank Seidel <fseidel@suse.de>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent dd2ee9fb
...@@ -82,6 +82,7 @@ static int kobil_tiocmset(struct usb_serial_port *port, struct file *file, ...@@ -82,6 +82,7 @@ static int kobil_tiocmset(struct usb_serial_port *port, struct file *file,
unsigned int set, unsigned int clear); unsigned int set, unsigned int clear);
static void kobil_read_int_callback( struct urb *urb ); static void kobil_read_int_callback( struct urb *urb );
static void kobil_write_callback( struct urb *purb ); static void kobil_write_callback( struct urb *purb );
static void kobil_set_termios(struct usb_serial_port *port, struct ktermios *old);
static struct usb_device_id id_table [] = { static struct usb_device_id id_table [] = {
...@@ -119,6 +120,7 @@ static struct usb_serial_driver kobil_device = { ...@@ -119,6 +120,7 @@ static struct usb_serial_driver kobil_device = {
.attach = kobil_startup, .attach = kobil_startup,
.shutdown = kobil_shutdown, .shutdown = kobil_shutdown,
.ioctl = kobil_ioctl, .ioctl = kobil_ioctl,
.set_termios = kobil_set_termios,
.tiocmget = kobil_tiocmget, .tiocmget = kobil_tiocmget,
.tiocmset = kobil_tiocmset, .tiocmset = kobil_tiocmset,
.open = kobil_open, .open = kobil_open,
...@@ -137,7 +139,6 @@ struct kobil_private { ...@@ -137,7 +139,6 @@ struct kobil_private {
int cur_pos; // index of the next char to send in buf int cur_pos; // index of the next char to send in buf
__u16 device_type; __u16 device_type;
int line_state; int line_state;
struct ktermios internal_termios;
}; };
...@@ -216,7 +217,7 @@ static void kobil_shutdown (struct usb_serial *serial) ...@@ -216,7 +217,7 @@ static void kobil_shutdown (struct usb_serial *serial)
static int kobil_open (struct usb_serial_port *port, struct file *filp) static int kobil_open (struct usb_serial_port *port, struct file *filp)
{ {
int i, result = 0; int result = 0;
struct kobil_private *priv; struct kobil_private *priv;
unsigned char *transfer_buffer; unsigned char *transfer_buffer;
int transfer_buffer_length = 8; int transfer_buffer_length = 8;
...@@ -242,16 +243,6 @@ static int kobil_open (struct usb_serial_port *port, struct file *filp) ...@@ -242,16 +243,6 @@ static int kobil_open (struct usb_serial_port *port, struct file *filp)
port->tty->termios->c_iflag = IGNBRK | IGNPAR | IXOFF; port->tty->termios->c_iflag = IGNBRK | IGNPAR | IXOFF;
port->tty->termios->c_oflag &= ~ONLCR; // do NOT translate CR to CR-NL (0x0A -> 0x0A 0x0D) port->tty->termios->c_oflag &= ~ONLCR; // do NOT translate CR to CR-NL (0x0A -> 0x0A 0x0D)
// set up internal termios structure
priv->internal_termios.c_iflag = port->tty->termios->c_iflag;
priv->internal_termios.c_oflag = port->tty->termios->c_oflag;
priv->internal_termios.c_cflag = port->tty->termios->c_cflag;
priv->internal_termios.c_lflag = port->tty->termios->c_lflag;
for (i=0; i<NCCS; i++) {
priv->internal_termios.c_cc[i] = port->tty->termios->c_cc[i];
}
// allocate memory for transfer buffer // allocate memory for transfer buffer
transfer_buffer = kzalloc(transfer_buffer_length, GFP_KERNEL); transfer_buffer = kzalloc(transfer_buffer_length, GFP_KERNEL);
if (! transfer_buffer) { if (! transfer_buffer) {
...@@ -358,24 +349,26 @@ static void kobil_close (struct usb_serial_port *port, struct file *filp) ...@@ -358,24 +349,26 @@ static void kobil_close (struct usb_serial_port *port, struct file *filp)
} }
static void kobil_read_int_callback( struct urb *purb) static void kobil_read_int_callback(struct urb *urb)
{ {
int result; int result;
struct usb_serial_port *port = (struct usb_serial_port *) purb->context; struct usb_serial_port *port = urb->context;
struct tty_struct *tty; struct tty_struct *tty;
unsigned char *data = purb->transfer_buffer; unsigned char *data = urb->transfer_buffer;
int status = urb->status;
// char *dbg_data; // char *dbg_data;
dbg("%s - port %d", __FUNCTION__, port->number); dbg("%s - port %d", __FUNCTION__, port->number);
if (purb->status) { if (status) {
dbg("%s - port %d Read int status not zero: %d", __FUNCTION__, port->number, purb->status); dbg("%s - port %d Read int status not zero: %d",
__FUNCTION__, port->number, status);
return; return;
} }
tty = port->tty; tty = port->tty;
if (purb->actual_length) { if (urb->actual_length) {
// BEGIN DEBUG // BEGIN DEBUG
/* /*
dbg_data = kzalloc((3 * purb->actual_length + 10) * sizeof(char), GFP_KERNEL); dbg_data = kzalloc((3 * purb->actual_length + 10) * sizeof(char), GFP_KERNEL);
...@@ -390,15 +383,15 @@ static void kobil_read_int_callback( struct urb *purb) ...@@ -390,15 +383,15 @@ static void kobil_read_int_callback( struct urb *purb)
*/ */
// END DEBUG // END DEBUG
tty_buffer_request_room(tty, purb->actual_length); tty_buffer_request_room(tty, urb->actual_length);
tty_insert_flip_string(tty, data, purb->actual_length); tty_insert_flip_string(tty, data, urb->actual_length);
tty_flip_buffer_push(tty); tty_flip_buffer_push(tty);
} }
// someone sets the dev to 0 if the close method has been called // someone sets the dev to 0 if the close method has been called
port->interrupt_in_urb->dev = port->serial->dev; port->interrupt_in_urb->dev = port->serial->dev;
result = usb_submit_urb( port->interrupt_in_urb, GFP_ATOMIC ); result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
dbg("%s - port %d Send read URB returns: %i", __FUNCTION__, port->number, result); dbg("%s - port %d Send read URB returns: %i", __FUNCTION__, port->number, result);
} }
...@@ -605,102 +598,79 @@ static int kobil_tiocmset(struct usb_serial_port *port, struct file *file, ...@@ -605,102 +598,79 @@ static int kobil_tiocmset(struct usb_serial_port *port, struct file *file,
return (result < 0) ? result : 0; return (result < 0) ? result : 0;
} }
static void kobil_set_termios(struct usb_serial_port *port, struct ktermios *old)
static int kobil_ioctl(struct usb_serial_port *port, struct file *file,
unsigned int cmd, unsigned long arg)
{ {
struct kobil_private * priv; struct kobil_private * priv;
int result; int result;
unsigned short urb_val = 0; unsigned short urb_val = 0;
unsigned char *transfer_buffer; int c_cflag = port->tty->termios->c_cflag;
int transfer_buffer_length = 8; speed_t speed;
char *settings; void * settings;
void __user *user_arg = (void __user *)arg;
priv = usb_get_serial_port_data(port); priv = usb_get_serial_port_data(port);
if ((priv->device_type == KOBIL_USBTWIN_PRODUCT_ID) || (priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID)) { if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID || priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID)
// This device doesn't support ioctl calls // This device doesn't support ioctl calls
return 0; return;
}
switch (cmd) {
case TCGETS: // 0x5401
if (!access_ok(VERIFY_WRITE, user_arg, sizeof(struct ktermios))) {
dbg("%s - port %d Error in access_ok", __FUNCTION__, port->number);
return -EFAULT;
}
if (kernel_termios_to_user_termios((struct ktermios __user *)arg,
&priv->internal_termios))
return -EFAULT;
return 0;
case TCSETS: // 0x5402
if (!(port->tty->termios)) {
dbg("%s - port %d Error: port->tty->termios is NULL", __FUNCTION__, port->number);
return -ENOTTY;
}
if (!access_ok(VERIFY_READ, user_arg, sizeof(struct ktermios))) {
dbg("%s - port %d Error in access_ok", __FUNCTION__, port->number);
return -EFAULT;
}
if (user_termios_to_kernel_termios(&priv->internal_termios,
(struct ktermios __user *)arg))
return -EFAULT;
settings = kzalloc(50, GFP_KERNEL);
if (! settings) {
return -ENOBUFS;
}
switch (priv->internal_termios.c_cflag & CBAUD) { switch (speed = tty_get_baud_rate(port->tty)) {
case B1200: case 1200:
urb_val = SUSBCR_SBR_1200; urb_val = SUSBCR_SBR_1200;
strcat(settings, "1200 ");
break; break;
case B9600: case 9600:
default: default:
urb_val = SUSBCR_SBR_9600; urb_val = SUSBCR_SBR_9600;
strcat(settings, "9600 ");
break; break;
} }
urb_val |= (c_cflag & CSTOPB) ? SUSBCR_SPASB_2StopBits : SUSBCR_SPASB_1StopBit;
urb_val |= (priv->internal_termios.c_cflag & CSTOPB) ? SUSBCR_SPASB_2StopBits : SUSBCR_SPASB_1StopBit; settings = kzalloc(50, GFP_KERNEL);
strcat(settings, (priv->internal_termios.c_cflag & CSTOPB) ? "2 StopBits " : "1 StopBit "); if (! settings)
return;
if (priv->internal_termios.c_cflag & PARENB) { sprintf(settings, "%d ", speed);
if (priv->internal_termios.c_cflag & PARODD) {
urb_val |= SUSBCR_SPASB_OddParity; if (c_cflag & PARENB) {
strcat(settings, "Odd Parity"); if (c_cflag & PARODD) {
} else { urb_val |= SUSBCR_SPASB_OddParity;
urb_val |= SUSBCR_SPASB_EvenParity; strcat(settings, "Odd Parity");
strcat(settings, "Even Parity");
}
} else { } else {
urb_val |= SUSBCR_SPASB_NoParity; urb_val |= SUSBCR_SPASB_EvenParity;
strcat(settings, "No Parity"); strcat(settings, "Even Parity");
} }
dbg("%s - port %d setting port to: %s", __FUNCTION__, port->number, settings ); } else {
urb_val |= SUSBCR_SPASB_NoParity;
strcat(settings, "No Parity");
}
result = usb_control_msg( port->serial->dev, result = usb_control_msg( port->serial->dev,
usb_rcvctrlpipe(port->serial->dev, 0 ), usb_rcvctrlpipe(port->serial->dev, 0 ),
SUSBCRequest_SetBaudRateParityAndStopBits, SUSBCRequest_SetBaudRateParityAndStopBits,
USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT, USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
urb_val, urb_val,
0, 0,
settings, settings,
0, 0,
KOBIL_TIMEOUT KOBIL_TIMEOUT
); );
kfree(settings);
}
dbg("%s - port %d Send set_baudrate URB returns: %i", __FUNCTION__, port->number, result); static int kobil_ioctl(struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
kfree(settings); {
struct kobil_private * priv = usb_get_serial_port_data(port);
unsigned char *transfer_buffer;
int transfer_buffer_length = 8;
int result;
if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID || priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID)
// This device doesn't support ioctl calls
return 0; return 0;
switch (cmd) {
case TCFLSH: // 0x540B case TCFLSH: // 0x540B
transfer_buffer = kmalloc(transfer_buffer_length, GFP_KERNEL); transfer_buffer = kmalloc(transfer_buffer_length, GFP_KERNEL);
if (! transfer_buffer) { if (! transfer_buffer)
return -ENOBUFS; return -ENOBUFS;
}
result = usb_control_msg( port->serial->dev, result = usb_control_msg( port->serial->dev,
usb_rcvctrlpipe(port->serial->dev, 0 ), usb_rcvctrlpipe(port->serial->dev, 0 ),
...@@ -714,15 +684,13 @@ static int kobil_ioctl(struct usb_serial_port *port, struct file *file, ...@@ -714,15 +684,13 @@ static int kobil_ioctl(struct usb_serial_port *port, struct file *file,
); );
dbg("%s - port %d Send reset_all_queues (FLUSH) URB returns: %i", __FUNCTION__, port->number, result); dbg("%s - port %d Send reset_all_queues (FLUSH) URB returns: %i", __FUNCTION__, port->number, result);
kfree(transfer_buffer); kfree(transfer_buffer);
return ((result < 0) ? -EFAULT : 0); return (result < 0) ? -EFAULT : 0;
default:
return -ENOIOCTLCMD;
} }
return -ENOIOCTLCMD;
} }
static int __init kobil_init (void) static int __init kobil_init (void)
{ {
int retval; int retval;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment