load a keymap in KEYBOARD_Init() based on the contents of "/wiikbd.map"
[libogc.git] / libwiikeyboard / usbkeyboard.c
blob64a9e16dc15b38c67729774294c3da581c197edf
1 /*-------------------------------------------------------------
3 usbkeyboard.c -- Usb keyboard support(boot protocol)
5 Copyright (C) 2008, 2009
6 DAVY Guillaume davyg2@gmail.com
7 dhewg
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
26 distribution.
28 -------------------------------------------------------------*/
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <malloc.h>
35 #include <gccore.h>
36 #include <ogc/usb.h>
38 #include <wiikeyboard/usbkeyboard.h>
40 #define HEAP_SIZE 4096
41 #define DEVLIST_MAXSIZE 8
43 static s32 hId = -1;
45 //Callback when the keyboard is disconnected
46 static s32 _disconnect(s32 retval,void* data)
48 USBKeyboard *key = (USBKeyboard*) data;
49 key->connect = false;
51 if (!key->cb)
52 return 1;
54 USBKeyboard_event ev;
55 ev.type = USBKEYBOARD_DISCONNECTED;
57 key->cb(ev,key->cbData);
59 return 1;
62 static void USBKeyboard_SubmitEvent(USBKeyboard *key, USBKeyboard_eventType type, u8 code)
64 if (!key->cb)
65 return;
67 USBKeyboard_event ev;
68 ev.type = type;
69 ev.keyCode = code;
71 key->cb(ev,key->cbData);
74 //init the ioheap
75 s32 USBKeyboard_Initialize(void)
77 if(hId > 0)
78 return 0;
80 hId = iosCreateHeap(HEAP_SIZE);
82 if(hId < 0)
83 return IPC_ENOHEAP;
85 return IPC_OK;
88 //Destroy the io heap
89 s32 USBKeyboard_Deinitialize(void)
91 if(hId < 0)
92 return -1;
94 s32 retval;
95 retval = iosDestroyHeap(hId);
96 hId = -1;
97 return retval;
100 //Search for a keyboard connected to the wii usb port
101 //Thanks to Sven Peter usbstorage support
102 s32 USBKeyboard_Find(u16 *vid, u16 *pid)
104 u8 *buffer;
105 u8 dummy;
106 u8 i;
107 u16 p_vid, p_pid;
108 bool found = false;
110 if (!vid || !pid)
111 return -1;
113 buffer = memalign(32, DEVLIST_MAXSIZE << 3);
114 if(buffer == NULL)
115 return -1;
116 memset(buffer, 0, DEVLIST_MAXSIZE << 3);
118 if (USB_GetDeviceList("/dev/usb/oh0", buffer, DEVLIST_MAXSIZE, 0, &dummy) < 0)
120 free(buffer);
121 return -2;
124 for(i = 0; i < DEVLIST_MAXSIZE; i++)
126 p_vid = *((u16 *) (buffer + (i << 3) + 4));
127 p_pid = *((u16 *) (buffer + (i << 3) + 6));
129 if ((p_vid==0) || (p_pid==0))
130 continue;
132 s32 fd=0;
133 if (USB_OpenDevice("oh0", p_vid, p_pid, &fd) < 0)
134 continue;
136 u32 iConf, iInterface;
137 usb_devdesc udd;
138 usb_configurationdesc *ucd;
139 usb_interfacedesc *uid;
140 USB_GetDescriptors(fd, &udd);
141 for(iConf = 0; iConf < udd.bNumConfigurations; iConf++)
143 ucd = &udd.configurations[iConf];
144 for(iInterface = 0; iInterface < ucd->bNumInterfaces; iInterface++)
146 uid = &ucd->interfaces[iInterface];
147 if ( (uid->bInterfaceClass == USB_CLASS_HID) && (uid->bInterfaceSubClass == USB_SUBCLASS_BOOT) && (uid->bInterfaceProtocol== USB_PROTOCOL_KEYBOARD))
149 *vid = p_vid;
150 *pid = p_pid;
151 found = true;
152 break;
156 if (found)
157 break;
160 USB_FreeDescriptors(&udd);
161 USB_CloseDevice(&fd);
164 free(buffer);
166 if (found)
167 return 1;
169 return 0;
172 //Open a keyboard from his pid and vid that you retrieved with USBKeyboard_Find
173 s32 USBKeyboard_Open(USBKeyboard *key, u16 vid, u16 pid)
175 if (!key)
176 return -1;
178 key->connect = false;
180 if (USB_OpenDevice("oh0", vid ,pid, &key->fd) < 0)
181 return -1;
183 u32 iConf, iInterface, iEp;
184 usb_devdesc udd;
185 usb_configurationdesc *ucd;
186 usb_interfacedesc *uid;
187 usb_endpointdesc *ued;
189 //Search a interrupt endPoint thanks to the usb descriptor
190 USB_GetDescriptors(key->fd, &udd);
191 for(iConf = 0; iConf < udd.bNumConfigurations; iConf++)
193 ucd = &udd.configurations[iConf];
194 for(iInterface = 0; iInterface < ucd->bNumInterfaces; iInterface++)
196 uid = &ucd->interfaces[iInterface];
197 if ( (uid->bInterfaceClass == USB_CLASS_HID) && (uid->bInterfaceSubClass == USB_SUBCLASS_BOOT) && (uid->bInterfaceProtocol== USB_PROTOCOL_KEYBOARD))
199 for(iEp = 0; iEp < uid->bNumEndpoints; iEp++)
201 ued = &uid->endpoints[iEp];
202 if (ued->bmAttributes != USB_ENPOINT_INTERRUPT)
203 continue;
204 if (!(ued->bEndpointAddress & USB_ENDPOINT_IN))
205 continue;
206 key->ep = ued->bEndpointAddress;
207 key->ep_size = ued->wMaxPacketSize;
208 key->configuration = ucd->bConfigurationValue;
209 key->interface = uid->bInterfaceNumber;
210 key->altInterface = uid->bAlternateSetting;
211 goto found;
216 USB_FreeDescriptors(&udd);
217 return -2;
219 found:
220 USB_FreeDescriptors(&udd);
222 u8 conf;
224 if(USB_GetConfiguration(key->fd, &conf) < 0) {
225 USBKeyboard_Close(key);
226 return -3;
229 if(conf != key->configuration && USB_SetConfiguration(key->fd, key->configuration) < 0) {
230 USBKeyboard_Close(key);
231 return -4;
234 if(key->altInterface != 0 && USB_SetAlternativeInterface(key->fd, key->interface, key->altInterface) < 0) {
235 USBKeyboard_Close(key);
236 return -5;
239 if (USBKeyboard_Get_Protocol(key)!=0)
241 if (USBKeyboard_Set_Protocol(key, 0)<0)
243 USBKeyboard_Close(key);
244 return -6;
246 if (USBKeyboard_Get_Protocol(key)==1)
248 USBKeyboard_Close(key);
249 return -7;
253 if (USB_DeviceRemovalNotifyAsync(key->fd,&_disconnect,key)<0)
255 USBKeyboard_Close(key);
256 return -8;
259 key->leds = 0;
260 key->vid = vid;
261 key->pid = pid;
262 key->connect = true;
264 return 1;
267 //Close the device
268 s32 USBKeyboard_Close(USBKeyboard *key)
270 s32 res = USB_CloseDevice(&(key->fd));
271 key->connect = false;
273 return res;
276 //Get the protocol, 0=bout protocol and 1=report protocol
277 s32 USBKeyboard_Get_Protocol(USBKeyboard *key)
279 s32 protocol;
280 u8 *buffer = 0;
281 buffer = iosAlloc(hId, 1);
282 if (buffer == NULL)
283 return -1;
284 USB_WriteCtrlMsg(key->fd,USB_REQTYPE_GET,USB_REQ_GETPROTOCOL,0,0,1,buffer);
285 protocol=*buffer;
286 iosFree(hId, buffer);
287 return protocol;
290 //Modify the protocol, 0=bout protocol and 1=report protocol
291 s32 USBKeyboard_Set_Protocol(USBKeyboard *key, u8 protocol)
293 return USB_WriteCtrlMsg(key->fd,USB_REQTYPE_SET,USB_REQ_SETPROTOCOL,protocol,0,0,0);
296 //Get an input report from interrupt pipe
297 s32 USBKeyboard_Get_InputReport_Intr(USBKeyboard *key)
299 u8 *buffer = 0;
300 buffer = iosAlloc(hId, 8);
301 if (buffer == NULL)
302 return -1;
303 s32 ret = USB_ReadIntrMsg(key->fd,key->ep,8,buffer);
304 memcpy(key->keyNew,buffer,8);
305 iosFree(hId, buffer);
306 return ret;
309 //Get an input report from control pipe
310 s32 USBKeyboard_Get_OutputReport_Ctrl(USBKeyboard *key,u8 *leds)
312 u8 *buffer = 0;
313 buffer = iosAlloc(hId, 1);
314 if (buffer == NULL)
315 return -1;
316 s32 ret = USB_WriteCtrlMsg(key->fd,USB_REQTYPE_GET,USB_REQ_GETREPORT, USB_REPTYPE_OUTPUT<<8 | 0,0,1,buffer);
317 memcpy(leds,buffer,1);
318 iosFree(hId, buffer);
319 return ret;
322 //Set an input report to control pipe
323 s32 USBKeyboard_Set_OutputReport_Ctrl(USBKeyboard *key)
325 u8 *buffer = 0;
326 buffer = iosAlloc(hId, 1);
327 if (buffer == NULL)
328 return -1;
329 memcpy(buffer,&key->leds,1);
330 s32 ret = USB_WriteCtrlMsg(key->fd,USB_REQTYPE_SET,USB_REQ_SETREPORT, USB_REPTYPE_OUTPUT<<8 | 0,0,1,buffer);
331 iosFree(hId, buffer);
332 return ret;
335 //Scan for key presses and generate events for the callback function
336 s32 USBKeyboard_Scan(USBKeyboard *key)
338 u8 i;
339 u8 bad_message[6] = {0x01, 0x01, 0x01, 0x01, 0x01, 0x01};
340 if (USBKeyboard_Get_InputReport_Intr(key)<0)
341 return -1;
343 if (memcmp(key->keyNew + 2, bad_message, 6) == 0)
344 return 0;
346 if(key->keyNew[0] != key->oldState) {
347 if ((key->keyNew[0] & 0x02) && !(key->oldState & 0x02)) {
348 USBKeyboard_SubmitEvent(key, USBKEYBOARD_PRESSED, 0xe1);
349 } else if ((key->oldState & 0x02) && !(key->keyNew[0] & 0x02)) {
350 USBKeyboard_SubmitEvent(key, USBKEYBOARD_RELEASED, 0xe1);
353 if ((key->keyNew[0] & 0x20) && !(key->oldState & 0x20)) {
354 USBKeyboard_SubmitEvent(key, USBKEYBOARD_PRESSED, 0xe5);
355 } else if ((key->oldState & 0x20) && !(key->keyNew[0] & 0x20)) {
356 USBKeyboard_SubmitEvent(key, USBKEYBOARD_RELEASED, 0xe5);
359 if ((key->keyNew[0] & 0x01) && !(key->oldState & 0x01)) {
360 USBKeyboard_SubmitEvent(key, USBKEYBOARD_PRESSED, 0xe0);
361 } else if ((key->oldState & 0x01) && !(key->keyNew[0] & 0x01)) {
362 USBKeyboard_SubmitEvent(key, USBKEYBOARD_RELEASED, 0xe0);
365 if ((key->keyNew[0] & 0x10) && !(key->oldState & 0x10)) {
366 USBKeyboard_SubmitEvent(key, USBKEYBOARD_PRESSED, 0xe4);
367 } else if ((key->oldState & 0x10) && !(key->keyNew[0] & 0x10)) {
368 USBKeyboard_SubmitEvent(key, USBKEYBOARD_RELEASED, 0xe4);
371 if ((key->keyNew[0] & 0x04) && !(key->oldState & 0x04)) {
372 USBKeyboard_SubmitEvent(key, USBKEYBOARD_PRESSED, 0xe2);
373 } else if ((key->oldState & 0x04) && !(key->keyNew[0] & 0x04)) {
374 USBKeyboard_SubmitEvent(key, USBKEYBOARD_RELEASED, 0xe2);
377 if ((key->keyNew[0] & 0x40) && !(key->oldState & 0x40)) {
378 USBKeyboard_SubmitEvent(key, USBKEYBOARD_PRESSED, 0xe6);
379 } else if ((key->oldState & 0x40) && !(key->keyNew[0] & 0x40)) {
380 USBKeyboard_SubmitEvent(key, USBKEYBOARD_RELEASED, 0xe6);
383 if ((key->keyNew[0] & 0x08) && !(key->oldState & 0x08)) {
384 USBKeyboard_SubmitEvent(key, USBKEYBOARD_PRESSED, 0xe3);
385 } else if ((key->oldState & 0x08) && !(key->keyNew[0] & 0x08)) {
386 USBKeyboard_SubmitEvent(key, USBKEYBOARD_RELEASED, 0xe3);
389 if ((key->keyNew[0] & 0x80) && !(key->oldState & 0x80)) {
390 USBKeyboard_SubmitEvent(key, USBKEYBOARD_PRESSED, 0xe7);
391 } else if ((key->oldState & 0x80) && !(key->keyNew[0] & 0x80)) {
392 USBKeyboard_SubmitEvent(key, USBKEYBOARD_RELEASED, 0xe7);
395 for (i = 2; i < 8; i++)
397 if (key->keyOld[i] > 3 && memchr(key->keyNew + 2, key->keyOld[i], 6) == NULL)
399 USBKeyboard_SubmitEvent(key, USBKEYBOARD_RELEASED, key->keyOld[i]);
401 if (key->keyNew[i] > 3 && memchr(key->keyOld + 2, key->keyNew[i], 6) == NULL)
403 USBKeyboard_SubmitEvent(key, USBKEYBOARD_PRESSED, key->keyNew[i]);
406 memcpy(key->keyOld, key->keyNew, 8);
407 key->oldState = key->keyNew[0];
408 return 0;
411 //Turn on/off a led
412 s32 USBKeyboard_SetLed(USBKeyboard *key, const USBKeyboard_led led, bool on)
414 if (on)
415 key->leds = key->leds | (1 << led );
416 else
417 key->leds = key->leds & (255 ^ (1 << led));
419 if (USBKeyboard_Set_OutputReport_Ctrl(key)<0)
420 return -2;
422 return 1;
425 //Toggle a led
426 s32 USBKeyboard_ToggleLed(USBKeyboard *key, const USBKeyboard_led led)
428 key->leds = key->leds ^ (1 << led);
429 if (USBKeyboard_Set_OutputReport_Ctrl(key)<0)
430 return -2;
431 return 1;
434 //Set the callback function which will handle the keyboard events
435 void USBKeyboard_SetCB(USBKeyboard* key,eventcallback cb, void* data)
437 key->cb = cb;
438 key->cbData = data;