diff options
Diffstat (limited to 'firmware/usbstack/usb_hid.c')
-rw-r--r-- | firmware/usbstack/usb_hid.c | 288 |
1 files changed, 288 insertions, 0 deletions
diff --git a/firmware/usbstack/usb_hid.c b/firmware/usbstack/usb_hid.c new file mode 100644 index 0000000000..c3cd5d9a04 --- /dev/null +++ b/firmware/usbstack/usb_hid.c | |||
@@ -0,0 +1,288 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2009 by Tomer Shalev | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #include "string.h" | ||
22 | #include "system.h" | ||
23 | #include "usb_core.h" | ||
24 | #include "usb_drv.h" | ||
25 | #include "kernel.h" | ||
26 | #include "usb_hid.h" | ||
27 | #include "usb_class_driver.h" | ||
28 | #define LOGF_ENABLE | ||
29 | #include "logf.h" | ||
30 | |||
31 | #ifdef USB_HID | ||
32 | |||
33 | #define CONCAT(low, high) ((high << 8) | low) | ||
34 | #define SIZE_VALUE 0x01 | ||
35 | /* HID main items (HID1_11.pdf, page 38) */ | ||
36 | #define INPUT (0x80 | SIZE_VALUE) | ||
37 | #define OUTPUT (0x90 | SIZE_VALUE) | ||
38 | #define FEATURE (0xb0 | SIZE_VALUE) | ||
39 | #define COLLECTION (0xa0 | SIZE_VALUE) | ||
40 | #define COLLECTION_APPLICATION CONCAT(COLLECTION, 0x01) | ||
41 | #define END_COLLECTION 0xc0 | ||
42 | /* HID global items (HID1_11.pdf, page 45) */ | ||
43 | #define USAGE_PAGE (0x04 | SIZE_VALUE) | ||
44 | #define LOGICAL_MINIMUM (0x14 | SIZE_VALUE) | ||
45 | #define LOGICAL_MAXIMUM (0x24 | SIZE_VALUE) | ||
46 | #define PHYSICAL_MINIMUM (0x34 | SIZE_VALUE) | ||
47 | #define PHYSICAL_MAXIMUM (0x44 | SIZE_VALUE) | ||
48 | #define UNIT_EXPONENT (0x54 | SIZE_VALUE) | ||
49 | #define UNIT (0x64 | SIZE_VALUE) | ||
50 | #define REPORT_SIZE (0x74 | SIZE_VALUE) | ||
51 | #define REPORT_ID (0x84 | SIZE_VALUE) | ||
52 | #define REPORT_COUNT (0x94 | SIZE_VALUE) | ||
53 | #define PUSH (0xa4 | SIZE_VALUE) | ||
54 | #define POP (0xb4 | SIZE_VALUE) | ||
55 | /* Hut1_12.pdf, Table 1, page 14 */ | ||
56 | #define USAGE_PAGE_CONSUMER CONCAT(USAGE_PAGE, 0x0c) | ||
57 | /* Hut1_12.pdf, Table 17, page 77 */ | ||
58 | #define CONSUMER_USAGE 0x09 | ||
59 | #define CONSUMER_USAGE_CONTROL CONCAT(CONSUMER_USAGE, 0x01) | ||
60 | #define CONSUMER_USAGE_MUTE CONCAT(CONSUMER_USAGE, 0xe2) | ||
61 | #define CONSUMER_USAGE_VOLUME_INCREMENT CONCAT(CONSUMER_USAGE, 0xe9) | ||
62 | #define CONSUMER_USAGE_VOLUME_DECREMENT CONCAT(CONSUMER_USAGE, 0xea) | ||
63 | /* Hut1_12.pdf, Table 4, page 20 */ | ||
64 | #define CONSUMER_CONTROL CONCAT(COLLECTION_APPLICATION, 0x01) | ||
65 | |||
66 | #define USB_DT_HID 0x21 | ||
67 | #define USB_DT_REPORT 0x22 | ||
68 | #define USB_DT_PHYSICAL_DESCRIPTOR 0x23 | ||
69 | |||
70 | /* serial interface */ | ||
71 | static struct usb_interface_descriptor __attribute__((aligned(2))) | ||
72 | interface_descriptor = | ||
73 | { | ||
74 | .bLength = sizeof(struct usb_interface_descriptor), | ||
75 | .bDescriptorType = USB_DT_INTERFACE, | ||
76 | .bInterfaceNumber = 0, | ||
77 | .bAlternateSetting = 0, | ||
78 | .bNumEndpoints = 1, | ||
79 | .bInterfaceClass = USB_CLASS_HID, | ||
80 | .bInterfaceSubClass = 0, | ||
81 | .bInterfaceProtocol = 0, | ||
82 | .iInterface = 0 | ||
83 | }; | ||
84 | |||
85 | /* USB_DT_HID: Endpoint descriptor */ | ||
86 | struct usb_hid_descriptor { | ||
87 | uint8_t bLength; | ||
88 | uint8_t bDescriptorType; | ||
89 | uint16_t wBcdHID; | ||
90 | uint8_t bCountryCode; | ||
91 | uint8_t bNumDescriptors; | ||
92 | uint8_t bDescriptorType0; | ||
93 | uint16_t wDescriptorLength0; | ||
94 | } __attribute__ ((packed)); | ||
95 | |||
96 | /* USB_DT_REPORT: Endpoint descriptor */ | ||
97 | static struct usb_hid_descriptor __attribute__((aligned(2))) hid_descriptor = | ||
98 | { | ||
99 | .bLength = sizeof(struct usb_hid_descriptor), | ||
100 | .bDescriptorType = USB_DT_HID, | ||
101 | .wBcdHID = 0x0100, | ||
102 | .bCountryCode = 0, | ||
103 | .bNumDescriptors = 1, | ||
104 | .bDescriptorType0 = 0x22, | ||
105 | .wDescriptorLength0 = 0 | ||
106 | }; | ||
107 | |||
108 | static struct usb_endpoint_descriptor __attribute__((aligned(2))) endpoint_descriptor = | ||
109 | { | ||
110 | .bLength = sizeof(struct usb_endpoint_descriptor), | ||
111 | .bDescriptorType = USB_DT_ENDPOINT, | ||
112 | .bEndpointAddress = 0, | ||
113 | .bmAttributes = USB_ENDPOINT_XFER_INT, | ||
114 | .wMaxPacketSize = 0, | ||
115 | .bInterval = 0 | ||
116 | }; | ||
117 | |||
118 | /* USB_DT_REPORT: Endpoint descriptor */ | ||
119 | struct usb_report_descriptor { | ||
120 | uint16_t wUsagePage; | ||
121 | uint16_t wUsage; | ||
122 | uint16_t wCollection; | ||
123 | uint16_t wCollectionItems[12]; | ||
124 | uint8_t wEndCollection; | ||
125 | } __attribute__ ((packed)); | ||
126 | |||
127 | static struct usb_report_descriptor __attribute__((aligned(2))) report_descriptor = | ||
128 | { | ||
129 | .wUsagePage = USAGE_PAGE_CONSUMER, | ||
130 | .wUsage = CONSUMER_USAGE_CONTROL, | ||
131 | .wCollection = COLLECTION_APPLICATION, | ||
132 | .wCollectionItems = { | ||
133 | CONCAT(LOGICAL_MINIMUM, 0x0), | ||
134 | CONCAT(LOGICAL_MAXIMUM, 0x1), | ||
135 | USAGE_PAGE_CONSUMER, | ||
136 | CONSUMER_USAGE_MUTE, | ||
137 | CONSUMER_USAGE_VOLUME_INCREMENT, | ||
138 | CONSUMER_USAGE_VOLUME_DECREMENT, | ||
139 | CONCAT(REPORT_COUNT, 0x3), | ||
140 | CONCAT(REPORT_SIZE, 0x1), | ||
141 | CONCAT(INPUT, 0x42), | ||
142 | CONCAT(REPORT_COUNT, 0x5), | ||
143 | CONCAT(REPORT_SIZE, 0x1), | ||
144 | CONCAT(INPUT, 0x01) | ||
145 | }, | ||
146 | .wEndCollection = END_COLLECTION | ||
147 | }; | ||
148 | |||
149 | static int ep_in; | ||
150 | static int usb_interface; | ||
151 | |||
152 | int usb_hid_request_endpoints(struct usb_class_driver *drv) | ||
153 | { | ||
154 | ep_in = usb_core_request_endpoint(USB_DIR_IN, drv); | ||
155 | if (ep_in < 0) | ||
156 | return -1; | ||
157 | |||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | int usb_hid_set_first_interface(int interface) | ||
162 | { | ||
163 | usb_interface = interface; | ||
164 | |||
165 | return interface + 1; | ||
166 | } | ||
167 | |||
168 | |||
169 | int usb_hid_get_config_descriptor(unsigned char *dest,int max_packet_size) | ||
170 | { | ||
171 | unsigned char *orig_dest = dest; | ||
172 | |||
173 | logf("hid: config desc."); | ||
174 | interface_descriptor.bInterfaceNumber = usb_interface; | ||
175 | PACK_DESCRIPTOR(dest, interface_descriptor); | ||
176 | |||
177 | hid_descriptor.wDescriptorLength0 = sizeof(report_descriptor); | ||
178 | PACK_DESCRIPTOR(dest, hid_descriptor); | ||
179 | |||
180 | /* Ignore max_packet_size and set to 1 bytes long packet size */ | ||
181 | (void)max_packet_size; | ||
182 | endpoint_descriptor.wMaxPacketSize = 1; | ||
183 | endpoint_descriptor.bInterval = 8; | ||
184 | |||
185 | endpoint_descriptor.bEndpointAddress = ep_in; | ||
186 | PACK_DESCRIPTOR(dest, endpoint_descriptor); | ||
187 | |||
188 | return (dest - orig_dest); | ||
189 | } | ||
190 | |||
191 | void usb_hid_init_connection(void) | ||
192 | { | ||
193 | logf("hid: init connection"); | ||
194 | } | ||
195 | |||
196 | /* called by usb_code_init() */ | ||
197 | void usb_hid_init(void) | ||
198 | { | ||
199 | logf("hid: init"); | ||
200 | } | ||
201 | |||
202 | void usb_hid_disconnect(void) | ||
203 | { | ||
204 | logf("hid: disconnect"); | ||
205 | } | ||
206 | |||
207 | /* called by usb_core_transfer_complete() */ | ||
208 | void usb_hid_transfer_complete(int ep,int dir, int status, int length) | ||
209 | { | ||
210 | (void)ep; | ||
211 | (void)dir; | ||
212 | (void)status; | ||
213 | (void)length; | ||
214 | |||
215 | logf("hid: transfer complete. ep %d, dir %d, status %d ,length %d", | ||
216 | ep, dir, status, length); | ||
217 | } | ||
218 | |||
219 | /* HID-only class specific requests */ | ||
220 | #define USB_HID_GET_REPORT 0x01 | ||
221 | #define USB_HID_GET_IDLE 0x02 | ||
222 | #define USB_HID_GET_PROTOCOL 0x03 | ||
223 | #define USB_HID_SET_REPORT 0x09 | ||
224 | #define USB_HID_SET_IDLE 0x0a | ||
225 | #define USB_HID_SET_PROTOCOL 0x0b | ||
226 | |||
227 | /* called by usb_core_control_request() */ | ||
228 | bool usb_hid_control_request(struct usb_ctrlrequest* req, unsigned char* dest) | ||
229 | { | ||
230 | bool handled = false; | ||
231 | |||
232 | switch(req->bRequestType & USB_TYPE_MASK) { | ||
233 | case USB_TYPE_STANDARD: { | ||
234 | switch(req->wValue>>8) { /* type */ | ||
235 | case USB_DT_REPORT: { | ||
236 | logf("hid: report"); | ||
237 | if (dest == NULL) { | ||
238 | logf("dest is NULL!"); | ||
239 | } | ||
240 | if (dest) { | ||
241 | unsigned char *orig_dest = dest; | ||
242 | PACK_DESCRIPTOR(dest, report_descriptor); | ||
243 | if(usb_drv_send(EP_CONTROL, orig_dest, dest - orig_dest)) | ||
244 | break; | ||
245 | usb_core_ack_control(req); | ||
246 | |||
247 | } | ||
248 | handled = true; | ||
249 | break; | ||
250 | } | ||
251 | default: | ||
252 | logf("hid: unsup. std. req"); | ||
253 | break; | ||
254 | } | ||
255 | break; | ||
256 | } | ||
257 | |||
258 | case USB_TYPE_CLASS: { | ||
259 | switch (req->bRequest) { | ||
260 | case USB_HID_SET_IDLE: | ||
261 | logf("hid: set idle"); | ||
262 | usb_core_ack_control(req); | ||
263 | handled = true; | ||
264 | break; | ||
265 | default: | ||
266 | //logf("hid: unsup. cls. req"); | ||
267 | logf("%d: unsup. cls. req", req->bRequest); | ||
268 | break; | ||
269 | } | ||
270 | break; | ||
271 | } | ||
272 | |||
273 | case USB_TYPE_VENDOR: | ||
274 | logf("hid: unsup. ven. req"); | ||
275 | break; | ||
276 | } | ||
277 | return handled; | ||
278 | } | ||
279 | |||
280 | void usb_hid_send(unsigned char *data, int length) | ||
281 | { | ||
282 | (void)data; | ||
283 | (void)(length); | ||
284 | |||
285 | logf("hid: send %d bytes: \"%s\"", length, data); | ||
286 | } | ||
287 | |||
288 | #endif /*USB_HID*/ | ||