diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-07-21 22:00:56 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-07-21 22:00:56 +0000 |
commit | 168660f24dfc46c2702acbe4701a446f42a59578 (patch) | |
tree | f431368afbf6b1b71809cf3fd904d800ea126f4d /drivers/usb | |
parent | 6420f767924fa73b0ea267864d96820815f4ba5a (diff) |
Merge with Linux 2.4.0-test5-pre3.
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/Config.in | 8 | ||||
-rw-r--r-- | drivers/usb/microtek.c | 10 | ||||
-rw-r--r-- | drivers/usb/ov511.c | 63 | ||||
-rw-r--r-- | drivers/usb/serial/keyspan.c | 727 | ||||
-rw-r--r-- | drivers/usb/serial/keyspan.h | 326 | ||||
-rw-r--r-- | drivers/usb/serial/keyspan_usa28msg.h | 4 | ||||
-rw-r--r-- | drivers/usb/usb.c | 2 |
7 files changed, 844 insertions, 296 deletions
diff --git a/drivers/usb/Config.in b/drivers/usb/Config.in index 7e29c7807..51229c0c0 100644 --- a/drivers/usb/Config.in +++ b/drivers/usb/Config.in @@ -59,10 +59,10 @@ comment 'USB Devices' dep_tristate ' USB Kodak DC-2xx Camera support' CONFIG_USB_DC2XX $CONFIG_USB if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then dep_tristate ' USB Mustek MDC800 Digital Camera support (EXPERIMENTAL)' CONFIG_USB_MDC800 $CONFIG_USB - dep_tristate ' USB Mass Storage support (EXPERIMENTAL)' CONFIG_USB_STORAGE $CONFIG_USB $CONFIG_SCSI - if [ "$CONFIG_USB_STORAGE" != "n" ]; then - bool ' USB Mass Storage verbose debug' CONFIG_USB_STORAGE_DEBUG - fi + fi + dep_tristate ' USB Mass Storage support' CONFIG_USB_STORAGE $CONFIG_USB $CONFIG_SCSI + if [ "$CONFIG_USB_STORAGE" != "n" ]; then + bool ' USB Mass Storage verbose debug' CONFIG_USB_STORAGE_DEBUG fi dep_tristate ' USS720 parport driver' CONFIG_USB_USS720 $CONFIG_USB $CONFIG_PARPORT dep_tristate ' DABUSB driver' CONFIG_USB_DABUSB $CONFIG_USB diff --git a/drivers/usb/microtek.c b/drivers/usb/microtek.c index 70a50d91f..a3de2b732 100644 --- a/drivers/usb/microtek.c +++ b/drivers/usb/microtek.c @@ -151,18 +151,18 @@ static struct usb_driver mts_usb_driver = { #define MTS_NAME "microtek usb (rev " MTS_VERSION "): " #define MTS_WARNING(x...) \ - printk( KERN_WARNING MTS_NAME ## x ) + printk( KERN_WARNING MTS_NAME x ) #define MTS_ERROR(x...) \ - printk( KERN_ERR MTS_NAME ## x ) + printk( KERN_ERR MTS_NAME x ) #define MTS_INT_ERROR(x...) \ - MTS_ERROR( ## x ) + MTS_ERROR(x) #define MTS_MESSAGE(x...) \ - printk( KERN_INFO MTS_NAME ## x ) + printk( KERN_INFO MTS_NAME x ) #if defined MTS_DO_DEBUG #define MTS_DEBUG(x...) \ - printk( KERN_DEBUG MTS_NAME ## x ) + printk( KERN_DEBUG MTS_NAME x ) #define MTS_DEBUG_GOT_HERE() \ MTS_DEBUG("got to %s:%d (%s)\n", __FILE__, (int)__LINE__, __PRETTY_FUNCTION__ ) diff --git a/drivers/usb/ov511.c b/drivers/usb/ov511.c index 1862415fa..462a49957 100644 --- a/drivers/usb/ov511.c +++ b/drivers/usb/ov511.c @@ -30,7 +30,7 @@ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -static const char version[] = "1.19"; +static const char version[] = "1.20"; #define __NO_VERSION__ @@ -101,6 +101,12 @@ static int force_rgb = 0; /* Number of seconds before inactive buffers are deallocated */ static int buf_timeout = 5; +/* Number of cameras to stream from simultaneously */ +static int cams = 1; + +/* Prevent apps from timing out if frame is not done in time */ +static int retry_sync = 0; + MODULE_PARM(autoadjust, "i"); MODULE_PARM(debug, "i"); MODULE_PARM(fix_rgb_offset, "i"); @@ -110,6 +116,8 @@ MODULE_PARM(i2c_detect_tries, "i"); MODULE_PARM(aperture, "i"); MODULE_PARM(force_rgb, "i"); MODULE_PARM(buf_timeout, "i"); +MODULE_PARM(cams, "i"); +MODULE_PARM(retry_sync, "i"); MODULE_AUTHOR("Mark McClelland <mmcclelland@delphi.com> & Bret Wallach & Orion Sky Lawlor <olawlor@acm.org> & Kevin Moore & Charl P. Botha <cpbotha@ieee.org> & Claudio Matsuoka <claudio@conectiva.com>"); MODULE_DESCRIPTION("OV511 USB Camera Driver"); @@ -1676,7 +1684,7 @@ static void ov511_isoc_irq(struct urb *urb) static int ov511_init_isoc(struct usb_ov511 *ov511) { urb_t *urb; - int fx, err, n; + int fx, err, n, size; PDEBUG(3, "*** Initializing capture ***"); @@ -1686,11 +1694,29 @@ static int ov511_init_isoc(struct usb_ov511 *ov511) ov511->scratchlen = 0; if (ov511->bridge == BRG_OV511) - ov511_set_packet_size(ov511, 993); + if (cams == 1) size = 993; + else if (cams == 2) size = 513; + else if (cams == 3 || cams == 4) size = 257; + else { + err("\"cams\" parameter too high!"); + return -1; + } else if (ov511->bridge == BRG_OV511PLUS) - ov511_set_packet_size(ov511, 961); - else + if (cams == 1) size = 961; + else if (cams == 2) size = 513; + else if (cams == 3 || cams == 4) size = 257; + else if (cams >= 5 && cams <= 8) size = 129; + else if (cams >= 9 && cams <= 31) size = 33; + else { + err("\"cams\" parameter too high!"); + return -1; + } + else { err("invalid bridge type"); + return -1; + } + + ov511_set_packet_size(ov511, size); for (n = 0; n < OV511_NUMSBUF; n++) { urb = usb_alloc_urb(FRAMES_PER_DESC); @@ -2085,11 +2111,15 @@ static int ov511_ioctl(struct video_device *vdev, unsigned int cmd, void *arg) if (copy_from_user(&p, arg, sizeof(p))) return -EFAULT; + if (p.palette != VIDEO_PALETTE_GREY && + p.palette != VIDEO_PALETTE_RGB24 && + p.palette != VIDEO_PALETTE_YUV422 && + p.palette != VIDEO_PALETTE_YUV422P) + return -EINVAL; + if (ov7610_set_picture(ov511, &p)) return -EIO; - /* FIXME: check validity */ - PDEBUG(4, "Setting depth=%d, palette=%d", p.depth, p.palette); for (i = 0; i < OV511_NUMFRAMES; i++) { ov511->frame[i].depth = p.depth; @@ -2294,8 +2324,23 @@ redo: init_waitqueue_head(&ov511->frame[frame].wq); #endif interruptible_sleep_on(&ov511->frame[frame].wq); - if (signal_pending(current)) - return -EINTR; + if (signal_pending(current)) { + if (retry_sync) { + PDEBUG(3, "***retry sync***"); + + /* Polling apps will destroy frames with that! */ + ov511_new_frame(ov511, frame); + ov511->curframe = -1; + + /* This will request another frame. */ + if (waitqueue_active(&ov511->frame[frame].wq)) + wake_up_interruptible(&ov511->frame[frame].wq); + + return 0; + } else { + return -EINTR; + } + } } while (ov511->frame[frame].grabstate == FRAME_GRABBING); if (ov511->frame[frame].grabstate == FRAME_ERROR) { diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index 6bd9074a9..397e2bf48 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c @@ -22,9 +22,9 @@ Tip 'o the hat to Linuxcare for supporting staff in their work on open source projects. - Sat Jul 8 11:11:48 EST 2000 Hugh - First public release - nothing works except the firmware upload. - Tested on PPC and x86 architectures, seems to behave... + Tue Jul 18 16:14:52 EST 2000 Hugh + Basic character input/output for USA-19 now mostly works, + fixed at 9600 baud for the moment. */ @@ -55,94 +55,45 @@ #include <linux/usb.h> #include "usb-serial.h" - -struct ezusb_hex_record { - __u16 address; - __u8 data_size; - __u8 data[16]; +#include "keyspan.h" + + /* Per device and per port private data */ +struct keyspan_serial_private { + struct urb *in_urbs[8]; + struct urb *out_urbs[8]; + char out_buffer[64]; + char in_buffer[64]; }; - /* Conditionally include firmware images, if they aren't - included create a null pointer instead. Current - firmware images aren't optimised to remove duplicate - addresses. */ -#ifdef CONFIG_USB_SERIAL_KEYSPAN_USA28 - #include "keyspan_usa28_fw.h" -#else - static const struct ezusb_hex_record *keyspan_usa28_firmware = NULL; -#endif +struct keyspan_port_private { + /* Keep track of which output endpoint to use */ + int out_flip; -#ifdef CONFIG_USB_SERIAL_KEYSPAN_USA28X - #include "keyspan_usa28x_fw.h" -#else - static const struct ezusb_hex_record *keyspan_usa28x_firmware = NULL; -#endif + /* Settings for the port */ + int baud; + int old_baud; + enum {parity_none, parity_odd, parity_even} parity; + enum {flow_none, flow_cts, flow_xon} flow_control; + int rts_state; + int dtr_state; -#ifdef CONFIG_USB_SERIAL_KEYSPAN_USA19 - #include "keyspan_usa19_fw.h" -#else - static const struct ezusb_hex_record *keyspan_usa19_firmware = NULL; -#endif - -#ifdef CONFIG_USB_SERIAL_KEYSPAN_USA18X - #include "keyspan_usa18x_fw.h" -#else - static const struct ezusb_hex_record *keyspan_usa18x_firmware = NULL; -#endif +}; -#ifdef CONFIG_USB_SERIAL_KEYSPAN_USA19W - #include "keyspan_usa19w_fw.h" -#else - static const struct ezusb_hex_record *keyspan_usa19w_firmware = NULL; -#endif - /* Include Keyspan message headers (not here yet, need some tweaks + /* FIXME this will break if multiple physical interfaces used */ +static wait_queue_head_t out_wait; + + /* Include Keyspan message headers (not both yet, need some tweaks to get clean build) */ /*#include "keyspan_usa26msg.h"*/ -/*#include "keyspan_usa28msg.h"*/ +#include "keyspan_usa28msg.h" /* If you don't get debugging output, uncomment the following two lines to enable cheat. */ #undef dbg #define dbg printk - - /* function prototypes for Keyspan serial converter */ -static int keyspan_open (struct usb_serial_port *port, - struct file *filp); -static void keyspan_close (struct usb_serial_port *port, - struct file *filp); -static int keyspan_startup (struct usb_serial *serial); -static void keyspan_shutdown (struct usb_serial *serial); -static void keyspan_rx_interrupt (struct urb *urb); -static void keyspan_rx_throttle (struct usb_serial_port *port); -static void keyspan_rx_unthrottle (struct usb_serial_port *port); -static int keyspan_write_room (struct usb_serial_port *port); -static int keyspan_write (struct usb_serial_port *port, - int from_user, - const unsigned char *buf, - int count); -static void keyspan_write_bulk_callback (struct urb *urb); -static int keyspan_chars_in_buffer (struct usb_serial_port *port); -static int keyspan_ioctl (struct usb_serial_port *port, - struct file *file, - unsigned int cmd, - unsigned long arg); -static void keyspan_set_termios (struct usb_serial_port *port, - struct termios *old); -static void keyspan_break_ctl (struct usb_serial_port *port, - int break_state); -static int keyspan_fake_startup (struct usb_serial *serial); - - /* Functions - mostly stubs for now */ - -static void keyspan_rx_interrupt (struct urb *urb) -{ - -} - - static void keyspan_rx_throttle (struct usb_serial_port *port) { dbg("keyspan_rx_throttle port %d", port->number); @@ -170,8 +121,23 @@ static void keyspan_set_termios (struct usb_serial_port *port, static int keyspan_ioctl(struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg) { + unsigned int value; dbg("keyspan_ioctl_info"); + + switch (cmd) { + case TIOCMGET: + value = TIOCM_DTR | TIOCM_RNG; + if (copy_to_user((unsigned int *)arg, &value, sizeof(int))) { + return -EFAULT; + } + else { + return 0; + } + + default: + return -ENOIOCTLCMD; + } return -ENOIOCTLCMD; } @@ -179,22 +145,151 @@ static int keyspan_ioctl(struct usb_serial_port *port, struct file *file, static int keyspan_write(struct usb_serial_port *port, int from_user, const unsigned char *buf, int count) { - dbg("keyspan_write called\n"); - return(count); + struct usb_serial *serial = port->serial; + struct keyspan_serial_private *s_priv; + struct keyspan_port_private *p_priv; + int current_urb; + int i; + + s_priv = (struct keyspan_serial_private *)(serial->private); + p_priv = (struct keyspan_port_private *)(port->private); + + if (p_priv->out_flip == 0) { + current_urb = 0; + p_priv->out_flip = 1; + } + else { + current_urb = 1; + p_priv->out_flip = 0; + } + + dbg("keyspan_write called for port %d (%d) chars {", port->number, count); + for (i = 0; i < count ; i++) { + dbg("%02x ", buf[i]); + } + dbg("}\n"); + + if (count == 0) { + dbg("write request of 0 bytes"); + return (0); + } + + /* only send data if we have a bulk out endpoint */ + if (s_priv->out_urbs[current_urb]) { + while (s_priv->out_urbs[current_urb]->status == -EINPROGRESS) { + dbg (__FUNCTION__ " INPROGRES\n"); + interruptible_sleep_on(&out_wait); + if (signal_pending(current)) { + dbg (__FUNCTION__ " signal\n"); + return (-ERESTARTSYS); + } + } + /*if (s_priv->out_urbs[current_urb]->status == -EINPROGRESS) { + dbg ("already writing"); + return (-EAGAIN); + }*/ + /* First byte in buffer is "last flag" - unused so + for now so set to zero */ + memset(s_priv->out_urbs[current_urb]->transfer_buffer, 0, 1); + + if (from_user) { + copy_from_user(s_priv->out_urbs[current_urb]->transfer_buffer + 1, buf, count); + } + else { + memcpy (s_priv->out_urbs[current_urb]->transfer_buffer + 1, buf, count); + } + + /* send the data out the bulk port */ + s_priv->out_urbs[current_urb]->transfer_buffer_length = count + 1; + + if (usb_submit_urb(s_priv->out_urbs[current_urb])) { + dbg("usb_submit_urb(write bulk) failed"); + } + + return (count); + } + + /* no bulk out, so return 0 bytes written */ + return (0); } static void keyspan_write_bulk_callback (struct urb *urb) { + int endpoint; + + endpoint = usb_pipeendpoint(urb->pipe); + + dbg("keyspan_write_bulk_callback for endpoint %d\n", endpoint); + + /* Only do wakeup if this callback is from one of the data + endpoints. */ + if (endpoint == 2 || endpoint == 3) { + wake_up_interruptible(&out_wait); + } - dbg("keyspan_write_bulk_callback called\n"); } +static void keyspan_read_bulk_callback (struct urb *urb) +{ + int i; + int endpoint; + struct usb_serial *serial; + struct usb_serial_port *port; + struct tty_struct *tty; + unsigned char *data = urb->transfer_buffer; + + endpoint = usb_pipeendpoint(urb->pipe); + + + if (urb->status) { + dbg(__FUNCTION__ "nonzero status: %x on endpoint %d.\n", + urb->status, endpoint); + return; + } + + switch (endpoint) { + + /* If this is one of the data endpoints, stuff it's + contents into the tty flip_buffer. */ + case 1: + case 2: serial = (struct usb_serial *) urb->context; + port = &serial->port[0]; + tty = port->tty; + if (urb->actual_length) { + for (i = 0; i < urb->actual_length ; ++i) { + tty_insert_flip_char(tty, data[i], 0); + } + tty_flip_buffer_push(tty); + } + break; + + /* INACK endpoint */ + case 3: dbg(__FUNCTION__ " callback for INACK endpoint\n"); + break; + + /* INSTAT endpoint */ + case 4: dbg(__FUNCTION__ " callback for INSTAT endpoint\n"); + break; + + default: + dbg(__FUNCTION__ " callback for unknown endpoint!\n"); + break; + } + + /* Resubmit urb so we continue receiving */ + if (usb_submit_urb(urb)) { + dbg(__FUNCTION__ "resubmit read urb failed.\n"); + } + return; + +} + static int keyspan_write_room (struct usb_serial_port *port) { - dbg("keyspan_write_room called\n"); - return (1); +// dbg("keyspan_write_room called\n"); + return (32); } @@ -207,13 +302,64 @@ static int keyspan_chars_in_buffer (struct usb_serial_port *port) static int keyspan_open (struct usb_serial_port *port, struct file *filp) { - dbg("keyspan_open called\n"); + struct keyspan_port_private *p_priv; + struct keyspan_serial_private *s_priv; + struct usb_serial *serial = port->serial; + int i; + + s_priv = (struct keyspan_serial_private *)(serial->private); + p_priv = (struct keyspan_port_private *)(port->private); + + dbg("keyspan_open called.\n"); + + if (port->active) { + dbg(__FUNCTION__ "port->active already true!\n"); + return (-EINVAL); + } + + p_priv = (struct keyspan_port_private *)(port->private); + + p_priv->out_flip = 0; + port->active = 1; + + /* Start reading from port */ + for (i = 0; i < 4; i++) { + if (s_priv->in_urbs[i]) { + if (usb_submit_urb(s_priv->in_urbs[i])) { + dbg(__FUNCTION__ " submit in urb %d failed", i); + } + } + + } + + keyspan_usa19_send_setup(serial, port); + return (0); } static void keyspan_close(struct usb_serial_port *port, struct file *filp) { + int i; + struct usb_serial *serial = port->serial; /* FIXME should so sanity check */ + struct keyspan_serial_private *s_priv; + + s_priv = (struct keyspan_serial_private *)(serial->private); + + /* Stop reading/writing urbs */ + for (i = 0; i < 4; i++) { + if (s_priv->in_urbs[i]) { + usb_unlink_urb(s_priv->in_urbs[i]); + } + + } + for (i = 0; i < 3; i++) { + if (s_priv->out_urbs[i]) { + usb_unlink_urb(s_priv->out_urbs[i]); + } + + } + port->active = 0; dbg("keyspan_close called\n"); } @@ -283,230 +429,261 @@ static int keyspan_fake_startup (struct usb_serial *serial) } record++; } - /* bring device out of reset. Renumeration will occur in a moment - and the new device will bind to the real driver */ + /* bring device out of reset. Renumeration will occur in a + moment and the new device will bind to the real driver */ response = ezusb_set_reset(serial, 0); - /* we want this device to fail to have a driver assigned to it. */ + /* we don't want this device to have a driver assigned to it. */ return (1); } - - /* Gets called by the "real" driver (ie once firmware is loaded - and renumeration has taken place. */ -static int keyspan_startup (struct usb_serial *serial) + /* USA-19 uses three output endpoints and four input + endpoints. First two output endpoints are for + data (used in an alternating fashion), the third is + output control. First two input endpoints are for + data (again alternating), the third is the ACK + endpoint, the fourth is input status. */ +static void keyspan_usa19_setup_urbs(struct usb_serial *serial) { - dbg("keyspan_startup called.\n"); + struct keyspan_serial_private *s_priv; + int i; - return (0); + s_priv = (struct keyspan_serial_private *)(serial->private); + + /* Output urbs first */ + dbg(__FUNCTION__ "Allocating output urbs.\n"); + for (i = 0; i < 3; i++) { + + s_priv->out_urbs[i] = usb_alloc_urb (0); /* No ISO */ + if (!s_priv->out_urbs[i]) { + dbg (__FUNCTION__ "Alloc for %d out urb failed.\n", i); + return; + } + + FILL_BULK_URB(s_priv->out_urbs[i], serial->dev, + usb_sndbulkpipe(serial->dev, i + 1), + &s_priv->out_buffer[i], sizeof(s_priv->out_buffer[i]), + keyspan_write_bulk_callback, + serial); + } + + /* Now input urbs */ + dbg(__FUNCTION__ "Allocating input urbs.\n"); + for (i = 0; i < 4; i++) { + + s_priv->in_urbs[i] = usb_alloc_urb (0); /* No ISO */ + if (!s_priv->in_urbs[i]) { + dbg (__FUNCTION__ "Alloc for %d in urb failed.\n", i); + return; + } + + FILL_BULK_URB(s_priv->in_urbs[i], serial->dev, + usb_rcvbulkpipe(serial->dev, i + 0x81), + &s_priv->in_buffer[i], sizeof(s_priv->in_buffer[i]), + keyspan_read_bulk_callback, + serial); + } + } -static void keyspan_shutdown (struct usb_serial *serial) +static int keyspan_usa19_calc_baud(u32 baud_rate, u8 *rate_hi, u8 *rate_low) { - dbg("keyspan_shutdown called.\n"); + u32 b16, /* baud rate times 16 (actual rate used internally) */ + div, /* divisor */ + cnt; /* inverse of divisor (programmed into 8051) */ + + /* prevent divide by zero... */ + if( (b16 = (baud_rate * 16L)) == 0) { + return (KEYSPAN_INVALID_BAUD_RATE); + } + + /* calculate the divisor and the counter (its inverse) */ + if( (div = (USA19_BAUDCLK / b16)) == 0) { + return (KEYSPAN_INVALID_BAUD_RATE); + } + else { + cnt = 0 - div; + } + + if(div > 0xffff) { + return (KEYSPAN_INVALID_BAUD_RATE); + } + + /* return the counter values */ + *rate_low = (u8) (cnt & 0xff); + *rate_hi = (u8) ((cnt >> 8) & 0xff); + dbg(__FUNCTION__ " Baud rate of %d is %02x %02x.\n", baud_rate, *rate_hi, *rate_low); + + return (KEYSPAN_BAUD_RATE_OK); } - /* Miscellaneous defines, datastructures etc. */ - -#define KEYSPAN_VENDOR_ID 0x06cd - - /* Device info needed for the Keyspan serial converter */ -static __u16 keyspan_vendor_id = KEYSPAN_VENDOR_ID; - - /* Product IDs for the five products supported, pre-renumeration */ -static __u16 keyspan_usa18x_pre_product_id = 0x0105; -static __u16 keyspan_usa19_pre_product_id = 0x0103; -static __u16 keyspan_usa19w_pre_product_id = 0x0106; -static __u16 keyspan_usa28_pre_product_id = 0x0101; -static __u16 keyspan_usa28x_pre_product_id = 0x0102; - - /* Product IDs post-renumeration */ -static __u16 keyspan_usa18x_product_id = 0x0112; -static __u16 keyspan_usa19_product_id = 0x0107; -static __u16 keyspan_usa19w_product_id = 0x0108; -static __u16 keyspan_usa28_product_id = 0x010f; -static __u16 keyspan_usa28x_product_id = 0x0110; - - /* Structs for the devices, pre and post renumeration. - These are incomplete at present - HAB 20000708 */ -struct usb_serial_device_type keyspan_usa18x_pre_device = { - name: "Keyspan USA18X - (prerenumeration)", - idVendor: &keyspan_vendor_id, - idProduct: &keyspan_usa18x_pre_product_id, - needs_interrupt_in: DONT_CARE, - needs_bulk_in: DONT_CARE, - needs_bulk_out: DONT_CARE, - num_interrupt_in: NUM_DONT_CARE, - num_bulk_in: NUM_DONT_CARE, - num_bulk_out: NUM_DONT_CARE, - num_ports: 1, - startup: keyspan_fake_startup -}; +static int keyspan_usa19_send_setup(struct usb_serial *serial, struct usb_serial_port *port) +{ + struct portControlMessage msg; + struct keyspan_serial_private *s_priv; + struct keyspan_port_private *p_priv; -struct usb_serial_device_type keyspan_usa19_pre_device = { - name: "Keyspan USA19 - (prerenumeration)", - idVendor: &keyspan_vendor_id, - idProduct: &keyspan_usa19_pre_product_id, - needs_interrupt_in: DONT_CARE, - needs_bulk_in: DONT_CARE, - needs_bulk_out: DONT_CARE, - num_interrupt_in: NUM_DONT_CARE, - num_bulk_in: NUM_DONT_CARE, - num_bulk_out: NUM_DONT_CARE, - num_ports: 1, - startup: keyspan_fake_startup -}; + s_priv = (struct keyspan_serial_private *)(serial->private); + p_priv = (struct keyspan_port_private *)(port->private); + //memset(msg, 0, sizeof (struct portControlMessage)); + + msg.setBaudRate = 1; + if (keyspan_usa19_calc_baud(9600, &msg.baudHi, &msg.baudLo) == + KEYSPAN_INVALID_BAUD_RATE ) { + dbg(__FUNCTION__ "Invalid baud rate requested %d.\n", 9600); + msg.baudLo = 0xff; + msg.baudHi = 0xb2; /* Values for 9600 baud */ + } -struct usb_serial_device_type keyspan_usa19w_pre_device = { - name: "Keyspan USA19W - (prerenumeration)", - idVendor: &keyspan_vendor_id, - idProduct: &keyspan_usa19w_pre_product_id, - needs_interrupt_in: DONT_CARE, - needs_bulk_in: DONT_CARE, - needs_bulk_out: DONT_CARE, - num_interrupt_in: NUM_DONT_CARE, - num_bulk_in: NUM_DONT_CARE, - num_bulk_out: NUM_DONT_CARE, - num_ports: 1, - startup: keyspan_fake_startup -}; + /* If parity is enabled, we must calculate it ourselves. */ + if (p_priv->parity) { + msg.parity = 1; + } + else { + msg.parity = 0; + } + msg.ctsFlowControl = 0; + msg.xonFlowControl = 0; + msg.rts = 1; + msg.dtr = 0; + + msg.forwardingLength = 1; + msg.forwardMs = 10; + msg.breakThreshold = 45; + msg.xonChar = 17; + msg.xoffChar = 19; + + msg._txOn = 1; + msg._txOff = 0; + msg.txFlush = 0; + msg.txForceXoff = 0; + msg.txBreak = 0; + msg.rxOn = 1; + msg.rxOff = 0; + msg.rxFlush = 0; + msg.rxForward = 0; + msg.returnStatus = 1; + msg.resetDataToggle = 1; -struct usb_serial_device_type keyspan_usa28_pre_device = { - name: "Keyspan USA28 - (prerenumeration)", - idVendor: &keyspan_vendor_id, - idProduct: &keyspan_usa28_pre_product_id, - needs_interrupt_in: DONT_CARE, - needs_bulk_in: DONT_CARE, - needs_bulk_out: DONT_CARE, - num_interrupt_in: NUM_DONT_CARE, - num_bulk_in: NUM_DONT_CARE, - num_bulk_out: NUM_DONT_CARE, - num_ports: 2, - startup: keyspan_fake_startup -}; + + /* only do something if we have a bulk out endpoint */ + if (s_priv->out_urbs[2]) { + if (s_priv->out_urbs[2]->status == -EINPROGRESS) { + dbg (__FUNCTION__ " already writing"); + return(-1); + } + memcpy (s_priv->out_urbs[2]->transfer_buffer, &msg, sizeof(msg)); + + /* send the data out the device on control endpoint */ + s_priv->out_urbs[2]->transfer_buffer_length = sizeof(msg); -struct usb_serial_device_type keyspan_usa28x_pre_device = { - name: "Keyspan USA28X - (prerenumeration)", - idVendor: &keyspan_vendor_id, - idProduct: &keyspan_usa28x_pre_product_id, - needs_interrupt_in: DONT_CARE, - needs_bulk_in: DONT_CARE, - needs_bulk_out: DONT_CARE, - num_interrupt_in: NUM_DONT_CARE, - num_bulk_in: NUM_DONT_CARE, - num_bulk_out: NUM_DONT_CARE, - num_ports: 2, - startup: keyspan_fake_startup -}; + if (usb_submit_urb(s_priv->out_urbs[2])) { + dbg(__FUNCTION__ " usb_submit_urb(setup) failed\n"); + } + else { + dbg(__FUNCTION__ " usb_submit_urb(setup) OK %d bytes\n", s_priv->out_urbs[2]->transfer_buffer_length); + } + + } + return (0); +} -struct usb_serial_device_type keyspan_usa18x_device = { - name: "Keyspan USA18X", - idVendor: &keyspan_vendor_id, - idProduct: &keyspan_usa18x_product_id, - needs_interrupt_in: DONT_CARE, - needs_bulk_in: DONT_CARE, - needs_bulk_out: DONT_CARE, - num_interrupt_in: NUM_DONT_CARE, - num_bulk_in: NUM_DONT_CARE, - num_bulk_out: NUM_DONT_CARE, - num_ports: 1, - open: keyspan_open, - close: keyspan_close, - throttle: keyspan_rx_throttle, - unthrottle: keyspan_rx_unthrottle, - set_termios: keyspan_set_termios, -}; + /* Gets called by the "real" driver (ie once firmware is loaded + and renumeration has taken place. */ +static int keyspan_startup (struct usb_serial *serial) +{ + int i; + struct usb_serial_port *port; -struct usb_serial_device_type keyspan_usa19_device = { - name: "Keyspan USA19", - idVendor: &keyspan_vendor_id, - idProduct: &keyspan_usa19_product_id, - needs_interrupt_in: DONT_CARE, - needs_bulk_in: DONT_CARE, - needs_bulk_out: DONT_CARE, - num_interrupt_in: NUM_DONT_CARE, - num_bulk_in: NUM_DONT_CARE, - num_bulk_out: NUM_DONT_CARE, - num_ports: 1, - open: keyspan_open, - close: keyspan_close, - write: keyspan_write, - write_room: keyspan_write_room, - write_bulk_callback: keyspan_write_bulk_callback, - read_int_callback: keyspan_rx_interrupt, - chars_in_buffer: keyspan_chars_in_buffer, - throttle: keyspan_rx_throttle, - unthrottle: keyspan_rx_unthrottle, - ioctl: keyspan_ioctl, - set_termios: keyspan_set_termios, - break_ctl: keyspan_break_ctl, - startup: keyspan_startup, - shutdown: keyspan_shutdown, -}; + dbg("keyspan_startup called.\n"); + /* Setup private data for serial driver */ + serial->private = kmalloc(sizeof(struct keyspan_serial_private), GFP_KERNEL); + if (!serial->private) { + dbg(__FUNCTION__ "kmalloc for keyspan_serial_private failed!.\n"); + return (1); + } + memset(serial->private, 0, sizeof(struct keyspan_serial_private)); + + init_waitqueue_head(&out_wait); + + /* Now setup per port private data */ + for (i = 0; i < serial->num_ports; i++) { + port = &serial->port[i]; + port->private = kmalloc(sizeof(struct keyspan_port_private), GFP_KERNEL); + if (!port->private) { + dbg(__FUNCTION__ "kmalloc for keyspan_port_private (%d) failed!.\n", i); + return (1); + } + memset(port->private, 0, sizeof(struct keyspan_port_private)); + } -struct usb_serial_device_type keyspan_usa19w_device = { - name: "Keyspan USA19W", - idVendor: &keyspan_vendor_id, - idProduct: &keyspan_usa19w_product_id, - needs_interrupt_in: DONT_CARE, - needs_bulk_in: DONT_CARE, - needs_bulk_out: DONT_CARE, - num_interrupt_in: NUM_DONT_CARE, - num_bulk_in: NUM_DONT_CARE, - num_bulk_out: NUM_DONT_CARE, - num_ports: 1, - open: keyspan_open, - close: keyspan_close, - throttle: keyspan_rx_throttle, - unthrottle: keyspan_rx_unthrottle, - set_termios: keyspan_set_termios, -}; + + switch (serial->dev->descriptor.idProduct) { + case 0x0107: keyspan_usa19_setup_urbs(serial); + //keyspan_send_usa19_setup(serial); + break; -struct usb_serial_device_type keyspan_usa28_device = { - name: "Keyspan USA28", - idVendor: &keyspan_vendor_id, - idProduct: &keyspan_usa28_product_id, - needs_interrupt_in: DONT_CARE, - needs_bulk_in: DONT_CARE, - needs_bulk_out: DONT_CARE, - num_interrupt_in: NUM_DONT_CARE, - num_bulk_in: NUM_DONT_CARE, - num_bulk_out: NUM_DONT_CARE, - num_ports: 2, - open: keyspan_open, - close: keyspan_close, - throttle: keyspan_rx_throttle, - unthrottle: keyspan_rx_unthrottle, - set_termios: keyspan_set_termios, -}; + default: break; + } + + return (0); +} -struct usb_serial_device_type keyspan_usa28x_device = { - name: "Keyspan USA28X", - idVendor: &keyspan_vendor_id, - idProduct: &keyspan_usa28x_product_id, - needs_interrupt_in: DONT_CARE, - needs_bulk_in: DONT_CARE, - needs_bulk_out: DONT_CARE, - num_interrupt_in: NUM_DONT_CARE, - num_bulk_in: NUM_DONT_CARE, - num_bulk_out: NUM_DONT_CARE, - num_ports: 2, - open: keyspan_open, - close: keyspan_close, - throttle: keyspan_rx_throttle, - unthrottle: keyspan_rx_unthrottle, - set_termios: keyspan_set_termios, -}; +static void keyspan_shutdown (struct usb_serial *serial) +{ + int i; + struct usb_serial_port *port; + struct keyspan_serial_private *s_priv; + dbg("keyspan_shutdown called freeing "); + s_priv = (struct keyspan_serial_private *)(serial->private); + + /* Stop reading/writing urbs */ + for (i = 0; i < 4; i++) { + if (s_priv->in_urbs[i]) { + usb_unlink_urb(s_priv->in_urbs[i]); + } + + } + for (i = 0; i < 3; i++) { + if (s_priv->out_urbs[i]) { + usb_unlink_urb(s_priv->out_urbs[i]); + } + } + /* Now free them */ + for (i = 0; i < 7; i ++) { + if (s_priv->in_urbs[i] != NULL) { + dbg("in%d ", i); + usb_free_urb(s_priv->in_urbs[i]); + } + + if (s_priv->out_urbs[i] != NULL) { + dbg("out%d ", i); + usb_free_urb(s_priv->out_urbs[i]); + } + } + dbg("urbs.\n"); + + dbg("Freeing serial->private.\n"); + kfree(serial->private); + + dbg("Freeing port->private.\n"); + /* Now free per port private data */ + for (i = 0; i < serial->num_ports; i++) { + port = &serial->port[i]; + kfree(port->private); + } + +} #endif /* CONFIG_USB_SERIAL_KEYSPAN */ diff --git a/drivers/usb/serial/keyspan.h b/drivers/usb/serial/keyspan.h new file mode 100644 index 000000000..ce966dc4f --- /dev/null +++ b/drivers/usb/serial/keyspan.h @@ -0,0 +1,326 @@ +/* + Keyspan USB to Serial Converter driver + + (C) Copyright (C) 2000 + Hugh Blemings <hugh@linuxcare.com> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + See http://www.linuxcare.com.au/hugh/keyspan.html for more + information on this driver. + + Code in this driver inspired by and in a number of places taken + from Brian Warner's original Keyspan-PDA driver. + + This driver has been put together with the support of Innosys, Inc. + and Keyspan, Inc the manufacturers of the Keyspan USB-serial products. + Thanks Guys :) + + Tip 'o the hat to Linuxcare for supporting staff in their work on + open source projects. + + See keyspan.c for update history. + +*/ + +#ifndef __LINUX_USB_SERIAL_KEYSPAN_H +#define __LINUX_USB_SERIAL_KEYSPAN_H + + + /* Function prototypes for Keyspan serial converter */ +static int keyspan_open (struct usb_serial_port *port, + struct file *filp); +static void keyspan_close (struct usb_serial_port *port, + struct file *filp); +static int keyspan_startup (struct usb_serial *serial); +static void keyspan_shutdown (struct usb_serial *serial); +static void keyspan_rx_throttle (struct usb_serial_port *port); +static void keyspan_rx_unthrottle (struct usb_serial_port *port); +static int keyspan_write_room (struct usb_serial_port *port); +static int keyspan_write (struct usb_serial_port *port, + int from_user, + const unsigned char *buf, + int count); +static void keyspan_write_bulk_callback (struct urb *urb); +static void keyspan_read_bulk_callback (struct urb *urb); +static int keyspan_chars_in_buffer (struct usb_serial_port *port); +static int keyspan_ioctl (struct usb_serial_port *port, + struct file *file, + unsigned int cmd, + unsigned long arg); +static void keyspan_set_termios (struct usb_serial_port *port, + struct termios *old); +static void keyspan_break_ctl (struct usb_serial_port *port, + int break_state); +static int keyspan_fake_startup (struct usb_serial *serial); + +static int keyspan_usa19_calc_baud (u32 baud_rate, u8 *rate_hi, + u8 *rate_low); +static void keyspan_usa19_setup_urbs (struct usb_serial *serial); +static int keyspan_usa19_send_setup (struct usb_serial *serial, + struct usb_serial_port *port); + + + /* Functions from usbserial.c for ezusb firmware handling */ +extern int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit); +extern int ezusb_writememory (struct usb_serial *serial, int address, unsigned char *data, int length, __u8 bRequest); + + /* Struct used for firmware */ +struct ezusb_hex_record { + __u16 address; + __u8 data_size; + __u8 data[16]; +}; + /* Conditionally include firmware images, if they aren't + included create a null pointer instead. Current + firmware images aren't optimised to remove duplicate + addresses. */ +#ifdef CONFIG_USB_SERIAL_KEYSPAN_USA28 + #include "keyspan_usa28_fw.h" +#else + static const struct ezusb_hex_record *keyspan_usa28_firmware = NULL; +#endif + +#ifdef CONFIG_USB_SERIAL_KEYSPAN_USA28X + #include "keyspan_usa28x_fw.h" +#else + static const struct ezusb_hex_record *keyspan_usa28x_firmware = NULL; +#endif + +#ifdef CONFIG_USB_SERIAL_KEYSPAN_USA19 + #include "keyspan_usa19_fw.h" +#else + static const struct ezusb_hex_record *keyspan_usa19_firmware = NULL; +#endif + +#ifdef CONFIG_USB_SERIAL_KEYSPAN_USA18X + #include "keyspan_usa18x_fw.h" +#else + static const struct ezusb_hex_record *keyspan_usa18x_firmware = NULL; +#endif + +#ifdef CONFIG_USB_SERIAL_KEYSPAN_USA19W + #include "keyspan_usa19w_fw.h" +#else + static const struct ezusb_hex_record *keyspan_usa19w_firmware = NULL; +#endif + + + /* Values used for baud rate calculation - device specific */ +#define KEYSPAN_INVALID_BAUD_RATE (-1) +#define KEYSPAN_BAUD_RATE_OK (0) +#define USA19_BAUDCLK (12000000L) + + /* Device info for the Keyspan serial converter */ +#define KEYSPAN_VENDOR_ID (0x06cd) +static __u16 keyspan_vendor_id = KEYSPAN_VENDOR_ID; + + /* Product IDs for the five products supported, pre-renumeration */ +static __u16 keyspan_usa18x_pre_product_id = 0x0105; +static __u16 keyspan_usa19_pre_product_id = 0x0103; +static __u16 keyspan_usa19w_pre_product_id = 0x0106; +static __u16 keyspan_usa28_pre_product_id = 0x0101; +static __u16 keyspan_usa28x_pre_product_id = 0x0102; + + /* Product IDs post-renumeration */ +static __u16 keyspan_usa18x_product_id = 0x0112; +static __u16 keyspan_usa19_product_id = 0x0107; +static __u16 keyspan_usa19w_product_id = 0x0108; +static __u16 keyspan_usa28_product_id = 0x010f; +static __u16 keyspan_usa28x_product_id = 0x0110; + + /* Structs for the devices, pre and post renumeration. + These are incomplete at present - HAB 20000708 */ +struct usb_serial_device_type keyspan_usa18x_pre_device = { + name: "Keyspan USA18X - (prerenumeration)", + idVendor: &keyspan_vendor_id, + idProduct: &keyspan_usa18x_pre_product_id, + needs_interrupt_in: DONT_CARE, + needs_bulk_in: DONT_CARE, + needs_bulk_out: DONT_CARE, + num_interrupt_in: NUM_DONT_CARE, + num_bulk_in: NUM_DONT_CARE, + num_bulk_out: NUM_DONT_CARE, + num_ports: 1, + startup: keyspan_fake_startup +}; + +struct usb_serial_device_type keyspan_usa19_pre_device = { + name: "Keyspan USA19 - (prerenumeration)", + idVendor: &keyspan_vendor_id, + idProduct: &keyspan_usa19_pre_product_id, + needs_interrupt_in: DONT_CARE, + needs_bulk_in: DONT_CARE, + needs_bulk_out: DONT_CARE, + num_interrupt_in: NUM_DONT_CARE, + num_bulk_in: NUM_DONT_CARE, + num_bulk_out: NUM_DONT_CARE, + num_ports: 1, + startup: keyspan_fake_startup +}; + + +struct usb_serial_device_type keyspan_usa19w_pre_device = { + name: "Keyspan USA19W - (prerenumeration)", + idVendor: &keyspan_vendor_id, + idProduct: &keyspan_usa19w_pre_product_id, + needs_interrupt_in: DONT_CARE, + needs_bulk_in: DONT_CARE, + needs_bulk_out: DONT_CARE, + num_interrupt_in: NUM_DONT_CARE, + num_bulk_in: NUM_DONT_CARE, + num_bulk_out: NUM_DONT_CARE, + num_ports: 1, + startup: keyspan_fake_startup +}; + + +struct usb_serial_device_type keyspan_usa28_pre_device = { + name: "Keyspan USA28 - (prerenumeration)", + idVendor: &keyspan_vendor_id, + idProduct: &keyspan_usa28_pre_product_id, + needs_interrupt_in: DONT_CARE, + needs_bulk_in: DONT_CARE, + needs_bulk_out: DONT_CARE, + num_interrupt_in: NUM_DONT_CARE, + num_bulk_in: NUM_DONT_CARE, + num_bulk_out: NUM_DONT_CARE, + num_ports: 2, + startup: keyspan_fake_startup +}; + +struct usb_serial_device_type keyspan_usa28x_pre_device = { + name: "Keyspan USA28X - (prerenumeration)", + idVendor: &keyspan_vendor_id, + idProduct: &keyspan_usa28x_pre_product_id, + needs_interrupt_in: DONT_CARE, + needs_bulk_in: DONT_CARE, + needs_bulk_out: DONT_CARE, + num_interrupt_in: NUM_DONT_CARE, + num_bulk_in: NUM_DONT_CARE, + num_bulk_out: NUM_DONT_CARE, + num_ports: 2, + startup: keyspan_fake_startup +}; + + +struct usb_serial_device_type keyspan_usa18x_device = { + name: "Keyspan USA18X", + idVendor: &keyspan_vendor_id, + idProduct: &keyspan_usa18x_product_id, + needs_interrupt_in: DONT_CARE, + needs_bulk_in: DONT_CARE, + needs_bulk_out: DONT_CARE, + num_interrupt_in: NUM_DONT_CARE, + num_bulk_in: NUM_DONT_CARE, + num_bulk_out: NUM_DONT_CARE, + num_ports: 1, + open: keyspan_open, + close: keyspan_close, + throttle: keyspan_rx_throttle, + unthrottle: keyspan_rx_unthrottle, + set_termios: keyspan_set_termios, +}; + +struct usb_serial_device_type keyspan_usa19_device = { + name: "Keyspan USA19", + idVendor: &keyspan_vendor_id, + idProduct: &keyspan_usa19_product_id, + needs_interrupt_in: DONT_CARE, + needs_bulk_in: MUST_HAVE, + needs_bulk_out: MUST_HAVE, + num_interrupt_in: NUM_DONT_CARE, + num_bulk_in: 3, + num_bulk_out: 4, + num_ports: 1, + open: keyspan_open, + close: keyspan_close, + write: keyspan_write, + write_room: keyspan_write_room, + write_bulk_callback: keyspan_write_bulk_callback, + read_int_callback: keyspan_read_bulk_callback, + chars_in_buffer: keyspan_chars_in_buffer, + throttle: keyspan_rx_throttle, + unthrottle: keyspan_rx_unthrottle, + ioctl: keyspan_ioctl, + set_termios: keyspan_set_termios, + break_ctl: keyspan_break_ctl, + startup: keyspan_startup, + shutdown: keyspan_shutdown, +}; + + +struct usb_serial_device_type keyspan_usa19w_device = { + name: "Keyspan USA19W", + idVendor: &keyspan_vendor_id, + idProduct: &keyspan_usa19w_product_id, + needs_interrupt_in: DONT_CARE, + needs_bulk_in: DONT_CARE, + needs_bulk_out: DONT_CARE, + num_interrupt_in: NUM_DONT_CARE, + num_bulk_in: NUM_DONT_CARE, + num_bulk_out: NUM_DONT_CARE, + num_ports: 1, + open: keyspan_open, + close: keyspan_close, + throttle: keyspan_rx_throttle, + unthrottle: keyspan_rx_unthrottle, + set_termios: keyspan_set_termios, +}; + + +struct usb_serial_device_type keyspan_usa28_device = { + name: "Keyspan USA28", + idVendor: &keyspan_vendor_id, + idProduct: &keyspan_usa28_product_id, + needs_interrupt_in: DONT_CARE, + needs_bulk_in: DONT_CARE, + needs_bulk_out: DONT_CARE, + num_interrupt_in: NUM_DONT_CARE, + num_bulk_in: NUM_DONT_CARE, + num_bulk_out: NUM_DONT_CARE, + num_ports: 2, + open: keyspan_open, + close: keyspan_close, + throttle: keyspan_rx_throttle, + unthrottle: keyspan_rx_unthrottle, + set_termios: keyspan_set_termios, +}; + + +struct usb_serial_device_type keyspan_usa28x_device = { + name: "Keyspan USA28X", + idVendor: &keyspan_vendor_id, + idProduct: &keyspan_usa28x_product_id, + needs_interrupt_in: DONT_CARE, + needs_bulk_in: DONT_CARE, + needs_bulk_out: DONT_CARE, + num_interrupt_in: NUM_DONT_CARE, + num_bulk_in: NUM_DONT_CARE, + num_bulk_out: NUM_DONT_CARE, + num_ports: 2, + open: keyspan_open, + close: keyspan_close, + write: keyspan_write, + write_room: keyspan_write_room, + write_bulk_callback: keyspan_write_bulk_callback, + read_int_callback: keyspan_read_bulk_callback, + chars_in_buffer: keyspan_chars_in_buffer, + throttle: keyspan_rx_throttle, + unthrottle: keyspan_rx_unthrottle, + ioctl: keyspan_ioctl, + set_termios: keyspan_set_termios, + break_ctl: keyspan_break_ctl, + startup: keyspan_startup, + shutdown: keyspan_shutdown, + + + +}; + + + +#endif diff --git a/drivers/usb/serial/keyspan_usa28msg.h b/drivers/usb/serial/keyspan_usa28msg.h index 69ba3cfae..6378bc5b0 100644 --- a/drivers/usb/serial/keyspan_usa28msg.h +++ b/drivers/usb/serial/keyspan_usa28msg.h @@ -94,9 +94,9 @@ #ifndef __USA28MSG__ #define __USA28MSG__ -#ifndef STUBS +/*#ifndef STUBS #include "datadefs.h" -#endif +#endif*/ typedef struct txAckMessage { diff --git a/drivers/usb/usb.c b/drivers/usb/usb.c index 9c650cfdc..bfac6098b 100644 --- a/drivers/usb/usb.c +++ b/drivers/usb/usb.c @@ -428,7 +428,7 @@ int usb_interface_claimed(struct usb_interface *iface) void usb_driver_release_interface(struct usb_driver *driver, struct usb_interface *iface) { /* this should never happen, don't release something that's not ours */ - if (iface->driver != driver || !iface) + if (!iface || iface->driver != driver) return; iface->driver = NULL; |