1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* |
3 | * printer.c -- Printer gadget driver |
4 | * |
5 | * Copyright (C) 2003-2005 David Brownell |
6 | * Copyright (C) 2006 Craig W. Nadler |
7 | */ |
8 | |
9 | #include <linux/module.h> |
10 | #include <linux/kernel.h> |
11 | #include <asm/byteorder.h> |
12 | |
13 | #include <linux/usb/ch9.h> |
14 | #include <linux/usb/composite.h> |
15 | #include <linux/usb/gadget.h> |
16 | #include <linux/usb/g_printer.h> |
17 | |
18 | USB_GADGET_COMPOSITE_OPTIONS(); |
19 | |
20 | #define DRIVER_DESC "Printer Gadget" |
21 | #define DRIVER_VERSION "2015 FEB 17" |
22 | |
23 | static const char shortname [] = "printer" ; |
24 | |
25 | #include "u_printer.h" |
26 | |
27 | /*-------------------------------------------------------------------------*/ |
28 | |
29 | /* DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!! |
30 | * Instead: allocate your own, using normal USB-IF procedures. |
31 | */ |
32 | |
33 | /* Thanks to NetChip Technologies for donating this product ID. |
34 | */ |
35 | #define PRINTER_VENDOR_NUM 0x0525 /* NetChip */ |
36 | #define PRINTER_PRODUCT_NUM 0xa4a8 /* Linux-USB Printer Gadget */ |
37 | |
38 | /* Some systems will want different product identifiers published in the |
39 | * device descriptor, either numbers or strings or both. These string |
40 | * parameters are in UTF-8 (superset of ASCII's 7 bit characters). |
41 | */ |
42 | |
43 | module_param_named(iSerialNum, coverwrite.serial_number, charp, S_IRUGO); |
44 | MODULE_PARM_DESC(iSerialNum, "1" ); |
45 | |
46 | static char *iPNPstring; |
47 | module_param(iPNPstring, charp, S_IRUGO); |
48 | MODULE_PARM_DESC(iPNPstring, "MFG:linux;MDL:g_printer;CLS:PRINTER;SN:1;" ); |
49 | |
50 | /* Number of requests to allocate per endpoint, not used for ep0. */ |
51 | static unsigned qlen = 10; |
52 | module_param(qlen, uint, S_IRUGO|S_IWUSR); |
53 | MODULE_PARM_DESC(qlen, "The number of 8k buffers to use per endpoint" ); |
54 | |
55 | #define QLEN qlen |
56 | |
57 | static struct usb_function_instance *fi_printer; |
58 | static struct usb_function *f_printer; |
59 | |
60 | /*-------------------------------------------------------------------------*/ |
61 | |
62 | /* |
63 | * DESCRIPTORS ... most are static, but strings and (full) configuration |
64 | * descriptors are built on demand. |
65 | */ |
66 | |
67 | static struct usb_device_descriptor device_desc = { |
68 | .bLength = sizeof device_desc, |
69 | .bDescriptorType = USB_DT_DEVICE, |
70 | /* .bcdUSB = DYNAMIC */ |
71 | .bDeviceClass = USB_CLASS_PER_INTERFACE, |
72 | .bDeviceSubClass = 0, |
73 | .bDeviceProtocol = 0, |
74 | .idVendor = cpu_to_le16(PRINTER_VENDOR_NUM), |
75 | .idProduct = cpu_to_le16(PRINTER_PRODUCT_NUM), |
76 | .bNumConfigurations = 1 |
77 | }; |
78 | |
79 | static const struct usb_descriptor_header *otg_desc[2]; |
80 | |
81 | /*-------------------------------------------------------------------------*/ |
82 | |
83 | /* descriptors that are built on-demand */ |
84 | |
85 | static char product_desc [40] = DRIVER_DESC; |
86 | static char serial_num [40] = "1" ; |
87 | static char *pnp_string = |
88 | "MFG:linux;MDL:g_printer;CLS:PRINTER;SN:1;" ; |
89 | |
90 | /* static strings, in UTF-8 */ |
91 | static struct usb_string strings [] = { |
92 | [USB_GADGET_MANUFACTURER_IDX].s = "" , |
93 | [USB_GADGET_PRODUCT_IDX].s = product_desc, |
94 | [USB_GADGET_SERIAL_IDX].s = serial_num, |
95 | { } /* end of list */ |
96 | }; |
97 | |
98 | static struct usb_gadget_strings stringtab_dev = { |
99 | .language = 0x0409, /* en-us */ |
100 | .strings = strings, |
101 | }; |
102 | |
103 | static struct usb_gadget_strings *dev_strings[] = { |
104 | &stringtab_dev, |
105 | NULL, |
106 | }; |
107 | |
108 | static struct usb_configuration printer_cfg_driver = { |
109 | .label = "printer" , |
110 | .bConfigurationValue = 1, |
111 | .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, |
112 | }; |
113 | |
114 | static int printer_do_config(struct usb_configuration *c) |
115 | { |
116 | struct usb_gadget *gadget = c->cdev->gadget; |
117 | int status = 0; |
118 | |
119 | usb_ep_autoconfig_reset(gadget); |
120 | |
121 | usb_gadget_set_selfpowered(gadget); |
122 | |
123 | if (gadget_is_otg(g: gadget)) { |
124 | printer_cfg_driver.descriptors = otg_desc; |
125 | printer_cfg_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; |
126 | } |
127 | |
128 | f_printer = usb_get_function(fi: fi_printer); |
129 | if (IS_ERR(ptr: f_printer)) |
130 | return PTR_ERR(ptr: f_printer); |
131 | |
132 | status = usb_add_function(c, f_printer); |
133 | if (status < 0) |
134 | usb_put_function(f: f_printer); |
135 | |
136 | return status; |
137 | } |
138 | |
139 | static int printer_bind(struct usb_composite_dev *cdev) |
140 | { |
141 | struct f_printer_opts *opts; |
142 | int ret; |
143 | |
144 | fi_printer = usb_get_function_instance(name: "printer" ); |
145 | if (IS_ERR(ptr: fi_printer)) |
146 | return PTR_ERR(ptr: fi_printer); |
147 | |
148 | opts = container_of(fi_printer, struct f_printer_opts, func_inst); |
149 | opts->minor = 0; |
150 | opts->q_len = QLEN; |
151 | if (iPNPstring) { |
152 | opts->pnp_string = kstrdup(s: iPNPstring, GFP_KERNEL); |
153 | if (!opts->pnp_string) { |
154 | ret = -ENOMEM; |
155 | goto fail_put_func_inst; |
156 | } |
157 | opts->pnp_string_allocated = true; |
158 | /* |
159 | * we don't free this memory in case of error |
160 | * as printer cleanup func will do this for us |
161 | */ |
162 | } else { |
163 | opts->pnp_string = pnp_string; |
164 | } |
165 | |
166 | ret = usb_string_ids_tab(c: cdev, str: strings); |
167 | if (ret < 0) |
168 | goto fail_put_func_inst; |
169 | |
170 | device_desc.iManufacturer = strings[USB_GADGET_MANUFACTURER_IDX].id; |
171 | device_desc.iProduct = strings[USB_GADGET_PRODUCT_IDX].id; |
172 | device_desc.iSerialNumber = strings[USB_GADGET_SERIAL_IDX].id; |
173 | |
174 | if (gadget_is_otg(g: cdev->gadget) && !otg_desc[0]) { |
175 | struct usb_descriptor_header *usb_desc; |
176 | |
177 | usb_desc = usb_otg_descriptor_alloc(gadget: cdev->gadget); |
178 | if (!usb_desc) { |
179 | ret = -ENOMEM; |
180 | goto fail_put_func_inst; |
181 | } |
182 | usb_otg_descriptor_init(gadget: cdev->gadget, otg_desc: usb_desc); |
183 | otg_desc[0] = usb_desc; |
184 | otg_desc[1] = NULL; |
185 | } |
186 | |
187 | ret = usb_add_config(cdev, &printer_cfg_driver, printer_do_config); |
188 | if (ret) |
189 | goto fail_free_otg_desc; |
190 | |
191 | usb_composite_overwrite_options(cdev, covr: &coverwrite); |
192 | return ret; |
193 | |
194 | fail_free_otg_desc: |
195 | kfree(objp: otg_desc[0]); |
196 | otg_desc[0] = NULL; |
197 | fail_put_func_inst: |
198 | usb_put_function_instance(fi: fi_printer); |
199 | return ret; |
200 | } |
201 | |
202 | static int printer_unbind(struct usb_composite_dev *cdev) |
203 | { |
204 | usb_put_function(f: f_printer); |
205 | usb_put_function_instance(fi: fi_printer); |
206 | |
207 | kfree(objp: otg_desc[0]); |
208 | otg_desc[0] = NULL; |
209 | |
210 | return 0; |
211 | } |
212 | |
213 | static struct usb_composite_driver printer_driver = { |
214 | .name = shortname, |
215 | .dev = &device_desc, |
216 | .strings = dev_strings, |
217 | .max_speed = USB_SPEED_SUPER, |
218 | .bind = printer_bind, |
219 | .unbind = printer_unbind, |
220 | }; |
221 | |
222 | module_usb_composite_driver(printer_driver); |
223 | |
224 | MODULE_DESCRIPTION(DRIVER_DESC); |
225 | MODULE_AUTHOR("Craig Nadler" ); |
226 | MODULE_LICENSE("GPL" ); |
227 | |