1 /*-------------------------------------------------------------
3 usbkeyboard.c -- Usb keyboard support(boot protocol)
5 Copyright (C) 2008, 2009
6 DAVY Guillaume davyg2@gmail.com
9 This software is provided 'as-is', without any express or implied
10 warranty. In no event will the authors be held liable for any
11 damages arising from the use of this software.
13 Permission is granted to anyone to use this software for any
14 purpose, including commercial applications, and to alter it and
15 redistribute it freely, subject to the following restrictions:
17 1. The origin of this software must not be misrepresented; you
18 must not claim that you wrote the original software. If you use
19 this software in a product, an acknowledgment in the product
20 documentation would be appreciated but is not required.
22 2. Altered source versions must be plainly marked as such, and
23 must not be misrepresented as being the original software.
25 3. This notice may not be removed or altered from any source
28 -------------------------------------------------------------*/
36 #include <wiikeyboard/usbkeyboard.h>
38 #define HEAP_SIZE 4096
39 #define DEVLIST_MAXSIZE 8
40 #define KEY_ERROR 0x01
43 #define USB_MOD_CTRL_L 0x01
44 #define USB_MOD_SHIFT_L 0x02
45 #define USB_MOD_ALT_L 0x04
46 #define USB_MOD_META_L 0x08
47 #define USB_MOD_CTRL_R 0x10
48 #define USB_MOD_SHIFT_R 0x20
49 #define USB_MOD_ALT_R 0x40
50 #define USB_MOD_META_R 0x80
54 u8 keycode
[MAXKEYCODE
];
62 struct ukbd_data sc_ndata
;
63 struct ukbd_data sc_odata
;
78 static struct ukbd
*_kbd
= NULL
;
80 static u8 _ukbd_mod_map
[][2] = {
81 { USB_MOD_CTRL_L
, 224 },
82 { USB_MOD_SHIFT_L
, 225 },
83 { USB_MOD_ALT_L
, 226 },
84 { USB_MOD_META_L
, 227 },
85 { USB_MOD_CTRL_R
, 228 },
86 { USB_MOD_SHIFT_R
, 229 },
87 { USB_MOD_ALT_R
, 230 },
88 { USB_MOD_META_R
, 231 }
91 #define MODMAPSIZE (sizeof(_ukbd_mod_map)/sizeof(_ukbd_mod_map[0]))
93 static void _submit(USBKeyboard_eventType type
, u8 code
)
105 //Callback when the keyboard is disconnected
106 static s32
_disconnect(s32 retval
, void *data
)
110 _kbd
->connected
= false;
112 _submit(USBKEYBOARD_DISCONNECTED
, 0);
117 //Get the protocol, 0=boot protocol and 1=report protocol
118 static s32
_get_protocol(void)
123 if(!_kbd
|| _kbd
->fd
==-1) return -1;
125 buffer
= iosAlloc(hId
, 1);
130 USB_WriteCtrlMsg(_kbd
->fd
, USB_REQTYPE_GET
, USB_REQ_GETPROTOCOL
, 0, _kbd
->interface
, 1, buffer
);
133 iosFree(hId
, buffer
);
138 //Modify the protocol, 0=boot protocol and 1=report protocol
139 static s32
_set_protocol(u8 protocol
)
141 if(!_kbd
|| _kbd
->fd
==-1) return -1;
142 return USB_WriteCtrlMsg(_kbd
->fd
, USB_REQTYPE_SET
, USB_REQ_SETPROTOCOL
, protocol
, _kbd
->interface
, 0, NULL
);
145 //Get an input report from interrupt pipe
146 static s32
_get_input_report(void)
150 if(!_kbd
|| _kbd
->fd
==-1) return -1;
151 buffer
= iosAlloc(hId
, 8);
156 s32 ret
= USB_ReadIntrMsg(_kbd
->fd
, _kbd
->ep
, 8, buffer
);
158 memcpy(&_kbd
->sc_ndata
, buffer
, 8);
159 iosFree(hId
, buffer
);
161 _kbd
->sc_ndata
.modifiers
= (_kbd
->sc_ndata
.modifiers
<< 8) | (_kbd
->sc_ndata
.modifiers
>> 8);
167 //Get an input report from control pipe
168 static s32
_get_output_report(u8
*leds
)
171 if(!_kbd
|| _kbd
->fd
==-1) return -1;
172 buffer
= iosAlloc(hId
, 1);
177 s32 ret
= USB_WriteCtrlMsg(_kbd
->fd
, USB_REQTYPE_GET
, USB_REQ_GETREPORT
, USB_REPTYPE_OUTPUT
<< 8, _kbd
->interface
, 1, buffer
);
179 memcpy(leds
, buffer
, 1);
180 iosFree(hId
, buffer
);
186 //Set an input report to control pipe
187 static s32
_set_output_report(void)
190 if(!_kbd
|| _kbd
->fd
==-1) return -1;
191 buffer
= iosAlloc(hId
, 1);
196 memcpy(buffer
, &_kbd
->leds
, 1);
197 s32 ret
= USB_WriteCtrlMsg(_kbd
->fd
, USB_REQTYPE_SET
, USB_REQ_SETREPORT
, USB_REPTYPE_OUTPUT
<< 8, _kbd
->interface
, 1, buffer
);
199 iosFree(hId
, buffer
);
205 s32
USBKeyboard_Initialize(void)
210 hId
= iosCreateHeap(HEAP_SIZE
);
218 //Destroy the io heap
219 s32
USBKeyboard_Deinitialize(void)
225 retval
= iosDestroyHeap(hId
);
231 //Search for a keyboard connected to the wii usb port
232 //Thanks to Sven Peter usbstorage support
233 s32
USBKeyboard_Open(const eventcallback cb
)
235 usb_device_entry
*buffer
;
236 u8 device_count
, i
, conf
;
239 u32 iConf
, iInterface
, iEp
;
241 usb_configurationdesc
*ucd
;
242 usb_interfacedesc
*uid
;
243 usb_endpointdesc
*ued
;
245 buffer
= (usb_device_entry
*)iosAlloc(hId
, DEVLIST_MAXSIZE
* sizeof(usb_device_entry
));
249 memset(buffer
, 0, DEVLIST_MAXSIZE
* sizeof(usb_device_entry
));
251 if (USB_GetDeviceList(buffer
, DEVLIST_MAXSIZE
, USB_CLASS_HID
, &device_count
) < 0)
253 iosFree(hId
, buffer
);
258 if (_kbd
->fd
!= -1) USB_CloseDevice(&_kbd
->fd
);
260 _kbd
= (struct ukbd
*) malloc(sizeof(struct ukbd
));
266 memset(_kbd
, 0, sizeof(struct ukbd
));
269 for (i
= 0; i
< device_count
; i
++)
271 vid
= buffer
[i
].vid
;;
274 if ((vid
== 0) || (pid
== 0))
278 if (USB_OpenDevice(buffer
[i
].device_id
, vid
, pid
, &fd
) < 0)
281 if (USB_GetDescriptors(fd
, &udd
) < 0) {
282 USB_CloseDevice(&fd
);
286 for(iConf
= 0; iConf
< udd
.bNumConfigurations
; iConf
++)
288 ucd
= &udd
.configurations
[iConf
];
290 for(iInterface
= 0; iInterface
< ucd
->bNumInterfaces
; iInterface
++)
292 uid
= &ucd
->interfaces
[iInterface
];
294 if ((uid
->bInterfaceClass
== USB_CLASS_HID
) &&
295 (uid
->bInterfaceSubClass
== USB_SUBCLASS_BOOT
) &&
296 (uid
->bInterfaceProtocol
== USB_PROTOCOL_KEYBOARD
))
298 for(iEp
= 0; iEp
< uid
->bNumEndpoints
; iEp
++)
300 ued
= &uid
->endpoints
[iEp
];
302 if (ued
->bmAttributes
!= USB_ENDPOINT_INTERRUPT
)
305 if (!(ued
->bEndpointAddress
& USB_ENDPOINT_IN
))
311 _kbd
->configuration
= ucd
->bConfigurationValue
;
312 _kbd
->interface
= uid
->bInterfaceNumber
;
313 _kbd
->altInterface
= uid
->bAlternateSetting
;
315 _kbd
->ep
= ued
->bEndpointAddress
;
316 _kbd
->ep_size
= ued
->wMaxPacketSize
;
332 USB_FreeDescriptors(&udd
);
337 USB_CloseDevice(&fd
);
340 iosFree(hId
, buffer
);
345 if (USB_GetConfiguration(_kbd
->fd
, &conf
) < 0)
351 if (conf
!= _kbd
->configuration
&&
352 USB_SetConfiguration(_kbd
->fd
, _kbd
->configuration
) < 0)
358 if (_kbd
->altInterface
!= 0 &&
359 USB_SetAlternativeInterface(_kbd
->fd
, _kbd
->interface
, _kbd
->altInterface
) < 0)
365 if (_get_protocol() != 0)
367 if (_set_protocol(0) < 0)
373 if (_get_protocol() == 1)
380 if (USB_DeviceRemovalNotifyAsync(_kbd
->fd
, &_disconnect
, NULL
) < 0)
386 _kbd
->connected
= true;
392 void USBKeyboard_Close(void)
398 USB_CloseDevice(&_kbd
->fd
);
406 bool USBKeyboard_IsConnected(void) {
410 return _kbd
->connected
;
413 //Scan for key presses and generate events for the callback function
414 s32
USBKeyboard_Scan(void)
421 if (_get_input_report() < 0)
424 if (_kbd
->sc_ndata
.keycode
[0] == KEY_ERROR
)
427 if (_kbd
->sc_ndata
.modifiers
!= _kbd
->sc_odata
.modifiers
) {
428 for (i
= 0; i
< MODMAPSIZE
; ++i
) {
429 if ((_kbd
->sc_odata
.modifiers
& _ukbd_mod_map
[i
][0])
430 && !(_kbd
->sc_ndata
.modifiers
& _ukbd_mod_map
[i
][0]))
431 _submit(USBKEYBOARD_RELEASED
, _ukbd_mod_map
[i
][1]);
432 else if ((_kbd
->sc_ndata
.modifiers
& _ukbd_mod_map
[i
][0])
433 && !(_kbd
->sc_odata
.modifiers
& _ukbd_mod_map
[i
][0]))
434 _submit(USBKEYBOARD_PRESSED
, _ukbd_mod_map
[i
][1]);
438 for (i
= 0; i
< MAXKEYCODE
; i
++) {
439 if (_kbd
->sc_odata
.keycode
[i
] > 3) {
442 for (j
= 0; j
< MAXKEYCODE
; j
++) {
443 if (_kbd
->sc_odata
.keycode
[i
] == _kbd
->sc_ndata
.keycode
[j
]) {
450 _submit(USBKEYBOARD_RELEASED
, _kbd
->sc_odata
.keycode
[i
]);
453 if (_kbd
->sc_ndata
.keycode
[i
] > 3) {
456 for (j
= 0; j
< MAXKEYCODE
; j
++) {
457 if (_kbd
->sc_ndata
.keycode
[i
] == _kbd
->sc_odata
.keycode
[j
]) {
464 _submit(USBKEYBOARD_PRESSED
, _kbd
->sc_ndata
.keycode
[i
]);
468 _kbd
->sc_odata
= _kbd
->sc_ndata
;
474 s32
USBKeyboard_SetLed(const USBKeyboard_led led
, bool on
)
480 _kbd
->leds
= _kbd
->leds
| (1 << led
);
482 _kbd
->leds
= _kbd
->leds
& (255 ^ (1 << led
));
484 if (_set_output_report() < 0)
491 s32
USBKeyboard_ToggleLed(const USBKeyboard_led led
)
496 _kbd
->leds
= _kbd
->leds
^ (1 << led
);
498 if (_set_output_report() < 0)