Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

usb: gadget: f_acm: make bInterfaceProtocol configurable

The bInterfaceProtocol is hardcoded to USB_CDC_ACM_PROTO_AT_V25TER. This
will lead to problems with ModemManger which will gladly try to probe
that port as a modem if the gadget also has a network function.
ModemManager will try to send AT commands to the ACM port. Make the
bInterfaceProtocol configurable. For this, track the number of instances
and only allow write to the property if there are no intances (yet).

This will also set bFunctionProtocol to the same value, see commit
5c8db070b448 ("USB: Change acm_iad_descriptor bFunctionProtocol to
USB_CDC_ACM_PROTO_AT_V25TER") for more details.

Signed-off-by: Michael Walle <mwalle@kernel.org>
Link: https://lore.kernel.org/r/20240825180446.3757073-1-mwalle@kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Michael Walle and committed by
Greg Kroah-Hartman
a17f04d4 c146ede4

+61 -2
+7
Documentation/ABI/testing/configfs-usb-gadget-acm
··· 6 6 This item contains just one readonly attribute: port_num. 7 7 It contains the port number of the /dev/ttyGS<n> device 8 8 associated with acm function's instance "name". 9 + 10 + What: /config/usb-gadget/gadget/functions/acm.name/protocol 11 + Date: Aug 2024 12 + KernelVersion: 6.13 13 + Description: 14 + Reported bInterfaceProtocol for the ACM device. For legacy 15 + reasons, this defaults to 1 (USB_CDC_ACM_PROTO_AT_V25TER).
+50 -2
drivers/usb/gadget/function/f_acm.c
··· 41 41 struct gserial port; 42 42 u8 ctrl_id, data_id; 43 43 u8 port_num; 44 + u8 bInterfaceProtocol; 44 45 45 46 u8 pending; 46 47 ··· 90 89 .bInterfaceCount = 2, // control + data 91 90 .bFunctionClass = USB_CLASS_COMM, 92 91 .bFunctionSubClass = USB_CDC_SUBCLASS_ACM, 93 - .bFunctionProtocol = USB_CDC_ACM_PROTO_AT_V25TER, 92 + /* .bFunctionProtocol = DYNAMIC */ 94 93 /* .iFunction = DYNAMIC */ 95 94 }; 96 95 ··· 102 101 .bNumEndpoints = 1, 103 102 .bInterfaceClass = USB_CLASS_COMM, 104 103 .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM, 105 - .bInterfaceProtocol = USB_CDC_ACM_PROTO_AT_V25TER, 104 + /* .bInterfaceProtocol = DYNAMIC */ 106 105 /* .iInterface = DYNAMIC */ 107 106 }; 108 107 ··· 664 663 goto fail; 665 664 acm->notify = ep; 666 665 666 + acm_iad_descriptor.bFunctionProtocol = acm->bInterfaceProtocol; 667 + acm_control_interface_desc.bInterfaceProtocol = acm->bInterfaceProtocol; 668 + 667 669 /* allocate notification */ 668 670 acm->notify_req = gs_alloc_req(ep, 669 671 sizeof(struct usb_cdc_notification) + 2, ··· 723 719 static void acm_free_func(struct usb_function *f) 724 720 { 725 721 struct f_acm *acm = func_to_acm(f); 722 + struct f_serial_opts *opts; 723 + 724 + opts = container_of(f->fi, struct f_serial_opts, func_inst); 726 725 727 726 kfree(acm); 727 + mutex_lock(&opts->lock); 728 + opts->instances--; 729 + mutex_unlock(&opts->lock); 728 730 } 729 731 730 732 static void acm_resume(struct usb_function *f) ··· 771 761 acm->port.func.disable = acm_disable; 772 762 773 763 opts = container_of(fi, struct f_serial_opts, func_inst); 764 + mutex_lock(&opts->lock); 774 765 acm->port_num = opts->port_num; 766 + acm->bInterfaceProtocol = opts->protocol; 767 + opts->instances++; 768 + mutex_unlock(&opts->lock); 775 769 acm->port.func.unbind = acm_unbind; 776 770 acm->port.func.free_func = acm_free_func; 777 771 acm->port.func.resume = acm_resume; ··· 826 812 827 813 CONFIGFS_ATTR_RO(f_acm_, port_num); 828 814 815 + static ssize_t f_acm_protocol_show(struct config_item *item, char *page) 816 + { 817 + return sprintf(page, "%u\n", to_f_serial_opts(item)->protocol); 818 + } 819 + 820 + static ssize_t f_acm_protocol_store(struct config_item *item, 821 + const char *page, size_t count) 822 + { 823 + struct f_serial_opts *opts = to_f_serial_opts(item); 824 + int ret; 825 + 826 + mutex_lock(&opts->lock); 827 + 828 + if (opts->instances) { 829 + ret = -EBUSY; 830 + goto out; 831 + } 832 + 833 + ret = kstrtou8(page, 0, &opts->protocol); 834 + if (ret) 835 + goto out; 836 + ret = count; 837 + 838 + out: 839 + mutex_unlock(&opts->lock); 840 + return ret; 841 + } 842 + 843 + CONFIGFS_ATTR(f_acm_, protocol); 844 + 829 845 static struct configfs_attribute *acm_attrs[] = { 830 846 #ifdef CONFIG_U_SERIAL_CONSOLE 831 847 &f_acm_attr_console, 832 848 #endif 833 849 &f_acm_attr_port_num, 850 + &f_acm_attr_protocol, 834 851 NULL, 835 852 }; 836 853 ··· 877 832 878 833 opts = container_of(fi, struct f_serial_opts, func_inst); 879 834 gserial_free_line(opts->port_num); 835 + mutex_destroy(&opts->lock); 880 836 kfree(opts); 881 837 } 882 838 ··· 889 843 opts = kzalloc(sizeof(*opts), GFP_KERNEL); 890 844 if (!opts) 891 845 return ERR_PTR(-ENOMEM); 846 + opts->protocol = USB_CDC_ACM_PROTO_AT_V25TER; 892 847 opts->func_inst.free_func_inst = acm_free_instance; 848 + mutex_init(&opts->lock); 893 849 ret = gserial_alloc_line(&opts->port_num); 894 850 if (ret) { 895 851 kfree(opts);
+4
drivers/usb/gadget/function/u_serial.h
··· 17 17 struct f_serial_opts { 18 18 struct usb_function_instance func_inst; 19 19 u8 port_num; 20 + u8 protocol; 21 + 22 + struct mutex lock; /* protect instances */ 23 + int instances; 20 24 }; 21 25 22 26 /*