diff options
| -rw-r--r-- | drivers/usb/gadget/f_acm.c | 194 | ||||
| -rw-r--r-- | drivers/usb/gadget/u_serial.c | 56 | ||||
| -rw-r--r-- | drivers/usb/gadget/u_serial.h | 12 |
3 files changed, 235 insertions, 27 deletions
diff --git a/drivers/usb/gadget/f_acm.c b/drivers/usb/gadget/f_acm.c index f3bf5612af2d..5ee1590b8e9c 100644 --- a/drivers/usb/gadget/f_acm.c +++ b/drivers/usb/gadget/f_acm.c | |||
| @@ -47,16 +47,37 @@ struct f_acm { | |||
| 47 | u8 ctrl_id, data_id; | 47 | u8 ctrl_id, data_id; |
| 48 | u8 port_num; | 48 | u8 port_num; |
| 49 | 49 | ||
| 50 | u8 pending; | ||
| 51 | |||
| 52 | /* lock is mostly for pending and notify_req ... they get accessed | ||
| 53 | * by callbacks both from tty (open/close/break) under its spinlock, | ||
| 54 | * and notify_req.complete() which can't use that lock. | ||
| 55 | */ | ||
| 56 | spinlock_t lock; | ||
| 57 | |||
| 50 | struct acm_ep_descs fs; | 58 | struct acm_ep_descs fs; |
| 51 | struct acm_ep_descs hs; | 59 | struct acm_ep_descs hs; |
| 52 | 60 | ||
| 53 | struct usb_ep *notify; | 61 | struct usb_ep *notify; |
| 54 | struct usb_endpoint_descriptor *notify_desc; | 62 | struct usb_endpoint_descriptor *notify_desc; |
| 63 | struct usb_request *notify_req; | ||
| 55 | 64 | ||
| 56 | struct usb_cdc_line_coding port_line_coding; /* 8-N-1 etc */ | 65 | struct usb_cdc_line_coding port_line_coding; /* 8-N-1 etc */ |
| 66 | |||
| 67 | /* SetControlLineState request -- CDC 1.1 section 6.2.14 (INPUT) */ | ||
| 57 | u16 port_handshake_bits; | 68 | u16 port_handshake_bits; |
| 58 | #define RS232_RTS (1 << 1) /* unused with full duplex */ | 69 | #define ACM_CTRL_RTS (1 << 1) /* unused with full duplex */ |
| 59 | #define RS232_DTR (1 << 0) /* host is ready for data r/w */ | 70 | #define ACM_CTRL_DTR (1 << 0) /* host is ready for data r/w */ |
| 71 | |||
| 72 | /* SerialState notification -- CDC 1.1 section 6.3.5 (OUTPUT) */ | ||
| 73 | u16 serial_state; | ||
| 74 | #define ACM_CTRL_OVERRUN (1 << 6) | ||
| 75 | #define ACM_CTRL_PARITY (1 << 5) | ||
| 76 | #define ACM_CTRL_FRAMING (1 << 4) | ||
| 77 | #define ACM_CTRL_RI (1 << 3) | ||
| 78 | #define ACM_CTRL_BRK (1 << 2) | ||
| 79 | #define ACM_CTRL_DSR (1 << 1) | ||
| 80 | #define ACM_CTRL_DCD (1 << 0) | ||
| 60 | }; | 81 | }; |
| 61 | 82 | ||
| 62 | static inline struct f_acm *func_to_acm(struct usb_function *f) | 83 | static inline struct f_acm *func_to_acm(struct usb_function *f) |
| @@ -64,12 +85,17 @@ static inline struct f_acm *func_to_acm(struct usb_function *f) | |||
| 64 | return container_of(f, struct f_acm, port.func); | 85 | return container_of(f, struct f_acm, port.func); |
| 65 | } | 86 | } |
| 66 | 87 | ||
| 88 | static inline struct f_acm *port_to_acm(struct gserial *p) | ||
| 89 | { | ||
| 90 | return container_of(p, struct f_acm, port); | ||
| 91 | } | ||
| 92 | |||
| 67 | /*-------------------------------------------------------------------------*/ | 93 | /*-------------------------------------------------------------------------*/ |
| 68 | 94 | ||
| 69 | /* notification endpoint uses smallish and infrequent fixed-size messages */ | 95 | /* notification endpoint uses smallish and infrequent fixed-size messages */ |
| 70 | 96 | ||
| 71 | #define GS_LOG2_NOTIFY_INTERVAL 5 /* 1 << 5 == 32 msec */ | 97 | #define GS_LOG2_NOTIFY_INTERVAL 5 /* 1 << 5 == 32 msec */ |
| 72 | #define GS_NOTIFY_MAXPACKET 8 | 98 | #define GS_NOTIFY_MAXPACKET 10 /* notification + 2 bytes */ |
| 73 | 99 | ||
| 74 | /* interface and class descriptors: */ | 100 | /* interface and class descriptors: */ |
| 75 | 101 | ||
| @@ -115,7 +141,7 @@ static struct usb_cdc_acm_descriptor acm_descriptor __initdata = { | |||
| 115 | .bLength = sizeof(acm_descriptor), | 141 | .bLength = sizeof(acm_descriptor), |
| 116 | .bDescriptorType = USB_DT_CS_INTERFACE, | 142 | .bDescriptorType = USB_DT_CS_INTERFACE, |
| 117 | .bDescriptorSubType = USB_CDC_ACM_TYPE, | 143 | .bDescriptorSubType = USB_CDC_ACM_TYPE, |
| 118 | .bmCapabilities = (1 << 1), | 144 | .bmCapabilities = USB_CDC_CAP_LINE, |
| 119 | }; | 145 | }; |
| 120 | 146 | ||
| 121 | static struct usb_cdc_union_desc acm_union_desc __initdata = { | 147 | static struct usb_cdc_union_desc acm_union_desc __initdata = { |
| @@ -275,6 +301,11 @@ static int acm_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) | |||
| 275 | 301 | ||
| 276 | /* composite driver infrastructure handles everything except | 302 | /* composite driver infrastructure handles everything except |
| 277 | * CDC class messages; interface activation uses set_alt(). | 303 | * CDC class messages; interface activation uses set_alt(). |
| 304 | * | ||
| 305 | * Note CDC spec table 4 lists the ACM request profile. It requires | ||
| 306 | * encapsulated command support ... we don't handle any, and respond | ||
| 307 | * to them by stalling. Options include get/set/clear comm features | ||
| 308 | * (not that useful) and SEND_BREAK. | ||
| 278 | */ | 309 | */ |
| 279 | switch ((ctrl->bRequestType << 8) | ctrl->bRequest) { | 310 | switch ((ctrl->bRequestType << 8) | ctrl->bRequest) { |
| 280 | 311 | ||
| @@ -310,7 +341,7 @@ static int acm_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) | |||
| 310 | value = 0; | 341 | value = 0; |
| 311 | 342 | ||
| 312 | /* FIXME we should not allow data to flow until the | 343 | /* FIXME we should not allow data to flow until the |
| 313 | * host sets the RS232_DTR bit; and when it clears | 344 | * host sets the ACM_CTRL_DTR bit; and when it clears |
| 314 | * that bit, we should return to that no-flow state. | 345 | * that bit, we should return to that no-flow state. |
| 315 | */ | 346 | */ |
| 316 | acm->port_handshake_bits = w_value; | 347 | acm->port_handshake_bits = w_value; |
| @@ -348,9 +379,6 @@ static int acm_set_alt(struct usb_function *f, unsigned intf, unsigned alt) | |||
| 348 | /* we know alt == 0, so this is an activation or a reset */ | 379 | /* we know alt == 0, so this is an activation or a reset */ |
| 349 | 380 | ||
| 350 | if (intf == acm->ctrl_id) { | 381 | if (intf == acm->ctrl_id) { |
| 351 | /* REVISIT this may need more work when we start to | ||
| 352 | * send notifications ... | ||
| 353 | */ | ||
| 354 | if (acm->notify->driver_data) { | 382 | if (acm->notify->driver_data) { |
| 355 | VDBG(cdev, "reset acm control interface %d\n", intf); | 383 | VDBG(cdev, "reset acm control interface %d\n", intf); |
| 356 | usb_ep_disable(acm->notify); | 384 | usb_ep_disable(acm->notify); |
| @@ -395,6 +423,128 @@ static void acm_disable(struct usb_function *f) | |||
| 395 | 423 | ||
| 396 | /*-------------------------------------------------------------------------*/ | 424 | /*-------------------------------------------------------------------------*/ |
| 397 | 425 | ||
| 426 | /** | ||
| 427 | * acm_cdc_notify - issue CDC notification to host | ||
| 428 | * @acm: wraps host to be notified | ||
| 429 | * @type: notification type | ||
| 430 | * @value: Refer to cdc specs, wValue field. | ||
| 431 | * @data: data to be sent | ||
| 432 | * @length: size of data | ||
| 433 | * Context: irqs blocked, acm->lock held, acm_notify_req non-null | ||
| 434 | * | ||
| 435 | * Returns zero on sucess or a negative errno. | ||
| 436 | * | ||
| 437 | * See section 6.3.5 of the CDC 1.1 specification for information | ||
| 438 | * about the only notification we issue: SerialState change. | ||
| 439 | */ | ||
| 440 | static int acm_cdc_notify(struct f_acm *acm, u8 type, u16 value, | ||
| 441 | void *data, unsigned length) | ||
| 442 | { | ||
| 443 | struct usb_ep *ep = acm->notify; | ||
| 444 | struct usb_request *req; | ||
| 445 | struct usb_cdc_notification *notify; | ||
| 446 | const unsigned len = sizeof(*notify) + length; | ||
| 447 | void *buf; | ||
| 448 | int status; | ||
| 449 | |||
| 450 | req = acm->notify_req; | ||
| 451 | acm->notify_req = NULL; | ||
| 452 | acm->pending = false; | ||
| 453 | |||
| 454 | req->length = len; | ||
| 455 | notify = req->buf; | ||
| 456 | buf = notify + 1; | ||
| 457 | |||
| 458 | notify->bmRequestType = USB_DIR_IN | USB_TYPE_CLASS | ||
| 459 | | USB_RECIP_INTERFACE; | ||
| 460 | notify->bNotificationType = type; | ||
| 461 | notify->wValue = cpu_to_le16(value); | ||
| 462 | notify->wIndex = cpu_to_le16(acm->ctrl_id); | ||
| 463 | notify->wLength = cpu_to_le16(length); | ||
| 464 | memcpy(buf, data, length); | ||
| 465 | |||
| 466 | status = usb_ep_queue(ep, req, GFP_ATOMIC); | ||
| 467 | if (status < 0) { | ||
| 468 | ERROR(acm->port.func.config->cdev, | ||
| 469 | "acm ttyGS%d can't notify serial state, %d\n", | ||
| 470 | acm->port_num, status); | ||
| 471 | acm->notify_req = req; | ||
| 472 | } | ||
| 473 | |||
| 474 | return status; | ||
| 475 | } | ||
| 476 | |||
| 477 | static int acm_notify_serial_state(struct f_acm *acm) | ||
| 478 | { | ||
| 479 | struct usb_composite_dev *cdev = acm->port.func.config->cdev; | ||
| 480 | int status; | ||
| 481 | |||
| 482 | spin_lock(&acm->lock); | ||
| 483 | if (acm->notify_req) { | ||
| 484 | DBG(cdev, "acm ttyGS%d serial state %04x\n", | ||
| 485 | acm->port_num, acm->serial_state); | ||
| 486 | status = acm_cdc_notify(acm, USB_CDC_NOTIFY_SERIAL_STATE, | ||
| 487 | 0, &acm->serial_state, sizeof(acm->serial_state)); | ||
| 488 | } else { | ||
| 489 | acm->pending = true; | ||
| 490 | status = 0; | ||
| 491 | } | ||
| 492 | spin_unlock(&acm->lock); | ||
| 493 | return status; | ||
| 494 | } | ||
| 495 | |||
| 496 | static void acm_cdc_notify_complete(struct usb_ep *ep, struct usb_request *req) | ||
| 497 | { | ||
| 498 | struct f_acm *acm = req->context; | ||
| 499 | u8 doit = false; | ||
| 500 | |||
| 501 | /* on this call path we do NOT hold the port spinlock, | ||
| 502 | * which is why ACM needs its own spinlock | ||
| 503 | */ | ||
| 504 | spin_lock(&acm->lock); | ||
| 505 | if (req->status != -ESHUTDOWN) | ||
| 506 | doit = acm->pending; | ||
| 507 | acm->notify_req = req; | ||
| 508 | spin_unlock(&acm->lock); | ||
| 509 | |||
| 510 | if (doit) | ||
| 511 | acm_notify_serial_state(acm); | ||
| 512 | } | ||
| 513 | |||
| 514 | /* connect == the TTY link is open */ | ||
| 515 | |||
| 516 | static void acm_connect(struct gserial *port) | ||
| 517 | { | ||
| 518 | struct f_acm *acm = port_to_acm(port); | ||
| 519 | |||
| 520 | acm->serial_state |= ACM_CTRL_DSR | ACM_CTRL_DCD; | ||
| 521 | acm_notify_serial_state(acm); | ||
| 522 | } | ||
| 523 | |||
| 524 | static void acm_disconnect(struct gserial *port) | ||
| 525 | { | ||
| 526 | struct f_acm *acm = port_to_acm(port); | ||
| 527 | |||
| 528 | acm->serial_state &= ~(ACM_CTRL_DSR | ACM_CTRL_DCD); | ||
| 529 | acm_notify_serial_state(acm); | ||
| 530 | } | ||
| 531 | |||
| 532 | static int acm_send_break(struct gserial *port, int duration) | ||
| 533 | { | ||
| 534 | struct f_acm *acm = port_to_acm(port); | ||
| 535 | u16 state; | ||
| 536 | |||
| 537 | state = acm->serial_state; | ||
| 538 | state &= ~ACM_CTRL_BRK; | ||
| 539 | if (duration) | ||
| 540 | state |= ACM_CTRL_BRK; | ||
| 541 | |||
| 542 | acm->serial_state = state; | ||
| 543 | return acm_notify_serial_state(acm); | ||
| 544 | } | ||
| 545 | |||
| 546 | /*-------------------------------------------------------------------------*/ | ||
| 547 | |||
| 398 | /* ACM function driver setup/binding */ | 548 | /* ACM function driver setup/binding */ |
| 399 | static int __init | 549 | static int __init |
| 400 | acm_bind(struct usb_configuration *c, struct usb_function *f) | 550 | acm_bind(struct usb_configuration *c, struct usb_function *f) |
| @@ -443,8 +593,20 @@ acm_bind(struct usb_configuration *c, struct usb_function *f) | |||
| 443 | acm->notify = ep; | 593 | acm->notify = ep; |
| 444 | ep->driver_data = cdev; /* claim */ | 594 | ep->driver_data = cdev; /* claim */ |
| 445 | 595 | ||
| 596 | /* allocate notification */ | ||
| 597 | acm->notify_req = gs_alloc_req(ep, | ||
| 598 | sizeof(struct usb_cdc_notification) + 2, | ||
| 599 | GFP_KERNEL); | ||
| 600 | if (!acm->notify_req) | ||
| 601 | goto fail; | ||
| 602 | |||
| 603 | acm->notify_req->complete = acm_cdc_notify_complete; | ||
| 604 | acm->notify_req->context = acm; | ||
| 605 | |||
| 446 | /* copy descriptors, and track endpoint copies */ | 606 | /* copy descriptors, and track endpoint copies */ |
| 447 | f->descriptors = usb_copy_descriptors(acm_fs_function); | 607 | f->descriptors = usb_copy_descriptors(acm_fs_function); |
| 608 | if (!f->descriptors) | ||
| 609 | goto fail; | ||
| 448 | 610 | ||
| 449 | acm->fs.in = usb_find_endpoint(acm_fs_function, | 611 | acm->fs.in = usb_find_endpoint(acm_fs_function, |
| 450 | f->descriptors, &acm_fs_in_desc); | 612 | f->descriptors, &acm_fs_in_desc); |
| @@ -476,8 +638,6 @@ acm_bind(struct usb_configuration *c, struct usb_function *f) | |||
| 476 | f->hs_descriptors, &acm_hs_notify_desc); | 638 | f->hs_descriptors, &acm_hs_notify_desc); |
| 477 | } | 639 | } |
| 478 | 640 | ||
| 479 | /* FIXME provide a callback for triggering notifications */ | ||
| 480 | |||
| 481 | DBG(cdev, "acm ttyGS%d: %s speed IN/%s OUT/%s NOTIFY/%s\n", | 641 | DBG(cdev, "acm ttyGS%d: %s speed IN/%s OUT/%s NOTIFY/%s\n", |
| 482 | acm->port_num, | 642 | acm->port_num, |
| 483 | gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full", | 643 | gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full", |
| @@ -486,6 +646,9 @@ acm_bind(struct usb_configuration *c, struct usb_function *f) | |||
| 486 | return 0; | 646 | return 0; |
| 487 | 647 | ||
| 488 | fail: | 648 | fail: |
| 649 | if (acm->notify_req) | ||
| 650 | gs_free_req(acm->notify, acm->notify_req); | ||
| 651 | |||
| 489 | /* we might as well release our claims on endpoints */ | 652 | /* we might as well release our claims on endpoints */ |
| 490 | if (acm->notify) | 653 | if (acm->notify) |
| 491 | acm->notify->driver_data = NULL; | 654 | acm->notify->driver_data = NULL; |
| @@ -502,10 +665,13 @@ fail: | |||
| 502 | static void | 665 | static void |
| 503 | acm_unbind(struct usb_configuration *c, struct usb_function *f) | 666 | acm_unbind(struct usb_configuration *c, struct usb_function *f) |
| 504 | { | 667 | { |
| 668 | struct f_acm *acm = func_to_acm(f); | ||
| 669 | |||
| 505 | if (gadget_is_dualspeed(c->cdev->gadget)) | 670 | if (gadget_is_dualspeed(c->cdev->gadget)) |
| 506 | usb_free_descriptors(f->hs_descriptors); | 671 | usb_free_descriptors(f->hs_descriptors); |
| 507 | usb_free_descriptors(f->descriptors); | 672 | usb_free_descriptors(f->descriptors); |
| 508 | kfree(func_to_acm(f)); | 673 | gs_free_req(acm->notify, acm->notify_req); |
| 674 | kfree(acm); | ||
| 509 | } | 675 | } |
| 510 | 676 | ||
| 511 | /* Some controllers can't support CDC ACM ... */ | 677 | /* Some controllers can't support CDC ACM ... */ |
| @@ -569,8 +735,14 @@ int __init acm_bind_config(struct usb_configuration *c, u8 port_num) | |||
| 569 | if (!acm) | 735 | if (!acm) |
| 570 | return -ENOMEM; | 736 | return -ENOMEM; |
| 571 | 737 | ||
| 738 | spin_lock_init(&acm->lock); | ||
| 739 | |||
| 572 | acm->port_num = port_num; | 740 | acm->port_num = port_num; |
| 573 | 741 | ||
| 742 | acm->port.connect = acm_connect; | ||
| 743 | acm->port.disconnect = acm_disconnect; | ||
| 744 | acm->port.send_break = acm_send_break; | ||
| 745 | |||
| 574 | acm->port.func.name = "acm"; | 746 | acm->port.func.name = "acm"; |
| 575 | acm->port.func.strings = acm_strings; | 747 | acm->port.func.strings = acm_strings; |
| 576 | /* descriptors are per-instance copies */ | 748 | /* descriptors are per-instance copies */ |
diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c index 6641efa55639..53d59287f2bc 100644 --- a/drivers/usb/gadget/u_serial.c +++ b/drivers/usb/gadget/u_serial.c | |||
| @@ -60,7 +60,8 @@ | |||
| 60 | * tty_struct links to the tty/filesystem framework | 60 | * tty_struct links to the tty/filesystem framework |
| 61 | * | 61 | * |
| 62 | * gserial <---> gs_port ... links will be null when the USB link is | 62 | * gserial <---> gs_port ... links will be null when the USB link is |
| 63 | * inactive; managed by gserial_{connect,disconnect}(). | 63 | * inactive; managed by gserial_{connect,disconnect}(). each gserial |
| 64 | * instance can wrap its own USB control protocol. | ||
| 64 | * gserial->ioport == usb_ep->driver_data ... gs_port | 65 | * gserial->ioport == usb_ep->driver_data ... gs_port |
| 65 | * gs_port->port_usb ... gserial | 66 | * gs_port->port_usb ... gserial |
| 66 | * | 67 | * |
| @@ -181,7 +182,7 @@ static void gs_buf_clear(struct gs_buf *gb) | |||
| 181 | /* | 182 | /* |
| 182 | * gs_buf_data_avail | 183 | * gs_buf_data_avail |
| 183 | * | 184 | * |
| 184 | * Return the number of bytes of data available in the circular | 185 | * Return the number of bytes of data written into the circular |
| 185 | * buffer. | 186 | * buffer. |
| 186 | */ | 187 | */ |
| 187 | static unsigned gs_buf_data_avail(struct gs_buf *gb) | 188 | static unsigned gs_buf_data_avail(struct gs_buf *gb) |
| @@ -282,7 +283,7 @@ gs_buf_get(struct gs_buf *gb, char *buf, unsigned count) | |||
| 282 | * Allocate a usb_request and its buffer. Returns a pointer to the | 283 | * Allocate a usb_request and its buffer. Returns a pointer to the |
| 283 | * usb_request or NULL if there is an error. | 284 | * usb_request or NULL if there is an error. |
| 284 | */ | 285 | */ |
| 285 | static struct usb_request * | 286 | struct usb_request * |
| 286 | gs_alloc_req(struct usb_ep *ep, unsigned len, gfp_t kmalloc_flags) | 287 | gs_alloc_req(struct usb_ep *ep, unsigned len, gfp_t kmalloc_flags) |
| 287 | { | 288 | { |
| 288 | struct usb_request *req; | 289 | struct usb_request *req; |
| @@ -306,7 +307,7 @@ gs_alloc_req(struct usb_ep *ep, unsigned len, gfp_t kmalloc_flags) | |||
| 306 | * | 307 | * |
| 307 | * Free a usb_request and its buffer. | 308 | * Free a usb_request and its buffer. |
| 308 | */ | 309 | */ |
| 309 | static void gs_free_req(struct usb_ep *ep, struct usb_request *req) | 310 | void gs_free_req(struct usb_ep *ep, struct usb_request *req) |
| 310 | { | 311 | { |
| 311 | kfree(req->buf); | 312 | kfree(req->buf); |
| 312 | usb_ep_free_request(ep, req); | 313 | usb_ep_free_request(ep, req); |
| @@ -788,10 +789,13 @@ static int gs_open(struct tty_struct *tty, struct file *file) | |||
| 788 | 789 | ||
| 789 | /* if connected, start the I/O stream */ | 790 | /* if connected, start the I/O stream */ |
| 790 | if (port->port_usb) { | 791 | if (port->port_usb) { |
| 792 | struct gserial *gser = port->port_usb; | ||
| 793 | |||
| 791 | pr_debug("gs_open: start ttyGS%d\n", port->port_num); | 794 | pr_debug("gs_open: start ttyGS%d\n", port->port_num); |
| 792 | gs_start_io(port); | 795 | gs_start_io(port); |
| 793 | 796 | ||
| 794 | /* REVISIT for ACM, issue "network connected" event */ | 797 | if (gser->connect) |
| 798 | gser->connect(gser); | ||
| 795 | } | 799 | } |
| 796 | 800 | ||
| 797 | pr_debug("gs_open: ttyGS%d (%p,%p)\n", port->port_num, tty, file); | 801 | pr_debug("gs_open: ttyGS%d (%p,%p)\n", port->port_num, tty, file); |
| @@ -818,6 +822,7 @@ static int gs_writes_finished(struct gs_port *p) | |||
| 818 | static void gs_close(struct tty_struct *tty, struct file *file) | 822 | static void gs_close(struct tty_struct *tty, struct file *file) |
| 819 | { | 823 | { |
| 820 | struct gs_port *port = tty->driver_data; | 824 | struct gs_port *port = tty->driver_data; |
| 825 | struct gserial *gser; | ||
| 821 | 826 | ||
| 822 | spin_lock_irq(&port->port_lock); | 827 | spin_lock_irq(&port->port_lock); |
| 823 | 828 | ||
| @@ -837,26 +842,27 @@ static void gs_close(struct tty_struct *tty, struct file *file) | |||
| 837 | port->openclose = true; | 842 | port->openclose = true; |
| 838 | port->open_count = 0; | 843 | port->open_count = 0; |
| 839 | 844 | ||
| 840 | if (port->port_usb) | 845 | gser = port->port_usb; |
| 841 | /* REVISIT for ACM, issue "network disconnected" event */; | 846 | if (gser && gser->disconnect) |
| 847 | gser->disconnect(gser); | ||
| 842 | 848 | ||
| 843 | /* wait for circular write buffer to drain, disconnect, or at | 849 | /* wait for circular write buffer to drain, disconnect, or at |
| 844 | * most GS_CLOSE_TIMEOUT seconds; then discard the rest | 850 | * most GS_CLOSE_TIMEOUT seconds; then discard the rest |
| 845 | */ | 851 | */ |
| 846 | if (gs_buf_data_avail(&port->port_write_buf) > 0 | 852 | if (gs_buf_data_avail(&port->port_write_buf) > 0 && gser) { |
| 847 | && port->port_usb) { | ||
| 848 | spin_unlock_irq(&port->port_lock); | 853 | spin_unlock_irq(&port->port_lock); |
| 849 | wait_event_interruptible_timeout(port->drain_wait, | 854 | wait_event_interruptible_timeout(port->drain_wait, |
| 850 | gs_writes_finished(port), | 855 | gs_writes_finished(port), |
| 851 | GS_CLOSE_TIMEOUT * HZ); | 856 | GS_CLOSE_TIMEOUT * HZ); |
| 852 | spin_lock_irq(&port->port_lock); | 857 | spin_lock_irq(&port->port_lock); |
| 858 | gser = port->port_usb; | ||
| 853 | } | 859 | } |
| 854 | 860 | ||
| 855 | /* Iff we're disconnected, there can be no I/O in flight so it's | 861 | /* Iff we're disconnected, there can be no I/O in flight so it's |
| 856 | * ok to free the circular buffer; else just scrub it. And don't | 862 | * ok to free the circular buffer; else just scrub it. And don't |
| 857 | * let the push tasklet fire again until we're re-opened. | 863 | * let the push tasklet fire again until we're re-opened. |
| 858 | */ | 864 | */ |
| 859 | if (port->port_usb == NULL) | 865 | if (gser == NULL) |
| 860 | gs_buf_free(&port->port_write_buf); | 866 | gs_buf_free(&port->port_write_buf); |
| 861 | else | 867 | else |
| 862 | gs_buf_clear(&port->port_write_buf); | 868 | gs_buf_clear(&port->port_write_buf); |
| @@ -974,6 +980,24 @@ static void gs_unthrottle(struct tty_struct *tty) | |||
| 974 | spin_unlock_irqrestore(&port->port_lock, flags); | 980 | spin_unlock_irqrestore(&port->port_lock, flags); |
| 975 | } | 981 | } |
| 976 | 982 | ||
| 983 | static int gs_break_ctl(struct tty_struct *tty, int duration) | ||
| 984 | { | ||
| 985 | struct gs_port *port = tty->driver_data; | ||
| 986 | int status = 0; | ||
| 987 | struct gserial *gser; | ||
| 988 | |||
| 989 | pr_vdebug("gs_break_ctl: ttyGS%d, send break (%d) \n", | ||
| 990 | port->port_num, duration); | ||
| 991 | |||
| 992 | spin_lock_irq(&port->port_lock); | ||
| 993 | gser = port->port_usb; | ||
| 994 | if (gser && gser->send_break) | ||
| 995 | status = gser->send_break(gser, duration); | ||
| 996 | spin_unlock_irq(&port->port_lock); | ||
| 997 | |||
| 998 | return status; | ||
| 999 | } | ||
| 1000 | |||
| 977 | static const struct tty_operations gs_tty_ops = { | 1001 | static const struct tty_operations gs_tty_ops = { |
| 978 | .open = gs_open, | 1002 | .open = gs_open, |
| 979 | .close = gs_close, | 1003 | .close = gs_close, |
| @@ -983,6 +1007,7 @@ static const struct tty_operations gs_tty_ops = { | |||
| 983 | .write_room = gs_write_room, | 1007 | .write_room = gs_write_room, |
| 984 | .chars_in_buffer = gs_chars_in_buffer, | 1008 | .chars_in_buffer = gs_chars_in_buffer, |
| 985 | .unthrottle = gs_unthrottle, | 1009 | .unthrottle = gs_unthrottle, |
| 1010 | .break_ctl = gs_break_ctl, | ||
| 986 | }; | 1011 | }; |
| 987 | 1012 | ||
| 988 | /*-------------------------------------------------------------------------*/ | 1013 | /*-------------------------------------------------------------------------*/ |
| @@ -1230,14 +1255,17 @@ int gserial_connect(struct gserial *gser, u8 port_num) | |||
| 1230 | 1255 | ||
| 1231 | /* REVISIT if waiting on "carrier detect", signal. */ | 1256 | /* REVISIT if waiting on "carrier detect", signal. */ |
| 1232 | 1257 | ||
| 1233 | /* REVISIT for ACM, issue "network connection" status notification: | 1258 | /* if it's already open, start I/O ... and notify the serial |
| 1234 | * connected if open_count, else disconnected. | 1259 | * protocol about open/close status (connect/disconnect). |
| 1235 | */ | 1260 | */ |
| 1236 | |||
| 1237 | /* if it's already open, start I/O */ | ||
| 1238 | if (port->open_count) { | 1261 | if (port->open_count) { |
| 1239 | pr_debug("gserial_connect: start ttyGS%d\n", port->port_num); | 1262 | pr_debug("gserial_connect: start ttyGS%d\n", port->port_num); |
| 1240 | gs_start_io(port); | 1263 | gs_start_io(port); |
| 1264 | if (gser->connect) | ||
| 1265 | gser->connect(gser); | ||
| 1266 | } else { | ||
| 1267 | if (gser->disconnect) | ||
| 1268 | gser->disconnect(gser); | ||
| 1241 | } | 1269 | } |
| 1242 | 1270 | ||
| 1243 | spin_unlock_irqrestore(&port->port_lock, flags); | 1271 | spin_unlock_irqrestore(&port->port_lock, flags); |
diff --git a/drivers/usb/gadget/u_serial.h b/drivers/usb/gadget/u_serial.h index 7b561138f90e..af3910d01aea 100644 --- a/drivers/usb/gadget/u_serial.h +++ b/drivers/usb/gadget/u_serial.h | |||
| @@ -23,8 +23,7 @@ | |||
| 23 | * style I/O using the USB peripheral endpoints listed here, including | 23 | * style I/O using the USB peripheral endpoints listed here, including |
| 24 | * hookups to sysfs and /dev for each logical "tty" device. | 24 | * hookups to sysfs and /dev for each logical "tty" device. |
| 25 | * | 25 | * |
| 26 | * REVISIT need TTY --> USB event flow too, so ACM can report open/close | 26 | * REVISIT at least ACM could support tiocmget() if needed. |
| 27 | * as carrier detect events. Model after ECM. There's more ACM state too. | ||
| 28 | * | 27 | * |
| 29 | * REVISIT someday, allow multiplexing several TTYs over these endpoints. | 28 | * REVISIT someday, allow multiplexing several TTYs over these endpoints. |
| 30 | */ | 29 | */ |
| @@ -41,8 +40,17 @@ struct gserial { | |||
| 41 | 40 | ||
| 42 | /* REVISIT avoid this CDC-ACM support harder ... */ | 41 | /* REVISIT avoid this CDC-ACM support harder ... */ |
| 43 | struct usb_cdc_line_coding port_line_coding; /* 9600-8-N-1 etc */ | 42 | struct usb_cdc_line_coding port_line_coding; /* 9600-8-N-1 etc */ |
| 43 | |||
| 44 | /* notification callbacks */ | ||
| 45 | void (*connect)(struct gserial *p); | ||
| 46 | void (*disconnect)(struct gserial *p); | ||
| 47 | int (*send_break)(struct gserial *p, int duration); | ||
| 44 | }; | 48 | }; |
| 45 | 49 | ||
| 50 | /* utilities to allocate/free request and buffer */ | ||
| 51 | struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned len, gfp_t flags); | ||
| 52 | void gs_free_req(struct usb_ep *, struct usb_request *req); | ||
| 53 | |||
| 46 | /* port setup/teardown is handled by gadget driver */ | 54 | /* port setup/teardown is handled by gadget driver */ |
| 47 | int gserial_setup(struct usb_gadget *g, unsigned n_ports); | 55 | int gserial_setup(struct usb_gadget *g, unsigned n_ports); |
| 48 | void gserial_cleanup(void); | 56 | void gserial_cleanup(void); |
