ChangeSet 1.1006.11.5, 2003/03/11 17:45:38-08:00, [EMAIL PROTECTED]

[PATCH] USB: add support for Treo devices to the visor driver

Thanks to Adam Pennington <[EMAIL PROTECTED]> for the bulk of this work.


 drivers/usb/serial/visor.c |  227 +++++++++++++++++++++++++++++++++++++--------
 drivers/usb/serial/visor.h |   37 ++++++-
 2 files changed, 223 insertions(+), 41 deletions(-)


diff -Nru a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
--- a/drivers/usb/serial/visor.c        Thu Mar 27 16:02:35 2003
+++ b/drivers/usb/serial/visor.c        Thu Mar 27 16:02:35 2003
@@ -2,7 +2,7 @@
  * USB HandSpring Visor, Palm m50x, and Sony Clie driver
  * (supports all of the Palm OS USB devices)
  *
- *     Copyright (C) 1999 - 2002
+ *     Copyright (C) 1999 - 2003
  *         Greg Kroah-Hartman ([EMAIL PROTECTED])
  *
  *     This program is free software; you can redistribute it and/or modify
@@ -16,6 +16,16 @@
  *     Added support for the Sony Clie NZ90V device.  Thanks to Martin Brachtl
  *     <[EMAIL PROTECTED]> for the information.
  *
+ * (3/07/2003) Adam Pennington <[EMAIL PROTECTED]>
+ *      Backported version 2.1 of the driver from the 2.5 bitkeeper tree
+ *      making Treo actually work.
+ *
+ * (2/18/2003) Adam Powell <hazelsct at debian.org>
+ *     Backported 2.5 driver mods to support Handspring Treo.
+ *
+ * (2/11/2003) Adam Powell <hazelsct at debian.org>
+ *     Added device and vendor ids for the Samsung I330 phone.
+ *
  * (04/03/2002) gkh
  *     Added support for the Sony OS 4.1 devices.  Thanks to Hiroyuki ARAKI
  *     <[EMAIL PROTECTED]> for the information.
@@ -150,9 +160,9 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.6"
+#define DRIVER_VERSION "v1.7"
 #define DRIVER_AUTHOR "Greg Kroah-Hartman <[EMAIL PROTECTED]>"
-#define DRIVER_DESC "USB HandSpring Visor, Palm m50x, Sony Clié driver"
+#define DRIVER_DESC "USB HandSpring Visor, Palm m50x, Treo, Sony Clié driver"
 
 /* function prototypes for a handspring visor */
 static int  visor_open         (struct usb_serial_port *port, struct file *filp);
@@ -168,10 +178,14 @@
 static void visor_set_termios  (struct usb_serial_port *port, struct termios 
*old_termios);
 static void visor_write_bulk_callback  (struct urb *urb);
 static void visor_read_bulk_callback   (struct urb *urb);
+static void visor_read_int_callback    (struct urb *urb);
 static int  clie_3_5_startup   (struct usb_serial *serial);
+static void treo_attach                (struct usb_serial *serial);
 
 
 static struct usb_device_id id_table [] = {
+       { USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID) },
+       { USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_TREO_ID) },
        { USB_DEVICE(PALM_VENDOR_ID, PALM_M500_ID) },
        { USB_DEVICE(PALM_VENDOR_ID, PALM_M505_ID) },
        { USB_DEVICE(PALM_VENDOR_ID, PALM_M515_ID) },
@@ -182,12 +196,12 @@
        { USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_T_ID) },
        { USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_Z_ID) },
        { USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE_ID) },
-       { USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID) },
        { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID) },
        { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_S360_ID) },
        { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_1_ID) },
        { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_NX60_ID) },
        { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_NZ90V_ID) },
+       { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SCH_I330_ID) },
        { }                                     /* Terminating entry */
 };
 
@@ -198,6 +212,7 @@
 
 static __devinitdata struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID) },
+       { USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_TREO_ID) },
        { USB_DEVICE(PALM_VENDOR_ID, PALM_M500_ID) },
        { USB_DEVICE(PALM_VENDOR_ID, PALM_M505_ID) },
        { USB_DEVICE(PALM_VENDOR_ID, PALM_M515_ID) },
@@ -214,6 +229,7 @@
        { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_1_ID) },
        { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_NX60_ID) },
        { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_NZ90V_ID) },
