1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * f_serial.c - generic USB serial function 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/slab.h>
11*4882a593Smuzhiyun #include <linux/kernel.h>
12*4882a593Smuzhiyun #include <linux/module.h>
13*4882a593Smuzhiyun #include <linux/device.h>
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun #include "u_serial.h"
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun /*
19*4882a593Smuzhiyun * This function packages a simple "generic serial" port with no real
20*4882a593Smuzhiyun * control mechanisms, just raw data transfer over two bulk endpoints.
21*4882a593Smuzhiyun *
22*4882a593Smuzhiyun * Because it's not standardized, this isn't as interoperable as the
23*4882a593Smuzhiyun * CDC ACM driver. However, for many purposes it's just as functional
24*4882a593Smuzhiyun * if you can arrange appropriate host side drivers.
25*4882a593Smuzhiyun */
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun struct f_gser {
28*4882a593Smuzhiyun struct gserial port;
29*4882a593Smuzhiyun u8 data_id;
30*4882a593Smuzhiyun u8 port_num;
31*4882a593Smuzhiyun };
32*4882a593Smuzhiyun
func_to_gser(struct usb_function * f)33*4882a593Smuzhiyun static inline struct f_gser *func_to_gser(struct usb_function *f)
34*4882a593Smuzhiyun {
35*4882a593Smuzhiyun return container_of(f, struct f_gser, port.func);
36*4882a593Smuzhiyun }
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun /*-------------------------------------------------------------------------*/
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun /* interface descriptor: */
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun static struct usb_interface_descriptor gser_interface_desc = {
43*4882a593Smuzhiyun .bLength = USB_DT_INTERFACE_SIZE,
44*4882a593Smuzhiyun .bDescriptorType = USB_DT_INTERFACE,
45*4882a593Smuzhiyun /* .bInterfaceNumber = DYNAMIC */
46*4882a593Smuzhiyun .bNumEndpoints = 2,
47*4882a593Smuzhiyun .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
48*4882a593Smuzhiyun .bInterfaceSubClass = 0,
49*4882a593Smuzhiyun .bInterfaceProtocol = 0,
50*4882a593Smuzhiyun /* .iInterface = DYNAMIC */
51*4882a593Smuzhiyun };
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun /* full speed support: */
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun static struct usb_endpoint_descriptor gser_fs_in_desc = {
56*4882a593Smuzhiyun .bLength = USB_DT_ENDPOINT_SIZE,
57*4882a593Smuzhiyun .bDescriptorType = USB_DT_ENDPOINT,
58*4882a593Smuzhiyun .bEndpointAddress = USB_DIR_IN,
59*4882a593Smuzhiyun .bmAttributes = USB_ENDPOINT_XFER_BULK,
60*4882a593Smuzhiyun };
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun static struct usb_endpoint_descriptor gser_fs_out_desc = {
63*4882a593Smuzhiyun .bLength = USB_DT_ENDPOINT_SIZE,
64*4882a593Smuzhiyun .bDescriptorType = USB_DT_ENDPOINT,
65*4882a593Smuzhiyun .bEndpointAddress = USB_DIR_OUT,
66*4882a593Smuzhiyun .bmAttributes = USB_ENDPOINT_XFER_BULK,
67*4882a593Smuzhiyun };
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun static struct usb_descriptor_header *gser_fs_function[] = {
70*4882a593Smuzhiyun (struct usb_descriptor_header *) &gser_interface_desc,
71*4882a593Smuzhiyun (struct usb_descriptor_header *) &gser_fs_in_desc,
72*4882a593Smuzhiyun (struct usb_descriptor_header *) &gser_fs_out_desc,
73*4882a593Smuzhiyun NULL,
74*4882a593Smuzhiyun };
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun /* high speed support: */
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun static struct usb_endpoint_descriptor gser_hs_in_desc = {
79*4882a593Smuzhiyun .bLength = USB_DT_ENDPOINT_SIZE,
80*4882a593Smuzhiyun .bDescriptorType = USB_DT_ENDPOINT,
81*4882a593Smuzhiyun .bmAttributes = USB_ENDPOINT_XFER_BULK,
82*4882a593Smuzhiyun .wMaxPacketSize = cpu_to_le16(512),
83*4882a593Smuzhiyun };
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun static struct usb_endpoint_descriptor gser_hs_out_desc = {
86*4882a593Smuzhiyun .bLength = USB_DT_ENDPOINT_SIZE,
87*4882a593Smuzhiyun .bDescriptorType = USB_DT_ENDPOINT,
88*4882a593Smuzhiyun .bmAttributes = USB_ENDPOINT_XFER_BULK,
89*4882a593Smuzhiyun .wMaxPacketSize = cpu_to_le16(512),
90*4882a593Smuzhiyun };
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun static struct usb_descriptor_header *gser_hs_function[] = {
93*4882a593Smuzhiyun (struct usb_descriptor_header *) &gser_interface_desc,
94*4882a593Smuzhiyun (struct usb_descriptor_header *) &gser_hs_in_desc,
95*4882a593Smuzhiyun (struct usb_descriptor_header *) &gser_hs_out_desc,
96*4882a593Smuzhiyun NULL,
97*4882a593Smuzhiyun };
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun static struct usb_endpoint_descriptor gser_ss_in_desc = {
100*4882a593Smuzhiyun .bLength = USB_DT_ENDPOINT_SIZE,
101*4882a593Smuzhiyun .bDescriptorType = USB_DT_ENDPOINT,
102*4882a593Smuzhiyun .bmAttributes = USB_ENDPOINT_XFER_BULK,
103*4882a593Smuzhiyun .wMaxPacketSize = cpu_to_le16(1024),
104*4882a593Smuzhiyun };
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun static struct usb_endpoint_descriptor gser_ss_out_desc = {
107*4882a593Smuzhiyun .bLength = USB_DT_ENDPOINT_SIZE,
108*4882a593Smuzhiyun .bDescriptorType = USB_DT_ENDPOINT,
109*4882a593Smuzhiyun .bmAttributes = USB_ENDPOINT_XFER_BULK,
110*4882a593Smuzhiyun .wMaxPacketSize = cpu_to_le16(1024),
111*4882a593Smuzhiyun };
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun static struct usb_ss_ep_comp_descriptor gser_ss_bulk_comp_desc = {
114*4882a593Smuzhiyun .bLength = sizeof gser_ss_bulk_comp_desc,
115*4882a593Smuzhiyun .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
116*4882a593Smuzhiyun };
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun static struct usb_descriptor_header *gser_ss_function[] = {
119*4882a593Smuzhiyun (struct usb_descriptor_header *) &gser_interface_desc,
120*4882a593Smuzhiyun (struct usb_descriptor_header *) &gser_ss_in_desc,
121*4882a593Smuzhiyun (struct usb_descriptor_header *) &gser_ss_bulk_comp_desc,
122*4882a593Smuzhiyun (struct usb_descriptor_header *) &gser_ss_out_desc,
123*4882a593Smuzhiyun (struct usb_descriptor_header *) &gser_ss_bulk_comp_desc,
124*4882a593Smuzhiyun NULL,
125*4882a593Smuzhiyun };
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun /* string descriptors: */
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun static struct usb_string gser_string_defs[] = {
130*4882a593Smuzhiyun [0].s = "Generic Serial",
131*4882a593Smuzhiyun { } /* end of list */
132*4882a593Smuzhiyun };
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun static struct usb_gadget_strings gser_string_table = {
135*4882a593Smuzhiyun .language = 0x0409, /* en-us */
136*4882a593Smuzhiyun .strings = gser_string_defs,
137*4882a593Smuzhiyun };
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun static struct usb_gadget_strings *gser_strings[] = {
140*4882a593Smuzhiyun &gser_string_table,
141*4882a593Smuzhiyun NULL,
142*4882a593Smuzhiyun };
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun /*-------------------------------------------------------------------------*/
145*4882a593Smuzhiyun
gser_set_alt(struct usb_function * f,unsigned intf,unsigned alt)146*4882a593Smuzhiyun static int gser_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
147*4882a593Smuzhiyun {
148*4882a593Smuzhiyun struct f_gser *gser = func_to_gser(f);
149*4882a593Smuzhiyun struct usb_composite_dev *cdev = f->config->cdev;
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun /* we know alt == 0, so this is an activation or a reset */
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun if (gser->port.in->enabled) {
154*4882a593Smuzhiyun dev_dbg(&cdev->gadget->dev,
155*4882a593Smuzhiyun "reset generic ttyGS%d\n", gser->port_num);
156*4882a593Smuzhiyun gserial_disconnect(&gser->port);
157*4882a593Smuzhiyun }
158*4882a593Smuzhiyun if (!gser->port.in->desc || !gser->port.out->desc) {
159*4882a593Smuzhiyun dev_dbg(&cdev->gadget->dev,
160*4882a593Smuzhiyun "activate generic ttyGS%d\n", gser->port_num);
161*4882a593Smuzhiyun if (config_ep_by_speed(cdev->gadget, f, gser->port.in) ||
162*4882a593Smuzhiyun config_ep_by_speed(cdev->gadget, f, gser->port.out)) {
163*4882a593Smuzhiyun gser->port.in->desc = NULL;
164*4882a593Smuzhiyun gser->port.out->desc = NULL;
165*4882a593Smuzhiyun return -EINVAL;
166*4882a593Smuzhiyun }
167*4882a593Smuzhiyun }
168*4882a593Smuzhiyun gserial_connect(&gser->port, gser->port_num);
169*4882a593Smuzhiyun return 0;
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun
gser_disable(struct usb_function * f)172*4882a593Smuzhiyun static void gser_disable(struct usb_function *f)
173*4882a593Smuzhiyun {
174*4882a593Smuzhiyun struct f_gser *gser = func_to_gser(f);
175*4882a593Smuzhiyun struct usb_composite_dev *cdev = f->config->cdev;
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun dev_dbg(&cdev->gadget->dev,
178*4882a593Smuzhiyun "generic ttyGS%d deactivated\n", gser->port_num);
179*4882a593Smuzhiyun gserial_disconnect(&gser->port);
180*4882a593Smuzhiyun }
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun /*-------------------------------------------------------------------------*/
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun /* serial function driver setup/binding */
185*4882a593Smuzhiyun
gser_bind(struct usb_configuration * c,struct usb_function * f)186*4882a593Smuzhiyun static int gser_bind(struct usb_configuration *c, struct usb_function *f)
187*4882a593Smuzhiyun {
188*4882a593Smuzhiyun struct usb_composite_dev *cdev = c->cdev;
189*4882a593Smuzhiyun struct f_gser *gser = func_to_gser(f);
190*4882a593Smuzhiyun int status;
191*4882a593Smuzhiyun struct usb_ep *ep;
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun /* REVISIT might want instance-specific strings to help
194*4882a593Smuzhiyun * distinguish instances ...
195*4882a593Smuzhiyun */
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun /* maybe allocate device-global string ID */
198*4882a593Smuzhiyun if (gser_string_defs[0].id == 0) {
199*4882a593Smuzhiyun status = usb_string_id(c->cdev);
200*4882a593Smuzhiyun if (status < 0)
201*4882a593Smuzhiyun return status;
202*4882a593Smuzhiyun gser_string_defs[0].id = status;
203*4882a593Smuzhiyun }
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun /* allocate instance-specific interface IDs */
206*4882a593Smuzhiyun status = usb_interface_id(c, f);
207*4882a593Smuzhiyun if (status < 0)
208*4882a593Smuzhiyun goto fail;
209*4882a593Smuzhiyun gser->data_id = status;
210*4882a593Smuzhiyun gser_interface_desc.bInterfaceNumber = status;
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun status = -ENODEV;
213*4882a593Smuzhiyun
214*4882a593Smuzhiyun /* allocate instance-specific endpoints */
215*4882a593Smuzhiyun ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_in_desc);
216*4882a593Smuzhiyun if (!ep)
217*4882a593Smuzhiyun goto fail;
218*4882a593Smuzhiyun gser->port.in = ep;
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_out_desc);
221*4882a593Smuzhiyun if (!ep)
222*4882a593Smuzhiyun goto fail;
223*4882a593Smuzhiyun gser->port.out = ep;
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun /* support all relevant hardware speeds... we expect that when
226*4882a593Smuzhiyun * hardware is dual speed, all bulk-capable endpoints work at
227*4882a593Smuzhiyun * both speeds
228*4882a593Smuzhiyun */
229*4882a593Smuzhiyun gser_hs_in_desc.bEndpointAddress = gser_fs_in_desc.bEndpointAddress;
230*4882a593Smuzhiyun gser_hs_out_desc.bEndpointAddress = gser_fs_out_desc.bEndpointAddress;
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun gser_ss_in_desc.bEndpointAddress = gser_fs_in_desc.bEndpointAddress;
233*4882a593Smuzhiyun gser_ss_out_desc.bEndpointAddress = gser_fs_out_desc.bEndpointAddress;
234*4882a593Smuzhiyun
235*4882a593Smuzhiyun status = usb_assign_descriptors(f, gser_fs_function, gser_hs_function,
236*4882a593Smuzhiyun gser_ss_function, gser_ss_function);
237*4882a593Smuzhiyun if (status)
238*4882a593Smuzhiyun goto fail;
239*4882a593Smuzhiyun dev_dbg(&cdev->gadget->dev, "generic ttyGS%d: %s speed IN/%s OUT/%s\n",
240*4882a593Smuzhiyun gser->port_num,
241*4882a593Smuzhiyun gadget_is_superspeed(c->cdev->gadget) ? "super" :
242*4882a593Smuzhiyun gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
243*4882a593Smuzhiyun gser->port.in->name, gser->port.out->name);
244*4882a593Smuzhiyun return 0;
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun fail:
247*4882a593Smuzhiyun ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
248*4882a593Smuzhiyun
249*4882a593Smuzhiyun return status;
250*4882a593Smuzhiyun }
251*4882a593Smuzhiyun
to_f_serial_opts(struct config_item * item)252*4882a593Smuzhiyun static inline struct f_serial_opts *to_f_serial_opts(struct config_item *item)
253*4882a593Smuzhiyun {
254*4882a593Smuzhiyun return container_of(to_config_group(item), struct f_serial_opts,
255*4882a593Smuzhiyun func_inst.group);
256*4882a593Smuzhiyun }
257*4882a593Smuzhiyun
serial_attr_release(struct config_item * item)258*4882a593Smuzhiyun static void serial_attr_release(struct config_item *item)
259*4882a593Smuzhiyun {
260*4882a593Smuzhiyun struct f_serial_opts *opts = to_f_serial_opts(item);
261*4882a593Smuzhiyun
262*4882a593Smuzhiyun usb_put_function_instance(&opts->func_inst);
263*4882a593Smuzhiyun }
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun static struct configfs_item_operations serial_item_ops = {
266*4882a593Smuzhiyun .release = serial_attr_release,
267*4882a593Smuzhiyun };
268*4882a593Smuzhiyun
269*4882a593Smuzhiyun #ifdef CONFIG_U_SERIAL_CONSOLE
270*4882a593Smuzhiyun
f_serial_console_store(struct config_item * item,const char * page,size_t count)271*4882a593Smuzhiyun static ssize_t f_serial_console_store(struct config_item *item,
272*4882a593Smuzhiyun const char *page, size_t count)
273*4882a593Smuzhiyun {
274*4882a593Smuzhiyun return gserial_set_console(to_f_serial_opts(item)->port_num,
275*4882a593Smuzhiyun page, count);
276*4882a593Smuzhiyun }
277*4882a593Smuzhiyun
f_serial_console_show(struct config_item * item,char * page)278*4882a593Smuzhiyun static ssize_t f_serial_console_show(struct config_item *item, char *page)
279*4882a593Smuzhiyun {
280*4882a593Smuzhiyun return gserial_get_console(to_f_serial_opts(item)->port_num, page);
281*4882a593Smuzhiyun }
282*4882a593Smuzhiyun
283*4882a593Smuzhiyun CONFIGFS_ATTR(f_serial_, console);
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun #endif /* CONFIG_U_SERIAL_CONSOLE */
286*4882a593Smuzhiyun
f_serial_port_num_show(struct config_item * item,char * page)287*4882a593Smuzhiyun static ssize_t f_serial_port_num_show(struct config_item *item, char *page)
288*4882a593Smuzhiyun {
289*4882a593Smuzhiyun return sprintf(page, "%u\n", to_f_serial_opts(item)->port_num);
290*4882a593Smuzhiyun }
291*4882a593Smuzhiyun
292*4882a593Smuzhiyun CONFIGFS_ATTR_RO(f_serial_, port_num);
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun static struct configfs_attribute *acm_attrs[] = {
295*4882a593Smuzhiyun #ifdef CONFIG_U_SERIAL_CONSOLE
296*4882a593Smuzhiyun &f_serial_attr_console,
297*4882a593Smuzhiyun #endif
298*4882a593Smuzhiyun &f_serial_attr_port_num,
299*4882a593Smuzhiyun NULL,
300*4882a593Smuzhiyun };
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun static const struct config_item_type serial_func_type = {
303*4882a593Smuzhiyun .ct_item_ops = &serial_item_ops,
304*4882a593Smuzhiyun .ct_attrs = acm_attrs,
305*4882a593Smuzhiyun .ct_owner = THIS_MODULE,
306*4882a593Smuzhiyun };
307*4882a593Smuzhiyun
gser_free_inst(struct usb_function_instance * f)308*4882a593Smuzhiyun static void gser_free_inst(struct usb_function_instance *f)
309*4882a593Smuzhiyun {
310*4882a593Smuzhiyun struct f_serial_opts *opts;
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun opts = container_of(f, struct f_serial_opts, func_inst);
313*4882a593Smuzhiyun gserial_free_line(opts->port_num);
314*4882a593Smuzhiyun kfree(opts);
315*4882a593Smuzhiyun }
316*4882a593Smuzhiyun
gser_alloc_inst(void)317*4882a593Smuzhiyun static struct usb_function_instance *gser_alloc_inst(void)
318*4882a593Smuzhiyun {
319*4882a593Smuzhiyun struct f_serial_opts *opts;
320*4882a593Smuzhiyun int ret;
321*4882a593Smuzhiyun
322*4882a593Smuzhiyun opts = kzalloc(sizeof(*opts), GFP_KERNEL);
323*4882a593Smuzhiyun if (!opts)
324*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun opts->func_inst.free_func_inst = gser_free_inst;
327*4882a593Smuzhiyun ret = gserial_alloc_line(&opts->port_num);
328*4882a593Smuzhiyun if (ret) {
329*4882a593Smuzhiyun kfree(opts);
330*4882a593Smuzhiyun return ERR_PTR(ret);
331*4882a593Smuzhiyun }
332*4882a593Smuzhiyun config_group_init_type_name(&opts->func_inst.group, "",
333*4882a593Smuzhiyun &serial_func_type);
334*4882a593Smuzhiyun
335*4882a593Smuzhiyun return &opts->func_inst;
336*4882a593Smuzhiyun }
337*4882a593Smuzhiyun
gser_free(struct usb_function * f)338*4882a593Smuzhiyun static void gser_free(struct usb_function *f)
339*4882a593Smuzhiyun {
340*4882a593Smuzhiyun struct f_gser *serial;
341*4882a593Smuzhiyun
342*4882a593Smuzhiyun serial = func_to_gser(f);
343*4882a593Smuzhiyun kfree(serial);
344*4882a593Smuzhiyun }
345*4882a593Smuzhiyun
gser_unbind(struct usb_configuration * c,struct usb_function * f)346*4882a593Smuzhiyun static void gser_unbind(struct usb_configuration *c, struct usb_function *f)
347*4882a593Smuzhiyun {
348*4882a593Smuzhiyun struct f_gser *gser = func_to_gser(f);
349*4882a593Smuzhiyun
350*4882a593Smuzhiyun /* Ensure port is disconnected before unbinding */
351*4882a593Smuzhiyun gserial_disconnect(&gser->port);
352*4882a593Smuzhiyun usb_free_all_descriptors(f);
353*4882a593Smuzhiyun }
354*4882a593Smuzhiyun
gser_resume(struct usb_function * f)355*4882a593Smuzhiyun static void gser_resume(struct usb_function *f)
356*4882a593Smuzhiyun {
357*4882a593Smuzhiyun struct f_gser *gser = func_to_gser(f);
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun gserial_resume(&gser->port);
360*4882a593Smuzhiyun }
361*4882a593Smuzhiyun
gser_suspend(struct usb_function * f)362*4882a593Smuzhiyun static void gser_suspend(struct usb_function *f)
363*4882a593Smuzhiyun {
364*4882a593Smuzhiyun struct f_gser *gser = func_to_gser(f);
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun gserial_suspend(&gser->port);
367*4882a593Smuzhiyun }
368*4882a593Smuzhiyun
gser_alloc(struct usb_function_instance * fi)369*4882a593Smuzhiyun static struct usb_function *gser_alloc(struct usb_function_instance *fi)
370*4882a593Smuzhiyun {
371*4882a593Smuzhiyun struct f_gser *gser;
372*4882a593Smuzhiyun struct f_serial_opts *opts;
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun /* allocate and initialize one new instance */
375*4882a593Smuzhiyun gser = kzalloc(sizeof(*gser), GFP_KERNEL);
376*4882a593Smuzhiyun if (!gser)
377*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
378*4882a593Smuzhiyun
379*4882a593Smuzhiyun opts = container_of(fi, struct f_serial_opts, func_inst);
380*4882a593Smuzhiyun
381*4882a593Smuzhiyun gser->port_num = opts->port_num;
382*4882a593Smuzhiyun
383*4882a593Smuzhiyun gser->port.func.name = "gser";
384*4882a593Smuzhiyun gser->port.func.strings = gser_strings;
385*4882a593Smuzhiyun gser->port.func.bind = gser_bind;
386*4882a593Smuzhiyun gser->port.func.unbind = gser_unbind;
387*4882a593Smuzhiyun gser->port.func.set_alt = gser_set_alt;
388*4882a593Smuzhiyun gser->port.func.disable = gser_disable;
389*4882a593Smuzhiyun gser->port.func.free_func = gser_free;
390*4882a593Smuzhiyun gser->port.func.resume = gser_resume;
391*4882a593Smuzhiyun gser->port.func.suspend = gser_suspend;
392*4882a593Smuzhiyun
393*4882a593Smuzhiyun return &gser->port.func;
394*4882a593Smuzhiyun }
395*4882a593Smuzhiyun
396*4882a593Smuzhiyun DECLARE_USB_FUNCTION_INIT(gser, gser_alloc_inst, gser_alloc);
397*4882a593Smuzhiyun MODULE_LICENSE("GPL");
398*4882a593Smuzhiyun MODULE_AUTHOR("Al Borchers");
399*4882a593Smuzhiyun MODULE_AUTHOR("David Brownell");
400