There it is, let me know what you think. This is what I wrote for 2.4.x kernel, it should apply cleanly against the latest 2.4.27-pre1.
Jan --- linux-2.4.27-pre1/drivers/usb/serial/ftdi_sio.h 2004-04-22 23:16:51.000000000 +0200 +++ linux-2.4.27-pre1-jc/drivers/usb/serial/ftdi_sio.h 2004-04-22 23:36:46.000000000 +0200 @@ -165,6 +165,11 @@ #define PROTEGO_SPECIAL_3 0xFC72 /* special/unknown device */ #define PROTEGO_SPECIAL_4 0xFC73 /* special/unknown device */ +/* CCS Inc. ICDU/ICDU40 product ID - the FT232BM is used in an in-circuit-debugger */ +/* unit for PIC16's/PIC18's */ +#define FTDI_CCSICDU20_0_PID 0xF9D0 +#define FTDI_CCSICDU40_1_PID 0xF9D1 + /* Commands */ #define FTDI_SIO_RESET 0 /* Reset the port */ #define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */ --- linux-2.4.27-pre1/drivers/usb/serial/ftdi_sio.c 2004-04-22 23:16:51.000000000 +0200 +++ linux-2.4.27-pre1-jc/drivers/usb/serial/ftdi_sio.c 2004-04-22 23:36:46.000000000 +0200 @@ -16,6 +16,15 @@ * * See http://ftdi-usb-sio.sourceforge.net for upto date testing info * and extra documentation + * + * (07/Mar/2004) Jan Capek + * Added PID's for ICD-U20/ICD-U40 - incircuit PIC debuggers from CCS Inc. + * Extended ftdi_set_termios(), so that it handles changes of the + * termios setting with regards to old_termios. The code has been cleaned up + * and parts of the functionality have been moved to helper functions: + * - ftdi_set_cs_stopb_parb() - sets up character size, stop bits, parity bits + * - ftdi_handle_B0_transitions() - this handles transitions back and forth + * between to B0 and other baudrates (DTR is changed accordingly) * * (09/Feb/2004) Ian Abbott * Changed full name of USB-UIRT device to avoid "/" character. @@ -250,7 +259,7 @@ /* * Version Information */ -#define DRIVER_VERSION "v1.3.5" +#define DRIVER_VERSION "v1.3.6" #define DRIVER_AUTHOR "Greg Kroah-Hartman <[EMAIL PROTECTED]>, Bill Ryder <[EMAIL PROTECTED]>, Kuba Ober <[EMAIL PROTECTED]>" #define DRIVER_DESC "USB FTDI Serial Converters Driver" @@ -375,6 +384,8 @@ { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_5_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_6_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_VID, FTDI_PERLE_ULTRAPORT_PID, 0x400, 0xffff) }, + { USB_DEVICE(FTDI_VID, FTDI_CCSICDU20_0_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CCSICDU40_1_PID) }, { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2101_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2102_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2103_PID, 0x400, 0xffff) }, @@ -471,6 +482,8 @@ { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_5_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_6_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_VID, FTDI_PERLE_ULTRAPORT_PID, 0x400, 0xffff) }, + { USB_DEVICE(FTDI_VID, FTDI_CCSICDU20_0_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CCSICDU40_1_PID) }, { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2101_PID) }, { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2102_PID) }, { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2103_PID) }, @@ -1011,6 +1024,120 @@ } /* set_serial_info */ + +/* + * Sets character size(CS), stopbits(STOPB) and parity bits(PARB) for + * the usb_serial specified. + * + * @serial: FTDI device, where the settings are to be performed + * @cflag: new control flags from the termios settings + * + * Returns: wValue, that was written to the device via usb control message. + * It is used by the break command. + * + */ +static inline __u16 ftdi_set_cs_stopb_parb(struct usb_serial *serial, unsigned int cflag) +{ + __u16 urb_value = 0; + char buf[1]; + + dbg("%s", __FUNCTION__); + urb_value |= (cflag & CSTOPB ? FTDI_SIO_SET_DATA_STOP_BITS_2 : + FTDI_SIO_SET_DATA_STOP_BITS_1); + urb_value |= (cflag & PARENB ? + (cflag & PARODD ? FTDI_SIO_SET_DATA_PARITY_ODD : + FTDI_SIO_SET_DATA_PARITY_EVEN) : + FTDI_SIO_SET_DATA_PARITY_NONE); + if (cflag & CSIZE) { + switch (cflag & CSIZE) { + case CS5: urb_value |= 5; dbg("Setting CS5"); break; + case CS6: urb_value |= 6; dbg("Setting CS6"); break; + case CS7: urb_value |= 7; dbg("Setting CS7"); break; + case CS8: urb_value |= 8; dbg("Setting CS8"); break; + default: + err("CSIZE was set but not CS5-CS8"); + } + } + if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + FTDI_SIO_SET_DATA_REQUEST, + FTDI_SIO_SET_DATA_REQUEST_TYPE, + urb_value , 0, + buf, 0, 100) < 0) { + err("%s FAILED to set databits/stopbits/parity", __FUNCTION__); + } + + return urb_value; +} + +/* + * This is to make the ftdi_set_termios() function more readable as it originally + * didn't handle transitions from/to B0 correctly. The problem was in the fact + * that once the baudrate was dropped to B0, the DTR/RTS was pulled low however + * on a transition from B0 to Bxxx, the DTR would stay low all the time. + * This was semantically incorrect as some terminal programs (e.g. minicom) uses + * B0 to drop DTR and reset the modem and expect it to go high when any other + * baudrate is set(see serial.c). + * + * Transitions in baurate are handled as follows: + * - Bxxxx -> B0 - DTR and RTS is dropped and disables the HW flowcontrol + * - B0 -> Bxxxx - DTR is pulled high. RTS is pulled high only if HW + * flow control is not enabled. + * + * @port: pointer to the usb_serial_port structure as the port is referenced + * when handling dtr/rts changes + * @cflag: new termios control flags + * @old_termios: pointer to the old termios settings (this might be NULL) + * @old_baudrate: original baudrate, that we perform the transition from + * this is valid only if old_termios != NULL + * + * Returns: nothing + */ +static inline void ftdi_handle_B0_transitions(struct usb_serial_port *port, + unsigned int cflag, + struct termios *old_termios, + unsigned int old_baudrate) +{ + struct usb_serial *serial = port->serial; + + unsigned int new_baudrate = cflag & CBAUD; + char buf[1]; + + /* Handle transition to B0 */ + if (((old_baudrate != B0) || !old_termios) && (new_baudrate == B0)) { + dbg("%s: Bxxx->B0 transition", __FUNCTION__); + /* Disable flow control */ + if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + FTDI_SIO_SET_FLOW_CTRL_REQUEST, + FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, + 0, FTDI_SIO_DISABLE_FLOW_CTRL, + buf, 0, WDR_TIMEOUT) < 0) { + err("%s error from disable flowcontrol urb", __FUNCTION__); + } + + /* Drop RTS and DTR */ + if (set_dtr(port, LOW) < 0) { + err("%s Error from DTR LOW urb", __FUNCTION__); + } + if (set_rts(port, LOW) < 0) { + err("%s Error from RTS LOW urb", __FUNCTION__); + } + + } + /* Handle transition from B0 */ + else if (((old_baudrate == B0) || !old_termios) && (new_baudrate != B0)) { + dbg("%s: B0->Bxxx transition", __FUNCTION__); + /* Set DTR high*/ + if (set_dtr(port, HIGH) < 0){ + err("%s Error from DTR LOW urb", __FUNCTION__); + } + if (!(cflag & CRTSCTS)) + if (set_rts(port, HIGH) < 0) { + err("%s Error from RTS LOW urb", __FUNCTION__); + } + } + +} + /* * *************************************************************************** * FTDI driver specific functions @@ -1752,16 +1879,32 @@ } +/* used when checking if following input flags have changed */ +#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) -/* old_termios contains the original termios settings and tty->termios contains - * the new setting to be used +/* + * Actions taken: + * - checks if there any forced setting to be done (force_baud and force_rtscts) + * - in order to implement the same semantics as a regular serial driver, the + * old_termios settings are taken into account + * - when no change in settings is observed, function returns + * - function now handles correctly transitions back and forth between B0 and + * other baudrates (via ftdi_handle_B0_transitions()) + * - other termios settings are performed (character size, stop bits -> using + * helper function ftdi_set_cs_stopb_parb(), parity bits, flow control) + * + * @port: pointer to the usb_serial_port structure as the port is referenced + * when handling various settings + * @old_termios: pointer to the old termios settings (this might be NULL too), + * tty->termios contains the new setting to be used + * * WARNING: set_termios calls this with old_termios in kernel space */ - static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_termios) { /* ftdi_termios */ struct usb_serial *serial = port->serial; unsigned int cflag; + unsigned int old_baudrate = B0; /* baudrate value from old_termios for B0 transition detection */ struct ftdi_private *priv = (struct ftdi_private *)port->private; __u16 urb_value; /* will hold the new flags */ char buf[1]; /* Perhaps I should dynamically alloc this? */ @@ -1788,64 +1931,33 @@ cflag = port->tty->termios->c_cflag; - /* FIXME -For this cut I don't care if the line is really changing or - not - so just do the change regardless - should be able to - compare old_termios and tty->termios */ + /* Check if any change in termios settings occured*/ + if (old_termios) { + if ((cflag == old_termios->c_cflag) && + (RELEVANT_IFLAG(port->tty->termios->c_iflag) == + RELEVANT_IFLAG(old_termios->c_iflag))) { + dbg("%s - nothing to change", __FUNCTION__); + return; + } + old_baudrate = old_termios->c_cflag & CBAUD; + } + + /* NOTE These routines can get interrupted by ftdi_sio_read_bulk_callback - need to examine what this means - don't see any problems yet */ /* Set number of data bits, parity, stop bits */ - - urb_value = 0; - urb_value |= (cflag & CSTOPB ? FTDI_SIO_SET_DATA_STOP_BITS_2 : - FTDI_SIO_SET_DATA_STOP_BITS_1); - urb_value |= (cflag & PARENB ? - (cflag & PARODD ? FTDI_SIO_SET_DATA_PARITY_ODD : - FTDI_SIO_SET_DATA_PARITY_EVEN) : - FTDI_SIO_SET_DATA_PARITY_NONE); - if (cflag & CSIZE) { - switch (cflag & CSIZE) { - case CS5: urb_value |= 5; dbg("Setting CS5"); break; - case CS6: urb_value |= 6; dbg("Setting CS6"); break; - case CS7: urb_value |= 7; dbg("Setting CS7"); break; - case CS8: urb_value |= 8; dbg("Setting CS8"); break; - default: - err("CSIZE was set but not CS5-CS8"); - } - } - /* This is needed by the break command since it uses the same command - but is * or'ed with this value */ - priv->last_set_data_urb_value = urb_value; + priv->last_set_data_urb_value = ftdi_set_cs_stopb_parb(serial, cflag); - if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - FTDI_SIO_SET_DATA_REQUEST, - FTDI_SIO_SET_DATA_REQUEST_TYPE, - urb_value , 0, - buf, 0, 100) < 0) { - err("%s FAILED to set databits/stopbits/parity", __FUNCTION__); - } + /* B0->Bxxxx and Bxxxx->B0 baudrate transitions need special handling so that + DTR and RTS reflect the actual state */ + ftdi_handle_B0_transitions(port, cflag, old_termios, old_baudrate); /* Now do the baudrate */ - if ((cflag & CBAUD) == B0 ) { - /* Disable flow control */ - if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - FTDI_SIO_SET_FLOW_CTRL_REQUEST, - FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, - 0, 0, - buf, 0, WDR_TIMEOUT) < 0) { - err("%s error from disable flowcontrol urb", __FUNCTION__); - } - /* Drop RTS and DTR */ - if (set_dtr(port, LOW) < 0){ - err("%s Error from DTR LOW urb", __FUNCTION__); - } - if (set_rts(port, LOW) < 0){ - err("%s Error from RTS LOW urb", __FUNCTION__); - } - - } else { + if ((cflag & CBAUD) != B0 ) { /* set the baudrate determined before */ if (change_speed(port)) { err("%s urb failed to set baurdrate", __FUNCTION__); ------------------------------------------------------- This SF.net email is sponsored by: The Robotic Monkeys at ThinkGeek For a limited time only, get FREE Ground shipping on all orders of $35 or more. Hurry up and shop folks, this offer expires April 30th! http://www.thinkgeek.com/freeshipping/?cpg=12297 _______________________________________________ [EMAIL PROTECTED] To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel