From: Greg KH To: Alan Cox Cc: linux-usb-devel@lists.sourceforge.net Subject: [PATCH 14 of 15] USB Serial Visor driver updated This patch updates the visor driver. diff -Nru a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c --- a/drivers/usb/serial/visor.c Thu Jan 3 21:41:53 2002 +++ b/drivers/usb/serial/visor.c Thu Jan 3 21:41:53 2002 @@ -1,7 +1,8 @@ /* - * USB HandSpring Visor driver + * USB HandSpring Visor, Palm m50x, and Sony Clie driver + * (supports all of the Palm OS USB devices) * - * Copyright (C) 1999, 2000 + * Copyright (C) 1999 - 2001 * Greg Kroah-Hartman (greg@kroah.com) * * This program is free software; you can redistribute it and/or modify @@ -11,6 +12,19 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * (08/30/2001) gkh + * Added support for the Clie devices, both the 3.5 and 4.0 os versions. + * Many thanks to Daniel Burke, and Bryan Payne for helping with this. + * + * (08/23/2001) gkh + * fixed a few potential bugs pointed out by Oliver Neukum. + * + * (05/30/2001) gkh + * switched from using spinlock to a semaphore, which fixes lots of problems. + * + * (05/28/2000) gkh + * Added initial support for the Palm m500 and Palm m505 devices. + * * (04/08/2001) gb * Identify version on module load. * @@ -27,8 +41,11 @@ * * (11/12/2000) gkh * Fixed bug with data being dropped on the floor by forcing tty->low_latency - * to be on. This fixes the OHCI issue! + * to be on. Hopefully this fixes the OHCI issue! * + * (11/01/2000) Adam J. Richter + * usb_device_id table support + * * (10/05/2000) gkh * Fixed bug with urb->dev not being set properly, now that the usb * core needs it. @@ -106,9 +123,9 @@ /* * Version Information */ -#define DRIVER_VERSION "v1.0.0" +#define DRIVER_VERSION "v1.4" #define DRIVER_AUTHOR "Greg Kroah-Hartman " -#define DRIVER_DESC "USB HandSpring Visor driver" +#define DRIVER_DESC "USB HandSpring Visor, Palm m50x, Sony Clie driver" #define MIN(a,b) (((a)<(b))?(a):(b)) @@ -127,13 +144,14 @@ static void visor_write_bulk_callback (struct urb *urb); static void visor_read_bulk_callback (struct urb *urb); + /* All of the device info needed for the Handspring Visor */ static __u16 handspring_vendor_id = HANDSPRING_VENDOR_ID; static __u16 handspring_product_id = HANDSPRING_VISOR_ID; struct usb_serial_device_type handspring_device = { name: "Handspring Visor", - idVendor: &handspring_vendor_id, /* the Handspring vendor ID */ - idProduct: &handspring_product_id, /* the Handspring Visor product id */ + idVendor: &handspring_vendor_id, + idProduct: &handspring_product_id, needs_interrupt_in: MUST_HAVE_NOT, /* this device must not have an interrupt in endpoint */ needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */ needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */ @@ -156,6 +174,117 @@ read_bulk_callback: visor_read_bulk_callback, }; +/* device info for the Palm M500 */ +static __u16 palm_vendor_id = PALM_VENDOR_ID; +static __u16 palm_m500_id = PALM_M500_ID; +static __u16 palm_m505_id = PALM_M505_ID; +struct usb_serial_device_type palm_m500_device = { + name: "Palm M500", + idVendor: &palm_vendor_id, + idProduct: &palm_m500_id, + needs_interrupt_in: MUST_HAVE_NOT, /* this device must not have an interrupt in endpoint */ + needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */ + needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */ + num_interrupt_in: 0, + num_bulk_in: 2, + num_bulk_out: 2, + num_ports: 2, + open: visor_open, + close: visor_close, + throttle: visor_throttle, + unthrottle: visor_unthrottle, + startup: visor_startup, + shutdown: visor_shutdown, + ioctl: visor_ioctl, + set_termios: visor_set_termios, + write: visor_write, + write_room: visor_write_room, + chars_in_buffer: visor_chars_in_buffer, + write_bulk_callback: visor_write_bulk_callback, + read_bulk_callback: visor_read_bulk_callback, +}; + +/* device info for the Palm M505 */ +struct usb_serial_device_type palm_m505_device = { + name: "Palm M505", + idVendor: &palm_vendor_id, + idProduct: &palm_m505_id, + needs_interrupt_in: MUST_HAVE_NOT, /* this device must not have an interrupt in endpoint */ + needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */ + needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */ + num_interrupt_in: 0, + num_bulk_in: 2, + num_bulk_out: 2, + num_ports: 2, + open: visor_open, + close: visor_close, + throttle: visor_throttle, + unthrottle: visor_unthrottle, + startup: visor_startup, + shutdown: visor_shutdown, + ioctl: visor_ioctl, + set_termios: visor_set_termios, + write: visor_write, + write_room: visor_write_room, + chars_in_buffer: visor_chars_in_buffer, + write_bulk_callback: visor_write_bulk_callback, + read_bulk_callback: visor_read_bulk_callback, +}; + +/* device info for the Sony Clie OS version 3.5 */ +static __u16 sony_vendor_id = SONY_VENDOR_ID; +static __u16 sony_3_5_id = SONY_CLIE_3_5_ID; +static __u16 sony_4_0_id = SONY_CLIE_4_0_ID; +static struct usb_serial_device_type clie_3_5_device = { + name: "Sony Clie 3.5", + idVendor: &sony_vendor_id, + idProduct: &sony_3_5_id, + needs_interrupt_in: MUST_HAVE_NOT, /* this device must not have an interrupt in endpoint */ + needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */ + needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */ + num_interrupt_in: 0, + num_bulk_in: 1, + num_bulk_out: 1, + num_ports: 1, + open: visor_open, + close: visor_close, + throttle: visor_throttle, + unthrottle: visor_unthrottle, + ioctl: visor_ioctl, + set_termios: visor_set_termios, + write: visor_write, + write_room: visor_write_room, + chars_in_buffer: visor_chars_in_buffer, + write_bulk_callback: visor_write_bulk_callback, + read_bulk_callback: visor_read_bulk_callback, +}; + +/* device info for the Sony Clie OS version 4.0 */ +static struct usb_serial_device_type clie_4_0_device = { + name: "Sony Clie 4.0", + idVendor: &sony_vendor_id, + idProduct: &sony_4_0_id, + needs_interrupt_in: MUST_HAVE_NOT, /* this device must not have an interrupt in endpoint */ + needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */ + needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */ + num_interrupt_in: 0, + num_bulk_in: 2, + num_bulk_out: 2, + num_ports: 2, + open: visor_open, + close: visor_close, + throttle: visor_throttle, + unthrottle: visor_unthrottle, + startup: visor_startup, + shutdown: visor_shutdown, + ioctl: visor_ioctl, + set_termios: visor_set_termios, + write: visor_write, + write_room: visor_write_room, + chars_in_buffer: visor_chars_in_buffer, + write_bulk_callback: visor_write_bulk_callback, + read_bulk_callback: visor_read_bulk_callback, +}; #define NUM_URBS 24 #define URB_TRANSFER_BUFFER_SIZE 768 @@ -171,15 +300,14 @@ static int visor_open (struct usb_serial_port *port, struct file *filp) { struct usb_serial *serial = port->serial; - unsigned long flags; - int result; + int result = 0; if (port_paranoia_check (port, __FUNCTION__)) return -ENODEV; dbg(__FUNCTION__ " - port %d", port->number); - spin_lock_irqsave (&port->port_lock, flags); + down (&port->sem); ++port->open_count; MOD_INC_USE_COUNT; @@ -204,9 +332,9 @@ err(__FUNCTION__ " - failed submitting read urb, error %d", result); } - spin_unlock_irqrestore (&port->port_lock, flags); + up (&port->sem); - return 0; + return result; } @@ -214,7 +342,6 @@ { struct usb_serial *serial; unsigned char *transfer_buffer; - unsigned long flags; if (port_paranoia_check (port, __FUNCTION__)) return; @@ -225,28 +352,33 @@ if (!serial) return; - spin_lock_irqsave (&port->port_lock, flags); + down (&port->sem); --port->open_count; if (port->open_count <= 0) { - transfer_buffer = kmalloc (0x12, GFP_KERNEL); - if (!transfer_buffer) { - err(__FUNCTION__ " - kmalloc(%d) failed.", 0x12); - } else { - /* send a shutdown message to the device */ - usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_CLOSE_NOTIFICATION, - 0xc2, 0x0000, 0x0000, transfer_buffer, 0x12, 300); - kfree (transfer_buffer); + if (serial->dev) { + /* only send a shutdown message if the + * device is still here */ + transfer_buffer = kmalloc (0x12, GFP_KERNEL); + if (!transfer_buffer) { + err(__FUNCTION__ " - kmalloc(%d) failed.", 0x12); + } else { + /* send a shutdown message to the device */ + usb_control_msg (serial->dev, + usb_rcvctrlpipe(serial->dev, 0), + VISOR_CLOSE_NOTIFICATION, 0xc2, + 0x0000, 0x0000, + transfer_buffer, 0x12, 300); + kfree (transfer_buffer); + } + /* shutdown our bulk read */ + usb_unlink_urb (port->read_urb); } - - /* shutdown our bulk read */ - usb_unlink_urb (port->read_urb); port->active = 0; port->open_count = 0; - } - spin_unlock_irqrestore (&port->port_lock, flags); + up (&port->sem); /* 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); */ @@ -268,8 +400,6 @@ dbg(__FUNCTION__ " - port %d", port->number); - usb_serial_debug_data (__FILE__, __FUNCTION__, count, buf); - while (count > 0) { /* try to find a free urb in our list of them */ urb = NULL; @@ -294,11 +424,17 @@ } transfer_size = MIN (count, URB_TRANSFER_BUFFER_SIZE); - if (from_user) - copy_from_user (urb->transfer_buffer, current_position, transfer_size); - else + if (from_user) { + if (copy_from_user (urb->transfer_buffer, current_position, transfer_size)) { + bytes_sent = -EFAULT; + break; + } + } else { memcpy (urb->transfer_buffer, current_position, transfer_size); - + } + + usb_serial_debug_data (__FILE__, __FUNCTION__, transfer_size, urb->transfer_buffer); + /* build up our urb */ FILL_BULK_URB (urb, serial->dev, usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress), urb->transfer_buffer, transfer_size, visor_write_bulk_callback, port); @@ -306,8 +442,11 @@ /* send it down the pipe */ status = usb_submit_urb(urb); - if (status) - dbg(__FUNCTION__ " - usb_submit_urb(write bulk) failed with status = %d", status); + if (status) { + err(__FUNCTION__ " - usb_submit_urb(write bulk) failed with status = %d", status); + bytes_sent = status; + break; + } current_position += transfer_size; bytes_sent += transfer_size; @@ -328,7 +467,7 @@ dbg(__FUNCTION__ " - port %d", port->number); - spin_lock_irqsave (&port->port_lock, flags); + spin_lock_irqsave (&write_urb_pool_lock, flags); for (i = 0; i < NUM_URBS; ++i) { if (write_urb_pool[i]->status != -EINPROGRESS) { @@ -336,7 +475,7 @@ } } - spin_unlock_irqrestore (&port->port_lock, flags); + spin_unlock_irqrestore (&write_urb_pool_lock, flags); dbg(__FUNCTION__ " - returns %d", room); return (room); @@ -351,7 +490,7 @@ dbg(__FUNCTION__ " - port %d", port->number); - spin_lock_irqsave (&port->port_lock, flags); + spin_lock_irqsave (&write_urb_pool_lock, flags); for (i = 0; i < NUM_URBS; ++i) { if (write_urb_pool[i]->status == -EINPROGRESS) { @@ -359,7 +498,7 @@ } } - spin_unlock_irqrestore (&port->port_lock, flags); + spin_unlock_irqrestore (&write_urb_pool_lock, flags); dbg (__FUNCTION__ " - returns %d", chars); return (chars); @@ -441,15 +580,14 @@ static void visor_throttle (struct usb_serial_port *port) { - unsigned long flags; dbg(__FUNCTION__ " - port %d", port->number); - spin_lock_irqsave (&port->port_lock, flags); + down (&port->sem); usb_unlink_urb (port->read_urb); - spin_unlock_irqrestore (&port->port_lock, flags); + up (&port->sem); return; } @@ -457,19 +595,18 @@ static void visor_unthrottle (struct usb_serial_port *port) { - unsigned long flags; int result; dbg(__FUNCTION__ " - port %d", port->number); - spin_lock_irqsave (&port->port_lock, flags); + down (&port->sem); port->read_urb->dev = port->serial->dev; result = usb_submit_urb(port->read_urb); if (result) err(__FUNCTION__ " - failed submitting read urb, error %d", result); - spin_unlock_irqrestore (&port->port_lock, flags); + up (&port->sem); return; } @@ -527,6 +664,29 @@ } } + if ((serial->dev->descriptor.idVendor == PALM_VENDOR_ID) || + (serial->dev->descriptor.idVendor == SONY_VENDOR_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(__FUNCTION__ " - error getting first unknown palm command"); + } else { + usb_serial_debug_data (__FILE__, __FUNCTION__, 0x14, transfer_buffer); + } + 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(__FUNCTION__ " - error getting second unknown palm command"); + } else { + usb_serial_debug_data (__FILE__, __FUNCTION__, 0x14, transfer_buffer); + } + } + /* 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); @@ -567,10 +727,16 @@ /* This function is all nice and good, but we don't change anything based on it :) */ static void visor_set_termios (struct usb_serial_port *port, struct termios *old_termios) { - unsigned int cflag = port->tty->termios->c_cflag; + unsigned int cflag; dbg(__FUNCTION__ " - port %d", port->number); + if ((!port->tty) || (!port->tty->termios)) { + dbg(__FUNCTION__" - no tty structures"); + return; + } + + cflag = port->tty->termios->c_cflag; /* check that they really want us to change something */ if (old_termios) { if ((cflag == old_termios->c_cflag) && @@ -580,11 +746,6 @@ } } - if ((!port->tty) || (!port->tty->termios)) { - dbg(__FUNCTION__" - no tty structures"); - return; - } - /* get the byte size */ switch (cflag & CSIZE) { case CS5: dbg(__FUNCTION__ " - data bits = 5"); break; @@ -635,6 +796,10 @@ int i; usb_serial_register (&handspring_device); + usb_serial_register (&palm_m500_device); + usb_serial_register (&palm_m505_device); + usb_serial_register (&clie_3_5_device); + usb_serial_register (&clie_4_0_device); /* create our write urb pool and transfer buffers */ spin_lock_init (&write_urb_pool_lock); @@ -654,7 +819,7 @@ } } - info(DRIVER_VERSION ":" DRIVER_DESC); + info(DRIVER_DESC " " DRIVER_VERSION); return 0; } @@ -666,6 +831,10 @@ unsigned long flags; usb_serial_deregister (&handspring_device); + usb_serial_deregister (&palm_m500_device); + usb_serial_deregister (&palm_m505_device); + usb_serial_deregister (&clie_3_5_device); + usb_serial_deregister (&clie_4_0_device); spin_lock_irqsave (&write_urb_pool_lock, flags); diff -Nru a/drivers/usb/serial/visor.h b/drivers/usb/serial/visor.h --- a/drivers/usb/serial/visor.h Thu Jan 3 21:41:53 2002 +++ b/drivers/usb/serial/visor.h Thu Jan 3 21:41:53 2002 @@ -1,7 +1,7 @@ /* * USB HandSpring Visor driver * - * Copyright (C) 1999, 2000 + * Copyright (C) 1999 - 2001 * Greg Kroah-Hartman (greg@kroah.com) * * This program is free software; you can redistribute it and/or modify @@ -20,6 +20,14 @@ #define HANDSPRING_VENDOR_ID 0x082d #define HANDSPRING_VISOR_ID 0x0100 +#define PALM_VENDOR_ID 0x0830 +#define PALM_M500_ID 0x0001 +#define PALM_M505_ID 0x0002 + +#define SONY_VENDOR_ID 0x054C +#define SONY_CLIE_3_5_ID 0x0038 +#define SONY_CLIE_4_0_ID 0x0066 + /**************************************************************************** * Handspring Visor Vendor specific request codes (bRequest values) * A big thank you to Handspring for providing the following information. @@ -29,7 +37,7 @@ /**************************************************************************** * VISOR_REQUEST_BYTES_AVAILABLE asks the visor for the number of bytes that - * are available to be transfered to the host for the specified endpoint. + * are available to be transferred to the host for the specified endpoint. * Currently this is not used, and always returns 0x0001 ****************************************************************************/ #define VISOR_REQUEST_BYTES_AVAILABLE 0x01 @@ -69,6 +77,13 @@ #define VISOR_FUNCTION_HOTSYNC 0x02 #define VISOR_FUNCTION_CONSOLE 0x03 #define VISOR_FUNCTION_REMOTE_FILE_SYS 0x04 + + +/**************************************************************************** + * 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 #endif