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_INTERFACE_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_INTERFACE_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_INTERFACE_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_INTERFACE_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 s32
USBKeyboard_Deinitialize(void)
223 //Search for a keyboard connected to the wii usb port
224 //Thanks to Sven Peter usbstorage support
225 s32
USBKeyboard_Open(const eventcallback cb
)
227 usb_device_entry
*buffer
;
228 u8 device_count
, i
, conf
;
231 u32 iConf
, iInterface
, iEp
;
233 usb_configurationdesc
*ucd
;
234 usb_interfacedesc
*uid
;
235 usb_endpointdesc
*ued
;
237 buffer
= (usb_device_entry
*)iosAlloc(hId
, DEVLIST_MAXSIZE
* sizeof(usb_device_entry
));
241 memset(buffer
, 0, DEVLIST_MAXSIZE
* sizeof(usb_device_entry
));
243 if (USB_GetDeviceList(buffer
, DEVLIST_MAXSIZE
, USB_CLASS_HID
, &device_count
) < 0)
245 iosFree(hId
, buffer
);
250 if (_kbd
->fd
!= -1) USB_CloseDevice(&_kbd
->fd
);
252 _kbd
= (struct ukbd
*) malloc(sizeof(struct ukbd
));
258 memset(_kbd
, 0, sizeof(struct ukbd
));
261 for (i
= 0; i
< device_count
; i
++)
263 vid
= buffer
[i
].vid
;;
266 if ((vid
== 0) || (pid
== 0))
270 if (USB_OpenDevice(buffer
[i
].device_id
, vid
, pid
, &fd
) < 0)
273 if (USB_GetDescriptors(fd
, &udd
) < 0) {
274 USB_CloseDevice(&fd
);
278 for(iConf
= 0; iConf
< udd
.bNumConfigurations
; iConf
++)
280 ucd
= &udd
.configurations
[iConf
];
282 for(iInterface
= 0; iInterface
< ucd
->bNumInterfaces
; iInterface
++)
284 uid
= &ucd
->interfaces
[iInterface
];
286 if ((uid
->bInterfaceClass
== USB_CLASS_HID
) &&
287 (uid
->bInterfaceSubClass
== USB_SUBCLASS_BOOT
) &&
288 (uid
->bInterfaceProtocol
== USB_PROTOCOL_KEYBOARD
))
290 for(iEp
= 0; iEp
< uid
->bNumEndpoints
; iEp
++)
292 ued
= &uid
->endpoints
[iEp
];
294 if (ued
->bmAttributes
!= USB_ENDPOINT_INTERRUPT
)
297 if (!(ued
->bEndpointAddress
& USB_ENDPOINT_IN
))
303 _kbd
->configuration
= ucd
->bConfigurationValue
;
304 _kbd
->interface
= uid
->bInterfaceNumber
;
305 _kbd
->altInterface
= uid
->bAlternateSetting
;
307 _kbd
->ep
= ued
->bEndpointAddress
;
308 _kbd
->ep_size
= ued
->wMaxPacketSize
;
324 USB_FreeDescriptors(&udd
);
329 USB_CloseDevice(&fd
);
332 iosFree(hId
, buffer
);
337 if (USB_GetConfiguration(_kbd
->fd
, &conf
) < 0)
343 if (conf
!= _kbd
->configuration
&&
344 USB_SetConfiguration(_kbd
->fd
, _kbd
->configuration
) < 0)
350 if (_kbd
->altInterface
!= 0 &&
351 USB_SetAlternativeInterface(_kbd
->fd
, _kbd
->interface
, _kbd
->altInterface
) < 0)
357 if (_get_protocol() != 0)
359 if (_set_protocol(0) < 0)
365 if (_get_protocol() == 1)
372 if (USB_DeviceRemovalNotifyAsync(_kbd
->fd
, &_disconnect
, NULL
) < 0)
378 _kbd
->connected
= true;
384 void USBKeyboard_Close(void)
390 USB_CloseDevice(&_kbd
->fd
);
398 bool USBKeyboard_IsConnected(void) {
402 return _kbd
->connected
;
405 //Scan for key presses and generate events for the callback function
406 s32
USBKeyboard_Scan(void)
413 if (_get_input_report() < 0)
416 if (_kbd
->sc_ndata
.keycode
[0] == KEY_ERROR
)
419 if (_kbd
->sc_ndata
.modifiers
!= _kbd
->sc_odata
.modifiers
) {
420 for (i
= 0; i
< MODMAPSIZE
; ++i
) {
421 if ((_kbd
->sc_odata
.modifiers
& _ukbd_mod_map
[i
][0])
422 && !(_kbd
->sc_ndata
.modifiers
& _ukbd_mod_map
[i
][0]))
423 _submit(USBKEYBOARD_RELEASED
, _ukbd_mod_map
[i
][1]);
424 else if ((_kbd
->sc_ndata
.modifiers
& _ukbd_mod_map
[i
][0])
425 && !(_kbd
->sc_odata
.modifiers
& _ukbd_mod_map
[i
][0]))
426 _submit(USBKEYBOARD_PRESSED
, _ukbd_mod_map
[i
][1]);
430 for (i
= 0; i
< MAXKEYCODE
; i
++) {
431 if (_kbd
->sc_odata
.keycode
[i
] > 3) {
434 for (j
= 0; j
< MAXKEYCODE
; j
++) {
435 if (_kbd
->sc_odata
.keycode
[i
] == _kbd
->sc_ndata
.keycode
[j
]) {
442 _submit(USBKEYBOARD_RELEASED
, _kbd
->sc_odata
.keycode
[i
]);
445 if (_kbd
->sc_ndata
.keycode
[i
] > 3) {
448 for (j
= 0; j
< MAXKEYCODE
; j
++) {
449 if (_kbd
->sc_ndata
.keycode
[i
] == _kbd
->sc_odata
.keycode
[j
]) {
456 _submit(USBKEYBOARD_PRESSED
, _kbd
->sc_ndata
.keycode
[i
]);
460 _kbd
->sc_odata
= _kbd
->sc_ndata
;
466 s32
USBKeyboard_SetLed(const USBKeyboard_led led
, bool on
)
472 _kbd
->leds
= _kbd
->leds
| (1 << led
);
474 _kbd
->leds
= _kbd
->leds
& (255 ^ (1 << led
));
476 if (_set_output_report() < 0)
483 s32
USBKeyboard_ToggleLed(const USBKeyboard_led led
)
488 _kbd
->leds
= _kbd
->leds
^ (1 << led
);
490 if (_set_output_report() < 0)