+       { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SCH_I330_ID) },
        { }                                     /* Terminating entry */
 };
 
@@ -224,9 +240,9 @@
 /* All of the device info needed for the Handspring Visor, and Palm 4.0 devices */
 static struct usb_serial_device_type handspring_device = {
        .owner =                THIS_MODULE,
-       .name =                 "Handspring Visor / Palm 4.0 / Clié 4.x",
+       .name =                 "Handspring Visor / Treo / Palm 4.0 / Clié 4.x",
        .id_table =             id_table,
-       .num_interrupt_in =     0,
+       .num_interrupt_in =     NUM_DONT_CARE,
        .num_bulk_in =          2,
        .num_bulk_out =         2,
        .num_ports =            2,
@@ -243,6 +259,7 @@
        .chars_in_buffer =      visor_chars_in_buffer,
        .write_bulk_callback =  visor_write_bulk_callback,
        .read_bulk_callback =   visor_read_bulk_callback,
+       .read_int_callback =    visor_read_int_callback,
 };
 
 /* device info for the Sony Clie OS version 3.5 */
@@ -315,9 +332,19 @@
                           port->read_urb->transfer_buffer_length,
                           visor_read_bulk_callback, port);
        result = usb_submit_urb(port->read_urb);
-       if (result)
+       if (result) {
                err("%s - failed submitting read urb, error %d", __FUNCTION__, result);
+               goto exit;
+       }
        
+       if (port->interrupt_in_urb) {
+               dbg("%s - adding interrupt input for treo", __FUNCTION__);
+               result = usb_submit_urb(port->interrupt_in_urb);
+               if (result)
+                       err("%s - failed submitting interrupt urb, error %d\n",
+                           __FUNCTION__, result);
+       }
+exit:
        return result;
 }
 
@@ -336,6 +363,9 @@
        if (!serial)
                return;
        
+
+
+
        if (serial->dev) {
                /* only send a shutdown message if the 
                 * device is still here */
@@ -351,11 +381,25 @@
                                         transfer_buffer, 0x12, 300);
                        kfree (transfer_buffer);
                }
-               /* shutdown our bulk read */
+
+               /* shutdown our urbs */
                usb_unlink_urb (port->read_urb);
+               if (port->interrupt_in_urb)
+                 usb_unlink_urb (port->interrupt_in_urb);
+               /* 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),
+                                VISOR_CLOSE_NOTIFICATION, 0xc2,
+                                0x0000, 0x0000, 
+                                transfer_buffer, 0x12, 300);
+               kfree (transfer_buffer);                        
+               
+               }
        }
        /* Uncomment the following line if you want to see some statistics in your 
syslog */
-       /* info ("Bytes In = %d  Bytes Out = %d", bytes_in, bytes_out); */
+       info ("Bytes In = %d  Bytes Out = %d", bytes_in, bytes_out);
 }
 
 
@@ -552,6 +596,40 @@
 }
 
 
