ChangeSet 1.1289, 2003/12/12 12:18:04-08:00, marr@flex.com [PATCH] USB: MCT-U232 Patch for cts Brief Patch Description: Fix a problem in the 'mct_u232' driver whereby output data gets held up in the USB/RS-232 adapter for RS-232 devices which don't assert the 'CTS' signal. Background: The Belkin F5U109 is a 9-pin USB/RS-232 adapter that is supported by the existing 'mct_u232' kernel module.  Recently, I've been testing it under the 2.4.22 (Slackware 9.1) kernel and the 2.6.0-test9 kernel. I've connected a Garmin 'GPS35 TracPak' GPS receiver (RS-232 interface) and an ordinary RS-232 external modem to my PC's USB port via the Belkin F5U109 adapter. Problem: Although _reads_ from either of the RS-232 devices mentioned above work fine via the Belkin adapter, _writes_ to the GPS receiver are not being seen by the GPS.  Writes to the modem, however, work perfectly. Aside: The 'Linux USB Users' archives show that at least one other person (circa May 2002) had the exact same problem I'm having, but it sounds like no solution was ever determined because the person in question just bought a different USB/RS-232 adapter. Investigation: Using the 'seyon' terminal emulator in Linux and a crude hardware RS-232 "breakout box" that I hacked together, I've determined that the problem is related to the RTS/CTS RS-232 hardware handshaking. After further investigation, I've concluded that RS-232 devices which do not assert the 'Clear To Send' ('CTS') signal prevent the Belkin F5U109 adapter from transmitting data to the RS-232 device when the current (version 1.1) 'mct_u232' module is used. The data gets "queued up" (up to a point -- 16 bytes, I think) in the adapter but never transmitted. Since this GPS receiver works perfectly (reads and writes) when connected to a PC running W98se using the same Belkin adapter and the Belkin-supplied Windows driver, the Linux driver became suspect. After some testing with SniffUSB, I found that the Windows driver sends a couple of unique undocumented USB 'device requests' that the Linux driver does not. As it turns out, the second of those 2 requests is critical in making the adapter transmit data to a device which doesn't assert 'CTS'. For completeness, the Windows driver in use was determined from the 'Device Manager', 'Driver File Details' page:    U2SPORT.VXD    Provider: Magic Control Technology    File version: 1.21P.0104 for Win98/Me Solution: My patch adds the 2 missing USB 'device request' commands right after a baud-change command. This mimics the operation of the W98 driver. Unfortunately, after much testing, I found no other operation (besides a baud-change request) under Windows that triggers either of these 2 'device request' commands. This makes it impossible to fully document the behavior of these requests, but I've made entries for them alongside the others in the 'mct_u232.h' file. Purely for clarity, the patch also modifies various comments in 'mct_u232.h', mostly to reflect proper sizes of the various 'USB Device Request' fields per the USB 1.1 specification. The patch also updates the version number of the driver, corrects a minor typographical error, and documents a difference in the length of the data in a 'baud rate change' command for certain adapters which use a coded baud-rate rather than the conventional RS-232 baud rate divisor. drivers/usb/serial/mct_u232.c | 37 ++++++++++++++- drivers/usb/serial/mct_u232.h | 101 +++++++++++++++++++++++++++++++++--------- 2 files changed, 116 insertions(+), 22 deletions(-) diff -Nru a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c --- a/drivers/usb/serial/mct_u232.c Fri Dec 12 15:05:36 2003 +++ b/drivers/usb/serial/mct_u232.c Fri Dec 12 15:05:36 2003 @@ -24,6 +24,11 @@ * Basic tests have been performed with minicom/zmodem transfers and * modem dialing under Linux 2.4.0-test10 (for me it works fine). * + * 04-Nov-2003 Bill Marr + * - Mimic Windows driver by sending 2 USB 'device request' messages + * following normal 'baud rate change' message. This allows data to be + * transmitted to RS-232 devices which don't assert the 'CTS' signal. + * * 10-Nov-2001 Wolfgang Grandegger * - Fixed an endianess problem with the baudrate selection for PowerPC. * @@ -85,7 +90,7 @@ /* * Version Information */ -#define DRIVER_VERSION "v1.1" +#define DRIVER_VERSION "v1.2" #define DRIVER_AUTHOR "Wolfgang Grandegger " #define DRIVER_DESC "Magic Control Technology USB-RS232 converter driver" @@ -201,6 +206,7 @@ { unsigned int divisor; int rc; + unsigned char zero_byte = 0; divisor = cpu_to_le32(mct_u232_calculate_baud_rate(serial, value)); rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), MCT_U232_SET_BAUD_RATE_REQUEST, @@ -210,6 +216,35 @@ if (rc < 0) err("Set BAUD RATE %d failed (error = %d)", value, rc); dbg("set_baud_rate: value: %d, divisor: 0x%x", value, divisor); + + /* Mimic the MCT-supplied Windows driver (version 1.21P.0104), which + always sends two extra USB 'device request' messages after the + 'baud rate change' message. The actual functionality of the + request codes in these messages is not fully understood but these + particular codes are never seen in any operation besides a baud + rate change. Both of these messages send a single byte of data + whose value is always zero. The second of these two extra messages + is required in order for data to be properly written to an RS-232 + device which does not assert the 'CTS' signal. */ + + rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + MCT_U232_SET_UNKNOWN1_REQUEST, + MCT_U232_SET_REQUEST_TYPE, + 0, 0, &zero_byte, MCT_U232_SET_UNKNOWN1_SIZE, + WDR_TIMEOUT); + if (rc < 0) + err("Sending USB device request code %d failed (error = %d)", + MCT_U232_SET_UNKNOWN1_REQUEST, rc); + + rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + MCT_U232_SET_UNKNOWN2_REQUEST, + MCT_U232_SET_REQUEST_TYPE, + 0, 0, &zero_byte, MCT_U232_SET_UNKNOWN2_SIZE, + WDR_TIMEOUT); + if (rc < 0) + err("Sending USB device request code %d failed (error = %d)", + MCT_U232_SET_UNKNOWN2_REQUEST, rc); + return rc; } /* mct_u232_set_baud_rate */ diff -Nru a/drivers/usb/serial/mct_u232.h b/drivers/usb/serial/mct_u232.h --- a/drivers/usb/serial/mct_u232.h Fri Dec 12 15:05:36 2003 +++ b/drivers/usb/serial/mct_u232.h Fri Dec 12 15:05:36 2003 @@ -57,6 +57,21 @@ #define MCT_U232_SET_MODEM_CTRL_REQUEST 10 /* Set Modem Control Register (MCR) */ #define MCT_U232_SET_MODEM_CTRL_SIZE 1 +/* This USB device request code is not well understood. It is transmitted by + the MCT-supplied Windows driver whenever the baud rate changes. +*/ +#define MCT_U232_SET_UNKNOWN1_REQUEST 11 /* Unknown functionality */ +#define MCT_U232_SET_UNKNOWN1_SIZE 1 + +/* This USB device request code is not well understood. It is transmitted by + the MCT-supplied Windows driver whenever the baud rate changes. + + Without this USB device request, the USB/RS-232 adapter will not write to + RS-232 devices which do not assert the 'CTS' signal. +*/ +#define MCT_U232_SET_UNKNOWN2_REQUEST 12 /* Unknown functionality */ +#define MCT_U232_SET_UNKNOWN2_SIZE 1 + /* * Baud rate (divisor) */ @@ -137,22 +152,31 @@ * Baud rate (divisor) * ------------------- * - * BmRequestType: 0x4 (0100 0000B) - * bRequest: 0x5 - * wValue: 0x0 - * wIndex: 0x0 - * wLength: 0x4 + * BmRequestType: 0x40 (0100 0000B) + * bRequest: 0x05 + * wValue: 0x0000 + * wIndex: 0x0000 + * wLength: 0x0004 * Data: divisor = 115200 / baud_rate * + * SniffUSB observations (Nov 2003): Contrary to the 'wLength' value of 4 + * shown above, observations with a Belkin F5U109 adapter, using the + * MCT-supplied Windows98 driver (U2SPORT.VXD, "File version: 1.21P.0104 for + * Win98/Me"), show this request has a length of 1 byte, presumably because + * of the fact that the Belkin adapter and the 'Sitecom U232-P25' adapter + * use a baud-rate code instead of a conventional RS-232 baud rate divisor. + * The current source code for this driver does not reflect this fact, but + * the driver works fine with this adapter/driver combination nonetheless. + * * * Line Control Register (LCR) * --------------------------- * - * BmRequestType: 0x4 (0100 0000B) 0xc (1100 0000B) - * bRequest: 0x7 0x6 - * wValue: 0x0 - * wIndex: 0x0 - * wLength: 0x1 + * BmRequestType: 0x40 (0100 0000B) 0xc0 (1100 0000B) + * bRequest: 0x07 0x06 + * wValue: 0x0000 + * wIndex: 0x0000 + * wLength: 0x0001 * Data: LCR (see below) * * Bit 7: Divisor Latch Access Bit (DLAB). When set, access to the data @@ -186,18 +210,18 @@ * * SniffUSB observations: Bit 7 seems not to be used. There seem to be two bugs * in the Win98 driver: the break does not work (bit 6 is not asserted) and the - * sticky parity bit is not cleared when set once. The LCR can also be read + * stick parity bit is not cleared when set once. The LCR can also be read * back with USB request 6 but this has never been observed with SniffUSB. * * * Modem Control Register (MCR) * ---------------------------- * - * BmRequestType: 0x4 (0100 0000B) - * bRequest: 0xa - * wValue: 0x0 - * wIndex: 0x0 - * wLength: 0x1 + * BmRequestType: 0x40 (0100 0000B) + * bRequest: 0x0a + * wValue: 0x0000 + * wIndex: 0x0000 + * wLength: 0x0001 * Data: MCR (Bit 4..7, see below) * * Bit 7: Reserved, always 0. @@ -226,11 +250,11 @@ * Modem Status Register (MSR) * --------------------------- * - * BmRequestType: 0xc (1100 0000B) - * bRequest: 0x2 - * wValue: 0x0 - * wIndex: 0x0 - * wLength: 0x1 + * BmRequestType: 0xc0 (1100 0000B) + * bRequest: 0x02 + * wValue: 0x0000 + * wIndex: 0x0000 + * wLength: 0x0001 * Data: MSR (see below) * * Bit 7: Data Carrier Detect (CD). Reflects the state of the DCD line on the @@ -285,6 +309,41 @@ * SniffUSB observations: the LSR is returned as second byte on the interrupt-in * endpoint 0x83 to signal error conditions. Such errors have been seen with * minicom/zmodem transfers (CRC errors). + * + * + * Unknown #1 + * ------------------- + * + * BmRequestType: 0x40 (0100 0000B) + * bRequest: 0x0b + * wValue: 0x0000 + * wIndex: 0x0000 + * wLength: 0x0001 + * Data: 0x00 + * + * SniffUSB observations (Nov 2003): With the MCT-supplied Windows98 driver + * (U2SPORT.VXD, "File version: 1.21P.0104 for Win98/Me"), this request + * occurs immediately after a "Baud rate (divisor)" message. It was not + * observed at any other time. It is unclear what purpose this message + * serves. + * + * + * Unknown #2 + * ------------------- + * + * BmRequestType: 0x40 (0100 0000B) + * bRequest: 0x0c + * wValue: 0x0000 + * wIndex: 0x0000 + * wLength: 0x0001 + * Data: 0x00 + * + * SniffUSB observations (Nov 2003): With the MCT-supplied Windows98 driver + * (U2SPORT.VXD, "File version: 1.21P.0104 for Win98/Me"), this request + * occurs immediately after the 'Unknown #1' message (see above). It was + * not observed at any other time. It is unclear what other purpose (if + * any) this message might serve, but without it, the USB/RS-232 adapter + * will not write to RS-232 devices which do not assert the 'CTS' signal. * * * Flow control