Lines Matching +full:cdc +full:- +full:acm

1 // SPDX-License-Identifier: GPL-2.0+
3 * f_acm.c -- USB CDC serial (ACM) function driver
24 * This CDC ACM function support just wraps control functions and
25 * notifications around the generic serial-over-usb code.
27 * Because CDC ACM is standardized by the USB-IF, many host operating
28 * systems have drivers for it. Accordingly, ACM is the preferred
29 * interop solution for serial-port type connections. The control
31 * this bare-bones implementation.
33 * Note that even MS-Windows has some support for ACM. However, that
34 * support is somewhat broken because when you use ACM in a composite
36 * seem to understand CDC Union descriptors. The new "association"
37 * descriptors (roughly equivalent to CDC Unions) may sometimes help.
57 struct usb_cdc_line_coding port_line_coding; /* 8-N-1 etc */
59 /* SetControlLineState request -- CDC 1.1 section 6.2.14 (INPUT) */
61 /* SerialState notification -- CDC 1.1 section 6.3.5 (OUTPUT) */
75 /*-------------------------------------------------------------------------*/
77 /* notification endpoint uses smallish and infrequent fixed-size messages */
270 /* static strings, in UTF-8 */
272 [ACM_CTRL_IDX].s = "CDC Abstract Control Model (ACM)",
273 [ACM_DATA_IDX].s = "CDC ACM Data",
274 [ACM_IAD_IDX ].s = "CDC Serial",
279 .language = 0x0409, /* en-us */
288 /*-------------------------------------------------------------------------*/
290 /* ACM control ... data handling is delegated to tty library code.
299 struct f_acm *acm = ep->driver_data; in acm_complete_set_line_coding() local
300 struct usb_composite_dev *cdev = acm->port.func.config->cdev; in acm_complete_set_line_coding()
302 if (req->status != 0) { in acm_complete_set_line_coding()
303 dev_dbg(&cdev->gadget->dev, "acm ttyGS%d completion, err %d\n", in acm_complete_set_line_coding()
304 acm->port_num, req->status); in acm_complete_set_line_coding()
309 if (req->actual != sizeof(acm->port_line_coding)) { in acm_complete_set_line_coding()
310 dev_dbg(&cdev->gadget->dev, "acm ttyGS%d short resp, len %d\n", in acm_complete_set_line_coding()
311 acm->port_num, req->actual); in acm_complete_set_line_coding()
314 struct usb_cdc_line_coding *value = req->buf; in acm_complete_set_line_coding()
320 * the order of 9600-8-N-1 ... most of which means in acm_complete_set_line_coding()
323 acm->port_line_coding = *value; in acm_complete_set_line_coding()
331 struct f_acm *acm = func_to_acm(f); in acm_setup() local
332 struct usb_composite_dev *cdev = f->config->cdev; in acm_setup()
333 struct usb_request *req = cdev->req; in acm_setup()
334 int value = -EOPNOTSUPP; in acm_setup()
335 u16 w_index = le16_to_cpu(ctrl->wIndex); in acm_setup()
336 u16 w_value = le16_to_cpu(ctrl->wValue); in acm_setup()
337 u16 w_length = le16_to_cpu(ctrl->wLength); in acm_setup()
340 * CDC class messages; interface activation uses set_alt(). in acm_setup()
342 * Note CDC spec table 4 lists the ACM request profile. It requires in acm_setup()
347 switch ((ctrl->bRequestType << 8) | ctrl->bRequest) { in acm_setup()
353 || w_index != acm->ctrl_id) in acm_setup()
357 cdev->gadget->ep0->driver_data = acm; in acm_setup()
358 req->complete = acm_complete_set_line_coding; in acm_setup()
364 if (w_index != acm->ctrl_id) in acm_setup()
369 memcpy(req->buf, &acm->port_line_coding, value); in acm_setup()
375 if (w_index != acm->ctrl_id) in acm_setup()
382 * that bit, we should return to that no-flow state. in acm_setup()
384 acm->port_handshake_bits = w_value; in acm_setup()
389 if (w_index != acm->ctrl_id) in acm_setup()
392 acm_send_break(&acm->port, w_value); in acm_setup()
397 dev_vdbg(&cdev->gadget->dev, in acm_setup()
399 ctrl->bRequestType, ctrl->bRequest, in acm_setup()
405 dev_dbg(&cdev->gadget->dev, in acm_setup()
406 "acm ttyGS%d req%02x.%02x v%04x i%04x l%d\n", in acm_setup()
407 acm->port_num, ctrl->bRequestType, ctrl->bRequest, in acm_setup()
409 req->zero = 0; in acm_setup()
410 req->length = value; in acm_setup()
411 value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC); in acm_setup()
413 ERROR(cdev, "acm response on ttyGS%d, err %d\n", in acm_setup()
414 acm->port_num, value); in acm_setup()
423 struct f_acm *acm = func_to_acm(f); in acm_set_alt() local
424 struct usb_composite_dev *cdev = f->config->cdev; in acm_set_alt()
428 if (intf == acm->ctrl_id) { in acm_set_alt()
429 if (acm->notify->enabled) { in acm_set_alt()
430 dev_vdbg(&cdev->gadget->dev, in acm_set_alt()
431 "reset acm control interface %d\n", intf); in acm_set_alt()
432 usb_ep_disable(acm->notify); in acm_set_alt()
435 if (!acm->notify->desc) in acm_set_alt()
436 if (config_ep_by_speed(cdev->gadget, f, acm->notify)) in acm_set_alt()
437 return -EINVAL; in acm_set_alt()
439 usb_ep_enable(acm->notify); in acm_set_alt()
441 } else if (intf == acm->data_id) { in acm_set_alt()
442 if (acm->notify->enabled) { in acm_set_alt()
443 dev_dbg(&cdev->gadget->dev, in acm_set_alt()
444 "reset acm ttyGS%d\n", acm->port_num); in acm_set_alt()
445 gserial_disconnect(&acm->port); in acm_set_alt()
447 if (!acm->port.in->desc || !acm->port.out->desc) { in acm_set_alt()
448 dev_dbg(&cdev->gadget->dev, in acm_set_alt()
449 "activate acm ttyGS%d\n", acm->port_num); in acm_set_alt()
450 if (config_ep_by_speed(cdev->gadget, f, in acm_set_alt()
451 acm->port.in) || in acm_set_alt()
452 config_ep_by_speed(cdev->gadget, f, in acm_set_alt()
453 acm->port.out)) { in acm_set_alt()
454 acm->port.in->desc = NULL; in acm_set_alt()
455 acm->port.out->desc = NULL; in acm_set_alt()
456 return -EINVAL; in acm_set_alt()
459 gserial_connect(&acm->port, acm->port_num); in acm_set_alt()
462 return -EINVAL; in acm_set_alt()
469 struct f_acm *acm = func_to_acm(f); in acm_disable() local
470 struct usb_composite_dev *cdev = f->config->cdev; in acm_disable()
472 dev_dbg(&cdev->gadget->dev, "acm ttyGS%d deactivated\n", acm->port_num); in acm_disable()
473 gserial_disconnect(&acm->port); in acm_disable()
474 usb_ep_disable(acm->notify); in acm_disable()
477 /*-------------------------------------------------------------------------*/
480 * acm_cdc_notify - issue CDC notification to host
481 * @acm: wraps host to be notified
483 * @value: Refer to cdc specs, wValue field.
486 * Context: irqs blocked, acm->lock held, acm_notify_req non-null
490 * See section 6.3.5 of the CDC 1.1 specification for information
493 static int acm_cdc_notify(struct f_acm *acm, u8 type, u16 value, in acm_cdc_notify() argument
496 struct usb_ep *ep = acm->notify; in acm_cdc_notify()
503 req = acm->notify_req; in acm_cdc_notify()
504 acm->notify_req = NULL; in acm_cdc_notify()
505 acm->pending = false; in acm_cdc_notify()
507 req->length = len; in acm_cdc_notify()
508 notify = req->buf; in acm_cdc_notify()
511 notify->bmRequestType = USB_DIR_IN | USB_TYPE_CLASS in acm_cdc_notify()
513 notify->bNotificationType = type; in acm_cdc_notify()
514 notify->wValue = cpu_to_le16(value); in acm_cdc_notify()
515 notify->wIndex = cpu_to_le16(acm->ctrl_id); in acm_cdc_notify()
516 notify->wLength = cpu_to_le16(length); in acm_cdc_notify()
520 spin_unlock(&acm->lock); in acm_cdc_notify()
522 spin_lock(&acm->lock); in acm_cdc_notify()
525 ERROR(acm->port.func.config->cdev, in acm_cdc_notify()
526 "acm ttyGS%d can't notify serial state, %d\n", in acm_cdc_notify()
527 acm->port_num, status); in acm_cdc_notify()
528 acm->notify_req = req; in acm_cdc_notify()
534 static int acm_notify_serial_state(struct f_acm *acm) in acm_notify_serial_state() argument
536 struct usb_composite_dev *cdev = acm->port.func.config->cdev; in acm_notify_serial_state()
540 spin_lock(&acm->lock); in acm_notify_serial_state()
541 if (acm->notify_req) { in acm_notify_serial_state()
542 dev_dbg(&cdev->gadget->dev, "acm ttyGS%d serial state %04x\n", in acm_notify_serial_state()
543 acm->port_num, acm->serial_state); in acm_notify_serial_state()
544 serial_state = cpu_to_le16(acm->serial_state); in acm_notify_serial_state()
545 status = acm_cdc_notify(acm, USB_CDC_NOTIFY_SERIAL_STATE, in acm_notify_serial_state()
546 0, &serial_state, sizeof(acm->serial_state)); in acm_notify_serial_state()
548 acm->pending = true; in acm_notify_serial_state()
551 spin_unlock(&acm->lock); in acm_notify_serial_state()
557 struct f_acm *acm = req->context; in acm_cdc_notify_complete() local
561 * which is why ACM needs its own spinlock in acm_cdc_notify_complete()
563 spin_lock(&acm->lock); in acm_cdc_notify_complete()
564 if (req->status != -ESHUTDOWN) in acm_cdc_notify_complete()
565 doit = acm->pending; in acm_cdc_notify_complete()
566 acm->notify_req = req; in acm_cdc_notify_complete()
567 spin_unlock(&acm->lock); in acm_cdc_notify_complete()
570 acm_notify_serial_state(acm); in acm_cdc_notify_complete()
577 struct f_acm *acm = port_to_acm(port); in acm_connect() local
579 acm->serial_state |= USB_CDC_SERIAL_STATE_DSR | USB_CDC_SERIAL_STATE_DCD; in acm_connect()
580 acm_notify_serial_state(acm); in acm_connect()
585 struct f_acm *acm = port_to_acm(port); in acm_disconnect() local
587 acm->serial_state &= ~(USB_CDC_SERIAL_STATE_DSR | USB_CDC_SERIAL_STATE_DCD); in acm_disconnect()
588 acm_notify_serial_state(acm); in acm_disconnect()
593 struct f_acm *acm = port_to_acm(port); in acm_send_break() local
596 state = acm->serial_state; in acm_send_break()
601 acm->serial_state = state; in acm_send_break()
602 return acm_notify_serial_state(acm); in acm_send_break()
605 /*-------------------------------------------------------------------------*/
607 /* ACM function driver setup/binding */
611 struct usb_composite_dev *cdev = c->cdev; in acm_bind()
612 struct f_acm *acm = func_to_acm(f); in acm_bind() local
617 /* REVISIT might want instance-specific strings to help in acm_bind()
621 /* maybe allocate device-global string IDs, and patch descriptors */ in acm_bind()
630 /* allocate instance-specific interface IDs, and patch descriptors */ in acm_bind()
634 acm->ctrl_id = status; in acm_bind()
643 acm->data_id = status; in acm_bind()
649 status = -ENODEV; in acm_bind()
651 /* allocate instance-specific endpoints */ in acm_bind()
652 ep = usb_ep_autoconfig(cdev->gadget, &acm_fs_in_desc); in acm_bind()
655 acm->port.in = ep; in acm_bind()
657 ep = usb_ep_autoconfig(cdev->gadget, &acm_fs_out_desc); in acm_bind()
660 acm->port.out = ep; in acm_bind()
662 ep = usb_ep_autoconfig(cdev->gadget, &acm_fs_notify_desc); in acm_bind()
665 acm->notify = ep; in acm_bind()
667 acm_iad_descriptor.bFunctionProtocol = acm->bInterfaceProtocol; in acm_bind()
668 acm_control_interface_desc.bInterfaceProtocol = acm->bInterfaceProtocol; in acm_bind()
671 acm->notify_req = gs_alloc_req(ep, in acm_bind()
674 if (!acm->notify_req) in acm_bind()
677 acm->notify_req->complete = acm_cdc_notify_complete; in acm_bind()
678 acm->notify_req->context = acm; in acm_bind()
681 * hardware is dual speed, all bulk-capable endpoints work at in acm_bind()
697 dev_dbg(&cdev->gadget->dev, in acm_bind()
698 "acm ttyGS%d: IN/%s OUT/%s NOTIFY/%s\n", in acm_bind()
699 acm->port_num, in acm_bind()
700 acm->port.in->name, acm->port.out->name, in acm_bind()
701 acm->notify->name); in acm_bind()
705 if (acm->notify_req) in acm_bind()
706 gs_free_req(acm->notify, acm->notify_req); in acm_bind()
708 ERROR(cdev, "%s/%p: can't bind, err %d\n", f->name, f, status); in acm_bind()
715 struct f_acm *acm = func_to_acm(f); in acm_unbind() local
719 if (acm->notify_req) in acm_unbind()
720 gs_free_req(acm->notify, acm->notify_req); in acm_unbind()
725 struct f_acm *acm = func_to_acm(f); in acm_free_func() local
728 opts = container_of(f->fi, struct f_serial_opts, func_inst); in acm_free_func()
730 kfree(acm); in acm_free_func()
731 mutex_lock(&opts->lock); in acm_free_func()
732 opts->instances--; in acm_free_func()
733 mutex_unlock(&opts->lock); in acm_free_func()
738 struct f_acm *acm = func_to_acm(f); in acm_resume() local
740 gserial_resume(&acm->port); in acm_resume()
745 struct f_acm *acm = func_to_acm(f); in acm_suspend() local
747 gserial_suspend(&acm->port); in acm_suspend()
753 struct f_acm *acm; in acm_alloc_func() local
755 acm = kzalloc(sizeof(*acm), GFP_KERNEL); in acm_alloc_func()
756 if (!acm) in acm_alloc_func()
757 return ERR_PTR(-ENOMEM); in acm_alloc_func()
759 spin_lock_init(&acm->lock); in acm_alloc_func()
761 acm->port.connect = acm_connect; in acm_alloc_func()
762 acm->port.disconnect = acm_disconnect; in acm_alloc_func()
763 acm->port.send_break = acm_send_break; in acm_alloc_func()
765 acm->port.func.name = "acm"; in acm_alloc_func()
766 acm->port.func.strings = acm_strings; in acm_alloc_func()
767 /* descriptors are per-instance copies */ in acm_alloc_func()
768 acm->port.func.bind = acm_bind; in acm_alloc_func()
769 acm->port.func.set_alt = acm_set_alt; in acm_alloc_func()
770 acm->port.func.setup = acm_setup; in acm_alloc_func()
771 acm->port.func.disable = acm_disable; in acm_alloc_func()
774 mutex_lock(&opts->lock); in acm_alloc_func()
775 acm->port_num = opts->port_num; in acm_alloc_func()
776 acm->bInterfaceProtocol = opts->protocol; in acm_alloc_func()
777 opts->instances++; in acm_alloc_func()
778 mutex_unlock(&opts->lock); in acm_alloc_func()
779 acm->port.func.unbind = acm_unbind; in acm_alloc_func()
780 acm->port.func.free_func = acm_free_func; in acm_alloc_func()
781 acm->port.func.resume = acm_resume; in acm_alloc_func()
782 acm->port.func.suspend = acm_suspend; in acm_alloc_func()
784 return &acm->port.func; in acm_alloc_func()
797 usb_put_function_instance(&opts->func_inst); in acm_attr_release()
809 return gserial_set_console(to_f_serial_opts(item)->port_num, in f_acm_console_store()
815 return gserial_get_console(to_f_serial_opts(item)->port_num, page); in f_acm_console_show()
824 return sprintf(page, "%u\n", to_f_serial_opts(item)->port_num); in f_acm_port_num_show()
831 return sprintf(page, "%u\n", to_f_serial_opts(item)->protocol); in f_acm_protocol_show()
840 mutex_lock(&opts->lock); in f_acm_protocol_store()
842 if (opts->instances) { in f_acm_protocol_store()
843 ret = -EBUSY; in f_acm_protocol_store()
847 ret = kstrtou8(page, 0, &opts->protocol); in f_acm_protocol_store()
853 mutex_unlock(&opts->lock); in f_acm_protocol_store()
879 gserial_free_line(opts->port_num); in acm_free_instance()
880 mutex_destroy(&opts->lock); in acm_free_instance()
891 return ERR_PTR(-ENOMEM); in acm_alloc_instance()
892 opts->protocol = USB_CDC_ACM_PROTO_AT_V25TER; in acm_alloc_instance()
893 opts->func_inst.free_func_inst = acm_free_instance; in acm_alloc_instance()
894 mutex_init(&opts->lock); in acm_alloc_instance()
895 ret = gserial_alloc_line(&opts->port_num); in acm_alloc_instance()
900 config_group_init_type_name(&opts->func_inst.group, "", in acm_alloc_instance()
902 return &opts->func_inst; in acm_alloc_instance()
904 DECLARE_USB_FUNCTION_INIT(acm, acm_alloc_instance, acm_alloc_func);
905 MODULE_DESCRIPTION("USB CDC serial (ACM) function driver");