diff options
Diffstat (limited to 'drivers/usb/serial/mos7720.c')
-rw-r--r-- | drivers/usb/serial/mos7720.c | 134 |
1 files changed, 130 insertions, 4 deletions
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index 2ce1a2acf1a8..e0aa031c5418 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c | |||
@@ -81,12 +81,15 @@ struct moschip_serial { | |||
81 | 81 | ||
82 | static int debug; | 82 | static int debug; |
83 | 83 | ||
84 | static struct usb_serial_driver moschip7720_2port_driver; | ||
85 | |||
84 | #define USB_VENDOR_ID_MOSCHIP 0x9710 | 86 | #define USB_VENDOR_ID_MOSCHIP 0x9710 |
85 | #define MOSCHIP_DEVICE_ID_7720 0x7720 | 87 | #define MOSCHIP_DEVICE_ID_7720 0x7720 |
86 | #define MOSCHIP_DEVICE_ID_7715 0x7715 | 88 | #define MOSCHIP_DEVICE_ID_7715 0x7715 |
87 | 89 | ||
88 | static const struct usb_device_id moschip_port_id_table[] = { | 90 | static const struct usb_device_id moschip_port_id_table[] = { |
89 | { USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7720) }, | 91 | { USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7720) }, |
92 | { USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7715) }, | ||
90 | { } /* terminating entry */ | 93 | { } /* terminating entry */ |
91 | }; | 94 | }; |
92 | MODULE_DEVICE_TABLE(usb, moschip_port_id_table); | 95 | MODULE_DEVICE_TABLE(usb, moschip_port_id_table); |
@@ -186,6 +189,75 @@ exit: | |||
186 | } | 189 | } |
187 | 190 | ||
188 | /* | 191 | /* |
192 | * mos7715_interrupt_callback | ||
193 | * this is the 7715's callback function for when we have received data on | ||
194 | * the interrupt endpoint. | ||
195 | */ | ||
196 | static void mos7715_interrupt_callback(struct urb *urb) | ||
197 | { | ||
198 | int result; | ||
199 | int length; | ||
200 | int status = urb->status; | ||
201 | __u8 *data; | ||
202 | __u8 iir; | ||
203 | |||
204 | switch (status) { | ||
205 | case 0: | ||
206 | /* success */ | ||
207 | break; | ||
208 | case -ECONNRESET: | ||
209 | case -ENOENT: | ||
210 | case -ESHUTDOWN: | ||
211 | /* this urb is terminated, clean up */ | ||
212 | dbg("%s - urb shutting down with status: %d", __func__, | ||
213 | status); | ||
214 | return; | ||
215 | default: | ||
216 | dbg("%s - nonzero urb status received: %d", __func__, | ||
217 | status); | ||
218 | goto exit; | ||
219 | } | ||
220 | |||
221 | length = urb->actual_length; | ||
222 | data = urb->transfer_buffer; | ||
223 | |||
224 | /* Structure of data from 7715 device: | ||
225 | * Byte 1: IIR serial Port | ||
226 | * Byte 2: unused | ||
227 | * Byte 2: DSR parallel port | ||
228 | * Byte 4: FIFO status for both */ | ||
229 | |||
230 | if (unlikely(length != 4)) { | ||
231 | dbg("Wrong data !!!"); | ||
232 | return; | ||
233 | } | ||
234 | |||
235 | iir = data[0]; | ||
236 | if (!(iir & 0x01)) { /* serial port interrupt pending */ | ||
237 | switch (iir & 0x0f) { | ||
238 | case SERIAL_IIR_RLS: | ||
239 | dbg("Serial Port: Receiver status error or address " | ||
240 | "bit detected in 9-bit mode\n"); | ||
241 | break; | ||
242 | case SERIAL_IIR_CTI: | ||
243 | dbg("Serial Port: Receiver time out"); | ||
244 | break; | ||
245 | case SERIAL_IIR_MS: | ||
246 | dbg("Serial Port: Modem status change"); | ||
247 | break; | ||
248 | } | ||
249 | } | ||
250 | |||
251 | exit: | ||
252 | result = usb_submit_urb(urb, GFP_ATOMIC); | ||
253 | if (result) | ||
254 | dev_err(&urb->dev->dev, | ||
255 | "%s - Error %d submitting control urb\n", | ||
256 | __func__, result); | ||
257 | return; | ||
258 | } | ||
259 | |||
260 | /* | ||
189 | * mos7720_bulk_in_callback | 261 | * mos7720_bulk_in_callback |
190 | * this is the callback function for when we have received data on the | 262 | * this is the callback function for when we have received data on the |
191 | * bulk in endpoint. | 263 | * bulk in endpoint. |
@@ -283,7 +355,7 @@ static int send_mos_cmd(struct usb_serial *serial, __u8 request, __u16 value, | |||
283 | 355 | ||
284 | if (value < MOS_MAX_PORT) { | 356 | if (value < MOS_MAX_PORT) { |
285 | if (product == MOSCHIP_DEVICE_ID_7715) | 357 | if (product == MOSCHIP_DEVICE_ID_7715) |
286 | value = value*0x100+0x100; | 358 | value = 0x0200; /* identifies the 7715's serial port */ |
287 | else | 359 | else |
288 | value = value*0x100+0x200; | 360 | value = value*0x100+0x200; |
289 | } else { | 361 | } else { |
@@ -319,6 +391,35 @@ out: | |||
319 | return status; | 391 | return status; |
320 | } | 392 | } |
321 | 393 | ||
394 | |||
395 | /* | ||
396 | * mos77xx_probe | ||
397 | * this function installs the appropriate read interrupt endpoint callback | ||
398 | * depending on whether the device is a 7720 or 7715, thus avoiding costly | ||
399 | * run-time checks in the high-frequency callback routine itself. | ||
400 | */ | ||
401 | static int mos77xx_probe(struct usb_serial *serial, | ||
402 | const struct usb_device_id *id) | ||
403 | { | ||
404 | if (id->idProduct == MOSCHIP_DEVICE_ID_7715) | ||
405 | moschip7720_2port_driver.read_int_callback = | ||
406 | mos7715_interrupt_callback; | ||
407 | else | ||
408 | moschip7720_2port_driver.read_int_callback = | ||
409 | mos7720_interrupt_callback; | ||
410 | |||
411 | return 0; | ||
412 | } | ||
413 | |||
414 | static int mos77xx_calc_num_ports(struct usb_serial *serial) | ||
415 | { | ||
416 | u16 product = le16_to_cpu(serial->dev->descriptor.idProduct); | ||
417 | if (product == MOSCHIP_DEVICE_ID_7715) | ||
418 | return 1; | ||
419 | |||
420 | return 2; | ||
421 | } | ||
422 | |||
322 | static int mos7720_open(struct tty_struct *tty, struct usb_serial_port *port) | 423 | static int mos7720_open(struct tty_struct *tty, struct usb_serial_port *port) |
323 | { | 424 | { |
324 | struct usb_serial *serial; | 425 | struct usb_serial *serial; |
@@ -1495,6 +1596,7 @@ static int mos7720_startup(struct usb_serial *serial) | |||
1495 | struct usb_device *dev; | 1596 | struct usb_device *dev; |
1496 | int i; | 1597 | int i; |
1497 | char data; | 1598 | char data; |
1599 | u16 product = le16_to_cpu(serial->dev->descriptor.idProduct); | ||
1498 | 1600 | ||
1499 | dbg("%s: Entering ..........", __func__); | 1601 | dbg("%s: Entering ..........", __func__); |
1500 | 1602 | ||
@@ -1514,6 +1616,29 @@ static int mos7720_startup(struct usb_serial *serial) | |||
1514 | 1616 | ||
1515 | usb_set_serial_data(serial, mos7720_serial); | 1617 | usb_set_serial_data(serial, mos7720_serial); |
1516 | 1618 | ||
1619 | /* | ||
1620 | * The 7715 uses the first bulk in/out endpoint pair for the parallel | ||
1621 | * port, and the second for the serial port. Because the usbserial core | ||
1622 | * assumes both pairs are serial ports, we must engage in a bit of | ||
1623 | * subterfuge and swap the pointers for ports 0 and 1 in order to make | ||
1624 | * port 0 point to the serial port. However, both moschip devices use a | ||
1625 | * single interrupt-in endpoint for both ports (as mentioned a little | ||
1626 | * further down), and this endpoint was assigned to port 0. So after | ||
1627 | * the swap, we must copy the interrupt endpoint elements from port 1 | ||
1628 | * (as newly assigned) to port 0, and null out port 1 pointers. | ||
1629 | */ | ||
1630 | if (product == MOSCHIP_DEVICE_ID_7715) { | ||
1631 | struct usb_serial_port *tmp = serial->port[0]; | ||
1632 | serial->port[0] = serial->port[1]; | ||
1633 | serial->port[1] = tmp; | ||
1634 | serial->port[0]->interrupt_in_urb = tmp->interrupt_in_urb; | ||
1635 | serial->port[0]->interrupt_in_buffer = tmp->interrupt_in_buffer; | ||
1636 | serial->port[0]->interrupt_in_endpointAddress = | ||
1637 | tmp->interrupt_in_endpointAddress; | ||
1638 | serial->port[1]->interrupt_in_urb = NULL; | ||
1639 | serial->port[1]->interrupt_in_buffer = NULL; | ||
1640 | } | ||
1641 | |||
1517 | /* we set up the pointers to the endpoints in the mos7720_open * | 1642 | /* we set up the pointers to the endpoints in the mos7720_open * |
1518 | * function, as the structures aren't created yet. */ | 1643 | * function, as the structures aren't created yet. */ |
1519 | 1644 | ||
@@ -1529,7 +1654,7 @@ static int mos7720_startup(struct usb_serial *serial) | |||
1529 | 1654 | ||
1530 | /* Initialize all port interrupt end point to port 0 int | 1655 | /* Initialize all port interrupt end point to port 0 int |
1531 | * endpoint. Our device has only one interrupt endpoint | 1656 | * endpoint. Our device has only one interrupt endpoint |
1532 | * comman to all ports */ | 1657 | * common to all ports */ |
1533 | serial->port[i]->interrupt_in_endpointAddress = | 1658 | serial->port[i]->interrupt_in_endpointAddress = |
1534 | serial->port[0]->interrupt_in_endpointAddress; | 1659 | serial->port[0]->interrupt_in_endpointAddress; |
1535 | 1660 | ||
@@ -1584,11 +1709,12 @@ static struct usb_serial_driver moschip7720_2port_driver = { | |||
1584 | .description = "Moschip 2 port adapter", | 1709 | .description = "Moschip 2 port adapter", |
1585 | .usb_driver = &usb_driver, | 1710 | .usb_driver = &usb_driver, |
1586 | .id_table = moschip_port_id_table, | 1711 | .id_table = moschip_port_id_table, |
1587 | .num_ports = 2, | 1712 | .calc_num_ports = mos77xx_calc_num_ports, |
1588 | .open = mos7720_open, | 1713 | .open = mos7720_open, |
1589 | .close = mos7720_close, | 1714 | .close = mos7720_close, |
1590 | .throttle = mos7720_throttle, | 1715 | .throttle = mos7720_throttle, |
1591 | .unthrottle = mos7720_unthrottle, | 1716 | .unthrottle = mos7720_unthrottle, |
1717 | .probe = mos77xx_probe, | ||
1592 | .attach = mos7720_startup, | 1718 | .attach = mos7720_startup, |
1593 | .release = mos7720_release, | 1719 | .release = mos7720_release, |
1594 | .ioctl = mos7720_ioctl, | 1720 | .ioctl = mos7720_ioctl, |
@@ -1600,7 +1726,7 @@ static struct usb_serial_driver moschip7720_2port_driver = { | |||
1600 | .chars_in_buffer = mos7720_chars_in_buffer, | 1726 | .chars_in_buffer = mos7720_chars_in_buffer, |
1601 | .break_ctl = mos7720_break, | 1727 | .break_ctl = mos7720_break, |
1602 | .read_bulk_callback = mos7720_bulk_in_callback, | 1728 | .read_bulk_callback = mos7720_bulk_in_callback, |
1603 | .read_int_callback = mos7720_interrupt_callback, | 1729 | .read_int_callback = NULL /* dynamically assigned in probe() */ |
1604 | }; | 1730 | }; |
1605 | 1731 | ||
1606 | static int __init moschip7720_init(void) | 1732 | static int __init moschip7720_init(void) |