Hi, This patch against 2.4.11-pre1 updates the usb-serial pl2303 driver. It fixes a number of bugs and has been reported to be stable for a number of users. It is based on the code that has been in the -ac tree for a while.
thanks, greg k-h (temporary USB maintainer) diff --minimal -Nru a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c --- a/drivers/usb/serial/pl2303.c Mon Oct 1 10:48:29 2001 +++ b/drivers/usb/serial/pl2303.c Mon Oct 1 10:48:29 2001 @@ -12,6 +12,9 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * 2001_Sep_19 gkh + * Added break support. + * * 2001_Aug_30 gkh * fixed oops in write_bulk_callback. * @@ -53,7 +56,7 @@ /* * Version Information */ -#define DRIVER_VERSION "v0.7" +#define DRIVER_VERSION "v0.8" #define DRIVER_DESC "Prolific PL2303 USB to serial adaptor driver" @@ -67,6 +70,26 @@ MODULE_DEVICE_TABLE (usb, id_table); +#define SET_LINE_REQUEST_TYPE 0x21 +#define SET_LINE_REQUEST 0x20 + +#define SET_CONTROL_REQUEST_TYPE 0x21 +#define SET_CONTROL_REQUEST 0x22 + +#define BREAK_REQUEST_TYPE 0x21 +#define BREAK_REQUEST 0x23 +#define BREAK_ON 0xffff +#define BREAK_OFF 0x0000 + +#define GET_LINE_REQUEST_TYPE 0xa1 +#define GET_LINE_REQUEST 0x21 + +#define VENDOR_WRITE_REQUEST_TYPE 0x40 +#define VENDOR_WRITE_REQUEST 0x01 + +#define VENDOR_READ_REQUEST_TYPE 0xc0 +#define VENDOR_READ_REQUEST 0x01 + /* function prototypes for a PL2303 serial converter */ static int pl2303_open (struct usb_serial_port *port, struct file *filp); static void pl2303_close (struct usb_serial_port *port, struct file *filp); @@ -80,6 +103,7 @@ static int pl2303_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count); static void pl2303_break_ctl(struct usb_serial_port *port,int break_state); +static void pl2303_shutdown (struct usb_serial *serial); /* All of the device info needed for the PL2303 SIO serial converter */ @@ -102,6 +126,7 @@ read_bulk_callback: pl2303_read_bulk_callback, read_int_callback: pl2303_read_int_callback, write_bulk_callback: pl2303_write_bulk_callback, + shutdown: pl2303_shutdown, }; @@ -145,54 +170,60 @@ -static void -pl2303_set_termios (struct usb_serial_port *port, struct termios *old_termios) -{ /* pl2303_set_termios */ +static void pl2303_set_termios (struct usb_serial_port *port, struct termios +*old_termios) +{ struct usb_serial *serial = port->serial; - unsigned int cflag = port->tty->termios->c_cflag; - unsigned char buf[7] = { 0, 0, 0, 0, 0, 0, 0}; + unsigned int cflag; + unsigned char *buf; int baud; int i; + dbg (__FUNCTION__ " - port %d", port->number); - dbg ("pl2303_set_termios 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) && + (RELEVANT_IFLAG(port->tty->termios->c_iflag) == +RELEVANT_IFLAG(old_termios->c_iflag))) { + dbg(__FUNCTION__ " - nothing to change..."); + return; + } + } + buf = kmalloc (7, GFP_KERNEL); + if (!buf) { + err(__FUNCTION__ " - out of memory."); + return; + } + memset (buf, 0x00, 0x07); + i = usb_control_msg (serial->dev, usb_rcvctrlpipe (serial->dev, 0), - 0x21, 0xa1, 0, 0, buf, 7, 100); - + GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE, + 0, 0, buf, 7, 100); dbg ("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); i = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0), - 1, 0x40, 0, 1, NULL, 0, 100); + VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE, + 0, 1, NULL, 0, 100); dbg ("0x40:1:0:1 %d", i); - - if (cflag & CSIZE) { switch (cflag & CSIZE) { - case CS5: - buf[6] = 5; - dbg ("Setting CS5"); - break; - case CS6: - buf[6] = 6; - dbg ("Setting CS6"); - break; - case CS7: - buf[6] = 7; - dbg ("Setting CS7"); - break; - case CS8: - buf[6] = 8; - dbg ("Setting CS8"); - break; + case CS5: buf[6] = 5; break; + case CS6: buf[6] = 6; break; + case CS7: buf[6] = 7; break; default: - err ("CSIZE was set but not CS5-CS8"); + case CS8: buf[6] = 8; break; } + dbg (__FUNCTION__ " - data bits = %d", buf[6]); } baud = 0; @@ -216,7 +247,7 @@ err ("pl2303 driver does not support the baudrate requested (fix it)"); break; } - + dbg (__FUNCTION__ " - baud = %d", baud); if (baud) { buf[0] = baud & 0xff; buf[1] = (baud >> 8) & 0xff; @@ -224,16 +255,17 @@ buf[3] = (baud >> 24) & 0xff; } - /* For reference buf[4]=0 is 1 stop bits */ /* For reference buf[4]=1 is 1.5 stop bits */ /* For reference buf[4]=2 is 2 stop bits */ - if (cflag & CSTOPB) { buf[4] = 2; + dbg(__FUNCTION__ " - stop bits = 2"); + } else { + buf[4] = 0; + dbg(__FUNCTION__ " - stop bits = 1"); } - if (cflag & PARENB) { /* For reference buf[5]=0 is none parity */ /* For reference buf[5]=1 is odd parity */ @@ -242,45 +274,52 @@ /* For reference buf[5]=4 is space parity */ if (cflag & PARODD) { buf[5] = 1; + dbg(__FUNCTION__ " - parity = odd"); } else { buf[5] = 2; + dbg(__FUNCTION__ " - parity = even"); } + } else { + buf[5] = 0; + dbg(__FUNCTION__ " - parity = none"); } i = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0), - 0x20, 0x21, 0, 0, buf, 7, 100); - + SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE, + 0, 0, buf, 7, 100); dbg ("0x21:0x20:0:0 %d", i); i = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0), - 0x22, 0x21, 1, 0, NULL, 0, 100); - + SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE, + 1, 0, NULL, 0, 100); dbg ("0x21:0x22:1:0 %d", i); - +#if 0 i = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0), - 0x22, 0x21, 3, 0, NULL, 0, 100); + SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE, + 1, 0, NULL, 0, 100); + dbg ("0x21:0x22:1:0 %d", i); + i = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0), + SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE, + 3, 0, NULL, 0, 100); dbg ("0x21:0x22:3:0 %d", i); - +#endif buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0; i = usb_control_msg (serial->dev, usb_rcvctrlpipe (serial->dev, 0), - 0x21, 0xa1, 0, 0, buf, 7, 100); - + GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE, + 0, 0, buf, 7, 100); dbg ("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); if (cflag & CRTSCTS) { - i = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0), - 0x01, 0x40, 0x0, 0x41, NULL, 0, 100); - + VENDOR_WRITE_REQUEST_TYPE, +VENDOR_WRITE_REQUEST_TYPE, + 0x0, 0x41, NULL, 0, 100); dbg ("0x40:0x1:0x0:0x41 %d", i); - } - - return; + kfree (buf); } @@ -294,7 +333,7 @@ if (port_paranoia_check (port, __FUNCTION__)) return -ENODEV; - dbg (__FUNCTION__ "- port %d", port->number); + dbg (__FUNCTION__ " - port %d", port->number); down (&port->sem); @@ -311,20 +350,20 @@ #define SOUP(a,b,c,d) \ result=usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev,0), \ - b, a, c , d, NULL, 0, 100); \ + b, a, c, d, NULL, 0, 100); + \ dbg("0x%x:0x%x:0x%x:0x%x %d",a,b,c,d,result); - FISH (0xc0, 1, 0x8484, 0); - SOUP (0x40, 1, 0x0404, 0); - FISH (0xc0, 1, 0x8484, 0); - FISH (0xc0, 1, 0x8383, 0); - FISH (0xc0, 1, 0x8484, 0); - SOUP (0x40, 1, 0x0404, 1); - FISH (0xc0, 1, 0x8484, 0); - FISH (0xc0, 1, 0x8383, 0); - SOUP (0x40, 1, 0, 1); - SOUP (0x40, 1, 1, 0xc0); - SOUP (0x40, 1, 2, 4); + FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0); + SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0x0404, 0); + FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0); + FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8383, 0); + FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0); + SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0x0404, 1); + FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0); + FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8383, 0); + SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0, 1); + SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 1, 0xc0); + SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 2, 4); /* Setup termios */ *(port->tty->termios) = tty_std_termios; @@ -334,6 +373,7 @@ //FIXME: need to assert RTS and DTR if CRTSCTS off + dbg (__FUNCTION__ " - submitting read urb"); port->read_urb->dev = serial->dev; result = usb_submit_urb (port->read_urb); if (result) { @@ -343,6 +383,7 @@ return -EPROTO; } + dbg (__FUNCTION__ " - submitting interrupt urb"); port->interrupt_in_urb->dev = serial->dev; result = usb_submit_urb (port->interrupt_in_urb); if (result) { @@ -360,6 +401,7 @@ static void pl2303_close (struct usb_serial_port *port, struct file *filp) { unsigned int c_cflag; + int result; if (port_paranoia_check (port, __FUNCTION__)) return; @@ -377,28 +419,30 @@ } /* shutdown our urbs */ - usb_unlink_urb (port->write_urb); - usb_unlink_urb (port->read_urb); - usb_unlink_urb (port->interrupt_in_urb); + dbg (__FUNCTION__ " - shutting down urbs"); + result = usb_unlink_urb (port->write_urb); + if (result) + dbg (__FUNCTION__ " - usb_unlink_urb (write_urb) failed with +reason: %d", result); + + result = usb_unlink_urb (port->read_urb); + if (result) + dbg (__FUNCTION__ " - usb_unlink_urb (read_urb) failed with +reason: %d", result); + + result = usb_unlink_urb (port->interrupt_in_urb); + if (result) + dbg (__FUNCTION__ " - usb_unlink_urb (interrupt_in_urb) failed +with reason: %d", result); port->active = 0; port->open_count = 0; } up (&port->sem); + MOD_DEC_USE_COUNT; } -static int -pl2303_ioctl (struct usb_serial_port *port, struct file *file, - unsigned int cmd, unsigned long arg) +static int pl2303_ioctl (struct usb_serial_port *port, struct file *file, unsigned +int cmd, unsigned long arg) { -// struct usb_serial *serial = port->serial; -// __u16 urb_value=0; /* Will hold the new flags */ -// char buf[1]; -// int ret, mask; - - dbg ("pl2303_sio ioctl 0x%04x", cmd); /* Based on code from acm.c and others */ @@ -423,23 +467,50 @@ return(-ENOIOCTLCMD); break; } - dbg ("pl2303_ioctl returning 0"); return 0; -} /* pl2303_ioctl */ +} -static void pl2303_break_ctl(struct usb_serial_port *port,int break_state) +static void pl2303_break_ctl (struct usb_serial_port *port, int break_state) { -//FIXME + struct usb_serial *serial = port->serial; + u16 state; + int result; + + dbg (__FUNCTION__ " - port %d", port->number); + + if (break_state == 0) + state = BREAK_OFF; + else + state = BREAK_ON; + dbg (__FUNCTION__" - turning break %s", state==BREAK_OFF ? "off" : "on"); + + result = usb_control_msg (serial->dev, usb_rcvctrlpipe (serial->dev, 0), + BREAK_REQUEST, BREAK_REQUEST_TYPE, state, + 0, NULL, 0, 100); + if (result) + dbg (__FUNCTION__" - error sending break = %d", result); } -static void -pl2303_read_int_callback (struct urb *urb) +static void pl2303_shutdown (struct usb_serial *serial) +{ + int i; + + dbg (__FUNCTION__); + + /* stop everything on all ports */ + for (i = 0; i < serial->num_ports; ++i) + while (serial->port[i].open_count > 0) + pl2303_close (&serial->port[i], NULL); +} + + +static void pl2303_read_int_callback (struct urb *urb) { struct usb_serial_port *port = (struct usb_serial_port *) urb->context; - struct usb_serial *serial = get_usb_serial (port, "pl2303_read_int_callback"); + struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); //unsigned char *data = urb->transfer_buffer; //int i; @@ -482,13 +553,23 @@ return; } - /* PL2303 mysteriously fails with -EPROTO reschedule the read */ if (urb->status) { - urb->status = 0; - urb->dev = serial->dev; - result = usb_submit_urb(urb); - if (result) - err(__FUNCTION__ " - failed resubmitting read urb, error %d", result); + dbg (__FUNCTION__ " - urb->status = %d", urb->status); + if (!port->active) { + dbg (__FUNCTION__ " - port is closed, exiting."); + return; + } + if (urb->status == -EPROTO) { + /* PL2303 mysteriously fails with -EPROTO reschedule the read +*/ + dbg (__FUNCTION__ " - caught -EPROTO, resubmitting the urb"); + urb->status = 0; + urb->dev = serial->dev; + result = usb_submit_urb(urb); + if (result) + err(__FUNCTION__ " - failed resubmitting read urb, +error %d", result); + return; + } + dbg (__FUNCTION__ " - unable to handle the error, exiting."); return; } @@ -505,11 +586,13 @@ tty_flip_buffer_push (tty); } - /* Schedule the next read*/ - urb->dev = serial->dev; - result = usb_submit_urb(urb); - if (result) - err(__FUNCTION__ " - failed resubmitting read urb, error %d", result); + /* Schedule the next read _if_ we are still open */ + if (port->active) { + urb->dev = serial->dev; + result = usb_submit_urb(urb); + if (result) + err(__FUNCTION__ " - failed resubmitting read urb, error %d", +result); + } return; } _______________________________________________ [EMAIL PROTECTED] To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel