diff options
Diffstat (limited to 'drivers/usb/serial/mos7720.c')
-rw-r--r-- | drivers/usb/serial/mos7720.c | 185 |
1 files changed, 155 insertions, 30 deletions
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index 763e32a44be0..0d47f2c4d59f 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 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); |
@@ -106,7 +109,7 @@ static void mos7720_interrupt_callback(struct urb *urb) | |||
106 | __u8 sp1; | 109 | __u8 sp1; |
107 | __u8 sp2; | 110 | __u8 sp2; |
108 | 111 | ||
109 | dbg("%s", " : Entering\n"); | 112 | dbg(" : Entering"); |
110 | 113 | ||
111 | switch (status) { | 114 | switch (status) { |
112 | case 0: | 115 | case 0: |
@@ -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. |
@@ -206,7 +278,7 @@ static void mos7720_bulk_in_callback(struct urb *urb) | |||
206 | 278 | ||
207 | mos7720_port = urb->context; | 279 | mos7720_port = urb->context; |
208 | if (!mos7720_port) { | 280 | if (!mos7720_port) { |
209 | dbg("%s", "NULL mos7720_port pointer \n"); | 281 | dbg("NULL mos7720_port pointer"); |
210 | return ; | 282 | return ; |
211 | } | 283 | } |
212 | 284 | ||
@@ -218,7 +290,6 @@ static void mos7720_bulk_in_callback(struct urb *urb) | |||
218 | 290 | ||
219 | tty = tty_port_tty_get(&port->port); | 291 | tty = tty_port_tty_get(&port->port); |
220 | if (tty && urb->actual_length) { | 292 | if (tty && urb->actual_length) { |
221 | tty_buffer_request_room(tty, urb->actual_length); | ||
222 | tty_insert_flip_string(tty, data, urb->actual_length); | 293 | tty_insert_flip_string(tty, data, urb->actual_length); |
223 | tty_flip_buffer_push(tty); | 294 | tty_flip_buffer_push(tty); |
224 | } | 295 | } |
@@ -275,17 +346,15 @@ static void mos7720_bulk_out_data_callback(struct urb *urb) | |||
275 | * this function will be used for sending command to device | 346 | * this function will be used for sending command to device |
276 | */ | 347 | */ |
277 | static int send_mos_cmd(struct usb_serial *serial, __u8 request, __u16 value, | 348 | static int send_mos_cmd(struct usb_serial *serial, __u8 request, __u16 value, |
278 | __u16 index, void *data) | 349 | __u16 index, u8 *data) |
279 | { | 350 | { |
280 | int status; | 351 | int status; |
281 | unsigned int pipe; | 352 | u8 *buf; |
282 | u16 product = le16_to_cpu(serial->dev->descriptor.idProduct); | 353 | u16 product = le16_to_cpu(serial->dev->descriptor.idProduct); |
283 | __u8 requesttype; | ||
284 | __u16 size = 0x0000; | ||
285 | 354 | ||
286 | if (value < MOS_MAX_PORT) { | 355 | if (value < MOS_MAX_PORT) { |
287 | if (product == MOSCHIP_DEVICE_ID_7715) | 356 | if (product == MOSCHIP_DEVICE_ID_7715) |
288 | value = value*0x100+0x100; | 357 | value = 0x0200; /* identifies the 7715's serial port */ |
289 | else | 358 | else |
290 | value = value*0x100+0x200; | 359 | value = value*0x100+0x200; |
291 | } else { | 360 | } else { |
@@ -298,27 +367,58 @@ static int send_mos_cmd(struct usb_serial *serial, __u8 request, __u16 value, | |||
298 | } | 367 | } |
299 | 368 | ||
300 | if (request == MOS_WRITE) { | 369 | if (request == MOS_WRITE) { |
301 | request = (__u8)MOS_WRITE; | 370 | value = value + *data; |
302 | requesttype = (__u8)0x40; | 371 | status = usb_control_msg(serial->dev, |
303 | value = value + (__u16)*((unsigned char *)data); | 372 | usb_sndctrlpipe(serial->dev, 0), MOS_WRITE, |
304 | data = NULL; | 373 | 0x40, value, index, NULL, 0, MOS_WDR_TIMEOUT); |
305 | pipe = usb_sndctrlpipe(serial->dev, 0); | ||
306 | } else { | 374 | } else { |
307 | request = (__u8)MOS_READ; | 375 | buf = kmalloc(1, GFP_KERNEL); |
308 | requesttype = (__u8)0xC0; | 376 | if (!buf) { |
309 | size = 0x01; | 377 | status = -ENOMEM; |
310 | pipe = usb_rcvctrlpipe(serial->dev, 0); | 378 | goto out; |
379 | } | ||
380 | status = usb_control_msg(serial->dev, | ||
381 | usb_rcvctrlpipe(serial->dev, 0), MOS_READ, | ||
382 | 0xc0, value, index, buf, 1, MOS_WDR_TIMEOUT); | ||
383 | *data = *buf; | ||
384 | kfree(buf); | ||
311 | } | 385 | } |
312 | 386 | out: | |
313 | status = usb_control_msg(serial->dev, pipe, request, requesttype, | ||
314 | value, index, data, size, MOS_WDR_TIMEOUT); | ||
315 | |||
316 | if (status < 0) | 387 | if (status < 0) |
317 | dbg("Command Write failed Value %x index %x\n", value, index); | 388 | dbg("Command Write failed Value %x index %x", value, index); |
318 | 389 | ||
319 | return status; | 390 | return status; |
320 | } | 391 | } |
321 | 392 | ||
393 | |||
394 | /* | ||
395 | * mos77xx_probe | ||
396 | * this function installs the appropriate read interrupt endpoint callback | ||
397 | * depending on whether the device is a 7720 or 7715, thus avoiding costly | ||
398 | * run-time checks in the high-frequency callback routine itself. | ||
399 | */ | ||
400 | static int mos77xx_probe(struct usb_serial *serial, | ||
401 | const struct usb_device_id *id) | ||
402 | { | ||
403 | if (id->idProduct == MOSCHIP_DEVICE_ID_7715) | ||
404 | moschip7720_2port_driver.read_int_callback = | ||
405 | mos7715_interrupt_callback; | ||
406 | else | ||
407 | moschip7720_2port_driver.read_int_callback = | ||
408 | mos7720_interrupt_callback; | ||
409 | |||
410 | return 0; | ||
411 | } | ||
412 | |||
413 | static int mos77xx_calc_num_ports(struct usb_serial *serial) | ||
414 | { | ||
415 | u16 product = le16_to_cpu(serial->dev->descriptor.idProduct); | ||
416 | if (product == MOSCHIP_DEVICE_ID_7715) | ||
417 | return 1; | ||
418 | |||
419 | return 2; | ||
420 | } | ||
421 | |||
322 | static int mos7720_open(struct tty_struct *tty, struct usb_serial_port *port) | 422 | static int mos7720_open(struct tty_struct *tty, struct usb_serial_port *port) |
323 | { | 423 | { |
324 | struct usb_serial *serial; | 424 | struct usb_serial *serial; |
@@ -390,7 +490,7 @@ static int mos7720_open(struct tty_struct *tty, struct usb_serial_port *port) | |||
390 | */ | 490 | */ |
391 | port_number = port->number - port->serial->minor; | 491 | port_number = port->number - port->serial->minor; |
392 | send_mos_cmd(port->serial, MOS_READ, port_number, UART_LSR, &data); | 492 | send_mos_cmd(port->serial, MOS_READ, port_number, UART_LSR, &data); |
393 | dbg("SS::%p LSR:%x\n", mos7720_port, data); | 493 | dbg("SS::%p LSR:%x", mos7720_port, data); |
394 | 494 | ||
395 | dbg("Check:Sending Command .........."); | 495 | dbg("Check:Sending Command .........."); |
396 | 496 | ||
@@ -729,7 +829,7 @@ static void mos7720_throttle(struct tty_struct *tty) | |||
729 | struct moschip_port *mos7720_port; | 829 | struct moschip_port *mos7720_port; |
730 | int status; | 830 | int status; |
731 | 831 | ||
732 | dbg("%s- port %d\n", __func__, port->number); | 832 | dbg("%s- port %d", __func__, port->number); |
733 | 833 | ||
734 | mos7720_port = usb_get_serial_port_data(port); | 834 | mos7720_port = usb_get_serial_port_data(port); |
735 | 835 | ||
@@ -1208,7 +1308,7 @@ static void mos7720_set_termios(struct tty_struct *tty, | |||
1208 | return; | 1308 | return; |
1209 | } | 1309 | } |
1210 | 1310 | ||
1211 | dbg("%s\n", "setting termios - ASPIRE"); | 1311 | dbg("setting termios - ASPIRE"); |
1212 | 1312 | ||
1213 | cflag = tty->termios->c_cflag; | 1313 | cflag = tty->termios->c_cflag; |
1214 | 1314 | ||
@@ -1226,7 +1326,7 @@ static void mos7720_set_termios(struct tty_struct *tty, | |||
1226 | change_port_settings(tty, mos7720_port, old_termios); | 1326 | change_port_settings(tty, mos7720_port, old_termios); |
1227 | 1327 | ||
1228 | if (!port->read_urb) { | 1328 | if (!port->read_urb) { |
1229 | dbg("%s", "URB KILLED !!!!!\n"); | 1329 | dbg("URB KILLED !!!!!"); |
1230 | return; | 1330 | return; |
1231 | } | 1331 | } |
1232 | 1332 | ||
@@ -1495,6 +1595,7 @@ static int mos7720_startup(struct usb_serial *serial) | |||
1495 | struct usb_device *dev; | 1595 | struct usb_device *dev; |
1496 | int i; | 1596 | int i; |
1497 | char data; | 1597 | char data; |
1598 | u16 product = le16_to_cpu(serial->dev->descriptor.idProduct); | ||
1498 | 1599 | ||
1499 | dbg("%s: Entering ..........", __func__); | 1600 | dbg("%s: Entering ..........", __func__); |
1500 | 1601 | ||
@@ -1514,6 +1615,29 @@ static int mos7720_startup(struct usb_serial *serial) | |||
1514 | 1615 | ||
1515 | usb_set_serial_data(serial, mos7720_serial); | 1616 | usb_set_serial_data(serial, mos7720_serial); |
1516 | 1617 | ||
1618 | /* | ||
1619 | * The 7715 uses the first bulk in/out endpoint pair for the parallel | ||
1620 | * port, and the second for the serial port. Because the usbserial core | ||
1621 | * assumes both pairs are serial ports, we must engage in a bit of | ||
1622 | * subterfuge and swap the pointers for ports 0 and 1 in order to make | ||
1623 | * port 0 point to the serial port. However, both moschip devices use a | ||
1624 | * single interrupt-in endpoint for both ports (as mentioned a little | ||
1625 | * further down), and this endpoint was assigned to port 0. So after | ||
1626 | * the swap, we must copy the interrupt endpoint elements from port 1 | ||
1627 | * (as newly assigned) to port 0, and null out port 1 pointers. | ||
1628 | */ | ||
1629 | if (product == MOSCHIP_DEVICE_ID_7715) { | ||
1630 | struct usb_serial_port *tmp = serial->port[0]; | ||
1631 | serial->port[0] = serial->port[1]; | ||
1632 | serial->port[1] = tmp; | ||
1633 | serial->port[0]->interrupt_in_urb = tmp->interrupt_in_urb; | ||
1634 | serial->port[0]->interrupt_in_buffer = tmp->interrupt_in_buffer; | ||
1635 | serial->port[0]->interrupt_in_endpointAddress = | ||
1636 | tmp->interrupt_in_endpointAddress; | ||
1637 | serial->port[1]->interrupt_in_urb = NULL; | ||
1638 | serial->port[1]->interrupt_in_buffer = NULL; | ||
1639 | } | ||
1640 | |||
1517 | /* we set up the pointers to the endpoints in the mos7720_open * | 1641 | /* we set up the pointers to the endpoints in the mos7720_open * |
1518 | * function, as the structures aren't created yet. */ | 1642 | * function, as the structures aren't created yet. */ |
1519 | 1643 | ||
@@ -1529,7 +1653,7 @@ static int mos7720_startup(struct usb_serial *serial) | |||
1529 | 1653 | ||
1530 | /* Initialize all port interrupt end point to port 0 int | 1654 | /* Initialize all port interrupt end point to port 0 int |
1531 | * endpoint. Our device has only one interrupt endpoint | 1655 | * endpoint. Our device has only one interrupt endpoint |
1532 | * comman to all ports */ | 1656 | * common to all ports */ |
1533 | serial->port[i]->interrupt_in_endpointAddress = | 1657 | serial->port[i]->interrupt_in_endpointAddress = |
1534 | serial->port[0]->interrupt_in_endpointAddress; | 1658 | serial->port[0]->interrupt_in_endpointAddress; |
1535 | 1659 | ||
@@ -1584,11 +1708,12 @@ static struct usb_serial_driver moschip7720_2port_driver = { | |||
1584 | .description = "Moschip 2 port adapter", | 1708 | .description = "Moschip 2 port adapter", |
1585 | .usb_driver = &usb_driver, | 1709 | .usb_driver = &usb_driver, |
1586 | .id_table = moschip_port_id_table, | 1710 | .id_table = moschip_port_id_table, |
1587 | .num_ports = 2, | 1711 | .calc_num_ports = mos77xx_calc_num_ports, |
1588 | .open = mos7720_open, | 1712 | .open = mos7720_open, |
1589 | .close = mos7720_close, | 1713 | .close = mos7720_close, |
1590 | .throttle = mos7720_throttle, | 1714 | .throttle = mos7720_throttle, |
1591 | .unthrottle = mos7720_unthrottle, | 1715 | .unthrottle = mos7720_unthrottle, |
1716 | .probe = mos77xx_probe, | ||
1592 | .attach = mos7720_startup, | 1717 | .attach = mos7720_startup, |
1593 | .release = mos7720_release, | 1718 | .release = mos7720_release, |
1594 | .ioctl = mos7720_ioctl, | 1719 | .ioctl = mos7720_ioctl, |
@@ -1600,7 +1725,7 @@ static struct usb_serial_driver moschip7720_2port_driver = { | |||
1600 | .chars_in_buffer = mos7720_chars_in_buffer, | 1725 | .chars_in_buffer = mos7720_chars_in_buffer, |
1601 | .break_ctl = mos7720_break, | 1726 | .break_ctl = mos7720_break, |
1602 | .read_bulk_callback = mos7720_bulk_in_callback, | 1727 | .read_bulk_callback = mos7720_bulk_in_callback, |
1603 | .read_int_callback = mos7720_interrupt_callback, | 1728 | .read_int_callback = NULL /* dynamically assigned in probe() */ |
1604 | }; | 1729 | }; |
1605 | 1730 | ||
1606 | static int __init moschip7720_init(void) | 1731 | static int __init moschip7720_init(void) |