patch-2_6_7-vs1_9_1_12
[linux-2.6.git] / drivers / usb / serial / visor.c
index 37e0dae..377a184 100644 (file)
@@ -2,7 +2,7 @@
  * USB HandSpring Visor, Palm m50x, and Sony Clie driver
  * (supports all of the Palm OS USB devices)
  *
- *     Copyright (C) 1999 - 2003
+ *     Copyright (C) 1999 - 2004
  *         Greg Kroah-Hartman (greg@kroah.com)
  *
  *     This program is free software; you can redistribute it and/or modify
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/spinlock.h>
 #include <asm/uaccess.h>
 #include <linux/usb.h>
@@ -194,8 +195,8 @@ static int palm_os_3_probe (struct usb_serial *serial, const struct usb_device_i
 static int palm_os_4_probe (struct usb_serial *serial, const struct usb_device_id *id);
 
 /* Parameters that may be passed into the module. */
-static int vendor = -1;
-static int product = -1;
+static __u16 vendor;
+static __u16 product;
 
 static struct usb_device_id id_table [] = {
        { USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID),
@@ -222,6 +223,8 @@ static struct usb_device_id id_table [] = {
                .driver_info = (kernel_ulong_t)&palm_os_4_probe },
        { USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_Z_ID),
                .driver_info = (kernel_ulong_t)&palm_os_4_probe },
+       { USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE31_ID),
+               .driver_info = (kernel_ulong_t)&palm_os_4_probe },
        { USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE_ID),
                .driver_info = (kernel_ulong_t)&palm_os_4_probe },
        { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID),
@@ -273,6 +276,7 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(PALM_VENDOR_ID, PALM_M130_ID) },
        { USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_T_ID) },
        { USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_Z_ID) },
+       { USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE31_ID) },
        { USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE_ID) },
        { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_3_5_ID) },
        { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID) },
@@ -393,9 +397,6 @@ static int visor_open (struct usb_serial_port *port, struct file *filp)
        struct usb_serial *serial = port->serial;
        int result = 0;
 
