1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * serial.c -- USB gadget serial driver
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 2003 Al Borchers (alborchers@steinerpoint.com)
6*4882a593Smuzhiyun * Copyright (C) 2008 by David Brownell
7*4882a593Smuzhiyun * Copyright (C) 2008 by Nokia Corporation
8*4882a593Smuzhiyun */
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #include <linux/kernel.h>
11*4882a593Smuzhiyun #include <linux/device.h>
12*4882a593Smuzhiyun #include <linux/module.h>
13*4882a593Smuzhiyun #include <linux/tty.h>
14*4882a593Smuzhiyun #include <linux/tty_flip.h>
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun #include "u_serial.h"
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun /* Defines */
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun #define GS_VERSION_STR "v2.4"
22*4882a593Smuzhiyun #define GS_VERSION_NUM 0x2400
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun #define GS_LONG_NAME "Gadget Serial"
25*4882a593Smuzhiyun #define GS_VERSION_NAME GS_LONG_NAME " " GS_VERSION_STR
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun /*-------------------------------------------------------------------------*/
28*4882a593Smuzhiyun USB_GADGET_COMPOSITE_OPTIONS();
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun /* Thanks to NetChip Technologies for donating this product ID.
31*4882a593Smuzhiyun *
32*4882a593Smuzhiyun * DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!!
33*4882a593Smuzhiyun * Instead: allocate your own, using normal USB-IF procedures.
34*4882a593Smuzhiyun */
35*4882a593Smuzhiyun #define GS_VENDOR_ID 0x0525 /* NetChip */
36*4882a593Smuzhiyun #define GS_PRODUCT_ID 0xa4a6 /* Linux-USB Serial Gadget */
37*4882a593Smuzhiyun #define GS_CDC_PRODUCT_ID 0xa4a7 /* ... as CDC-ACM */
38*4882a593Smuzhiyun #define GS_CDC_OBEX_PRODUCT_ID 0xa4a9 /* ... as CDC-OBEX */
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun /* string IDs are assigned dynamically */
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun #define STRING_DESCRIPTION_IDX USB_GADGET_FIRST_AVAIL_IDX
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun static struct usb_string strings_dev[] = {
45*4882a593Smuzhiyun [USB_GADGET_MANUFACTURER_IDX].s = "",
46*4882a593Smuzhiyun [USB_GADGET_PRODUCT_IDX].s = GS_VERSION_NAME,
47*4882a593Smuzhiyun [USB_GADGET_SERIAL_IDX].s = "",
48*4882a593Smuzhiyun [STRING_DESCRIPTION_IDX].s = NULL /* updated; f(use_acm) */,
49*4882a593Smuzhiyun { } /* end of list */
50*4882a593Smuzhiyun };
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun static struct usb_gadget_strings stringtab_dev = {
53*4882a593Smuzhiyun .language = 0x0409, /* en-us */
54*4882a593Smuzhiyun .strings = strings_dev,
55*4882a593Smuzhiyun };
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun static struct usb_gadget_strings *dev_strings[] = {
58*4882a593Smuzhiyun &stringtab_dev,
59*4882a593Smuzhiyun NULL,
60*4882a593Smuzhiyun };
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun static struct usb_device_descriptor device_desc = {
63*4882a593Smuzhiyun .bLength = USB_DT_DEVICE_SIZE,
64*4882a593Smuzhiyun .bDescriptorType = USB_DT_DEVICE,
65*4882a593Smuzhiyun /* .bcdUSB = DYNAMIC */
66*4882a593Smuzhiyun /* .bDeviceClass = f(use_acm) */
67*4882a593Smuzhiyun .bDeviceSubClass = 0,
68*4882a593Smuzhiyun .bDeviceProtocol = 0,
69*4882a593Smuzhiyun /* .bMaxPacketSize0 = f(hardware) */
70*4882a593Smuzhiyun .idVendor = cpu_to_le16(GS_VENDOR_ID),
71*4882a593Smuzhiyun /* .idProduct = f(use_acm) */
72*4882a593Smuzhiyun .bcdDevice = cpu_to_le16(GS_VERSION_NUM),
73*4882a593Smuzhiyun /* .iManufacturer = DYNAMIC */
74*4882a593Smuzhiyun /* .iProduct = DYNAMIC */
75*4882a593Smuzhiyun .bNumConfigurations = 1,
76*4882a593Smuzhiyun };
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun static const struct usb_descriptor_header *otg_desc[2];
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun /*-------------------------------------------------------------------------*/
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun /* Module */
83*4882a593Smuzhiyun MODULE_DESCRIPTION(GS_VERSION_NAME);
84*4882a593Smuzhiyun MODULE_AUTHOR("Al Borchers");
85*4882a593Smuzhiyun MODULE_AUTHOR("David Brownell");
86*4882a593Smuzhiyun MODULE_LICENSE("GPL");
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun static bool use_acm = true;
89*4882a593Smuzhiyun module_param(use_acm, bool, 0);
90*4882a593Smuzhiyun MODULE_PARM_DESC(use_acm, "Use CDC ACM, default=yes");
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun static bool use_obex = false;
93*4882a593Smuzhiyun module_param(use_obex, bool, 0);
94*4882a593Smuzhiyun MODULE_PARM_DESC(use_obex, "Use CDC OBEX, default=no");
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun static unsigned n_ports = 1;
97*4882a593Smuzhiyun module_param(n_ports, uint, 0);
98*4882a593Smuzhiyun MODULE_PARM_DESC(n_ports, "number of ports to create, default=1");
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun static bool enable = true;
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun static int switch_gserial_enable(bool do_enable);
103*4882a593Smuzhiyun
enable_set(const char * s,const struct kernel_param * kp)104*4882a593Smuzhiyun static int enable_set(const char *s, const struct kernel_param *kp)
105*4882a593Smuzhiyun {
106*4882a593Smuzhiyun bool do_enable;
107*4882a593Smuzhiyun int ret;
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun if (!s) /* called for no-arg enable == default */
110*4882a593Smuzhiyun return 0;
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun ret = strtobool(s, &do_enable);
113*4882a593Smuzhiyun if (ret || enable == do_enable)
114*4882a593Smuzhiyun return ret;
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun ret = switch_gserial_enable(do_enable);
117*4882a593Smuzhiyun if (!ret)
118*4882a593Smuzhiyun enable = do_enable;
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun return ret;
121*4882a593Smuzhiyun }
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun static const struct kernel_param_ops enable_ops = {
124*4882a593Smuzhiyun .set = enable_set,
125*4882a593Smuzhiyun .get = param_get_bool,
126*4882a593Smuzhiyun };
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun module_param_cb(enable, &enable_ops, &enable, 0644);
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun /*-------------------------------------------------------------------------*/
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun static struct usb_configuration serial_config_driver = {
133*4882a593Smuzhiyun /* .label = f(use_acm) */
134*4882a593Smuzhiyun /* .bConfigurationValue = f(use_acm) */
135*4882a593Smuzhiyun /* .iConfiguration = DYNAMIC */
136*4882a593Smuzhiyun .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
137*4882a593Smuzhiyun };
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun static struct usb_function_instance *fi_serial[MAX_U_SERIAL_PORTS];
140*4882a593Smuzhiyun static struct usb_function *f_serial[MAX_U_SERIAL_PORTS];
141*4882a593Smuzhiyun
serial_register_ports(struct usb_composite_dev * cdev,struct usb_configuration * c,const char * f_name)142*4882a593Smuzhiyun static int serial_register_ports(struct usb_composite_dev *cdev,
143*4882a593Smuzhiyun struct usb_configuration *c, const char *f_name)
144*4882a593Smuzhiyun {
145*4882a593Smuzhiyun int i;
146*4882a593Smuzhiyun int ret;
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun ret = usb_add_config_only(cdev, c);
149*4882a593Smuzhiyun if (ret)
150*4882a593Smuzhiyun goto out;
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun for (i = 0; i < n_ports; i++) {
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun fi_serial[i] = usb_get_function_instance(f_name);
155*4882a593Smuzhiyun if (IS_ERR(fi_serial[i])) {
156*4882a593Smuzhiyun ret = PTR_ERR(fi_serial[i]);
157*4882a593Smuzhiyun goto fail;
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun f_serial[i] = usb_get_function(fi_serial[i]);
161*4882a593Smuzhiyun if (IS_ERR(f_serial[i])) {
162*4882a593Smuzhiyun ret = PTR_ERR(f_serial[i]);
163*4882a593Smuzhiyun goto err_get_func;
164*4882a593Smuzhiyun }
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun ret = usb_add_function(c, f_serial[i]);
167*4882a593Smuzhiyun if (ret)
168*4882a593Smuzhiyun goto err_add_func;
169*4882a593Smuzhiyun }
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun return 0;
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun err_add_func:
174*4882a593Smuzhiyun usb_put_function(f_serial[i]);
175*4882a593Smuzhiyun err_get_func:
176*4882a593Smuzhiyun usb_put_function_instance(fi_serial[i]);
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun fail:
179*4882a593Smuzhiyun i--;
180*4882a593Smuzhiyun while (i >= 0) {
181*4882a593Smuzhiyun usb_remove_function(c, f_serial[i]);
182*4882a593Smuzhiyun usb_put_function(f_serial[i]);
183*4882a593Smuzhiyun usb_put_function_instance(fi_serial[i]);
184*4882a593Smuzhiyun i--;
185*4882a593Smuzhiyun }
186*4882a593Smuzhiyun out:
187*4882a593Smuzhiyun return ret;
188*4882a593Smuzhiyun }
189*4882a593Smuzhiyun
gs_bind(struct usb_composite_dev * cdev)190*4882a593Smuzhiyun static int gs_bind(struct usb_composite_dev *cdev)
191*4882a593Smuzhiyun {
192*4882a593Smuzhiyun int status;
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun /* Allocate string descriptor numbers ... note that string
195*4882a593Smuzhiyun * contents can be overridden by the composite_dev glue.
196*4882a593Smuzhiyun */
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun status = usb_string_ids_tab(cdev, strings_dev);
199*4882a593Smuzhiyun if (status < 0)
200*4882a593Smuzhiyun goto fail;
201*4882a593Smuzhiyun device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
202*4882a593Smuzhiyun device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
203*4882a593Smuzhiyun status = strings_dev[STRING_DESCRIPTION_IDX].id;
204*4882a593Smuzhiyun serial_config_driver.iConfiguration = status;
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun if (gadget_is_otg(cdev->gadget)) {
207*4882a593Smuzhiyun if (!otg_desc[0]) {
208*4882a593Smuzhiyun struct usb_descriptor_header *usb_desc;
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun usb_desc = usb_otg_descriptor_alloc(cdev->gadget);
211*4882a593Smuzhiyun if (!usb_desc) {
212*4882a593Smuzhiyun status = -ENOMEM;
213*4882a593Smuzhiyun goto fail;
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun usb_otg_descriptor_init(cdev->gadget, usb_desc);
216*4882a593Smuzhiyun otg_desc[0] = usb_desc;
217*4882a593Smuzhiyun otg_desc[1] = NULL;
218*4882a593Smuzhiyun }
219*4882a593Smuzhiyun serial_config_driver.descriptors = otg_desc;
220*4882a593Smuzhiyun serial_config_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
221*4882a593Smuzhiyun }
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun /* register our configuration */
224*4882a593Smuzhiyun if (use_acm) {
225*4882a593Smuzhiyun status = serial_register_ports(cdev, &serial_config_driver,
226*4882a593Smuzhiyun "acm");
227*4882a593Smuzhiyun usb_ep_autoconfig_reset(cdev->gadget);
228*4882a593Smuzhiyun } else if (use_obex)
229*4882a593Smuzhiyun status = serial_register_ports(cdev, &serial_config_driver,
230*4882a593Smuzhiyun "obex");
231*4882a593Smuzhiyun else {
232*4882a593Smuzhiyun status = serial_register_ports(cdev, &serial_config_driver,
233*4882a593Smuzhiyun "gser");
234*4882a593Smuzhiyun }
235*4882a593Smuzhiyun if (status < 0)
236*4882a593Smuzhiyun goto fail1;
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun usb_composite_overwrite_options(cdev, &coverwrite);
239*4882a593Smuzhiyun INFO(cdev, "%s\n", GS_VERSION_NAME);
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun return 0;
242*4882a593Smuzhiyun fail1:
243*4882a593Smuzhiyun kfree(otg_desc[0]);
244*4882a593Smuzhiyun otg_desc[0] = NULL;
245*4882a593Smuzhiyun fail:
246*4882a593Smuzhiyun return status;
247*4882a593Smuzhiyun }
248*4882a593Smuzhiyun
gs_unbind(struct usb_composite_dev * cdev)249*4882a593Smuzhiyun static int gs_unbind(struct usb_composite_dev *cdev)
250*4882a593Smuzhiyun {
251*4882a593Smuzhiyun int i;
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun for (i = 0; i < n_ports; i++) {
254*4882a593Smuzhiyun usb_put_function(f_serial[i]);
255*4882a593Smuzhiyun usb_put_function_instance(fi_serial[i]);
256*4882a593Smuzhiyun }
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun kfree(otg_desc[0]);
259*4882a593Smuzhiyun otg_desc[0] = NULL;
260*4882a593Smuzhiyun
261*4882a593Smuzhiyun return 0;
262*4882a593Smuzhiyun }
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun static struct usb_composite_driver gserial_driver = {
265*4882a593Smuzhiyun .name = "g_serial",
266*4882a593Smuzhiyun .dev = &device_desc,
267*4882a593Smuzhiyun .strings = dev_strings,
268*4882a593Smuzhiyun .max_speed = USB_SPEED_SUPER,
269*4882a593Smuzhiyun .bind = gs_bind,
270*4882a593Smuzhiyun .unbind = gs_unbind,
271*4882a593Smuzhiyun };
272*4882a593Smuzhiyun
switch_gserial_enable(bool do_enable)273*4882a593Smuzhiyun static int switch_gserial_enable(bool do_enable)
274*4882a593Smuzhiyun {
275*4882a593Smuzhiyun if (!serial_config_driver.label)
276*4882a593Smuzhiyun /* init() was not called, yet */
277*4882a593Smuzhiyun return 0;
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun if (do_enable)
280*4882a593Smuzhiyun return usb_composite_probe(&gserial_driver);
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun usb_composite_unregister(&gserial_driver);
283*4882a593Smuzhiyun return 0;
284*4882a593Smuzhiyun }
285*4882a593Smuzhiyun
init(void)286*4882a593Smuzhiyun static int __init init(void)
287*4882a593Smuzhiyun {
288*4882a593Smuzhiyun /* We *could* export two configs; that'd be much cleaner...
289*4882a593Smuzhiyun * but neither of these product IDs was defined that way.
290*4882a593Smuzhiyun */
291*4882a593Smuzhiyun if (use_acm) {
292*4882a593Smuzhiyun serial_config_driver.label = "CDC ACM config";
293*4882a593Smuzhiyun serial_config_driver.bConfigurationValue = 2;
294*4882a593Smuzhiyun device_desc.bDeviceClass = USB_CLASS_COMM;
295*4882a593Smuzhiyun device_desc.idProduct =
296*4882a593Smuzhiyun cpu_to_le16(GS_CDC_PRODUCT_ID);
297*4882a593Smuzhiyun } else if (use_obex) {
298*4882a593Smuzhiyun serial_config_driver.label = "CDC OBEX config";
299*4882a593Smuzhiyun serial_config_driver.bConfigurationValue = 3;
300*4882a593Smuzhiyun device_desc.bDeviceClass = USB_CLASS_COMM;
301*4882a593Smuzhiyun device_desc.idProduct =
302*4882a593Smuzhiyun cpu_to_le16(GS_CDC_OBEX_PRODUCT_ID);
303*4882a593Smuzhiyun } else {
304*4882a593Smuzhiyun serial_config_driver.label = "Generic Serial config";
305*4882a593Smuzhiyun serial_config_driver.bConfigurationValue = 1;
306*4882a593Smuzhiyun device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC;
307*4882a593Smuzhiyun device_desc.idProduct =
308*4882a593Smuzhiyun cpu_to_le16(GS_PRODUCT_ID);
309*4882a593Smuzhiyun }
310*4882a593Smuzhiyun strings_dev[STRING_DESCRIPTION_IDX].s = serial_config_driver.label;
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun if (!enable)
313*4882a593Smuzhiyun return 0;
314*4882a593Smuzhiyun
315*4882a593Smuzhiyun return usb_composite_probe(&gserial_driver);
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun module_init(init);
318*4882a593Smuzhiyun
cleanup(void)319*4882a593Smuzhiyun static void __exit cleanup(void)
320*4882a593Smuzhiyun {
321*4882a593Smuzhiyun if (enable)
322*4882a593Smuzhiyun usb_composite_unregister(&gserial_driver);
323*4882a593Smuzhiyun }
324*4882a593Smuzhiyun module_exit(cleanup);
325