blob: 1b4ba9ad7dd7c4012e104036c4bc20698f75f4d1 [file] [log] [blame]
Fabien Chouteau71adf112010-04-08 09:31:15 +02001/*
2 * hid.c -- HID Composite driver
3 *
4 * Based on multi.c
5 *
6 * Copyright (C) 2010 Fabien Chouteau <fabien.chouteau@barco.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
Fabien Chouteau71adf112010-04-08 09:31:15 +020012 */
13
James Sullinsaed76a12014-03-22 17:47:58 -050014#define DEBUG 1
15#define VERBOSE_DEBUG 1
Fabien Chouteau71adf112010-04-08 09:31:15 +020016
17#include <linux/kernel.h>
18#include <linux/platform_device.h>
19#include <linux/list.h>
20
James Sullinsaed76a12014-03-22 17:47:58 -050021#include <linux/usb/g_hid.h>
22
Fabien Chouteau71adf112010-04-08 09:31:15 +020023#define DRIVER_DESC "HID Gadget"
24#define DRIVER_VERSION "2010/03/16"
25
26/*-------------------------------------------------------------------------*/
27
28#define HIDG_VENDOR_NUM 0x0525 /* XXX NetChip */
29#define HIDG_PRODUCT_NUM 0xa4ac /* Linux-USB HID gadget */
30
31/*-------------------------------------------------------------------------*/
32
33/*
34 * kbuild is not very cooperative with respect to linking separately
35 * compiled library objects into one module. So for now we won't use
36 * separate compilation ... ensuring init/exit sections work to shrink
37 * the runtime footprint, and giving us at least some parts of what
38 * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
39 */
40
41#include "composite.c"
42#include "usbstring.c"
43#include "config.c"
44#include "epautoconf.c"
45
46#include "f_hid.c"
47
48
49struct hidg_func_node {
50 struct list_head node;
51 struct hidg_func_descriptor *func;
52};
53
54static LIST_HEAD(hidg_func_list);
55
James Sullinsaed76a12014-03-22 17:47:58 -050056
57/* hid descriptor for a keyboard */
58static struct hidg_func_descriptor my_hid_data = {
59 .subclass = 0, /* No subclass */
60 .protocol = 1, /* Keyboard */
61 .report_length = 8,
62 .report_desc_length = 63,
63 .report_desc = {
64 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
65 0x09, 0x06, /* USAGE (Keyboard) */
66 0xa1, 0x01, /* COLLECTION (Application) */
67 0x05, 0x07, /* USAGE_PAGE (Keyboard) */
68 0x19, 0xe0, /* USAGE_MINIMUM (Keyboard LeftControl) */
69 0x29, 0xe7, /* USAGE_MAXIMUM (Keyboard Right GUI) */
70 0x15, 0x00, /* LOGICAL_MINIMUM (0) */
71 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
72 0x75, 0x01, /* REPORT_SIZE (1) */
73 0x95, 0x08, /* REPORT_COUNT (8) */
74 0x81, 0x02, /* INPUT (Data,Var,Abs) */
75 0x95, 0x01, /* REPORT_COUNT (1) */
76 0x75, 0x08, /* REPORT_SIZE (8) */
77 0x81, 0x03, /* INPUT (Cnst,Var,Abs) */
78 0x95, 0x05, /* REPORT_COUNT (5) */
79 0x75, 0x01, /* REPORT_SIZE (1) */
80 0x05, 0x08, /* USAGE_PAGE (LEDs) */
81 0x19, 0x01, /* USAGE_MINIMUM (Num Lock) */
82 0x29, 0x05, /* USAGE_MAXIMUM (Kana) */
83 0x91, 0x02, /* OUTPUT (Data,Var,Abs) */
84 0x95, 0x01, /* REPORT_COUNT (1) */
85 0x75, 0x03, /* REPORT_SIZE (3) */
86 0x91, 0x03, /* OUTPUT (Cnst,Var,Abs) */
87 0x95, 0x06, /* REPORT_COUNT (6) */
88 0x75, 0x08, /* REPORT_SIZE (8) */
89 0x15, 0x00, /* LOGICAL_MINIMUM (0) */
90 0x25, 0x65, /* LOGICAL_MAXIMUM (101) */
91 0x05, 0x07, /* USAGE_PAGE (Keyboard) */
92 0x19, 0x00, /* USAGE_MINIMUM (Reserved) */
93 0x29, 0x65, /* USAGE_MAXIMUM (Keyboard Application) */
94 0x81, 0x00, /* INPUT (Data,Ary,Abs) */
95 0xc0 /* END_COLLECTION */
96 }
97};
98
James Sullinsec56b422014-05-04 15:05:17 -050099static void release_hid_dev(struct device *dev)
100{
101 // nothing
102}
103
James Sullinsaed76a12014-03-22 17:47:58 -0500104static struct platform_device my_hid = {
105 .name = "hidg",
106 .id = 0,
107 .num_resources = 0,
108 .resource = 0,
109 .dev.platform_data = &my_hid_data,
James Sullinsec56b422014-05-04 15:05:17 -0500110 .dev.release = &release_hid_dev,
James Sullinsaed76a12014-03-22 17:47:58 -0500111};
112
Fabien Chouteau71adf112010-04-08 09:31:15 +0200113/*-------------------------------------------------------------------------*/
114
115static struct usb_device_descriptor device_desc = {
116 .bLength = sizeof device_desc,
117 .bDescriptorType = USB_DT_DEVICE,
118
119 .bcdUSB = cpu_to_le16(0x0200),
120
121 /* .bDeviceClass = USB_CLASS_COMM, */
122 /* .bDeviceSubClass = 0, */
123 /* .bDeviceProtocol = 0, */
Orjan Friberg33d28322012-03-07 17:16:14 +0100124 .bDeviceClass = USB_CLASS_PER_INTERFACE,
125 .bDeviceSubClass = 0,
126 .bDeviceProtocol = 0,
Fabien Chouteau71adf112010-04-08 09:31:15 +0200127 /* .bMaxPacketSize0 = f(hardware) */
128
129 /* Vendor and product id can be overridden by module parameters. */
130 .idVendor = cpu_to_le16(HIDG_VENDOR_NUM),
131 .idProduct = cpu_to_le16(HIDG_PRODUCT_NUM),
132 /* .bcdDevice = f(hardware) */
133 /* .iManufacturer = DYNAMIC */
134 /* .iProduct = DYNAMIC */
135 /* NO SERIAL NUMBER */
136 .bNumConfigurations = 1,
137};
138
139static struct usb_otg_descriptor otg_descriptor = {
140 .bLength = sizeof otg_descriptor,
141 .bDescriptorType = USB_DT_OTG,
142
143 /* REVISIT SRP-only hardware is possible, although
144 * it would not be called "OTG" ...
145 */
146 .bmAttributes = USB_OTG_SRP | USB_OTG_HNP,
147};
148
149static const struct usb_descriptor_header *otg_desc[] = {
150 (struct usb_descriptor_header *) &otg_descriptor,
151 NULL,
152};
153
154
155/* string IDs are assigned dynamically */
156
157#define STRING_MANUFACTURER_IDX 0
158#define STRING_PRODUCT_IDX 1
159
160static char manufacturer[50];
161
162static struct usb_string strings_dev[] = {
163 [STRING_MANUFACTURER_IDX].s = manufacturer,
164 [STRING_PRODUCT_IDX].s = DRIVER_DESC,
165 { } /* end of list */
166};
167
168static struct usb_gadget_strings stringtab_dev = {
169 .language = 0x0409, /* en-us */
170 .strings = strings_dev,
171};
172
173static struct usb_gadget_strings *dev_strings[] = {
174 &stringtab_dev,
175 NULL,
176};
177
178
179
180/****************************** Configurations ******************************/
181
Michal Nazarewicze12995e2010-08-12 17:43:52 +0200182static int __init do_config(struct usb_configuration *c)
Fabien Chouteau71adf112010-04-08 09:31:15 +0200183{
184 struct hidg_func_node *e;
185 int func = 0, status = 0;
186
187 if (gadget_is_otg(c->cdev->gadget)) {
188 c->descriptors = otg_desc;
189 c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
190 }
191
192 list_for_each_entry(e, &hidg_func_list, node) {
193 status = hidg_bind_config(c, e->func, func++);
194 if (status)
195 break;
196 }
197
198 return status;
199}
200
201static struct usb_configuration config_driver = {
202 .label = "HID Gadget",
Fabien Chouteau71adf112010-04-08 09:31:15 +0200203 .bConfigurationValue = 1,
204 /* .iConfiguration = DYNAMIC */
205 .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
206};
207
208/****************************** Gadget Bind ******************************/
209
Michal Nazarewicze12995e2010-08-12 17:43:52 +0200210static int __init hid_bind(struct usb_composite_dev *cdev)
Fabien Chouteau71adf112010-04-08 09:31:15 +0200211{
212 struct usb_gadget *gadget = cdev->gadget;
213 struct list_head *tmp;
214 int status, gcnum, funcs = 0;
215
216 list_for_each(tmp, &hidg_func_list)
217 funcs++;
218
219 if (!funcs)
220 return -ENODEV;
221
222 /* set up HID */
223 status = ghid_setup(cdev->gadget, funcs);
224 if (status < 0)
225 return status;
226
227 gcnum = usb_gadget_controller_number(gadget);
228 if (gcnum >= 0)
229 device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum);
230 else
231 device_desc.bcdDevice = cpu_to_le16(0x0300 | 0x0099);
232
233
234 /* Allocate string descriptor numbers ... note that string
235 * contents can be overridden by the composite_dev glue.
236 */
237
238 /* device descriptor strings: manufacturer, product */
239 snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
240 init_utsname()->sysname, init_utsname()->release,
241 gadget->name);
242 status = usb_string_id(cdev);
243 if (status < 0)
244 return status;
245 strings_dev[STRING_MANUFACTURER_IDX].id = status;
246 device_desc.iManufacturer = status;
247
248 status = usb_string_id(cdev);
249 if (status < 0)
250 return status;
251 strings_dev[STRING_PRODUCT_IDX].id = status;
252 device_desc.iProduct = status;
253
254 /* register our configuration */
Uwe Kleine-Königc9bfff92010-08-12 17:43:55 +0200255 status = usb_add_config(cdev, &config_driver, do_config);
Fabien Chouteau71adf112010-04-08 09:31:15 +0200256 if (status < 0)
257 return status;
258
259 dev_info(&gadget->dev, DRIVER_DESC ", version: " DRIVER_VERSION "\n");
260
261 return 0;
262}
263
264static int __exit hid_unbind(struct usb_composite_dev *cdev)
265{
266 ghid_cleanup();
267 return 0;
268}
269
270static int __init hidg_plat_driver_probe(struct platform_device *pdev)
271{
272 struct hidg_func_descriptor *func = pdev->dev.platform_data;
273 struct hidg_func_node *entry;
274
275 if (!func) {
276 dev_err(&pdev->dev, "Platform data missing\n");
277 return -ENODEV;
278 }
279
280 entry = kzalloc(sizeof(*entry), GFP_KERNEL);
281 if (!entry)
282 return -ENOMEM;
283
284 entry->func = func;
285 list_add_tail(&entry->node, &hidg_func_list);
286
287 return 0;
288}
289
290static int __devexit hidg_plat_driver_remove(struct platform_device *pdev)
291{
292 struct hidg_func_node *e, *n;
293
294 list_for_each_entry_safe(e, n, &hidg_func_list, node) {
295 list_del(&e->node);
296 kfree(e);
297 }
298
299 return 0;
300}
301
302
303/****************************** Some noise ******************************/
304
305
306static struct usb_composite_driver hidg_driver = {
307 .name = "g_hid",
308 .dev = &device_desc,
309 .strings = dev_strings,
Tatyana Brokhman35a0e0b2011-06-29 16:41:49 +0300310 .max_speed = USB_SPEED_HIGH,
Fabien Chouteau71adf112010-04-08 09:31:15 +0200311 .unbind = __exit_p(hid_unbind),
312};
313
314static struct platform_driver hidg_plat_driver = {
315 .remove = __devexit_p(hidg_plat_driver_remove),
316 .driver = {
317 .owner = THIS_MODULE,
318 .name = "hidg",
319 },
320};
321
322
323MODULE_DESCRIPTION(DRIVER_DESC);
324MODULE_AUTHOR("Fabien Chouteau, Peter Korsgaard");
325MODULE_LICENSE("GPL");
326
327static int __init hidg_init(void)
328{
Peter Korsgaardda01c7a2010-04-26 10:05:06 +0200329 int status;
330
James Sullinsaed76a12014-03-22 17:47:58 -0500331 status = platform_device_register(&my_hid);
332 if (status < 0) {
333 printk("____ reg failed\n");
334 platform_device_unregister(&my_hid);
335 return status;
336 }
337
Peter Korsgaardda01c7a2010-04-26 10:05:06 +0200338 status = platform_driver_probe(&hidg_plat_driver,
339 hidg_plat_driver_probe);
340 if (status < 0)
341 return status;
342
Michal Nazarewicz07a18bd2010-08-12 17:43:54 +0200343 status = usb_composite_probe(&hidg_driver, hid_bind);
Peter Korsgaardda01c7a2010-04-26 10:05:06 +0200344 if (status < 0)
345 platform_driver_unregister(&hidg_plat_driver);
346
347 return status;
Fabien Chouteau71adf112010-04-08 09:31:15 +0200348}
349module_init(hidg_init);
350
351static void __exit hidg_cleanup(void)
352{
353 platform_driver_unregister(&hidg_plat_driver);
James Sullinsaed76a12014-03-22 17:47:58 -0500354 platform_device_unregister(&my_hid);
Fabien Chouteau71adf112010-04-08 09:31:15 +0200355 usb_composite_unregister(&hidg_driver);
356}
357module_exit(hidg_cleanup);