-       if (port_paranoia_check (port, __FUNCTION__))
-               return -ENODEV;
-       
        dbg("%s - port %d", __FUNCTION__, port->number);
 
        if (!port->read_urb) {
@@ -443,18 +444,10 @@ exit:
 
 static void visor_close (struct usb_serial_port *port, struct file * filp)
 {
-       struct usb_serial *serial;
        unsigned char *transfer_buffer;
 
-       if (port_paranoia_check (port, __FUNCTION__))
-               return;
-       
        dbg("%s - port %d", __FUNCTION__, port->number);
                         
-       serial = get_usb_serial (port, __FUNCTION__);
-       if (!serial)
-               return;
-       
        /* shutdown our urbs */
        usb_unlink_urb (port->read_urb);
        if (port->interrupt_in_urb)
@@ -463,8 +456,8 @@ static void visor_close (struct usb_serial_port *port, struct file * filp)
        /* Try to send shutdown message, if the device is gone, this will just fail. */
        transfer_buffer =  kmalloc (0x12, GFP_KERNEL);
        if (transfer_buffer) {
-               usb_control_msg (serial->dev,
-                                usb_rcvctrlpipe(serial->dev, 0),
+               usb_control_msg (port->serial->dev,
+                                usb_rcvctrlpipe(port->serial->dev, 0),
                                 VISOR_CLOSE_NOTIFICATION, 0xc2,
                                 0x0000, 0x0000, 
                                 transfer_buffer, 0x12, 300);
@@ -568,9 +561,6 @@ static void visor_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
        /* free up the transfer buffer, as usb_free_urb() does not do this */
        kfree (urb->transfer_buffer);
 
-       if (port_paranoia_check (port, __FUNCTION__))
-               return;
-       
        dbg("%s - port %d", __FUNCTION__, port->number);
        
        if (urb->status)
@@ -584,22 +574,13 @@ static void visor_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
 static void visor_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
 {
        struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
-       struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
        struct tty_struct *tty;
        unsigned char *data = urb->transfer_buffer;
        int i;
        int result;
 
-       if (port_paranoia_check (port, __FUNCTION__))
-               return;
-
        dbg("%s - port %d", __FUNCTION__, port->number);
 
-       if (!serial) {
-               dbg("%s - bad serial pointer, exiting", __FUNCTION__);
-               return;
-       }
-
        if (urb->status) {
                dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status);
                return;
@@ -622,9 +603,9 @@ static void visor_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
        bytes_in += urb->actual_length;
 
        /* Continue trying to always read  */
-       usb_fill_bulk_urb (port->read_urb, serial->dev,
-                          usb_rcvbulkpipe (serial->dev,
-                                           port->bulk_in_endpointAddress),
+       usb_fill_bulk_urb (port->read_urb, port->serial->dev,
+                          usb_rcvbulkpipe(port->serial->dev,
+                                          port->bulk_in_endpointAddress),
                           port->read_urb->transfer_buffer,
                           port->read_urb->transfer_buffer_length,
                           visor_read_bulk_callback, port);
@@ -699,7 +680,7 @@ static int palm_os_3_probe (struct usb_serial *serial, const struct usb_device_i
        char *string;
        int retval = 0;
        int i;
-       int num_ports;
+       int num_ports = 0;
 
        dbg("%s", __FUNCTION__);
 
@@ -721,41 +702,50 @@ static int palm_os_3_probe (struct usb_serial *serial, const struct usb_device_i
                        __FUNCTION__, retval);
                goto exit;
        }
-               
-       connection_info = (struct visor_connection_info *)transfer_buffer;
-
-       le16_to_cpus(&connection_info->num_ports);
-       num_ports = connection_info->num_ports;
-       /* handle devices that report invalid stuff here */
-       if (num_ports > 2)
-               num_ports = 2;
-       dev_info(dev, "%s: Number of ports: %d\n", serial->type->name,
-               connection_info->num_ports);
 
-       for (i = 0; i < num_ports; ++i) {
-               switch (connection_info->connections[i].port_function_id) {
-                       case VISOR_FUNCTION_GENERIC:
-                               string = "Generic";
-                               break;
-                       case VISOR_FUNCTION_DEBUGGER:
-                               string = "Debugger";
-                               break;
-                       case VISOR_FUNCTION_HOTSYNC:
-                               string = "HotSync";
-                               break;
-                       case VISOR_FUNCTION_CONSOLE:
-                               string = "Console";
-                               break;
-                       case VISOR_FUNCTION_REMOTE_FILE_SYS:
-                               string = "Remote File System";
-                               break;
-                       default:
-                               string = "unknown";
-                               break;  
+       if (retval == sizeof(*connection_info)) {
+               connection_info = (struct visor_connection_info *)transfer_buffer;
+
+               le16_to_cpus(&connection_info->num_ports);
+               num_ports = connection_info->num_ports;
+
+               for (i = 0; i < num_ports; ++i) {
+                       switch (connection_info->connections[i].port_function_id) {
+                               case VISOR_FUNCTION_GENERIC:
+                                       string = "Generic";
+                                       break;
+                               case VISOR_FUNCTION_DEBUGGER:
+                                       string = "Debugger";
+                                       break;
+                               case VISOR_FUNCTION_HOTSYNC:
+                                       string = "HotSync";
+                                       break;
+                               case VISOR_FUNCTION_CONSOLE:
+                                       string = "Console";
+                                       break;
+                               case VISOR_FUNCTION_REMOTE_FILE_SYS:
+                                       string = "Remote File System";
+                                       break;
+                               default:
+                                       string = "unknown";
+                                       break;
+                       }
+                       dev_info(dev, "%s: port %d, is for %s use\n",
+                               serial->type->name,
+                               connection_info->connections[i].port, string);
                }
-               dev_info(dev, "%s: port %d, is for %s use\n", serial->type->name,
-                        connection_info->connections[i].port, string);
        }
+       /*
+       * Handle devices that report invalid stuff here.
+       */
+       if (num_ports == 0 || num_ports > 2) {
+               dev_warn (dev, "%s: No valid connect info available\n",
+                       serial->type->name);
+               num_ports = 2;
+       }
+  
+       dev_info(dev, "%s: Number of ports: %d\n", serial->type->name,
+               num_ports);
 
        /*
         * save off our num_ports info so that we can use it in the
@@ -887,8 +877,7 @@ static int clie_3_5_startup (struct usb_serial *serial)
  
 static int treo_attach (struct usb_serial *serial)
 {
-       struct usb_serial_port *port;
-       int i;
+       struct usb_serial_port *swap_port;
 
        /* Only do this endpoint hack for the Handspring devices with
         * interrupt in endpoints, which for now are the Treo devices. */
@@ -898,31 +887,28 @@ static int treo_attach (struct usb_serial *serial)
 
        dbg("%s", __FUNCTION__);
 
-       /* Ok, this is pretty ugly, but these devices want to use the
-        * interrupt endpoint as paired up with a bulk endpoint for a
-        * "virtual serial port".  So let's force the endpoints to be
-        * where we want them to be. */
-       for (i = serial->num_bulk_in; i < serial->num_ports; ++i) {
-               port = serial->port[i];
-               port->read_urb = serial->port[0]->read_urb;
-               port->bulk_in_endpointAddress = serial->port[0]->bulk_in_endpointAddress;
-               port->bulk_in_buffer = serial->port[0]->bulk_in_buffer;
-       }
-
-       for (i = serial->num_bulk_out; i < serial->num_ports; ++i) {
-               port = serial->port[i];
-               port->write_urb = serial->port[0]->write_urb;
-               port->bulk_out_size = serial->port[0]->bulk_out_size;
-               port->bulk_out_endpointAddress = serial->port[0]->bulk_out_endpointAddress;
-               port->bulk_out_buffer = serial->port[0]->bulk_out_buffer;
-       }
-
-       for (i = serial->num_interrupt_in; i < serial->num_ports; ++i) {
-               port = serial->port[i];
-               port->interrupt_in_urb = serial->port[0]->interrupt_in_urb;
-               port->interrupt_in_endpointAddress = serial->port[0]->interrupt_in_endpointAddress;
-               port->interrupt_in_buffer = serial->port[0]->interrupt_in_buffer;
-       }
+       /*
+       * It appears that Treos want to use the 1st interrupt endpoint to
+       * communicate with the 2nd bulk out endpoint, so let's swap the 1st
+       * and 2nd bulk in and interrupt endpoints.  Note that swapping the
+       * bulk out endpoints would break lots of apps that want to communicate
+       * on the second port.
+       */
+#define COPY_PORT(dest, src)                                           \
+       dest->read_urb = src->read_urb;                                 \
+       dest->bulk_in_endpointAddress = src->bulk_in_endpointAddress;   \
+       dest->bulk_in_buffer = src->bulk_in_buffer;                     \
+       dest->interrupt_in_urb = src->interrupt_in_urb;                 \
+       dest->interrupt_in_endpointAddress = src->interrupt_in_endpointAddress; \
+       dest->interrupt_in_buffer = src->interrupt_in_buffer;
+
+       swap_port = kmalloc(sizeof(*swap_port), GFP_KERNEL);
+       if (!swap_port)
+               return -ENOMEM;
+       COPY_PORT(swap_port, serial->port[0]);
+       COPY_PORT(serial->port[0], serial->port[1]);
+       COPY_PORT(serial->port[1], swap_port);
+       kfree(swap_port);
 
        return 0;
 }
@@ -1099,10 +1085,10 @@ 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");
 
-MODULE_PARM(vendor, "i");
+module_param(vendor, ushort, 0);
 MODULE_PARM_DESC(vendor, "User specified vendor ID");
-MODULE_PARM(product, "i");
+module_param(product, ushort, 0);
 MODULE_PARM_DESC(product, "User specified product ID");