diff options
Diffstat (limited to 'drivers/usb/serial/usb_wwan.c')
-rw-r--r-- | drivers/usb/serial/usb_wwan.c | 124 |
1 files changed, 50 insertions, 74 deletions
diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c index e42aa398ed3..61a73ad1a18 100644 --- a/drivers/usb/serial/usb_wwan.c +++ b/drivers/usb/serial/usb_wwan.c | |||
@@ -447,10 +447,12 @@ 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) | 458 | if (endpoint == -1) |
@@ -472,101 +474,75 @@ static struct urb *usb_wwan_setup_urb(struct usb_serial *serial, int endpoint, | |||
472 | return urb; | 474 | return urb; |
473 | } | 475 | } |
474 | 476 | ||
475 | /* Setup urbs */ | 477 | int usb_wwan_port_probe(struct usb_serial_port *port) |
476 | static void usb_wwan_setup_urbs(struct usb_serial *serial) | ||
477 | { | 478 | { |
478 | int i, j; | ||
479 | struct usb_serial_port *port; | ||
480 | struct usb_wwan_port_private *portdata; | 479 | struct usb_wwan_port_private *portdata; |
480 | struct urb *urb; | ||
481 | u8 *buffer; | ||
482 | int err; | ||
483 | int i; | ||
481 | 484 | ||
482 | for (i = 0; i < serial->num_ports; i++) { | 485 | portdata = kzalloc(sizeof(*portdata), GFP_KERNEL); |
483 | port = serial->port[i]; | 486 | if (!portdata) |
484 | portdata = usb_get_serial_port_data(port); | 487 | return -ENOMEM; |
485 | 488 | ||
486 | /* Do indat endpoints first */ | 489 | 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 | 490 | ||
499 | /* outdat endpoints */ | 491 | for (i = 0; i < N_IN_URB; i++) { |
500 | for (j = 0; j < N_OUT_URB; ++j) { | 492 | buffer = (u8 *)__get_free_page(GFP_KERNEL); |
501 | portdata->out_urbs[j] = usb_wwan_setup_urb(serial, | 493 | if (!buffer) |
502 | port-> | 494 | goto bail_out_error; |
503 | bulk_out_endpointAddress, | 495 | portdata->in_buffer[i] = buffer; |
504 | USB_DIR_OUT, | 496 | |
505 | port, | 497 | urb = usb_wwan_setup_urb(port, port->bulk_in_endpointAddress, |
506 | portdata-> | 498 | USB_DIR_IN, port, |
507 | out_buffer | 499 | buffer, IN_BUFLEN, |
508 | [j], | 500 | usb_wwan_indat_callback); |
509 | OUT_BUFLEN, | 501 | portdata->in_urbs[i] = urb; |
510 | usb_wwan_outdat_callback); | ||
511 | } | ||
512 | } | 502 | } |
513 | } | ||
514 | |||
515 | int usb_wwan_startup(struct usb_serial *serial) | ||
516 | { | ||
517 | int i, j, err; | ||
518 | struct usb_serial_port *port; | ||
519 | struct usb_wwan_port_private *portdata; | ||
520 | u8 *buffer; | ||
521 | 503 | ||
522 | /* Now setup per port private data */ | 504 | for (i = 0; i < N_OUT_URB; i++) { |
523 | for (i = 0; i < serial->num_ports; i++) { | 505 | if (port->bulk_out_endpointAddress == -1) |
524 | port = serial->port[i]; | 506 | continue; |
525 | portdata = kzalloc(sizeof(*portdata), GFP_KERNEL); | ||
526 | if (!portdata) { | ||
527 | dev_dbg(&port->dev, "%s: kmalloc for usb_wwan_port_private (%d) failed!.\n", | ||
528 | __func__, i); | ||
529 | return 1; | ||
530 | } | ||
531 | init_usb_anchor(&portdata->delayed); | ||
532 | 507 | ||
533 | for (j = 0; j < N_IN_URB; j++) { | 508 | buffer = kmalloc(OUT_BUFLEN, GFP_KERNEL); |
534 | buffer = (u8 *) __get_free_page(GFP_KERNEL); | 509 | if (!buffer) |
535 | if (!buffer) | 510 | goto bail_out_error2; |
536 | goto bail_out_error; | 511 | portdata->out_buffer[i] = buffer; |
537 | portdata->in_buffer[j] = buffer; | ||
538 | } | ||
539 | 512 | ||
540 | for (j = 0; j < N_OUT_URB; j++) { | 513 | urb = usb_wwan_setup_urb(port, port->bulk_out_endpointAddress, |
541 | buffer = kmalloc(OUT_BUFLEN, GFP_KERNEL); | 514 | USB_DIR_OUT, port, |
542 | if (!buffer) | 515 | buffer, OUT_BUFLEN, |
543 | goto bail_out_error2; | 516 | usb_wwan_outdat_callback); |
544 | portdata->out_buffer[j] = buffer; | 517 | portdata->out_urbs[i] = urb; |
545 | } | 518 | } |
546 | 519 | ||
547 | usb_set_serial_port_data(port, portdata); | 520 | usb_set_serial_port_data(port, portdata); |
548 | 521 | ||
549 | if (!port->interrupt_in_urb) | 522 | if (port->interrupt_in_urb) { |
550 | continue; | ||
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 | { |