Skip to content

Commit a17f04d

Browse files
mwallegregkh
authored andcommitted
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 5c8db07 ("USB: Change acm_iad_descriptor bFunctionProtocol to USB_CDC_ACM_PROTO_AT_V25TER") for more details. Signed-off-by: Michael Walle <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent c146ede commit a17f04d

File tree

3 files changed

+61
-2
lines changed

3 files changed

+61
-2
lines changed

Documentation/ABI/testing/configfs-usb-gadget-acm

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,10 @@ Description:
66
This item contains just one readonly attribute: port_num.
77
It contains the port number of the /dev/ttyGS<n> device
88
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).

drivers/usb/gadget/function/f_acm.c

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ struct f_acm {
4141
struct gserial port;
4242
u8 ctrl_id, data_id;
4343
u8 port_num;
44+
u8 bInterfaceProtocol;
4445

4546
u8 pending;
4647

@@ -89,7 +90,7 @@ acm_iad_descriptor = {
8990
.bInterfaceCount = 2, // control + data
9091
.bFunctionClass = USB_CLASS_COMM,
9192
.bFunctionSubClass = USB_CDC_SUBCLASS_ACM,
92-
.bFunctionProtocol = USB_CDC_ACM_PROTO_AT_V25TER,
93+
/* .bFunctionProtocol = DYNAMIC */
9394
/* .iFunction = DYNAMIC */
9495
};
9596

@@ -101,7 +102,7 @@ static struct usb_interface_descriptor acm_control_interface_desc = {
101102
.bNumEndpoints = 1,
102103
.bInterfaceClass = USB_CLASS_COMM,
103104
.bInterfaceSubClass = USB_CDC_SUBCLASS_ACM,
104-
.bInterfaceProtocol = USB_CDC_ACM_PROTO_AT_V25TER,
105+
/* .bInterfaceProtocol = DYNAMIC */
105106
/* .iInterface = DYNAMIC */
106107
};
107108

@@ -663,6 +664,9 @@ acm_bind(struct usb_configuration *c, struct usb_function *f)
663664
goto fail;
664665
acm->notify = ep;
665666

667+
acm_iad_descriptor.bFunctionProtocol = acm->bInterfaceProtocol;
668+
acm_control_interface_desc.bInterfaceProtocol = acm->bInterfaceProtocol;
669+
666670
/* allocate notification */
667671
acm->notify_req = gs_alloc_req(ep,
668672
sizeof(struct usb_cdc_notification) + 2,
@@ -719,8 +723,14 @@ static void acm_unbind(struct usb_configuration *c, struct usb_function *f)
719723
static void acm_free_func(struct usb_function *f)
720724
{
721725
struct f_acm *acm = func_to_acm(f);
726+
struct f_serial_opts *opts;
727+
728+
opts = container_of(f->fi, struct f_serial_opts, func_inst);
722729

723730
kfree(acm);
731+
mutex_lock(&opts->lock);
732+
opts->instances--;
733+
mutex_unlock(&opts->lock);
724734
}
725735

726736
static void acm_resume(struct usb_function *f)
@@ -761,7 +771,11 @@ static struct usb_function *acm_alloc_func(struct usb_function_instance *fi)
761771
acm->port.func.disable = acm_disable;
762772

763773
opts = container_of(fi, struct f_serial_opts, func_inst);
774+
mutex_lock(&opts->lock);
764775
acm->port_num = opts->port_num;
776+
acm->bInterfaceProtocol = opts->protocol;
777+
opts->instances++;
778+
mutex_unlock(&opts->lock);
765779
acm->port.func.unbind = acm_unbind;
766780
acm->port.func.free_func = acm_free_func;
767781
acm->port.func.resume = acm_resume;
@@ -812,11 +826,42 @@ static ssize_t f_acm_port_num_show(struct config_item *item, char *page)
812826

813827
CONFIGFS_ATTR_RO(f_acm_, port_num);
814828

829+
static ssize_t f_acm_protocol_show(struct config_item *item, char *page)
830+
{
831+
return sprintf(page, "%u\n", to_f_serial_opts(item)->protocol);
832+
}
833+
834+
static ssize_t f_acm_protocol_store(struct config_item *item,
835+
const char *page, size_t count)
836+
{
837+
struct f_serial_opts *opts = to_f_serial_opts(item);
838+
int ret;
839+
840+
mutex_lock(&opts->lock);
841+
842+
if (opts->instances) {
843+
ret = -EBUSY;
844+
goto out;
845+
}
846+
847+
ret = kstrtou8(page, 0, &opts->protocol);
848+
if (ret)
849+
goto out;
850+
ret = count;
851+
852+
out:
853+
mutex_unlock(&opts->lock);
854+
return ret;
855+
}
856+
857+
CONFIGFS_ATTR(f_acm_, protocol);
858+
815859
static struct configfs_attribute *acm_attrs[] = {
816860
#ifdef CONFIG_U_SERIAL_CONSOLE
817861
&f_acm_attr_console,
818862
#endif
819863
&f_acm_attr_port_num,
864+
&f_acm_attr_protocol,
820865
NULL,
821866
};
822867

@@ -832,6 +877,7 @@ static void acm_free_instance(struct usb_function_instance *fi)
832877

833878
opts = container_of(fi, struct f_serial_opts, func_inst);
834879
gserial_free_line(opts->port_num);
880+
mutex_destroy(&opts->lock);
835881
kfree(opts);
836882
}
837883

@@ -843,7 +889,9 @@ static struct usb_function_instance *acm_alloc_instance(void)
843889
opts = kzalloc(sizeof(*opts), GFP_KERNEL);
844890
if (!opts)
845891
return ERR_PTR(-ENOMEM);
892+
opts->protocol = USB_CDC_ACM_PROTO_AT_V25TER;
846893
opts->func_inst.free_func_inst = acm_free_instance;
894+
mutex_init(&opts->lock);
847895
ret = gserial_alloc_line(&opts->port_num);
848896
if (ret) {
849897
kfree(opts);

drivers/usb/gadget/function/u_serial.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@
1717
struct f_serial_opts {
1818
struct usb_function_instance func_inst;
1919
u8 port_num;
20+
u8 protocol;
21+
22+
struct mutex lock; /* protect instances */
23+
int instances;
2024
};
2125

2226
/*

0 commit comments

Comments
 (0)