+static void visor_read_int_callback (struct urb *urb)
+{
+       switch (urb->status) {
+       case 0:
+               /* success */
+               break;
+       case -ECONNRESET:
+       case -ENOENT:
+       case -ESHUTDOWN:
+               /* this urb is terminated, clean up */
+               dbg("%s - urb shutting down with status: %d",
+                   __FUNCTION__, urb->status);
+               return;
+       default:
+               dbg("%s - nonzero urb status received: %d",
+                   __FUNCTION__, urb->status);
+               goto exit;
+       }
+
+       /*
+        * This information is still unknown what it can be used for.
+        * If anyone has an idea, please let the author know...
+        *
+        * Rumor has it this endpoint is used to notify when data
+        * is ready to be read from the bulk ones.
+        */
+       usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length,
+                              urb->transfer_buffer);
+
+exit:
+       return;
+}
+
+
 static void visor_throttle (struct usb_serial_port *port)
 {
        dbg("%s - port %d", __FUNCTION__, port->number);
@@ -575,30 +653,49 @@
 {
        int response;
        int i;
-       unsigned char *transfer_buffer =  kmalloc (256, GFP_KERNEL);
-
-       if (!transfer_buffer) {
-               err("%s - kmalloc(%d) failed.", __FUNCTION__, 256);
-               return -ENOMEM;
-       }
+       unsigned char *transfer_buffer;
 
        dbg("%s", __FUNCTION__);
 
        dbg("%s - Set config to 1", __FUNCTION__);
        usb_set_configuration (serial->dev, 1);
 
-       /* send a get connection info request */
-       response = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), 
VISOR_GET_CONNECTION_INFORMATION,
-                                       0xc2, 0x0000, 0x0000, transfer_buffer, 0x12, 
300);
-       if (response < 0) {
-               err("%s - error getting connection information", __FUNCTION__);
-       } else {
-               struct visor_connection_info *connection_info = (struct 
visor_connection_info *)transfer_buffer;
+       if ((serial->dev->descriptor.idVendor == HANDSPRING_VENDOR_ID) &&
+           (serial->dev->descriptor.idProduct == HANDSPRING_VISOR_ID)) {
+               struct visor_connection_info *connection_info;
                char *string;
+               int num_ports;
+
+               transfer_buffer = kmalloc (sizeof (*connection_info),
+                                          GFP_KERNEL);
+               if (!transfer_buffer) {
+                       err("%s - kmalloc(%d) failed.", __FUNCTION__,
+                           sizeof (*connection_info));
+                       return -ENOMEM;
+               }
 
+               /* send a get connection info request */
+               response = usb_control_msg (serial->dev,
+                                           usb_rcvctrlpipe(serial->dev, 0),
+                                           VISOR_GET_CONNECTION_INFORMATION,
+                                           0xc2, 0x0000, 0x0000,
+                                           transfer_buffer,
+                                           sizeof (*connection_info), 300);
+               if (response < 0) {
+                       err("%s - error getting connection information",
+                           __FUNCTION__);
+                       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;
                info("%s: Number of ports: %d", serial->type->name, 
connection_info->num_ports);
-               for (i = 0; i < connection_info->num_ports; ++i) {
+               for (i = 0; i < num_ports; ++i) {
                        switch (connection_info->connections[i].port_function_id) {
                                case VISOR_FUNCTION_GENERIC:
                                        string = "Generic";
@@ -622,32 +719,32 @@
                        info("%s: port %d, is for %s use and is bound to ttyUSB%d", 
serial->type->name,
                             connection_info->connections[i].port, string, 
serial->minor + i);
                }
-       }
+       } else {
+               struct palm_ext_connection_info *connection_info;
 
-       if ((serial->dev->descriptor.idVendor == PALM_VENDOR_ID) ||
-           ((serial->dev->descriptor.idVendor == SONY_VENDOR_ID) &&
-            (serial->dev->descriptor.idProduct != SONY_CLIE_4_1_ID))) {
-               /* Palm OS 4.0 Hack */
-               response = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 
0), 
-                                           PALM_GET_SOME_UNKNOWN_INFORMATION,
-                                           0xc2, 0x0000, 0x0000, transfer_buffer, 
-                                           0x14, 300);
-               if (response < 0) {
-                       err("%s - error getting first unknown palm command", 
__FUNCTION__);
-               } else {
-                       usb_serial_debug_data (__FILE__, __FUNCTION__, 0x14, 
transfer_buffer);
+               transfer_buffer = kmalloc (sizeof (*connection_info),
+                                          GFP_KERNEL);
+               if (!transfer_buffer) {
+                       err("%s - kmalloc(%d) failed.", __FUNCTION__,
+                           sizeof (*connection_info));
+                       return -ENOMEM;
                }
+
                response = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 
0), 
-                                           PALM_GET_SOME_UNKNOWN_INFORMATION,
+                                           PALM_GET_EXT_CONNECTION_INFORMATION,
                                            0xc2, 0x0000, 0x0000, transfer_buffer, 
-                                           0x14, 300);
+                                           sizeof (*connection_info), 300);
                if (response < 0) {
-                       err("%s - error getting second unknown palm command", 
__FUNCTION__);
+                       err("%s - error %d getting connection info",
+                           __FUNCTION__, response);
                } else {
                        usb_serial_debug_data (__FILE__, __FUNCTION__, 0x14, 
transfer_buffer);
                }
        }
 
+       /* Do our horrible Treo hack, if we should */
+       treo_attach(serial);
+
        /* ask for the number of bytes available, but ignore the response as it is 
broken */
        response = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), 
VISOR_REQUEST_BYTES_AVAILABLE,
                                        0xc2, 0x0000, 0x0005, transfer_buffer, 0x02, 
