aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/serial/mos7720.c
diff options
context:
space:
mode:
authorMike Dunn <mikedunn@newsguy.com>2010-01-26 12:12:12 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2010-03-02 17:54:47 -0500
commitfb088e335d78f866be2e56eac6d500112a96aa11 (patch)
tree84cd239a722a0087aeedb97d2c529a8f2a1e705b /drivers/usb/serial/mos7720.c
parentf10718f5b812a2c55e37396518d426f88d5e35fc (diff)
USB: serial: add support for serial port on the moschip 7715
Add support for the serial port on devices based on the MosChip 7715, which provides a serial and parallel port on a single usb interface. This is added to the existing driver for the Moschip 7720 dual serial port device. The 7715 is very similiar to the 7720, requiring only the addition of a calc_num_ports() function, a separate interrupt-in endpoint callback, and some manipulation of the port pointers added to the attach() function to correct the fact that the usbserial core erroneously assigns the first bulk in/out endpoint pair to the serial port (the 7715 uses these for its parallel port). There is no support for the 7715's parallel port yet. Signed-off-by: Mike Dunn <mikedunn@newsguy.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/serial/mos7720.c')
-rw-r--r--drivers/usb/serial/mos7720.c134
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
82static int debug; 82static int debug;
83 83
84static 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
88static const struct usb_device_id moschip_port_id_table[] = { 90static 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};
92MODULE_DEVICE_TABLE(usb, moschip_port_id_table); 95MODULE_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 */
196static 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
251exit:
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 */
401static 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
414static 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
322static int mos7720_open(struct tty_struct *tty, struct usb_serial_port *port) 423static 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
1606static int __init moschip7720_init(void) 1732static int __init moschip7720_init(void)