diff options
Diffstat (limited to 'drivers/usb/serial/usb_wwan.c')
-rw-r--r-- | drivers/usb/serial/usb_wwan.c | 130 |
1 files changed, 53 insertions, 77 deletions
diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c index e42aa398ed37..a3e9c095f0d8 100644 --- a/drivers/usb/serial/usb_wwan.c +++ b/drivers/usb/serial/usb_wwan.c | |||
@@ -447,15 +447,14 @@ void usb_wwan_close(struct usb_serial_port *port) | |||
447 | EXPORT_SYMBOL(usb_wwan_close); | 447 | EXPORT_SYMBOL(usb_wwan_close); |
448 | 448 | ||
449 | /* Helper functions used by usb_wwan_setup_urbs */ | 449 | /* Helper functions used by usb_wwan_setup_urbs */ |
450 | static struct urb *usb_wwan_setup_urb(struct usb_serial *serial, int endpoint, | 450 | static struct urb *usb_wwan_setup_urb(struct usb_serial_port *port, |
451 | int endpoint, | ||
451 | int dir, void *ctx, char *buf, int len, | 452 | int dir, void *ctx, char *buf, int len, |
452 | void (*callback) (struct urb *)) | 453 | void (*callback) (struct urb *)) |
453 | { | 454 | { |
455 | struct usb_serial *serial = port->serial; | ||
454 | struct urb *urb; | 456 | struct urb *urb; |
455 | 457 | ||
456 | if (endpoint == -1) | ||
457 | return NULL; /* endpoint not needed */ | ||
458 | |||
459 | urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */ | 458 | urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */ |
460 | if (urb == NULL) { | 459 | if (urb == NULL) { |
461 | dev_dbg(&serial->interface->dev, | 460 | dev_dbg(&serial->interface->dev, |
@@ -472,101 +471,78 @@ static struct urb *usb_wwan_setup_urb(struct usb_serial *serial, int endpoint, | |||
472 | return urb; | 471 | return urb; |
473 | } | 472 | } |
474 | 473 | ||
475 | /* Setup urbs */ | 474 | int usb_wwan_port_probe(struct usb_serial_port *port) |
476 | static void usb_wwan_setup_urbs(struct usb_serial *serial) | ||
477 | { | 475 | { |
478 | int i, j; | ||
479 | struct usb_serial_port *port; | ||
480 | struct usb_wwan_port_private *portdata; | 476 | struct usb_wwan_port_private *portdata; |
477 | struct urb *urb; | ||
478 | u8 *buffer; | ||
479 | int err; | ||
480 | int i; | ||
481 | 481 | ||
482 | for (i = 0; i < serial->num_ports; i++) { | 482 | portdata = kzalloc(sizeof(*portdata), GFP_KERNEL); |
483 | port = serial->port[i]; | 483 | if (!portdata) |
484 | portdata = usb_get_serial_port_data(port); | 484 | return -ENOMEM; |
485 | 485 | ||
486 | /* Do indat endpoints first */ | 486 | init_usb_anchor(&portdata->delayed); |
487 | for (j = 0; j < N_IN_URB; ++j) { | ||
488 | portdata->in_urbs[j] = usb_wwan_setup_urb(serial, | ||
489 | port-> | ||
490 | bulk_in_endpointAddress, | ||
491 | USB_DIR_IN, | ||
492 | port, | ||
493 | portdata-> | ||
494 | in_buffer[j], | ||
495 | IN_BUFLEN, | ||
496 | usb_wwan_indat_callback); | ||
497 | } | ||
498 | 487 | ||
499 | /* outdat endpoints */ | 488 | for (i = 0; i < N_IN_URB; i++) { |
500 | for (j = 0; j < N_OUT_URB; ++j) { | 489 | if (!port->bulk_in_size) |
501 | portdata->out_urbs[j] = usb_wwan_setup_urb(serial, | 490 | break; |
502 | port-> | ||
503 | bulk_out_endpointAddress, | ||
504 | USB_DIR_OUT, | ||
505 | port, | ||
506 | portdata-> | ||
507 | out_buffer | ||
508 | [j], | ||
509 | OUT_BUFLEN, | ||
510 | usb_wwan_outdat_callback); | ||
511 | } | ||
512 | } | ||
513 | } | ||
514 | 491 | ||
515 | int usb_wwan_startup(struct usb_serial *serial) | 492 | buffer = (u8 *)__get_free_page(GFP_KERNEL); |
516 | { | 493 | if (!buffer) |
517 | int i, j, err; | 494 | goto bail_out_error; |
518 | struct usb_serial_port *port; | 495 | portdata->in_buffer[i] = buffer; |
519 | struct usb_wwan_port_private *portdata; | ||
520 | u8 *buffer; | ||
521 | 496 | ||
522 | /* Now setup per port private data */ | 497 | urb = usb_wwan_setup_urb(port, port->bulk_in_endpointAddress, |
523 | for (i = 0; i < serial->num_ports; i++) { | 498 | USB_DIR_IN, port, |
524 | port = serial->port[i]; | 499 | buffer, IN_BUFLEN, |
525 | portdata = kzalloc(sizeof(*portdata), GFP_KERNEL); | 500 | usb_wwan_indat_callback); |
526 | if (!portdata) { | 501 | portdata->in_urbs[i] = urb; |
527 | dev_dbg(&port->dev, "%s: kmalloc for usb_wwan_port_private (%d) failed!.\n", | 502 | } |
528 | __func__, i); | ||
529 | return 1; | ||
530 | } | ||
531 | init_usb_anchor(&portdata->delayed); | ||
532 | 503 | ||
533 | for (j = 0; j < N_IN_URB; j++) { | 504 | for (i = 0; i < N_OUT_URB; i++) { |
534 | buffer = (u8 *) __get_free_page(GFP_KERNEL); | 505 | if (!port->bulk_out_size) |
535 | if (!buffer) | 506 | break; |
536 | goto bail_out_error; | ||
537 | portdata->in_buffer[j] = buffer; | ||
538 | } | ||
539 | 507 | ||
540 | for (j = 0; j < N_OUT_URB; j++) { | 508 | buffer = kmalloc(OUT_BUFLEN, GFP_KERNEL); |
541 | buffer = kmalloc(OUT_BUFLEN, GFP_KERNEL); | 509 | if (!buffer) |
542 | if (!buffer) | 510 | goto bail_out_error2; |
543 | goto bail_out_error2; | 511 | portdata->out_buffer[i] = buffer; |
544 | portdata->out_buffer[j] = buffer; | ||
545 | } | ||
546 | 512 | ||
547 | usb_set_serial_port_data(port, portdata); | 513 | urb = usb_wwan_setup_urb(port, port->bulk_out_endpointAddress, |
514 | USB_DIR_OUT, port, | ||
515 | buffer, OUT_BUFLEN, | ||
516 | usb_wwan_outdat_callback); | ||
517 | portdata->out_urbs[i] = urb; | ||
518 | } | ||
548 | 519 | ||
549 | if (!port->interrupt_in_urb) | 520 | usb_set_serial_port_data(port, portdata); |
550 | continue; | 521 | |
522 | if (port->interrupt_in_urb) { | ||
551 | err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); | 523 | err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); |
552 | if (err) | 524 | if (err) |
553 | dev_dbg(&port->dev, "%s: submit irq_in urb failed %d\n", | 525 | dev_dbg(&port->dev, "%s: submit irq_in urb failed %d\n", |
554 | __func__, err); | 526 | __func__, err); |
555 | } | 527 | } |
556 | usb_wwan_setup_urbs(serial); | 528 | |
557 | return 0; | 529 | return 0; |
558 | 530 | ||
559 | bail_out_error2: | 531 | bail_out_error2: |
560 | for (j = 0; j < N_OUT_URB; j++) | 532 | for (i = 0; i < N_OUT_URB; i++) { |
561 | kfree(portdata->out_buffer[j]); | 533 | usb_free_urb(portdata->out_urbs[i]); |
534 | kfree(portdata->out_buffer[i]); | ||
535 | } | ||
562 | bail_out_error: | 536 | bail_out_error: |
563 | for (j = 0; j < N_IN_URB; j++) | 537 | for (i = 0; i < N_IN_URB; i++) { |
564 | if (portdata->in_buffer[j]) | 538 | usb_free_urb(portdata->in_urbs[i]); |
565 | free_page((unsigned long)portdata->in_buffer[j]); | 539 | free_page((unsigned long)portdata->in_buffer[i]); |
540 | } | ||
566 | kfree(portdata); | 541 | kfree(portdata); |
567 | return 1; | 542 | |
543 | return -ENOMEM; | ||
568 | } | 544 | } |
569 | EXPORT_SYMBOL(usb_wwan_startup); | 545 | EXPORT_SYMBOL_GPL(usb_wwan_port_probe); |
570 | 546 | ||
571 | int usb_wwan_port_remove(struct usb_serial_port *port) | 547 | int usb_wwan_port_remove(struct usb_serial_port *port) |
572 | { | 548 | { |