Bug 70523

Summary: [umct] [patch] umct sending/receiving wrong characters
Product: Base System Reporter: Brian Candler <B.Candler>
Component: usbAssignee: Hans Petter Selasky <hselasky>
Status: Open ---    
Severity: Affects Only Me    
Priority: Normal    
Version: 5.2.1-RELEASE   
Hardware: Any   
OS: Any   

Description Brian Candler 2004-08-16 09:40:33 UTC
I plug in a 'Intel USB Solution USB-232' cable (USB to DB25). It identifies as:

ucom0: MCT Corporation. USB-232 Interfact Controller, rev 1.00/1.02, addr 3

(sic - Interfact not Interface)

However it consistently reads incorrect characters. Connecting back-to-back
with a real COM port, and using:
   cu -l ucom0 -s 19200
   cu -l cuaa0 -s 19200

* REAL COM PORT --> USB-232

If I send a space (20) I receive hex E8. If I send a capital A (41) I
receive hex E0. It's perfectly consistent, here's a mapping:

tx 20 30 31 32 33 34 35 36 37 38 39
rx e8 ec ec ed ed ee ee ef ef ec ec

tx 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f
rx e0 e0 e1 e1 e2 e2 e3 e3 e0 e0 e1 e1 e2 e2 e3 e3

tx 50 51 52 53 54 55 56 57 58 59 5a
rx e4 e4 e5 e5 e6 e6 e7 e7 e4 e4 e5

* USB-232 --> REAL COM PORT

This time I get two bytes on the COM port for each byte I send on the USB232.

tx 20   30   31   32             33
rx 00FC C0FC C3FC C4FC or CCFC   C7FC or CFFC

It does look rather a bit like speed mismatch (esp. USB-232 -> REAL), but I
tried different speed combinations and couldn't get them to talk.

I have not yet had a chance to try this device on a Linux box to see if
their mct_u232 driver works with it.

At 2400bps I managed to freeze the laptop totally, requiring me to remove
the battery and reboot. However that also happens with a different [uplcom]
USB->RS232 adaptor I have as well, so that's a subject of a different PR.

Fix: 

No idea! Would like to know if anyone else has a USB<->RS232 device which
uses the umct driver working successfully.
How-To-Repeat: 
See above. You need 'kldload umct', a genuine serial port, and a null-modem
serial cable. Run 'cu' at both ends (under 'script' if you want to catch the
data and use 'hexdump -C' to view it afterwards). I also have a little C
protocol-analyser program to view bytes directly in hex.
Comment 1 Brian Candler 2004-08-21 21:21:46 UTC
This device worked correctly under Linux, and I have now made a patch
[attached below] so that it works under FreeBSD too.

Looking at linux-2.4.27/drivers/usb/serial/mct_u232.[ch], you'll see that
there are two different ways of calculating the baud rate divider, depending
on which type of device you have. FreeBSD only implemented one of these, and
unfortunately I had the other sort of device.

I wasn't sure if there was an easy way to access the 'uaa' structure in the
middle of umct_calc_baud, so instead I added an extra structure member to
'sc' to flag which divider constants to use. If there's a way of doing this
without having to store this extra state then please do so.

I notice a new entry USB_PRODUCT_BELKIN_F5U409 has recently been added to
umct.c (but is not in the Linux driver); someone needs to check which way it
works.

Aside: Something else the Linux driver does is to send commands 11 and 12
(constants MCT_U232_SET_UNKNOWN1_REQUEST and MCT_U232_SET_UNKNOWN2_REQUEST)
after setting the baud rate. The comment says:

        /* 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. */

I tried making the FreeBSD driver do this too, but on my hardware it just
gave timeouts:

  /kernel: ucom0: ubsa_request: TIMEOUT

So I guess it's not needed for the device I have, and I've taken it out.
(That debug message should have said "umct_request", and the patch below
also fixes that)

Regards,

Brian Candler.

--- sys/dev/usb/umct.c.orig	Tue Apr 13 04:39:16 2004
+++ sys/dev/usb/umct.c	Sat Aug 21 21:17:07 2004
@@ -81,6 +81,7 @@
 	uint8_t			sc_msr;
 	uint8_t			sc_lcr;
 	uint8_t			sc_mcr;
+	uint8_t			sc_divider_type;
 #if __FreeBSD_version >= 500000
 	void			*sc_swicookie;
 #endif
@@ -193,6 +194,10 @@
 	sc->sc_intr_number = -1;
 	sc->sc_intr_pipe = NULL;
 
