Skip to contentSkip to conversation

usb: serial: ti_usb_3410_5052: add MOXA UPORT 11x0 support

PATCH In review Mathieu OTHACEHE 2 participants 2 messages Mar 2, 2016 – Apr 24, 2016

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 usb: serial: ti_usb_3410_5052: add MOXA UPORT 11x0 support

Add support for :

- UPort 1110 : 1 port RS-232 USB to Serial Hub.
- UPort 1130 : 1 port RS-422/485 USB to Serial Hub.
- UPort 1130I : 1 port RS-422/485 USB to Serial Hub with Isolation.
- UPort 1150 : 1 port RS-232/422/485 USB to Serial Hub.
- UPort 1150I : 1 port RS-232/422/485 USB to Serial Hub with Isolation.

These devices are based on TI 3410 chip.

---

Hi,

This patch add support for MOXA UPORT 11x0 devices to ti_usb_3410_5052. The informations are extracted from the now reverted mxu11x0 driver.

There is a delicate point in the attach callback.
The driver is comparing bNumConfigurations to 1 to see if the firmware has to be downloaded. I guess bNumConfigurations is 2 after firmware download and device reseting.

On MOXA 1110, bNumConfigurations is always 1, before and after firmware download. So, I also check that the interface has only 1 endpoint to determine if we have to download firmware or not.

Thanks,

Mathieu

 drivers/usb/serial/ti_usb_3410_5052.c | 44 ++++++++++++++++++++++++++++++++---
 drivers/usb/serial/ti_usb_3410_5052.h |  8 +++++++
 2 files changed, 49 insertions(+), 3 deletions(-)
drivers/usb/serial/ti_usb_3410_5052.c +41 -3
index 2694df2..b9119de 100644
@@ -80,6 +80,7 @@ struct ti_device {
 	int			td_open_port_count;
 	struct usb_serial	*td_serial;
 	int			td_is_3410;
+	int			td_model;
 	int			td_urb_error;
 };
 
@@ -160,6 +161,11 @@ static const struct usb_device_id ti_id_table_3410[] = {
 	{ USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_STRIP_PORT_ID) },
 	{ USB_DEVICE(TI_VENDOR_ID, FRI2_PRODUCT_ID) },
 	{ USB_DEVICE(HONEYWELL_VENDOR_ID, HONEYWELL_HGI80_PRODUCT_ID) },
+	{ USB_DEVICE(MXU1_VENDOR_ID, MXU1_1110_PRODUCT_ID) },
+	{ USB_DEVICE(MXU1_VENDOR_ID, MXU1_1130_PRODUCT_ID) },
+	{ USB_DEVICE(MXU1_VENDOR_ID, MXU1_1150_PRODUCT_ID) },
+	{ USB_DEVICE(MXU1_VENDOR_ID, MXU1_1151_PRODUCT_ID) },
+	{ USB_DEVICE(MXU1_VENDOR_ID, MXU1_1131_PRODUCT_ID) },
 	{ }	/* terminator */
 };
 
@@ -193,6 +199,11 @@ static const struct usb_device_id ti_id_table_combined[] = {
 	{ USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_STRIP_PORT_ID) },
 	{ USB_DEVICE(TI_VENDOR_ID, FRI2_PRODUCT_ID) },
 	{ USB_DEVICE(HONEYWELL_VENDOR_ID, HONEYWELL_HGI80_PRODUCT_ID) },
+	{ USB_DEVICE(MXU1_VENDOR_ID, MXU1_1110_PRODUCT_ID) },
+	{ USB_DEVICE(MXU1_VENDOR_ID, MXU1_1130_PRODUCT_ID) },
+	{ USB_DEVICE(MXU1_VENDOR_ID, MXU1_1150_PRODUCT_ID) },
+	{ USB_DEVICE(MXU1_VENDOR_ID, MXU1_1151_PRODUCT_ID) },
+	{ USB_DEVICE(MXU1_VENDOR_ID, MXU1_1131_PRODUCT_ID) },
 	{ }	/* terminator */
 };
 
@@ -277,6 +288,11 @@ MODULE_FIRMWARE("mts_gsm.fw");
 MODULE_FIRMWARE("mts_edge.fw");
 MODULE_FIRMWARE("mts_mt9234mu.fw");
 MODULE_FIRMWARE("mts_mt9234zba.fw");
