aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/serial/mos7840.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-07-31 14:31:36 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-07-31 14:31:36 -0400
commit3132be9aefc6c7edd42156a35cc2a2134d154f5d (patch)
tree99dddada0e24e84d62855adf0a624c5ba4e35a01 /drivers/usb/serial/mos7840.c
parenta93f66dc5ff51a8f88f13e4a4b8e3e51ed89c0a5 (diff)
parentfed1f1ed90bce42ea010e2904cbc04e7b8304940 (diff)
Merge tag 'usb-3.11-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
Pull USB fixes from Greg KH: "Here are some tiny USB fixes for 3.11-rc4 Nothing major, some gadget fixes, some new device ids, a new tiny driver for the ANT+ USB device, and a number of fixes for the mos7840 driver that were much needed" * tag 'usb-3.11-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: USB: serial: ftdi_sio: add more RT Systems ftdi devices usb: chipidea: fix the build error with randconfig usb: chipidea: cast PORTSC_PTS and DEVLC_PTS macros usb: gadget: udc-core: fix the typo of udc state attribute usb: gadget: f_phonet: remove unused preprocessor conditional usb: gadget: multi: fix error return code in cdc_do_config() USB: mos7840: fix pointer casts USB: mos7840: fix race in led handling USB: mos7840: fix device-type detection USB: mos7840: fix race in register handling USB: serial: add driver for Suunto ANT+ USB device usb: gadget: free opts struct on error recovery usb: gadget: ether: put_usb_function on unbind usb: musb: fix resource passed from glue layer to musb
Diffstat (limited to 'drivers/usb/serial/mos7840.c')
-rw-r--r--drivers/usb/serial/mos7840.c150
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
186static int device_type; 186enum mos7840_flag {
187 MOS7840_FLAG_CTRL_BUSY,
188 MOS7840_FLAG_LED_BUSY,
189};
187 190
188static const struct usb_device_id id_table[] = { 191static 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);
485out:
486 clear_bit_unlock(MOS7840_FLAG_CTRL_BUSY, &mos7840_port->flags);
479} 487}
480 488
481static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg, 489static 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
540static void mos7840_set_led_sync(struct usb_serial_port *port, __u16 reg, 554static 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
580static 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
820static 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
2190static int mos7840_calc_num_ports(struct usb_serial *serial) 2193static 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 2223out:
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
2229static 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)
2226static int mos7840_port_probe(struct usb_serial_port *port) 2239static 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;
2438error: 2458error:
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,