Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

USB: serial: mos7840: Fixed MCS7820 device attach problem

A MCS7820 device supports two serial ports and a MCS7840 device supports
four serial ports. Both devices use the same driver, but the attach function
in driver was unable to correctly handle the port numbers for MCS7820
device. This problem has been fixed in this patch and this fix has been
verified on x86 Linux kernel 3.2.9 with both MCS7820 and MCS7840 devices.

Signed-off-by: Donald Lee <donald@asix.com.tw>
Cc: stable <stable@vger.kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Donald Lee and committed by
Greg Kroah-Hartman
093ea2d3 53c6bc24

+56 -25
+56 -25
drivers/usb/serial/mos7840.c
··· 174 174 175 175 #define CLK_MULTI_REGISTER ((__u16)(0x02)) 176 176 #define CLK_START_VALUE_REGISTER ((__u16)(0x03)) 177 + #define GPIO_REGISTER ((__u16)(0x07)) 177 178 178 179 #define SERIAL_LCR_DLAB ((__u16)(0x0080)) 179 180 ··· 1102 1101 mos7840_port->read_urb = port->read_urb; 1103 1102 1104 1103 /* set up our bulk in urb */ 1105 - 1106 - usb_fill_bulk_urb(mos7840_port->read_urb, 1107 - serial->dev, 1108 - usb_rcvbulkpipe(serial->dev, 1109 - port->bulk_in_endpointAddress), 1110 - port->bulk_in_buffer, 1111 - mos7840_port->read_urb->transfer_buffer_length, 1112 - mos7840_bulk_in_callback, mos7840_port); 1104 + if ((serial->num_ports == 2) 1105 + && ((((__u16)port->number - 1106 + (__u16)(port->serial->minor)) % 2) != 0)) { 1107 + usb_fill_bulk_urb(mos7840_port->read_urb, 1108 + serial->dev, 1109 + usb_rcvbulkpipe(serial->dev, 1110 + (port->bulk_in_endpointAddress) + 2), 1111 + port->bulk_in_buffer, 1112 + mos7840_port->read_urb->transfer_buffer_length, 1113 + mos7840_bulk_in_callback, mos7840_port); 1114 + } else { 1115 + usb_fill_bulk_urb(mos7840_port->read_urb, 1116 + serial->dev, 1117 + usb_rcvbulkpipe(serial->dev, 1118 + port->bulk_in_endpointAddress), 1119 + port->bulk_in_buffer, 1120 + mos7840_port->read_urb->transfer_buffer_length, 1121 + mos7840_bulk_in_callback, mos7840_port); 1122 + } 1113 1123 1114 1124 dbg("mos7840_open: bulkin endpoint is %d", 1115 1125 port->bulk_in_endpointAddress); ··· 1531 1519 memcpy(urb->transfer_buffer, current_position, transfer_size); 1532 1520 1533 1521 /* fill urb with data and submit */ 1534 - usb_fill_bulk_urb(urb, 1535 - serial->dev, 1536 - usb_sndbulkpipe(serial->dev, 1537 - port->bulk_out_endpointAddress), 1538 - urb->transfer_buffer, 1539 - transfer_size, 1540 - mos7840_bulk_out_data_callback, mos7840_port); 1522 + if ((serial->num_ports == 2) 1523 + && ((((__u16)port->number - 1524 + (__u16)(port->serial->minor)) % 2) != 0)) { 1525 + usb_fill_bulk_urb(urb, 1526 + serial->dev, 1527 + usb_sndbulkpipe(serial->dev, 1528 + (port->bulk_out_endpointAddress) + 2), 1529 + urb->transfer_buffer, 1530 + transfer_size, 1531 + mos7840_bulk_out_data_callback, mos7840_port); 1532 + } else { 1533 + usb_fill_bulk_urb(urb, 1534 + serial->dev, 1535 + usb_sndbulkpipe(serial->dev, 1536 + port->bulk_out_endpointAddress), 1537 + urb->transfer_buffer, 1538 + transfer_size, 1539 + mos7840_bulk_out_data_callback, mos7840_port); 1540 + } 1541 1541 1542 1542 data1 = urb->transfer_buffer; 1543 1543 dbg("bulkout endpoint is %d", port->bulk_out_endpointAddress); ··· 1862 1838 1863 1839 } else { 1864 1840 #ifdef HW_flow_control 1865 - / *setting h/w flow control bit to 0 */ 1841 + /* setting h/w flow control bit to 0 */ 1866 1842 Data = 0xb; 1867 1843 mos7840_port->shadowMCR = Data; 1868 1844 status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, ··· 2329 2305 2330 2306 static int mos7840_calc_num_ports(struct usb_serial *serial) 2331 2307 { 2332 - int mos7840_num_ports = 0; 2308 + __u16 Data = 0x00; 2309 + int ret = 0; 2310 + int mos7840_num_ports; 2333 2311 2334 - dbg("numberofendpoints: cur %d, alt %d", 2335 - (int)serial->interface->cur_altsetting->desc.bNumEndpoints, 2336 - (int)serial->interface->altsetting->desc.bNumEndpoints); 2337 - if (serial->interface->cur_altsetting->desc.bNumEndpoints == 5) { 2338 - mos7840_num_ports = serial->num_ports = 2; 2339 - } else if (serial->interface->cur_altsetting->desc.bNumEndpoints == 9) { 2312 + ret = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), 2313 + MCS_RDREQ, MCS_RD_RTYPE, 0, GPIO_REGISTER, &Data, 2314 + VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT); 2315 + 2316 + if ((Data & 0x01) == 0) { 2317 + mos7840_num_ports = 2; 2318 + serial->num_bulk_in = 2; 2319 + serial->num_bulk_out = 2; 2320 + serial->num_ports = 2; 2321 + } else { 2322 + mos7840_num_ports = 4; 2340 2323 serial->num_bulk_in = 4; 2341 2324 serial->num_bulk_out = 4; 2342 - mos7840_num_ports = serial->num_ports = 4; 2325 + serial->num_ports = 4; 2343 2326 } 2344 - dbg ("mos7840_num_ports = %d", mos7840_num_ports); 2327 + 2345 2328 return mos7840_num_ports; 2346 2329 } 2347 2330