+MODULE_FIRMWARE("moxa/moxa-1110.fw");
+MODULE_FIRMWARE("moxa/moxa-1130.fw");
+MODULE_FIRMWARE("moxa/moxa-1131.fw");
+MODULE_FIRMWARE("moxa/moxa-1150.fw");
+MODULE_FIRMWARE("moxa/moxa-1151.fw");
 
 module_param(closing_wait, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(closing_wait,
@@ -292,6 +308,7 @@ static int ti_startup(struct usb_serial *serial)
 {
 	struct ti_device *tdev;
 	struct usb_device *dev = serial->dev;
+	struct usb_host_interface *cur_altsetting;
 	int status;
 
 	dev_dbg(&dev->dev,
@@ -315,8 +332,13 @@ static int ti_startup(struct usb_serial *serial)
 	dev_dbg(&dev->dev, "%s - device type is %s\n", __func__,
 		tdev->td_is_3410 ? "3410" : "5052");
 
-	/* if we have only 1 configuration, download firmware */
-	if (dev->descriptor.bNumConfigurations == 1) {
+	tdev->td_model = le16_to_cpu(dev->descriptor.idProduct);
+
+	cur_altsetting = serial->interface->cur_altsetting;
+
+	/* if we have only 1 configuration and 1 endpoint, download firmware */
+	if (dev->descriptor.bNumConfigurations == 1 &&
+	    cur_altsetting->desc.bNumEndpoints == 1) {
 		status = ti_download_firmware(tdev);
 
 		if (status != 0)
@@ -371,7 +393,15 @@ static int ti_port_probe(struct usb_serial_port *port)
 	port->port.closing_wait = msecs_to_jiffies(10 * closing_wait);
 	tport->tp_port = port;
 	tport->tp_tdev = usb_get_serial_data(port->serial);
-	tport->tp_uart_mode = 0;	/* default is RS232 */
+
+	switch (tport->tp_tdev->td_model) {
+	case MXU1_1130_PRODUCT_ID:
+	case MXU1_1131_PRODUCT_ID:
+		tport->tp_uart_mode = TI_UART_485_RECEIVER_DISABLED;
+		break;
+	default:
+		tport->tp_uart_mode = TI_UART_232;	/* default is RS232 */
+	}
 
 	usb_set_serial_port_data(port, tport);
 
@@ -1479,6 +1509,14 @@ static int ti_download_firmware(struct ti_device *tdev)
 				strcpy(buf, "mts_mt9234zba.fw");
 				break;			}
 		}
+
+		if (le16_to_cpu(dev->descriptor.idVendor) == MXU1_VENDOR_ID) {
+			snprintf(buf,
+				sizeof(buf),
+				"moxa/moxa-%04x.fw",
+				le16_to_cpu(dev->descriptor.idProduct));
+		}
+
 		if (buf[0] == '\0') {
 			if (tdev->td_is_3410)
 				strcpy(buf, "ti_3410.fw");
drivers/usb/serial/ti_usb_3410_5052.h +8 -0
index 98f35c6..93ac6ad 100644
@@ -60,6 +60,14 @@
 #define HONEYWELL_VENDOR_ID		0x10ac
 #define HONEYWELL_HGI80_PRODUCT_ID	0x0102  /* Honeywell HGI80 */
 
+/* Moxa UPORT 11x0 vendor and product IDs */
+#define MXU1_VENDOR_ID				0x110a
+#define MXU1_1110_PRODUCT_ID			0x1110
+#define MXU1_1130_PRODUCT_ID			0x1130
+#define MXU1_1150_PRODUCT_ID			0x1150
+#define MXU1_1151_PRODUCT_ID			0x1151
+#define MXU1_1131_PRODUCT_ID			0x1131
+
 /* Commands */
 #define TI_GET_VERSION			0x01
 #define TI_GET_PORT_STATUS		0x02
Signature · 1 line
2.7.0
maintainer
#1 lore raw
Quoted 8 lines · Mathieu OTHACEHE

Add support for :

- UPort 1110 : 1 port RS-232 USB to Serial Hub.
- UPort 1130 : 1 port RS-422/485 USB to Serial Hub.
- UPort 1130I : 1 port RS-422/485 USB to Serial Hub with Isolation.
- UPort 1150 : 1 port RS-232/422/485 USB to Serial Hub.
- UPort 1150I : 1 port RS-232/422/485 USB to Serial Hub with Isolation.

Quoted 4 lines

These devices are based on TI 3410 chip.

---

Thanks for the patch and sorry for the late review.

Quoted 11 lines

This patch add support for MOXA UPORT 11x0 devices to ti_usb_3410_5052. The informations are extracted from the now reverted mxu11x0 driver.

There is a delicate point in the attach callback.
The driver is comparing bNumConfigurations to 1 to see if the firmware has to be downloaded. I guess bNumConfigurations is 2 after firmware download and device reseting.

On MOXA 1110, bNumConfigurations is always 1, before and after firmware download. So, I also check that the interface has only 1 endpoint to determine if we have to download firmware or not.

That sounds reasonable.

Quoted 17 lines
 drivers/usb/serial/ti_usb_3410_5052.c | 44 ++++++++++++++++++++++++++++++++---
 drivers/usb/serial/ti_usb_3410_5052.h |  8 +++++++
 2 files changed, 49 insertions(+), 3 deletions(-)
drivers/usb/serial/ti_usb_3410_5052.c +1 -0
index 2694df2..b9119de 100644
@@ -80,6 +80,7 @@ struct ti_device {
 	int			td_open_port_count;
 	struct usb_serial	*td_serial;
 	int			td_is_3410;
+	int			td_model;
 	int			td_urb_error;
 };
 

drivers/usb/serial/ti_usb_3410_5052.c static const struct usb_device_id ti_id_table_3410[] = { · line 168

Quoted 8 lines
drivers/usb/serial/ti_usb_3410_5052.c +5 -0
@@ -160,6 +161,11 @@ static const struct usb_device_id ti_id_table_3410[] = {
 	{ USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_STRIP_PORT_ID) },
 	{ USB_DEVICE(TI_VENDOR_ID, FRI2_PRODUCT_ID) },
 	{ USB_DEVICE(HONEYWELL_VENDOR_ID, HONEYWELL_HGI80_PRODUCT_ID) },
+	{ USB_DEVICE(MXU1_VENDOR_ID, MXU1_1110_PRODUCT_ID) },
+	{ USB_DEVICE(MXU1_VENDOR_ID, MXU1_1130_PRODUCT_ID) },
+	{ USB_DEVICE(MXU1_VENDOR_ID, MXU1_1150_PRODUCT_ID) },
+	{ USB_DEVICE(MXU1_VENDOR_ID, MXU1_1151_PRODUCT_ID) },
+	{ USB_DEVICE(MXU1_VENDOR_ID, MXU1_1131_PRODUCT_ID) },

Keep these sorted internally at least.

drivers/usb/serial/ti_usb_3410_5052.c static const struct usb_device_id ti_id_table_combined[] = { · line 206

Quoted 12 lines
drivers/usb/serial/ti_usb_3410_5052.c +5 -0
 	{ }	/* terminator */
 };
 
@@ -193,6 +199,11 @@ static const struct usb_device_id ti_id_table_combined[] = {
 	{ USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_STRIP_PORT_ID) },
 	{ USB_DEVICE(TI_VENDOR_ID, FRI2_PRODUCT_ID) },
 	{ USB_DEVICE(HONEYWELL_VENDOR_ID, HONEYWELL_HGI80_PRODUCT_ID) },
+	{ USB_DEVICE(MXU1_VENDOR_ID, MXU1_1110_PRODUCT_ID) },
+	{ USB_DEVICE(MXU1_VENDOR_ID, MXU1_1130_PRODUCT_ID) },
+	{ USB_DEVICE(MXU1_VENDOR_ID, MXU1_1150_PRODUCT_ID) },
+	{ USB_DEVICE(MXU1_VENDOR_ID, MXU1_1151_PRODUCT_ID) },
+	{ USB_DEVICE(MXU1_VENDOR_ID, MXU1_1131_PRODUCT_ID) },

Ditto.

Quoted 24 lines
drivers/usb/serial/ti_usb_3410_5052.c +6 -0
 	{ }	/* terminator */
 };
 
@@ -277,6 +288,11 @@ MODULE_FIRMWARE("mts_gsm.fw");
 MODULE_FIRMWARE("mts_edge.fw");
 MODULE_FIRMWARE("mts_mt9234mu.fw");
 MODULE_FIRMWARE("mts_mt9234zba.fw");
+MODULE_FIRMWARE("moxa/moxa-1110.fw");
+MODULE_FIRMWARE("moxa/moxa-1130.fw");
+MODULE_FIRMWARE("moxa/moxa-1131.fw");
+MODULE_FIRMWARE("moxa/moxa-1150.fw");
+MODULE_FIRMWARE("moxa/moxa-1151.fw");
 
 module_param(closing_wait, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(closing_wait,
@@ -292,6 +308,7 @@ static int ti_startup(struct usb_serial *serial)
 {
 	struct ti_device *tdev;
 	struct usb_device *dev = serial->dev;
+	struct usb_host_interface *cur_altsetting;
 	int status;
 
 	dev_dbg(&dev->dev,

drivers/usb/serial/ti_usb_3410_5052.c static int ti_startup(struct usb_serial *serial) · line 335

Quoted 6 lines
drivers/usb/serial/ti_usb_3410_5052.c +1 -2
@@ -315,8 +332,13 @@ static int ti_startup(struct usb_serial *serial)
 	dev_dbg(&dev->dev, "%s - device type is %s\n", __func__,
 		tdev->td_is_3410 ? "3410" : "5052");
 
-	/* if we have only 1 configuration, download firmware */
-	if (dev->descriptor.bNumConfigurations == 1) {
+	tdev->td_model = le16_to_cpu(dev->descriptor.idProduct);

Instead of storing the model (which really is the vid-dependent pid), just set an rs485-only flag when you detect a Moxa 1130/1131 here.

drivers/usb/serial/ti_usb_3410_5052.c static int ti_startup(struct usb_serial *serial) · line 341

Quoted 5 lines
drivers/usb/serial/ti_usb_3410_5052.c +5 -0
+	cur_altsetting = serial->interface->cur_altsetting;
+
+	/* if we have only 1 configuration and 1 endpoint, download firmware */
+	if (dev->descriptor.bNumConfigurations == 1 &&
+	    cur_altsetting->desc.bNumEndpoints == 1) {

Indent continuation lines two tabs further, or rewrite so that you don't need a line break.

Quoted 7 lines
drivers/usb/serial/ti_usb_3410_5052.c +0 -0
 		status = ti_download_firmware(tdev);
 
 		if (status != 0)
@@ -371,7 +393,15 @@ static int ti_port_probe(struct usb_serial_port *port)
 	port->port.closing_wait = msecs_to_jiffies(10 * closing_wait);
 	tport->tp_port = port;
 	tport->tp_tdev = usb_get_serial_data(port->serial);

drivers/usb/serial/ti_usb_3410_5052.c static int ti_port_probe(struct usb_serial_port *port) · line 404

Quoted 10 lines
drivers/usb/serial/ti_usb_3410_5052.c +9 -1
-	tport->tp_uart_mode = 0;	/* default is RS232 */
+
+	switch (tport->tp_tdev->td_model) {
+	case MXU1_1130_PRODUCT_ID:
+	case MXU1_1131_PRODUCT_ID:
+		tport->tp_uart_mode = TI_UART_485_RECEIVER_DISABLED;
+		break;
+	default:
+		tport->tp_uart_mode = TI_UART_232;	/* default is RS232 */
+	}

Use the flag set mentioned above instead.

Quoted 5 lines
drivers/usb/serial/ti_usb_3410_5052.c +0 -0
 	usb_set_serial_port_data(port, tport);
 
@@ -1479,6 +1509,14 @@ static int ti_download_firmware(struct ti_device *tdev)
 				strcpy(buf, "mts_mt9234zba.fw");

drivers/usb/serial/ti_usb_3410_5052.c static int ti_download_firmware(struct ti_device *tdev) · line 1519

Quoted 10 lines
drivers/usb/serial/ti_usb_3410_5052.c +8 -0
 				break;			}
 		}
+
+		if (le16_to_cpu(dev->descriptor.idVendor) == MXU1_VENDOR_ID) {
+			snprintf(buf,
+				sizeof(buf),
+				"moxa/moxa-%04x.fw",
+				le16_to_cpu(dev->descriptor.idProduct));
+		}
+

Looks like this code could use a few vid/pid temporaries.

I'm not sure it makes sense to try to load a "ti_usb-v110a-p1150.fw" firmware before requesting the moxa firmware. Avoids a confusing:

usb 1-2.2: Direct firmware load for ti_usb-v110a-p1150.fw failed with error -2

message too.

Quoted 8 lines
drivers/usb/serial/ti_usb_3410_5052.c +0 -0
 		if (buf[0] == '\0') {
 			if (tdev->td_is_3410)
 				strcpy(buf, "ti_3410.fw");
drivers/usb/serial/ti_usb_3410_5052.h +0 -0
index 98f35c6..93ac6ad 100644

drivers/usb/serial/ti_usb_3410_5052.h line 69

Quoted 10 lines
drivers/usb/serial/ti_usb_3410_5052.h +7 -0
@@ -60,6 +60,14 @@
 #define HONEYWELL_VENDOR_ID		0x10ac
 #define HONEYWELL_HGI80_PRODUCT_ID	0x0102  /* Honeywell HGI80 */
 
+/* Moxa UPORT 11x0 vendor and product IDs */
+#define MXU1_VENDOR_ID				0x110a
+#define MXU1_1110_PRODUCT_ID			0x1110
+#define MXU1_1130_PRODUCT_ID			0x1130
+#define MXU1_1150_PRODUCT_ID			0x1150
+#define MXU1_1151_PRODUCT_ID			0x1151
+#define MXU1_1131_PRODUCT_ID			0x1131

Keep these sorted too.

drivers/usb/serial/ti_usb_3410_5052.h line 73

Quoted 4 lines
drivers/usb/serial/ti_usb_3410_5052.h +1 -0
+
 /* Commands */
 #define TI_GET_VERSION			0x01
 #define TI_GET_PORT_STATUS		0x02

I did a quick test of the patch using a Moxa 1150-device. Works at 115200, but communication appeared broken at 9600. Looks like the baud rate calculations are similar but not identical to what the Moxa driver does. Is this something you have looked into?

Thanks,
Johan