Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / drivers / usb / serial / kobil_sct.c
index 82319a9..87dfcd8 100644 (file)
@@ -21,6 +21,9 @@
  * Supported readers: USB TWIN, KAAN Standard Plus and SecOVID Reader Plus
  * (Adapter K), B1 Professional and KAAN Professional (Adapter B)
  * 
+ * (21/05/2004) tw
+ *      Fix bug with P'n'P readers
+ *
  * (28/05/2003) tw
  *      Add support for KAAN SIM
  *
 #include <asm/uaccess.h>
 #include <linux/usb.h>
 #include <linux/ioctl.h>
-
-
+#include "usb-serial.h"
 #include "kobil_sct.h"
-//#include "../core/usb-debug.c"
 
-#ifdef CONFIG_USB_SERIAL_DEBUG
-       static int debug = 1;
-#else
-       static int debug;
-#endif
-
-#include "usb-serial.h"
+static int debug;
 
 /* Version Information */
-#define DRIVER_VERSION "28/05/2003"
+#define DRIVER_VERSION "21/05/2004"
 #define DRIVER_AUTHOR "KOBIL Systems GmbH - http://www.kobil.com"
 #define DRIVER_DESC "KOBIL USB Smart Card Terminal Driver (experimental)"
 
@@ -78,7 +73,7 @@ static int  kobil_startup (struct usb_serial *serial);
 static void kobil_shutdown (struct usb_serial *serial);
 static int  kobil_open (struct usb_serial_port *port, struct file *filp);
 static void kobil_close (struct usb_serial_port *port, struct file *filp);