300);
@@ -655,6 +752,7 @@
                err("%s - error getting bytes available request", __FUNCTION__);
        }
 
+exit:
        kfree (transfer_buffer);
 
        /* continue on with initialization */
@@ -702,6 +800,46 @@
        return 0;
 }
 
+static void treo_attach (struct usb_serial *serial)
+{
+       struct usb_serial_port *port;
+       int i;
+
+       /* Only do this endpoint hack for the Handspring devices with
+        * interrupt in endpoints, which for now are the Treo devices. */
+       if ((serial->dev->descriptor.idVendor != HANDSPRING_VENDOR_ID) ||
+           (serial->num_interrupt_in == 0))
+               return;
+
+       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;
+       }
+}
+
 static void visor_shutdown (struct usb_serial *serial)
 {
        dbg("%s", __FUNCTION__);
@@ -849,4 +987,15 @@
 
 MODULE_PARM(debug, "i");
 MODULE_PARM_DESC(debug, "Debug enabled or not");
+
+
+
+
+
+
+
+
+
+
+
 
diff -Nru a/drivers/usb/serial/visor.h b/drivers/usb/serial/visor.h
--- a/drivers/usb/serial/visor.h        Thu Mar 27 16:02:35 2003
+++ b/drivers/usb/serial/visor.h        Thu Mar 27 16:02:35 2003
@@ -1,7 +1,7 @@
 /*
  * USB HandSpring Visor driver
  *
- *     Copyright (C) 1999 - 2002
+ *     Copyright (C) 1999 - 2003
  *         Greg Kroah-Hartman ([EMAIL PROTECTED])
  *
  *     This program is free software; you can redistribute it and/or modify
@@ -19,6 +19,7 @@
 
 #define HANDSPRING_VENDOR_ID           0x082d
 #define HANDSPRING_VISOR_ID            0x0100
+#define HANDSPRING_TREO_ID             0x0200
 
 #define PALM_VENDOR_ID                 0x0830
 #define PALM_M500_ID                   0x0001
@@ -40,6 +41,9 @@
 #define SONY_CLIE_NX60_ID              0x00DA
 #define SONY_CLIE_NZ90V_ID             0x00E9
 
+#define SAMSUNG_VENDOR_ID              0x04E8
+#define SAMSUNG_SCH_I330_ID            0x8001
+
 /****************************************************************************
  * Handspring Visor Vendor specific request codes (bRequest values)
  * A big thank you to Handspring for providing the following information.
@@ -95,7 +99,36 @@
  * PALM_GET_SOME_UNKNOWN_INFORMATION is sent by the host during enumeration to
  * get some information from the M series devices, that is currently unknown.
  ****************************************************************************/
-#define PALM_GET_SOME_UNKNOWN_INFORMATION      0x04
+#define PALM_GET_EXT_CONNECTION_INFORMATION    0x04
+
+/**
+ * struct palm_ext_connection_info - return data from a 
PALM_GET_EXT_CONNECTION_INFORMATION request
+ * @num_ports: maximum number of functions/connections in use
+ * @endpoint_numbers_different: will be 1 if in and out endpoints numbers are
+ *     different, otherwise it is 0.  If value is 1, then
+ *     connections.end_point_info is non-zero.  If value is 0, then
+ *     connections.port contains the endpoint number, which is the same for in
+ *     and out.
+ * @port_function_id: contains the creator id of the applicaton that opened
+ *     this connection.
+ * @port: contains the in/out endpoint number.  Is 0 if in and out endpoint
+ *     numbers are different.
+ * @end_point_info: high nubbe is in endpoint and low nibble will indicate out
+ *     endpoint.  Is 0 if in and out endpoints are the same.
+ *
+ * The maximum number of connections currently supported is 2
+ */
+struct palm_ext_connection_info {
+       __u8 num_ports;         
+       __u8 endpoint_numbers_different;
+       __u16 reserved1;
+       struct {
+               __u32 port_function_id;
+               __u8 port;
+               __u8 end_point_info;
+               __u16 reserved;
+       } connections[2];
+};
 
 #endif
 



-------------------------------------------------------
This SF.net email is sponsored by:
The Definitive IT and Networking Event. Be There!
NetWorld+Interop Las Vegas 2003 -- Register today!
http://ads.sourceforge.net/cgi-bin/redirect.pl?keyn0001en
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to