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

Reply via email to