-static int  kobil_write (struct usb_serial_port *port, int from_user, 
+static int  kobil_write (struct usb_serial_port *port, 
                         const unsigned char *buf, int count);
 static int  kobil_write_room(struct usb_serial_port *port);
 static int  kobil_ioctl(struct usb_serial_port *port, struct file *file,
@@ -102,17 +97,20 @@ static struct usb_device_id id_table [] = {
 MODULE_DEVICE_TABLE (usb, id_table);
 
 static struct usb_driver kobil_driver = {
-       .owner =        THIS_MODULE,
        .name =         "kobil",
        .probe =        usb_serial_probe,
        .disconnect =   usb_serial_disconnect,
        .id_table =     id_table,
+       .no_dynamic_id =        1,
 };
 
 
-struct usb_serial_device_type kobil_device = {
-       .owner =                THIS_MODULE,
-       .name =                 "KOBIL USB smart card terminal",
+static struct usb_serial_driver kobil_device = {
+       .driver = {
+               .owner =        THIS_MODULE,
+               .name =         "kobil",
+       },
+       .description =          "KOBIL USB smart card terminal",
        .id_table =             id_table,
        .num_interrupt_in =     NUM_DONT_CARE,
        .num_bulk_in =          0,
@@ -160,7 +158,7 @@ static int kobil_startup (struct usb_serial *serial)
 
        priv->filled = 0;
        priv->cur_pos = 0;
-       priv->device_type = serial->product;
+       priv->device_type = le16_to_cpu(serial->dev->descriptor.idProduct);
        priv->line_state = 0;
 
        switch (priv->device_type){
@@ -183,7 +181,7 @@ static int kobil_startup (struct usb_serial *serial)
        pdev = serial->dev;
        actconfig = pdev->actconfig;
        interface = actconfig->interface[0];
-       altsetting = interface->altsetting;
+       altsetting = interface->cur_altsetting;
        endpoint = altsetting->endpoint;
   
        for (i = 0; i < altsetting->desc.bNumEndpoints; i++) {
@@ -230,9 +228,6 @@ static int kobil_open (struct usb_serial_port *port, struct file *filp)
        priv = usb_get_serial_port_data(port);
        priv->line_state = 0;
 
-       if (port_paranoia_check (port, __FUNCTION__))
-               return -ENODEV;
-
        // someone sets the dev to 0 if the close method has been called
        port->interrupt_in_urb->dev = port->serial->dev;
 
@@ -260,11 +255,9 @@ static int kobil_open (struct usb_serial_port *port, struct file *filp)
        }
        
        // allocate memory for transfer buffer
-       transfer_buffer = (unsigned char *) kmalloc(transfer_buffer_length, GFP_KERNEL);  
+       transfer_buffer = kzalloc(transfer_buffer_length, GFP_KERNEL);
        if (! transfer_buffer) {
                return -ENOMEM;
-       } else {
-               memset(transfer_buffer, 0, transfer_buffer_length);
        }
        
        // allocate write_urb
@@ -342,6 +335,12 @@ static int kobil_open (struct usb_serial_port *port, struct file *filp)
                        );
                dbg("%s - port %d Send reset_all_queues URB returns: %i", __FUNCTION__, port->number, result);
        }
+       if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID || priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID ||
+           priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID) {
+               // start reading (Adapter B 'cause PNP string)
+               result = usb_submit_urb( port->interrupt_in_urb, GFP_ATOMIC  ); 
+               dbg("%s - port %d Send read URB returns: %i", __FUNCTION__, port->number, result);
+       }
 
        kfree(transfer_buffer);
        return 0;
@@ -352,20 +351,18 @@ static void kobil_close (struct usb_serial_port *port, struct file *filp)
 {
        dbg("%s - port %d", __FUNCTION__, port->number);
 
-       if (port->write_urb){
-               usb_unlink_urb( port->write_urb );
+       if (port->write_urb) {
+               usb_kill_urb(port->write_urb);
                usb_free_urb( port->write_urb );
-               port->write_urb = 0;
-       }
-       if (port->interrupt_in_urb){
-               usb_unlink_urb (port->interrupt_in_urb);
+               port->write_urb = NULL;
        }
+       if (port->interrupt_in_urb)
+               usb_kill_urb(port->interrupt_in_urb);
 }
 
 
 static void kobil_read_int_callback( struct urb *purb, struct pt_regs *regs)
 {
-       int i;
        int result;
        struct usb_serial_port *port = (struct usb_serial_port *) purb->context;
        struct tty_struct *tty;
@@ -384,11 +381,10 @@ static void kobil_read_int_callback( struct urb *purb, struct pt_regs *regs)
                
                // BEGIN DEBUG
                /*
-                 dbg_data = (unsigned char *) kmalloc((3 *  purb->actual_length + 10) * sizeof(char), GFP_KERNEL);
+                 dbg_data = kzalloc((3 *  purb->actual_length + 10) * sizeof(char), GFP_KERNEL);
                  if (! dbg_data) {
                  return;
                  }
-                 memset(dbg_data, 0, (3 *  purb->actual_length + 10));
                  for (i = 0; i < purb->actual_length; i++) { 
                  sprintf(dbg_data +3*i, "%02X ", data[i]); 
                  }
@@ -397,14 +393,8 @@ static void kobil_read_int_callback( struct urb *purb, struct pt_regs *regs)
                */
                // END DEBUG
 
-               for (i = 0; i < purb->actual_length; ++i) {
-                       // if we insert more than TTY_FLIPBUF_SIZE characters, we drop them.
-                       if(tty->flip.count >= TTY_FLIPBUF_SIZE) {
-                               tty_flip_buffer_push(tty);
-                       }
-                       // this doesn't actually push the data through unless tty->low_latency is set
-                       tty_insert_flip_char(tty, data[i], 0);
-               }
+               tty_buffer_request_room(tty, purb->actual_length);
+               tty_insert_flip_string(tty, data, purb->actual_length);
                tty_flip_buffer_push(tty);
        }
 
@@ -421,7 +411,7 @@ static void kobil_write_callback( struct urb *purb, struct pt_regs *regs )
 }
 
 
-static int kobil_write (struct usb_serial_port *port, int from_user, 
+static int kobil_write (struct usb_serial_port *port, 
                        const unsigned char *buf, int count)
 {
        int length = 0;
@@ -442,15 +432,9 @@ static int kobil_write (struct usb_serial_port *port, int from_user,
        }
 
        // Copy data to buffer
-       if (from_user) {
-               if (copy_from_user(priv->buf + priv->filled, buf, count)) {
-                       return -EFAULT;
-               }
-       } else {
-               memcpy (priv->buf + priv->filled, buf, count);
-       }
+       memcpy (priv->buf + priv->filled, buf, count);
 
-       usb_serial_debug_data (__FILE__, __FUNCTION__, count, priv->buf + priv->filled);
+       usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, priv->buf + priv->filled);
 
        priv->filled = priv->filled + count;
 
@@ -459,6 +443,10 @@ static int kobil_write (struct usb_serial_port *port, int from_user,
        if ( ((priv->device_type != KOBIL_ADAPTER_B_PRODUCT_ID) && (priv->filled > 2) && (priv->filled >= (priv->buf[1] + 3))) || 
             ((priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID) && (priv->filled > 3) && (priv->filled >= (priv->buf[2] + 4))) ) {
                
+               // stop reading (except TWIN and KAAN SIM)
+               if ( (priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID) || (priv->device_type == KOBIL_ADAPTER_K_PRODUCT_ID) )
+                       usb_kill_urb(port->interrupt_in_urb);
+
                todo = priv->filled - priv->cur_pos;
 
                while(todo > 0) {
@@ -466,25 +454,23 @@ static int kobil_write (struct usb_serial_port *port, int from_user,
                        length = (todo < 8) ? todo : 8;
                        // copy data to transfer buffer
                        memcpy(port->write_urb->transfer_buffer, priv->buf + priv->cur_pos, length );
-                       
-                       usb_fill_bulk_urb( port->write_urb,
-                                          port->serial->dev,
-                                          usb_sndbulkpipe( port->serial->dev, priv->write_int_endpoint_address),
-                                          port->write_urb->transfer_buffer,
-                                          length,
-                                          kobil_write_callback,
-                                          port
+                       usb_fill_int_urb( port->write_urb,
+                                         port->serial->dev,
+                                         usb_sndintpipe(port->serial->dev, priv->write_int_endpoint_address),
+                                         port->write_urb->transfer_buffer,
+                                         length,
+                                         kobil_write_callback,
+                                         port,
+                                         8
                                );
 
                        priv->cur_pos = priv->cur_pos + length;
-                       result = usb_submit_urb( port->write_urb, GFP_ATOMIC );
+                       result = usb_submit_urb( port->write_urb, GFP_NOIO );
                        dbg("%s - port %d Send write URB returns: %i", __FUNCTION__, port->number, result);
                        todo = priv->filled - priv->cur_pos;
 
                        if (todo > 0) {
-                               //mdelay(16);
-                               set_current_state(TASK_UNINTERRUPTIBLE);
-                               schedule_timeout(24 * HZ / 1000);
+                               msleep(24);
                        }
 
                } // end while
@@ -495,9 +481,14 @@ static int kobil_write (struct usb_serial_port *port, int from_user,
                // someone sets the dev to 0 if the close method has been called
                port->interrupt_in_urb->dev = port->serial->dev;
                
-               // start reading
-               result = usb_submit_urb( port->interrupt_in_urb, GFP_ATOMIC ); 
-               dbg("%s - port %d Send read URB returns: %i", __FUNCTION__, port->number, result);
+               // start reading (except TWIN and KAAN SIM)
+               if ( (priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID) || (priv->device_type == KOBIL_ADAPTER_K_PRODUCT_ID) ) {
+                       // someone sets the dev to 0 if the close method has been called
+                       port->interrupt_in_urb->dev = port->serial->dev;
+                       
+                       result = usb_submit_urb( port->interrupt_in_urb, GFP_NOIO ); 
+                       dbg("%s - port %d Send read URB returns: %i", __FUNCTION__, port->number, result);
+               }
        }
        return count;
 }
@@ -524,11 +515,10 @@ static int kobil_tiocmget(struct usb_serial_port *port, struct file *file)
        }
 
        // allocate memory for transfer buffer
-       transfer_buffer = (unsigned char *) kmalloc(transfer_buffer_length, GFP_KERNEL);  
+       transfer_buffer = kzalloc(transfer_buffer_length, GFP_KERNEL);
        if (!transfer_buffer) {
                return -ENOMEM;
        }
-       memset(transfer_buffer, 0, transfer_buffer_length);
 
        result = usb_control_msg( port->serial->dev, 
                                  usb_rcvctrlpipe(port->serial->dev, 0 ), 
@@ -570,11 +560,10 @@ static int  kobil_tiocmset(struct usb_serial_port *port, struct file *file,
        }
 
        // allocate memory for transfer buffer
-       transfer_buffer = (unsigned char *) kmalloc(transfer_buffer_length, GFP_KERNEL);
+       transfer_buffer = kzalloc(transfer_buffer_length, GFP_KERNEL);
        if (! transfer_buffer) {
                return -ENOMEM;
        }
-       memset(transfer_buffer, 0, transfer_buffer_length);
 
        if (set & TIOCM_RTS)
                rts = 1;
@@ -629,6 +618,7 @@ static int  kobil_ioctl(struct usb_serial_port *port, struct file *file,
        unsigned char *transfer_buffer;
        int transfer_buffer_length = 8;
        char *settings;
+       void __user *user_arg = (void __user *)arg;
 
        priv = usb_get_serial_port_data(port);
        if ((priv->device_type == KOBIL_USBTWIN_PRODUCT_ID) || (priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID)) {
@@ -638,12 +628,11 @@ static int  kobil_ioctl(struct usb_serial_port *port, struct file *file,
 
        switch (cmd) {
        case TCGETS:   // 0x5401
-               result = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct termios));
-               if (result) {
-                       dbg("%s - port %d Error in verify_area", __FUNCTION__, port->number);
-                       return(result);
+               if (!access_ok(VERIFY_WRITE, user_arg, sizeof(struct termios))) {
+                       dbg("%s - port %d Error in access_ok", __FUNCTION__, port->number);
+                       return -EFAULT;
                }
-               if (kernel_termios_to_user_termios((struct termios *)arg,
+               if (kernel_termios_to_user_termios((struct termios __user *)arg,
                                                   &priv->internal_termios))
                        return -EFAULT;
                return 0;
@@ -653,20 +642,18 @@ static int  kobil_ioctl(struct usb_serial_port *port, struct file *file,
                        dbg("%s - port %d Error: port->tty->termios is NULL", __FUNCTION__, port->number);
                        return -ENOTTY;
                }
-               result = verify_area(VERIFY_READ, (void *)arg, sizeof(struct termios));
-               if (result) {
-                       dbg("%s - port %d Error in verify_area", __FUNCTION__, port->number);
-                       return result;
+               if (!access_ok(VERIFY_READ, user_arg, sizeof(struct termios))) {
+                       dbg("%s - port %d Error in access_ok", __FUNCTION__, port->number);
+                       return -EFAULT;
                }
                if (user_termios_to_kernel_termios(&priv->internal_termios,
-                                                  (struct termios *)arg))
+                                                  (struct termios __user *)arg))
                        return -EFAULT;
                
-               settings = (unsigned char *) kmalloc(50, GFP_KERNEL);  
+               settings = kzalloc(50, GFP_KERNEL);
                if (! settings) {
                        return -ENOBUFS;
                }
-               memset(settings, 0, 50);
 
                switch (priv->internal_termios.c_cflag & CBAUD) {
                case B1200:
@@ -773,5 +760,5 @@ MODULE_AUTHOR( DRIVER_AUTHOR );
 MODULE_DESCRIPTION( DRIVER_DESC );
 MODULE_LICENSE( "GPL" );
 
-MODULE_PARM(debug, "i");
+module_param(debug, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(debug, "Debug enabled or not");