2 Copyright 2011 Jun Wako <wakojun@gmail.com>
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "usbconfig.h"
25 #include "host_driver.h"
29 static uint8_t vusb_keyboard_leds
= 0;
30 static uint8_t vusb_idle_rate
= 0;
32 /* Keyboard report send buffer */
34 static report_keyboard_t kbuf
[KBUF_SIZE
];
35 static uint8_t kbuf_head
= 0;
36 static uint8_t kbuf_tail
= 0;
44 static keyboard_report_t keyboard_report
; // sent to PC
46 /* transfer keyboard report from buffer */
47 void vusb_transfer_keyboard(void)
49 if (usbInterruptIsReady()) {
50 if (kbuf_head
!= kbuf_tail
) {
51 usbSetInterrupt((void *)&kbuf
[kbuf_tail
], sizeof(report_keyboard_t
));
52 kbuf_tail
= (kbuf_tail
+ 1) % KBUF_SIZE
;
54 print("V-USB: kbuf["); pdec(kbuf_tail
); print("->"); pdec(kbuf_head
); print("](");
55 phex((kbuf_head
< kbuf_tail
) ? (KBUF_SIZE
- kbuf_tail
+ kbuf_head
) : (kbuf_head
- kbuf_tail
));
63 /*------------------------------------------------------------------*
65 *------------------------------------------------------------------*/
66 static uint8_t keyboard_leds(void);
67 static void send_keyboard(report_keyboard_t
*report
);
68 static void send_mouse(report_mouse_t
*report
);
69 static void send_system(uint16_t data
);
70 static void send_consumer(uint16_t data
);
72 static host_driver_t driver
= {
80 host_driver_t
*vusb_driver(void)
85 static uint8_t keyboard_leds(void) {
86 return vusb_keyboard_leds
;
89 static void send_keyboard(report_keyboard_t
*report
)
91 uint8_t next
= (kbuf_head
+ 1) % KBUF_SIZE
;
92 if (next
!= kbuf_tail
) {
93 kbuf
[kbuf_head
] = *report
;
96 debug("kbuf: full\n");
99 // NOTE: send key strokes of Macro
101 vusb_transfer_keyboard();
107 report_mouse_t report
;
108 } __attribute__ ((packed
)) vusb_mouse_report_t
;
110 static void send_mouse(report_mouse_t
*report
)
112 vusb_mouse_report_t r
= {
113 .report_id
= REPORT_ID_MOUSE
,
116 if (usbInterruptIsReady3()) {
117 usbSetInterrupt3((void *)&r
, sizeof(vusb_mouse_report_t
));
125 } __attribute__ ((packed
)) report_extra_t
;
127 static void send_system(uint16_t data
)
129 static uint16_t last_data
= 0;
130 if (data
== last_data
) return;
133 report_extra_t report
= {
134 .report_id
= REPORT_ID_SYSTEM
,
137 if (usbInterruptIsReady3()) {
138 usbSetInterrupt3((void *)&report
, sizeof(report
));
142 static void send_consumer(uint16_t data
)
144 static uint16_t last_data
= 0;
145 if (data
== last_data
) return;
148 report_extra_t report
= {
149 .report_id
= REPORT_ID_CONSUMER
,
152 if (usbInterruptIsReady3()) {
153 usbSetInterrupt3((void *)&report
, sizeof(report
));
159 /*------------------------------------------------------------------*
160 * Request from host *
161 *------------------------------------------------------------------*/
170 usbMsgLen_t
usbFunctionSetup(uchar data
[8])
172 usbRequest_t
*rq
= (void *)data
;
174 if((rq
->bmRequestType
& USBRQ_TYPE_MASK
) == USBRQ_TYPE_CLASS
){ /* class request type */
175 if(rq
->bRequest
== USBRQ_HID_GET_REPORT
){
176 debug("GET_REPORT:");
177 /* we only have one report type, so don't look at wValue */
178 usbMsgPtr
= (void *)&keyboard_report
;
179 return sizeof(keyboard_report
);
180 }else if(rq
->bRequest
== USBRQ_HID_GET_IDLE
){
182 //debug_hex(vusb_idle_rate);
183 usbMsgPtr
= &vusb_idle_rate
;
185 }else if(rq
->bRequest
== USBRQ_HID_SET_IDLE
){
186 vusb_idle_rate
= rq
->wValue
.bytes
[1];
188 debug_hex(vusb_idle_rate
);
189 }else if(rq
->bRequest
== USBRQ_HID_SET_REPORT
){
190 debug("SET_REPORT: ");
191 // Report Type: 0x02(Out)/ReportID: 0x00(none) && Interface: 0(keyboard)
192 if (rq
->wValue
.word
== 0x0200 && rq
->wIndex
.word
== 0) {
194 last_req
.kind
= SET_LED
;
195 last_req
.len
= rq
->wLength
.word
;
197 return USB_NO_MSG
; // to get data in usbFunctionWrite
203 /* no vendor specific requests implemented */
206 return 0; /* default for not implemented requests: return no data back to host */
209 uchar
usbFunctionWrite(uchar
*data
, uchar len
)
211 if (last_req
.len
== 0) {
214 switch (last_req
.kind
) {
219 vusb_keyboard_leds
= data
[0];
233 /*------------------------------------------------------------------*
235 *------------------------------------------------------------------*/
238 * Report Descriptor for keyboard
240 * from an example in HID spec appendix
242 const PROGMEM uchar keyboard_hid_report
[] = {
243 0x05, 0x01, // Usage Page (Generic Desktop),
244 0x09, 0x06, // Usage (Keyboard),
245 0xA1, 0x01, // Collection (Application),
246 0x75, 0x01, // Report Size (1),
247 0x95, 0x08, // Report Count (8),
248 0x05, 0x07, // Usage Page (Key Codes),
249 0x19, 0xE0, // Usage Minimum (224),
250 0x29, 0xE7, // Usage Maximum (231),
251 0x15, 0x00, // Logical Minimum (0),
252 0x25, 0x01, // Logical Maximum (1),
253 0x81, 0x02, // Input (Data, Variable, Absolute), ;Modifier byte
254 0x95, 0x01, // Report Count (1),
255 0x75, 0x08, // Report Size (8),
256 0x81, 0x03, // Input (Constant), ;Reserved byte
257 0x95, 0x05, // Report Count (5),
258 0x75, 0x01, // Report Size (1),
259 0x05, 0x08, // Usage Page (LEDs),
260 0x19, 0x01, // Usage Minimum (1),
261 0x29, 0x05, // Usage Maximum (5),
262 0x91, 0x02, // Output (Data, Variable, Absolute), ;LED report
263 0x95, 0x01, // Report Count (1),
264 0x75, 0x03, // Report Size (3),
265 0x91, 0x03, // Output (Constant), ;LED report padding
266 0x95, 0x06, // Report Count (6),
267 0x75, 0x08, // Report Size (8),
268 0x15, 0x00, // Logical Minimum (0),
269 0x26, 0xFF, 0x00, // Logical Maximum(255),
270 0x05, 0x07, // Usage Page (Key Codes),
271 0x19, 0x00, // Usage Minimum (0),
272 0x29, 0xFF, // Usage Maximum (255),
273 0x81, 0x00, // Input (Data, Array),
274 0xc0 // End Collection
278 * Report Descriptor for mouse
280 * Mouse Protocol 1, HID 1.11 spec, Appendix B, page 59-60, with wheel extension
281 * http://www.microchip.com/forums/tm.aspx?high=&m=391435&mpage=1#391521
282 * http://www.keil.com/forum/15671/
283 * http://www.microsoft.com/whdc/device/input/wheel.mspx
285 const PROGMEM uchar mouse_hid_report
[] = {
287 0x05, 0x01, // USAGE_PAGE (Generic Desktop)
288 0x09, 0x02, // USAGE (Mouse)
289 0xa1, 0x01, // COLLECTION (Application)
290 0x85, REPORT_ID_MOUSE
, // REPORT_ID (1)
291 0x09, 0x01, // USAGE (Pointer)
292 0xa1, 0x00, // COLLECTION (Physical)
293 // ---------------------------- Buttons
294 0x05, 0x09, // USAGE_PAGE (Button)
295 0x19, 0x01, // USAGE_MINIMUM (Button 1)
296 0x29, 0x05, // USAGE_MAXIMUM (Button 5)
297 0x15, 0x00, // LOGICAL_MINIMUM (0)
298 0x25, 0x01, // LOGICAL_MAXIMUM (1)
299 0x75, 0x01, // REPORT_SIZE (1)
300 0x95, 0x05, // REPORT_COUNT (5)
301 0x81, 0x02, // INPUT (Data,Var,Abs)
302 0x75, 0x03, // REPORT_SIZE (3)
303 0x95, 0x01, // REPORT_COUNT (1)
304 0x81, 0x03, // INPUT (Cnst,Var,Abs)
305 // ---------------------------- X,Y position
306 0x05, 0x01, // USAGE_PAGE (Generic Desktop)
307 0x09, 0x30, // USAGE (X)
308 0x09, 0x31, // USAGE (Y)
309 0x15, 0x81, // LOGICAL_MINIMUM (-127)
310 0x25, 0x7f, // LOGICAL_MAXIMUM (127)
311 0x75, 0x08, // REPORT_SIZE (8)
312 0x95, 0x02, // REPORT_COUNT (2)
313 0x81, 0x06, // INPUT (Data,Var,Rel)
314 // ---------------------------- Vertical wheel
315 0x09, 0x38, // USAGE (Wheel)
316 0x15, 0x81, // LOGICAL_MINIMUM (-127)
317 0x25, 0x7f, // LOGICAL_MAXIMUM (127)
318 0x35, 0x00, // PHYSICAL_MINIMUM (0) - reset physical
319 0x45, 0x00, // PHYSICAL_MAXIMUM (0)
320 0x75, 0x08, // REPORT_SIZE (8)
321 0x95, 0x01, // REPORT_COUNT (1)
322 0x81, 0x06, // INPUT (Data,Var,Rel)
323 // ---------------------------- Horizontal wheel
324 0x05, 0x0c, // USAGE_PAGE (Consumer Devices)
325 0x0a, 0x38, 0x02, // USAGE (AC Pan)
326 0x15, 0x81, // LOGICAL_MINIMUM (-127)
327 0x25, 0x7f, // LOGICAL_MAXIMUM (127)
328 0x75, 0x08, // REPORT_SIZE (8)
329 0x95, 0x01, // REPORT_COUNT (1)
330 0x81, 0x06, // INPUT (Data,Var,Rel)
331 0xc0, // END_COLLECTION
332 0xc0, // END_COLLECTION
334 0x05, 0x01, // USAGE_PAGE (Generic Desktop)
335 0x09, 0x80, // USAGE (System Control)
336 0xa1, 0x01, // COLLECTION (Application)
337 0x85, REPORT_ID_SYSTEM
, // REPORT_ID (2)
338 0x15, 0x01, // LOGICAL_MINIMUM (0x1)
339 0x26, 0xb7, 0x00, // LOGICAL_MAXIMUM (0xb7)
340 0x19, 0x01, // USAGE_MINIMUM (0x1)
341 0x29, 0xb7, // USAGE_MAXIMUM (0xb7)
342 0x75, 0x10, // REPORT_SIZE (16)
343 0x95, 0x01, // REPORT_COUNT (1)
344 0x81, 0x00, // INPUT (Data,Array,Abs)
345 0xc0, // END_COLLECTION
347 0x05, 0x0c, // USAGE_PAGE (Consumer Devices)
348 0x09, 0x01, // USAGE (Consumer Control)
349 0xa1, 0x01, // COLLECTION (Application)
350 0x85, REPORT_ID_CONSUMER
, // REPORT_ID (3)
351 0x15, 0x01, // LOGICAL_MINIMUM (0x1)
352 0x26, 0x9c, 0x02, // LOGICAL_MAXIMUM (0x29c)
353 0x19, 0x01, // USAGE_MINIMUM (0x1)
354 0x2a, 0x9c, 0x02, // USAGE_MAXIMUM (0x29c)
355 0x75, 0x10, // REPORT_SIZE (16)
356 0x95, 0x01, // REPORT_COUNT (1)
357 0x81, 0x00, // INPUT (Data,Array,Abs)
358 0xc0, // END_COLLECTION
363 * Descriptor for compite device: Keyboard + Mouse
365 * contains: device, interface, HID and endpoint descriptors
367 #if USB_CFG_DESCR_PROPS_CONFIGURATION
368 const PROGMEM
char usbDescriptorConfiguration
[] = { /* USB configuration descriptor */
369 9, /* sizeof(usbDescriptorConfiguration): length of descriptor in bytes */
370 USBDESCR_CONFIG
, /* descriptor type */
371 9 + (9 + 9 + 7) + (9 + 9 + 7), 0,
372 //18 + 7 * USB_CFG_HAVE_INTRIN_ENDPOINT + 7 * USB_CFG_HAVE_INTRIN_ENDPOINT3 + 9, 0,
373 /* total length of data returned (including inlined descriptors) */
374 2, /* number of interfaces in this configuration */
375 1, /* index of this configuration */
376 0, /* configuration name string index */
377 #if USB_CFG_IS_SELF_POWERED
378 (1 << 7) | USBATTR_SELFPOWER
, /* attributes */
380 (1 << 7), /* attributes */
382 USB_CFG_MAX_BUS_POWER
/2, /* max USB current in 2mA units */
387 /* Interface descriptor */
388 9, /* sizeof(usbDescrInterface): length of descriptor in bytes */
389 USBDESCR_INTERFACE
, /* descriptor type */
390 0, /* index of this interface */
391 0, /* alternate setting for this interface */
392 USB_CFG_HAVE_INTRIN_ENDPOINT
, /* endpoints excl 0: number of endpoint descriptors to follow */
393 USB_CFG_INTERFACE_CLASS
,
394 USB_CFG_INTERFACE_SUBCLASS
,
395 USB_CFG_INTERFACE_PROTOCOL
,
396 0, /* string index for interface */
398 9, /* sizeof(usbDescrHID): length of descriptor in bytes */
399 USBDESCR_HID
, /* descriptor type: HID */
400 0x01, 0x01, /* BCD representation of HID version */
401 0x00, /* target country code */
402 0x01, /* number of HID Report (or other HID class) Descriptor infos to follow */
403 0x22, /* descriptor type: report */
404 sizeof(keyboard_hid_report
), 0, /* total length of report descriptor */
405 /* Endpoint descriptor */
406 #if USB_CFG_HAVE_INTRIN_ENDPOINT /* endpoint descriptor for endpoint 1 */
407 7, /* sizeof(usbDescrEndpoint) */
408 USBDESCR_ENDPOINT
, /* descriptor type = endpoint */
409 (char)0x81, /* IN endpoint number 1 */
410 0x03, /* attrib: Interrupt endpoint */
411 8, 0, /* maximum packet size */
412 USB_CFG_INTR_POLL_INTERVAL
, /* in ms */
418 /* Interface descriptor */
419 9, /* sizeof(usbDescrInterface): length of descriptor in bytes */
420 USBDESCR_INTERFACE
, /* descriptor type */
421 1, /* index of this interface */
422 0, /* alternate setting for this interface */
423 USB_CFG_HAVE_INTRIN_ENDPOINT3
, /* endpoints excl 0: number of endpoint descriptors to follow */
424 0x03, /* CLASS: HID */
425 0, /* SUBCLASS: none */
426 0, /* PROTOCOL: none */
427 0, /* string index for interface */
429 9, /* sizeof(usbDescrHID): length of descriptor in bytes */
430 USBDESCR_HID
, /* descriptor type: HID */
431 0x01, 0x01, /* BCD representation of HID version */
432 0x00, /* target country code */
433 0x01, /* number of HID Report (or other HID class) Descriptor infos to follow */
434 0x22, /* descriptor type: report */
435 sizeof(mouse_hid_report
), 0, /* total length of report descriptor */
436 #if USB_CFG_HAVE_INTRIN_ENDPOINT3 /* endpoint descriptor for endpoint 3 */
437 /* Endpoint descriptor */
438 7, /* sizeof(usbDescrEndpoint) */
439 USBDESCR_ENDPOINT
, /* descriptor type = endpoint */
440 (char)(0x80 | USB_CFG_EP3_NUMBER
), /* IN endpoint number 3 */
441 0x03, /* attrib: Interrupt endpoint */
442 8, 0, /* maximum packet size */
443 USB_CFG_INTR_POLL_INTERVAL
, /* in ms */
449 USB_PUBLIC usbMsgLen_t
usbFunctionDescriptor(struct usbRequest
*rq
)
454 debug("usbFunctionDescriptor: ");
455 debug_hex(rq->bmRequestType); debug(" ");
456 debug_hex(rq->bRequest); debug(" ");
457 debug_hex16(rq->wValue.word); debug(" ");
458 debug_hex16(rq->wIndex.word); debug(" ");
459 debug_hex16(rq->wLength.word); debug("\n");
461 switch (rq
->wValue
.bytes
[1]) {
462 #if USB_CFG_DESCR_PROPS_CONFIGURATION
463 case USBDESCR_CONFIG
:
464 usbMsgPtr
= (unsigned char *)usbDescriptorConfiguration
;
465 len
= sizeof(usbDescriptorConfiguration
);
469 switch (rq
->wValue
.bytes
[0]) {
471 usbMsgPtr
= (unsigned char *)(usbDescriptorConfiguration
+ 9 + 9);
475 usbMsgPtr
= (unsigned char *)(usbDescriptorConfiguration
+ 9 + (9 + 9 + 7) + 9);
480 case USBDESCR_HID_REPORT
:
481 /* interface index */
482 switch (rq
->wIndex
.word
) {
484 usbMsgPtr
= keyboard_hid_report
;
485 len
= sizeof(keyboard_hid_report
);
488 usbMsgPtr
= mouse_hid_report
;
489 len
= sizeof(mouse_hid_report
);
494 //debug("desc len: "); debug_hex(len); debug("\n");