+	if (uaa->product == USB_PRODUCT_MCT_SITECOM_USB232 ||
+	    uaa->product == USB_PRODUCT_BELKIN_F5U109)
+		sc->sc_divider_type = 1;
+	
 	err = usbd_set_config_index(dev, UMCT_CONFIG_INDEX, 1);
 	if (err) {
 		printf("%s: failed to set configuration: %s\n",
@@ -328,7 +333,7 @@
 
 	err = usbd_do_request(sc->sc_ucom.sc_udev, &req, oval);
 	if (err)
-		printf("%s: ubsa_request: %s\n",
+		printf("%s: umct_request: %s\n",
 		    USBDEVNAME(sc->sc_ucom.sc_dev), usbd_errstr(err));
 	return (err);
 }
@@ -418,22 +423,34 @@
 }
 
 Static int
-umct_calc_baud(u_int baud)
+umct_calc_baud(struct umct_softc *sc, u_int baud)
 {
-	switch(baud) {
-	case B300: return (0x1);
-	case B600: return (0x2);
-	case B1200: return (0x3);
-	case B2400: return (0x4);
-	case B4800: return (0x6);
-	case B9600: return (0x8);
-	case B19200: return (0x9);
-	case B38400: return (0xa);
-	case B57600: return (0xb);
-	case 115200: return (0xc);
-	case B0:
-	default:
-		break;
+	if (sc->sc_divider_type == 1) {
+		switch(baud) {
+		case B300: return (0x1);
+		case B600: return (0x2);
+		case B1200: return (0x3);
+		case B2400: return (0x4);
+		case B4800: return (0x6);
+		case B9600: return (0x8);
+		case B19200: return (0x9);
+		case B38400: return (0xa);
+		case B57600: return (0xb);
+		case 115200: return (0xc);
+		}
+	} else {
+		switch(baud) {
+		case B300: return 115200/300;
+		case B600: return 115200/600;
+		case B1200: return 115200/1200;
+		case B2400: return 115200/2400;
+		case B4800: return 115200/4800;
+		case B9600: return 115200/9600;
+		case B19200: return 115200/19200;
+		case B38400: return 115200/38400;
+		case B57600: return 115200/57600;
+		case 115200: return 115200/115200;
+		}
 	}
 
 	return (0x0);
@@ -446,7 +463,8 @@
 	uint32_t value;
 
 	sc = addr;
-	value = umct_calc_baud(ti->c_ospeed);
+	value = umct_calc_baud(sc, ti->c_ospeed);
+	if (value == 0) return (EIO);
 	umct_request(sc, UMCT_SET_BAUD, UMCT_SET_BAUD_SIZE, value);
 
 	value = sc->sc_lcr & 0x40;
Comment 2 Brian Candler 2004-08-21 21:21:46 UTC
This device worked correctly under Linux, and I have now made a patch
[attached below] so that it works under FreeBSD too.

Looking at linux-2.4.27/drivers/usb/serial/mct_u232.[ch], you'll see that
there are two different ways of calculating the baud rate divider, depending
on which type of device you have. FreeBSD only implemented one of these, and
unfortunately I had the other sort of device.

I wasn't sure if there was an easy way to access the 'uaa' structure in the
middle of umct_calc_baud, so instead I added an extra structure member to
'sc' to flag which divider constants to use. If there's a way of doing this
without having to store this extra state then please do so.

I notice a new entry USB_PRODUCT_BELKIN_F5U409 has recently been added to
umct.c (but is not in the Linux driver); someone needs to check which way it
works.

Aside: Something else the Linux driver does is to send commands 11 and 12
(constants MCT_U232_SET_UNKNOWN1_REQUEST and MCT_U232_SET_UNKNOWN2_REQUEST)
after setting the baud rate. The comment says:

        /* 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. */

I tried making the FreeBSD driver do this too, but on my hardware it just
gave timeouts:

  /kernel: ucom0: ubsa_request: TIMEOUT

So I guess it's not needed for the device I have, and I've taken it out.
(That debug message should have said "umct_request", and the patch below
also fixes that)

Regards,

Brian Candler.

--- sys/dev/usb/umct.c.orig	Tue Apr 13 04:39:16 2004
+++ sys/dev/usb/umct.c	Sat Aug 21 21:17:07 2004
@@ -81,6 +81,7 @@
 	uint8_t			sc_msr;
 	uint8_t			sc_lcr;
 	uint8_t			sc_mcr;
+	uint8_t			sc_divider_type;
 #if __FreeBSD_version >= 500000
 	void			*sc_swicookie;
 #endif
@@ -193,6 +194,10 @@
 	sc->sc_intr_number = -1;
 	sc->sc_intr_pipe = NULL;
 
+	if (uaa->product == USB_PRODUCT_MCT_SITECOM_USB232 ||
+	    uaa->product == USB_PRODUCT_BELKIN_F5U109)
+		sc->sc_divider_type = 1;
+	
 	err = usbd_set_config_index(dev, UMCT_CONFIG_INDEX, 1);
 	if (err) {
 		printf("%s: failed to set configuration: %s\n",
@@ -328,7 +333,7 @@
 
 	err = usbd_do_request(sc->sc_ucom.sc_udev, &req, oval);
 	if (err)
-		printf("%s: ubsa_request: %s\n",
+		printf("%s: umct_request: %s\n",
 		    USBDEVNAME(sc->sc_ucom.sc_dev), usbd_errstr(err));
 	return (err);
 }
@@ -418,22 +423,34 @@
 }
 
 Static int
-umct_calc_baud(u_int baud)
+umct_calc_baud(struct umct_softc *sc, u_int baud)
 {
-	switch(baud) {
-	case B300: return (0x1);
-	case B600: return (0x2);
-	case B1200: return (0x3);
-	case B2400: return (0x4);
-	case B4800: return (0x6);
-	case B9600: return (0x8);
-	case B19200: return (0x9);
-	case B38400: return (0xa);
-	case B57600: return (0xb);
-	case 115200: return (0xc);
-	case B0:
-	default:
-		break;
+	if (sc->sc_divider_type == 1) {
+		switch(baud) {
+		case B300: return (0x1);
+		case B600: return (0x2);
+		case B1200: return (0x3);
+		case B2400: return (0x4);
+		case B4800: return (0x6);
+		case B9600: return (0x8);
+		case B19200: return (0x9);
+		case B38400: return (0xa);
+		case B57600: return (0xb);
+		case 115200: return (0xc);
+		}
+	} else {
+		switch(baud) {
+		case B300: return 115200/300;
+		case B600: return 115200/600;
+		case B1200: return 115200/1200;
+		case B2400: return 115200/2400;
+		case B4800: return 115200/4800;
+		case B9600: return 115200/9600;
+		case B19200: return 115200/19200;
+		case B38400: return 115200/38400;
+		case B57600: return 115200/57600;
+		case 115200: return 115200/115200;
+		}
 	}
 
 	return (0x0);
@@ -446,7 +463,8 @@
 	uint32_t value;
 
 	sc = addr;
-	value = umct_calc_baud(ti->c_ospeed);
+	value = umct_calc_baud(sc, ti->c_ospeed);
+	if (value == 0) return (EIO);
 	umct_request(sc, UMCT_SET_BAUD, UMCT_SET_BAUD_SIZE, value);
 
 	value = sc->sc_lcr & 0x40;
_______________________________________________
freebsd-bugs@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-bugs
To unsubscribe, send any mail to "freebsd-bugs-unsubscribe@freebsd.org"
Comment 3 Brian Candler 2004-08-26 16:42:19 UTC
[Aside]
My Vaio, which was prone to freeze up completely with the other (uplcom)
USB->232 interface, has a UHCI USB controller. I applied the following two
patches to the base r4.10-RELEASE:
http://www.freebsd.org/cgi/cvsweb.cgi/src/sys/dev/usb/uhci.c.diff?r1=1.40.2.14&r2=1.151
http://www.freebsd.org/cgi/cvsweb.cgi/src/sys/sys/queue.h.diff?r1=1.54&r2=1.55
and the uplcom device seems to work now. Hasn't had much testing, but I'm
hopeful that things will be happier in 4.11-RELEASE :-)
Comment 4 Mark Linimon freebsd_committer freebsd_triage 2004-11-04 07:30:40 UTC
Responsible Changed
From-To: freebsd-bugs->freebsd-usb

Reassign to appropriate mailing list.
Comment 5 Eitan Adler freebsd_committer freebsd_triage 2011-07-24 23:39:58 UTC
Responsible Changed
From-To: freebsd-usb->hps

work
Comment 6 Mark Linimon freebsd_committer freebsd_triage 2011-07-25 18:04:21 UTC
Responsible Changed
From-To: hps->hselasky

Use committer's canonical login.
Comment 7 Hans Petter Selasky freebsd_committer 2014-10-30 16:51:35 UTC
Hi,

Is this still an issue with 9- and 10-stable ?

--HPS
Comment 8 Eitan Adler freebsd_committer freebsd_triage 2018-05-28 19:47:15 UTC
batch change:

For bugs that match the following
-  Status Is In progress 
AND
- Untouched since 2018-01-01.
AND
- Affects Base System OR Documentation

DO:

Reset to open status.


Note:
I did a quick pass but if you are getting this email it might be worthwhile to double check to see if this bug ought to be closed.