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