diff options
Diffstat (limited to 'drivers/usb/serial/mos7840.c')
-rw-r--r-- | drivers/usb/serial/mos7840.c | 150 |
1 files changed, 87 insertions, 63 deletions
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 603fb70dde80..d953d674f222 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c | |||
@@ -183,7 +183,10 @@ | |||
183 | #define LED_ON_MS 500 | 183 | #define LED_ON_MS 500 |
184 | #define LED_OFF_MS 500 | 184 | #define LED_OFF_MS 500 |
185 | 185 | ||
186 | static int device_type; | 186 | enum mos7840_flag { |
187 | MOS7840_FLAG_CTRL_BUSY, | ||
188 | MOS7840_FLAG_LED_BUSY, | ||
189 | }; | ||
187 | 190 | ||
188 | static const struct usb_device_id id_table[] = { | 191 | static const struct usb_device_id id_table[] = { |
189 | {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)}, | 192 | {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)}, |
@@ -238,9 +241,12 @@ struct moschip_port { | |||
238 | 241 | ||
239 | /* For device(s) with LED indicator */ | 242 | /* For device(s) with LED indicator */ |
240 | bool has_led; | 243 | bool has_led; |
241 | bool led_flag; | ||
242 | struct timer_list led_timer1; /* Timer for LED on */ | 244 | struct timer_list led_timer1; /* Timer for LED on */ |
243 | struct timer_list led_timer2; /* Timer for LED off */ | 245 | struct timer_list led_timer2; /* Timer for LED off */ |
246 | struct urb *led_urb; | ||
247 | struct usb_ctrlrequest *led_dr; | ||
248 | |||
249 | unsigned long flags; | ||
244 | }; | 250 | }; |
245 | 251 | ||
246 | /* | 252 | /* |
@@ -460,10 +466,10 @@ static void mos7840_control_callback(struct urb *urb) | |||
460 | case -ESHUTDOWN: | 466 | case -ESHUTDOWN: |
461 | /* this urb is terminated, clean up */ | 467 | /* this urb is terminated, clean up */ |
462 | dev_dbg(dev, "%s - urb shutting down with status: %d\n", __func__, status); | 468 | dev_dbg(dev, "%s - urb shutting down with status: %d\n", __func__, status); |
463 | return; | 469 | goto out; |
464 | default: | 470 | default: |
465 | dev_dbg(dev, "%s - nonzero urb status received: %d\n", __func__, status); | 471 | dev_dbg(dev, "%s - nonzero urb status received: %d\n", __func__, status); |
466 | return; | 472 | goto out; |
467 | } | 473 | } |
468 | 474 | ||
469 | dev_dbg(dev, "%s urb buffer size is %d\n", __func__, urb->actual_length); | 475 | dev_dbg(dev, "%s urb buffer size is %d\n", __func__, urb->actual_length); |
@@ -476,6 +482,8 @@ static void mos7840_control_callback(struct urb *urb) | |||
476 | mos7840_handle_new_msr(mos7840_port, regval); | 482 | mos7840_handle_new_msr(mos7840_port, regval); |
477 | else if (mos7840_port->MsrLsr == 1) | 483 | else if (mos7840_port->MsrLsr == 1) |
478 | mos7840_handle_new_lsr(mos7840_port, regval); | 484 | mos7840_handle_new_lsr(mos7840_port, regval); |
485 | out: | ||
486 | clear_bit_unlock(MOS7840_FLAG_CTRL_BUSY, &mos7840_port->flags); | ||
479 | } | 487 | } |
480 | 488 | ||
481 | static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg, | 489 | static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg, |
@@ -486,6 +494,9 @@ static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg, | |||
486 | unsigned char *buffer = mcs->ctrl_buf; | 494 | unsigned char *buffer = mcs->ctrl_buf; |
487 | int ret; | 495 | int ret; |
488 | 496 | ||
497 | if (test_and_set_bit_lock(MOS7840_FLAG_CTRL_BUSY, &mcs->flags)) | ||
498 | return -EBUSY; | ||
499 | |||
489 | dr->bRequestType = MCS_RD_RTYPE; | 500 | dr->bRequestType = MCS_RD_RTYPE; |
490 | dr->bRequest = MCS_RDREQ; | 501 | dr->bRequest = MCS_RDREQ; |
491 | dr->wValue = cpu_to_le16(Wval); /* 0 */ | 502 | dr->wValue = cpu_to_le16(Wval); /* 0 */ |
@@ -497,6 +508,9 @@ static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg, | |||
497 | mos7840_control_callback, mcs); | 508 | mos7840_control_callback, mcs); |
498 | mcs->control_urb->transfer_buffer_length = 2; | 509 | mcs->control_urb->transfer_buffer_length = 2; |
499 | ret = usb_submit_urb(mcs->control_urb, GFP_ATOMIC); | 510 | ret = usb_submit_urb(mcs->control_urb, GFP_ATOMIC); |
511 | if (ret) | ||
512 | clear_bit_unlock(MOS7840_FLAG_CTRL_BUSY, &mcs->flags); | ||
513 | |||
500 | return ret; | 514 | return ret; |
501 | } | 515 | } |
502 | 516 | ||
@@ -523,7 +537,7 @@ static void mos7840_set_led_async(struct moschip_port *mcs, __u16 wval, | |||
523 | __u16 reg) | 537 | __u16 reg) |
524 | { | 538 | { |
525 | struct usb_device *dev = mcs->port->serial->dev; | 539 | struct usb_device *dev = mcs->port->serial->dev; |
526 | struct usb_ctrlrequest *dr = mcs->dr; | 540 | struct usb_ctrlrequest *dr = mcs->led_dr; |
527 | 541 | ||
528 | dr->bRequestType = MCS_WR_RTYPE; | 542 | dr->bRequestType = MCS_WR_RTYPE; |
529 | dr->bRequest = MCS_WRREQ; | 543 | dr->bRequest = MCS_WRREQ; |
@@ -531,10 +545,10 @@ static void mos7840_set_led_async(struct moschip_port *mcs, __u16 wval, | |||
531 | dr->wIndex = cpu_to_le16(reg); | 545 | dr->wIndex = cpu_to_le16(reg); |
532 | dr->wLength = cpu_to_le16(0); | 546 | dr->wLength = cpu_to_le16(0); |
533 | 547 | ||
534 | usb_fill_control_urb(mcs->control_urb, dev, usb_sndctrlpipe(dev, 0), | 548 | usb_fill_control_urb(mcs->led_urb, dev, usb_sndctrlpipe(dev, 0), |
535 | (unsigned char *)dr, NULL, 0, mos7840_set_led_callback, NULL); | 549 | (unsigned char *)dr, NULL, 0, mos7840_set_led_callback, NULL); |
536 | 550 | ||
537 | usb_submit_urb(mcs->control_urb, GFP_ATOMIC); | 551 | usb_submit_urb(mcs->led_urb, GFP_ATOMIC); |
538 | } | 552 | } |
539 | 553 | ||
540 | static void mos7840_set_led_sync(struct usb_serial_port *port, __u16 reg, | 554 | static void mos7840_set_led_sync(struct usb_serial_port *port, __u16 reg, |
@@ -560,7 +574,19 @@ static void mos7840_led_flag_off(unsigned long arg) | |||
560 | { | 574 | { |
561 | struct moschip_port *mcs = (struct moschip_port *) arg; | 575 | struct moschip_port *mcs = (struct moschip_port *) arg; |
562 | 576 | ||
563 | mcs->led_flag = false; | 577 | clear_bit_unlock(MOS7840_FLAG_LED_BUSY, &mcs->flags); |
578 | } | ||
579 | |||
580 | static void mos7840_led_activity(struct usb_serial_port *port) | ||
581 | { | ||
582 | struct moschip_port *mos7840_port = usb_get_serial_port_data(port); | ||
583 | |||
584 | if (test_and_set_bit_lock(MOS7840_FLAG_LED_BUSY, &mos7840_port->flags)) | ||
585 | return; | ||
586 | |||
587 | mos7840_set_led_async(mos7840_port, 0x0301, MODEM_CONTROL_REGISTER); | ||
588 | mod_timer(&mos7840_port->led_timer1, | ||
589 | jiffies + msecs_to_jiffies(LED_ON_MS)); | ||
564 | } | 590 | } |
565 | 591 | ||
566 | /***************************************************************************** | 592 | /***************************************************************************** |
@@ -758,14 +784,8 @@ static void mos7840_bulk_in_callback(struct urb *urb) | |||
758 | return; | 784 | return; |
759 | } | 785 | } |
760 | 786 | ||
761 | /* Turn on LED */ | 787 | if (mos7840_port->has_led) |
762 | if (mos7840_port->has_led && !mos7840_port->led_flag) { | 788 | mos7840_led_activity(port); |
763 | mos7840_port->led_flag = true; | ||
764 | mos7840_set_led_async(mos7840_port, 0x0301, | ||
765 | MODEM_CONTROL_REGISTER); | ||
766 | mod_timer(&mos7840_port->led_timer1, | ||
767 | jiffies + msecs_to_jiffies(LED_ON_MS)); | ||
768 | } | ||
769 | 789 | ||
770 | mos7840_port->read_urb_busy = true; | 790 | mos7840_port->read_urb_busy = true; |
771 | retval = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC); | 791 | retval = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC); |
@@ -816,18 +836,6 @@ static void mos7840_bulk_out_data_callback(struct urb *urb) | |||
816 | /************************************************************************/ | 836 | /************************************************************************/ |
817 | /* D R I V E R T T Y I N T E R F A C E F U N C T I O N S */ | 837 | /* D R I V E R T T Y I N T E R F A C E F U N C T I O N S */ |
818 | /************************************************************************/ | 838 | /************************************************************************/ |
819 | #ifdef MCSSerialProbe | ||
820 | static int mos7840_serial_probe(struct usb_serial *serial, | ||
821 | const struct usb_device_id *id) | ||
822 | { | ||
823 | |||
824 | /*need to implement the mode_reg reading and updating\ | ||
825 | structures usb_serial_ device_type\ | ||
826 | (i.e num_ports, num_bulkin,bulkout etc) */ | ||
827 | /* Also we can update the changes attach */ | ||
828 | return 1; | ||
829 | } | ||
830 | #endif | ||
831 | 839 | ||
832 | /***************************************************************************** | 840 | /***************************************************************************** |
833 | * mos7840_open | 841 | * mos7840_open |
@@ -1454,13 +1462,8 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port, | |||
1454 | data1 = urb->transfer_buffer; | 1462 | data1 = urb->transfer_buffer; |
1455 | dev_dbg(&port->dev, "bulkout endpoint is %d\n", port->bulk_out_endpointAddress); | 1463 | dev_dbg(&port->dev, "bulkout endpoint is %d\n", port->bulk_out_endpointAddress); |
1456 | 1464 | ||
1457 | /* Turn on LED */ | 1465 | if (mos7840_port->has_led) |
1458 | if (mos7840_port->has_led && !mos7840_port->led_flag) { | 1466 | mos7840_led_activity(port); |
1459 | mos7840_port->led_flag = true; | ||
1460 | mos7840_set_led_sync(port, MODEM_CONTROL_REGISTER, 0x0301); | ||
1461 | mod_timer(&mos7840_port->led_timer1, | ||
1462 | jiffies + msecs_to_jiffies(LED_ON_MS)); | ||
1463 | } | ||
1464 | 1467 | ||
1465 | /* send it down the pipe */ | 1468 | /* send it down the pipe */ |
1466 | status = usb_submit_urb(urb, GFP_ATOMIC); | 1469 | status = usb_submit_urb(urb, GFP_ATOMIC); |
@@ -2187,38 +2190,48 @@ static int mos7810_check(struct usb_serial *serial) | |||
2187 | return 0; | 2190 | return 0; |
2188 | } | 2191 | } |
2189 | 2192 | ||
2190 | static int mos7840_calc_num_ports(struct usb_serial *serial) | 2193 | static int mos7840_probe(struct usb_serial *serial, |
2194 | const struct usb_device_id *id) | ||
2191 | { | 2195 | { |
2192 | __u16 data = 0x00; | 2196 | u16 product = serial->dev->descriptor.idProduct; |
2193 | u8 *buf; | 2197 | u8 *buf; |
2194 | int mos7840_num_ports; | 2198 | int device_type; |
2199 | |||
2200 | if (product == MOSCHIP_DEVICE_ID_7810 || | ||
2201 | product == MOSCHIP_DEVICE_ID_7820) { | ||
2202 | device_type = product; | ||
2203 | goto out; | ||
2204 | } | ||
2195 | 2205 | ||
2196 | buf = kzalloc(VENDOR_READ_LENGTH, GFP_KERNEL); | 2206 | buf = kzalloc(VENDOR_READ_LENGTH, GFP_KERNEL); |
2197 | if (buf) { | 2207 | if (!buf) |
2198 | usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), | 2208 | return -ENOMEM; |
2209 | |||
2210 | usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), | ||
2199 | MCS_RDREQ, MCS_RD_RTYPE, 0, GPIO_REGISTER, buf, | 2211 | MCS_RDREQ, MCS_RD_RTYPE, 0, GPIO_REGISTER, buf, |
2200 | VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT); | 2212 | VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT); |
2201 | data = *buf; | ||
2202 | kfree(buf); | ||
2203 | } | ||
2204 | 2213 | ||
2205 | if (serial->dev->descriptor.idProduct == MOSCHIP_DEVICE_ID_7810 || | 2214 | /* For a MCS7840 device GPIO0 must be set to 1 */ |
2206 | serial->dev->descriptor.idProduct == MOSCHIP_DEVICE_ID_7820) { | 2215 | if (buf[0] & 0x01) |
2207 | device_type = serial->dev->descriptor.idProduct; | 2216 | device_type = MOSCHIP_DEVICE_ID_7840; |
2208 | } else { | 2217 | else if (mos7810_check(serial)) |
2209 | /* For a MCS7840 device GPIO0 must be set to 1 */ | 2218 | device_type = MOSCHIP_DEVICE_ID_7810; |
2210 | if ((data & 0x01) == 1) | 2219 | else |
2211 | device_type = MOSCHIP_DEVICE_ID_7840; | 2220 | device_type = MOSCHIP_DEVICE_ID_7820; |
2212 | else if (mos7810_check(serial)) | 2221 | |
2213 | device_type = MOSCHIP_DEVICE_ID_7810; | 2222 | kfree(buf); |
2214 | else | 2223 | out: |
2215 | device_type = MOSCHIP_DEVICE_ID_7820; | 2224 | usb_set_serial_data(serial, (void *)(unsigned long)device_type); |
2216 | } | 2225 | |
2226 | return 0; | ||
2227 | } | ||
2228 | |||
2229 | static int mos7840_calc_num_ports(struct usb_serial *serial) | ||
2230 | { | ||
2231 | int device_type = (unsigned long)usb_get_serial_data(serial); | ||
2232 | int mos7840_num_ports; | ||
2217 | 2233 | ||
2218 | mos7840_num_ports = (device_type >> 4) & 0x000F; | 2234 | mos7840_num_ports = (device_type >> 4) & 0x000F; |
2219 | serial->num_bulk_in = mos7840_num_ports; | ||
2220 | serial->num_bulk_out = mos7840_num_ports; | ||
2221 | serial->num_ports = mos7840_num_ports; | ||
2222 | 2235 | ||
2223 | return mos7840_num_ports; | 2236 | return mos7840_num_ports; |
2224 | } | 2237 | } |
@@ -2226,6 +2239,7 @@ static int mos7840_calc_num_ports(struct usb_serial *serial) | |||
2226 | static int mos7840_port_probe(struct usb_serial_port *port) | 2239 | static int mos7840_port_probe(struct usb_serial_port *port) |
2227 | { | 2240 | { |
2228 | struct usb_serial *serial = port->serial; | 2241 | struct usb_serial *serial = port->serial; |
2242 | int device_type = (unsigned long)usb_get_serial_data(serial); | ||
2229 | struct moschip_port *mos7840_port; | 2243 | struct moschip_port *mos7840_port; |
2230 | int status; | 2244 | int status; |
2231 | int pnum; | 2245 | int pnum; |
@@ -2401,6 +2415,14 @@ static int mos7840_port_probe(struct usb_serial_port *port) | |||
2401 | if (device_type == MOSCHIP_DEVICE_ID_7810) { | 2415 | if (device_type == MOSCHIP_DEVICE_ID_7810) { |
2402 | mos7840_port->has_led = true; | 2416 | mos7840_port->has_led = true; |
2403 | 2417 | ||
2418 | mos7840_port->led_urb = usb_alloc_urb(0, GFP_KERNEL); | ||
2419 | mos7840_port->led_dr = kmalloc(sizeof(*mos7840_port->led_dr), | ||
2420 | GFP_KERNEL); | ||
2421 | if (!mos7840_port->led_urb || !mos7840_port->led_dr) { | ||
2422 | status = -ENOMEM; | ||
2423 | goto error; | ||
2424 | } | ||
2425 | |||
2404 | init_timer(&mos7840_port->led_timer1); | 2426 | init_timer(&mos7840_port->led_timer1); |
2405 | mos7840_port->led_timer1.function = mos7840_led_off; | 2427 | mos7840_port->led_timer1.function = mos7840_led_off; |
2406 | mos7840_port->led_timer1.expires = | 2428 | mos7840_port->led_timer1.expires = |
@@ -2413,8 +2435,6 @@ static int mos7840_port_probe(struct usb_serial_port *port) | |||
2413 | jiffies + msecs_to_jiffies(LED_OFF_MS); | 2435 | jiffies + msecs_to_jiffies(LED_OFF_MS); |
2414 | mos7840_port->led_timer2.data = (unsigned long)mos7840_port; | 2436 | mos7840_port->led_timer2.data = (unsigned long)mos7840_port; |
2415 | 2437 | ||
2416 | mos7840_port->led_flag = false; | ||
2417 | |||
2418 | /* Turn off LED */ | 2438 | /* Turn off LED */ |
2419 | mos7840_set_led_sync(port, MODEM_CONTROL_REGISTER, 0x0300); | 2439 | mos7840_set_led_sync(port, MODEM_CONTROL_REGISTER, 0x0300); |
2420 | } | 2440 | } |
@@ -2436,6 +2456,8 @@ out: | |||
2436 | } | 2456 | } |
2437 | return 0; | 2457 | return 0; |
2438 | error: | 2458 | error: |
2459 | kfree(mos7840_port->led_dr); | ||
2460 | usb_free_urb(mos7840_port->led_urb); | ||
2439 | kfree(mos7840_port->dr); | 2461 | kfree(mos7840_port->dr); |
2440 | kfree(mos7840_port->ctrl_buf); | 2462 | kfree(mos7840_port->ctrl_buf); |
2441 | usb_free_urb(mos7840_port->control_urb); | 2463 | usb_free_urb(mos7840_port->control_urb); |
@@ -2456,6 +2478,10 @@ static int mos7840_port_remove(struct usb_serial_port *port) | |||
2456 | 2478 | ||
2457 | del_timer_sync(&mos7840_port->led_timer1); | 2479 | del_timer_sync(&mos7840_port->led_timer1); |
2458 | del_timer_sync(&mos7840_port->led_timer2); | 2480 | del_timer_sync(&mos7840_port->led_timer2); |
2481 | |||
2482 | usb_kill_urb(mos7840_port->led_urb); | ||
2483 | usb_free_urb(mos7840_port->led_urb); | ||
2484 | kfree(mos7840_port->led_dr); | ||
2459 | } | 2485 | } |
2460 | usb_kill_urb(mos7840_port->control_urb); | 2486 | usb_kill_urb(mos7840_port->control_urb); |
2461 | usb_free_urb(mos7840_port->control_urb); | 2487 | usb_free_urb(mos7840_port->control_urb); |
@@ -2482,9 +2508,7 @@ static struct usb_serial_driver moschip7840_4port_device = { | |||
2482 | .throttle = mos7840_throttle, | 2508 | .throttle = mos7840_throttle, |
2483 | .unthrottle = mos7840_unthrottle, | 2509 | .unthrottle = mos7840_unthrottle, |
2484 | .calc_num_ports = mos7840_calc_num_ports, | 2510 | .calc_num_ports = mos7840_calc_num_ports, |
2485 | #ifdef MCSSerialProbe | 2511 | .probe = mos7840_probe, |
2486 | .probe = mos7840_serial_probe, | ||
2487 | #endif | ||
2488 | .ioctl = mos7840_ioctl, | 2512 | .ioctl = mos7840_ioctl, |
2489 | .set_termios = mos7840_set_termios, | 2513 | .set_termios = mos7840_set_termios, |
2490 | .break_ctl = mos7840_break, | 2514 | .break_ctl = mos7840_break, |