apply Brian's libwiikeyboard patches
[libogc.git] / libwiikeyboard / usbkeyboard.c
bloba87b89f22458663d80a08671beb88c80e7ed988d
1 /*-------------------------------------------------------------
3 usbkeyboard.c -- Usb keyboard support(boot protocole)
5 Copyright (C) 2008, 2009
6 DAVY Guillaume davyg2@gmail.com
8 This software is provided 'as-is', without any express or implied
9 warranty. In no event will the authors be held liable for any
10 damages arising from the use of this software.
12 Permission is granted to anyone to use this software for any
13 purpose, including commercial applications, and to alter it and
14 redistribute it freely, subject to the following restrictions:
16 1. The origin of this software must not be misrepresented; you
17 must not claim that you wrote the original software. If you use
18 this software in a product, an acknowledgment in the product
19 documentation would be appreciated but is not required.
21 2. Altered source versions must be plainly marked as such, and
22 must not be misrepresented as being the original software.
24 3. This notice may not be removed or altered from any source
25 distribution.
27 -------------------------------------------------------------*/
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <malloc.h>
34 #include <gccore.h>
35 #include <ogc/usb.h>
37 #include <wiikeyboard/usbkeyboard.h>
39 #define HEAP_SIZE 4096
41 static s32 hId = -1;
43 //Check if two device are equal
44 bool devEqual(device dev1,device dev2)
46 return (dev1.vid==dev2.vid && dev1.pid==dev2.pid);
49 //Call when the keyboard is disconnected
50 s32 _disconnect(s32 retval,void* data)
52 keyboard *key = (keyboard*) data;
53 key->connect = false;
54 USBKeyboard_event ev;
55 ev.type = USBKEYBOARD_DISCONNECTED;
56 u8 i;
57 for (i=0;i<key->numCB;i++)
58 (*key->cb[i]) (ev,key->cbData[i]);
59 return 1;
62 //init the ioheap
63 s32 USBKeyboard_Initialize()
65 if(hId > 0)
66 return 0;
68 hId = iosCreateHeap(HEAP_SIZE);
70 if(hId < 0)
71 return IPC_ENOHEAP;
73 return IPC_OK;
76 //Destroy the io heap
77 s32 USBKeyboard_Deinitialize()
79 s32 retval;
80 retval = iosDestroyHeap(hId);
81 hId = -1;
82 return retval;
85 //Search all the keyboard connected to the wii usb port
86 //Thanks to Sven Peter usbstorage support
87 s32 USBKeyboard_Find(device (*devs)[DEVLIST_MAXSIZE])
89 u8 *buffer;
90 u8 dummy;
91 u8 i;
92 u16 vid, pid;
94 buffer = memalign(32, DEVLIST_MAXSIZE << 3);
95 if(buffer == NULL)
96 return -1;
97 memset(buffer, 0, DEVLIST_MAXSIZE << 3);
99 if (USB_GetDeviceList("/dev/usb/oh0", buffer, DEVLIST_MAXSIZE, 0, &dummy) < 0)
101 free(buffer);
102 return -2;
105 u8 num=0;
106 for(i = 0; i < DEVLIST_MAXSIZE; i++)
108 memcpy(&vid, (buffer + (i << 3) + 4), 2);
109 memcpy(&pid, (buffer + (i << 3) + 6), 2);
111 if ((vid==0)||(pid==0))
112 continue;
114 s32 fd=0;
115 if (USB_OpenDevice("oh0",vid,pid,&fd)<0)
116 continue;
118 u32 iConf, iInterface;
119 usb_devdesc udd;
120 usb_configurationdesc *ucd;
121 usb_interfacedesc *uid;
122 USB_GetDescriptors(fd, &udd);
123 for(iConf = 0; iConf < udd.bNumConfigurations; iConf++)
125 ucd = &udd.configurations[iConf];
126 for(iInterface = 0; iInterface < ucd->bNumInterfaces; iInterface++)
128 uid = &ucd->interfaces[iInterface];
129 if ( (uid->bInterfaceClass == USB_CLASS_HID) && (uid->bInterfaceSubClass == USB_SUBCLASS_BOOT) && (uid->bInterfaceProtocol== USB_PROTOCOL_KEYBOARD))
131 (*devs)[num].vid = vid;
132 (*devs)[num].pid = pid;
133 num++;
134 break;
138 USB_FreeDescriptors(&udd);
139 USB_CloseDevice(&fd);
141 return num;
144 //Open a keyboard from his pid and vid that you can have with USBKeyboard_find
145 s32 USBKeyboard_Open(keyboard *key,device dev)
147 if (USB_OpenDevice("oh0",dev.vid,dev.pid,&key->fd)<0)
148 return -1;
150 u32 iConf, iInterface, iEp;
151 usb_devdesc udd;
152 usb_configurationdesc *ucd;
153 usb_interfacedesc *uid;
154 usb_endpointdesc *ued;
156 //Search a interrupt endPoint thanks to the usb descriptor
157 USB_GetDescriptors(key->fd, &udd);
158 for(iConf = 0; iConf < udd.bNumConfigurations; iConf++)
160 ucd = &udd.configurations[iConf];
161 for(iInterface = 0; iInterface < ucd->bNumInterfaces; iInterface++)
163 uid = &ucd->interfaces[iInterface];
164 if ( (uid->bInterfaceClass == USB_CLASS_HID) && (uid->bInterfaceSubClass == USB_SUBCLASS_BOOT) && (uid->bInterfaceProtocol== USB_PROTOCOL_KEYBOARD))
166 for(iEp = 0; iEp < uid->bNumEndpoints; iEp++)
168 ued = &uid->endpoints[iEp];
169 if (ued->bmAttributes != USB_ENPOINT_INTERRUPT)
170 continue;
171 if (!(ued->bEndpointAddress & USB_ENDPOINT_IN))
172 continue;
173 key->ep = ued->bEndpointAddress;
174 key->ep_size = ued->wMaxPacketSize;
175 key->configuration = ucd->bConfigurationValue;
176 key->interface = uid->bInterfaceNumber;
177 key->altInterface = uid->bAlternateSetting;
178 goto found;
183 USB_FreeDescriptors(&udd);
184 return -2;
186 found:
187 USB_FreeDescriptors(&udd);
189 u8 conf;
191 if(USB_GetConfiguration(key->fd, &conf) < 0)
192 return -3;
193 if(conf != key->configuration && USB_SetConfiguration(key->fd, key->configuration) < 0)
194 return -4;
195 if(key->altInterface != 0 && USB_SetAlternativeInterface(key->fd, key->interface, key->altInterface) < 0)
196 return -5;
198 if (USBKeyboard_Get_Protocol(key)!=0)
200 if (USBKeyboard_Set_Protocol(key, 0)<0)
202 USBKeyboard_Close(key);
203 return -6;
205 if (USBKeyboard_Get_Protocol(key)==1)
207 USBKeyboard_Close(key);
208 return -7;
212 key->leds = 0;
213 key->dev = dev;
214 key->numCB=0;
215 key->connect = true;
216 if (USB_DeviceRemovalNotifyAsync(key->fd,&_disconnect,key)<0)
218 USBKeyboard_Close(key);
219 return -8;
222 return 1;
225 //Close the device
226 s32 USBKeyboard_Close(keyboard *key)
228 return USB_CloseDevice(&(key->fd));
231 //Get the protocol, 0=bout protocol and 1=report protocol
232 s32 USBKeyboard_Get_Protocol(keyboard *key)
234 s32 protocol;
235 u8 *buffer = 0;
236 buffer = iosAlloc(hId, 1);
237 if (buffer == NULL)
238 return -1;
239 USB_WriteCtrlMsg(key->fd,USB_REQTYPE_GET,USB_REQ_GETPROTOCOL,0,0,1,buffer);
240 protocol=*buffer;
241 iosFree(hId, buffer);
242 return protocol;
245 //Modifie the protocol, 0=bout protocol and 1=report protocol
246 s32 USBKeyboard_Set_Protocol(keyboard *key, u8 protocol)
248 return USB_WriteCtrlMsg(key->fd,USB_REQTYPE_SET,USB_REQ_SETPROTOCOL,protocol,0,0,0);
251 //Get a input report from interrupt pipe
252 s32 USBKeyboard_Get_InputReport_Intr(keyboard *key)
254 u8 *buffer = 0;
255 buffer = iosAlloc(hId, 8);
256 if (buffer == NULL)
257 return -1;
258 s32 ret = USB_ReadIntrMsg(key->fd,key->ep,8,buffer);
259 memcpy(key->keyNew,buffer,8);
260 iosFree(hId, buffer);
261 return ret;
264 //Get a input report from control pipe
265 s32 USBKeyboard_Get_OutputReport_Ctrl(keyboard *key,u8 *leds)
267 u8 *buffer = 0;
268 buffer = iosAlloc(hId, 1);
269 if (buffer == NULL)
270 return -1;
271 s32 ret = USB_WriteCtrlMsg(key->fd,USB_REQTYPE_GET,USB_REQ_GETREPORT, USB_REPTYPE_OUTPUT<<8 | 0,0,1,buffer);
272 memcpy(leds,buffer,1);
273 iosFree(hId, buffer);
274 return ret;
277 //Set a input report to control pipe
278 s32 USBKeyboard_Set_OutputReport_Ctrl(keyboard *key)
280 u8 *buffer = 0;
281 buffer = iosAlloc(hId, 1);
282 if (buffer == NULL)
283 return -1;
284 memcpy(buffer,&key->leds,1);
285 s32 ret = USB_WriteCtrlMsg(key->fd,USB_REQTYPE_SET,USB_REQ_SETREPORT, USB_REPTYPE_OUTPUT<<8 | 0,0,1,buffer);
286 iosFree(hId, buffer);
287 return ret;
290 void USBKeyboard_SubmitEvent(keyboard *key, USBKeyboard_eventType type, u8 code)
292 USBKeyboard_event ev;
293 ev.type = type;
294 ev.keyCode = code;
295 u8 i;
296 for (i=0;i<key->numCB;i++)
297 (*key->cb[i]) (ev,key->cbData[i]);
300 //Get the pressed touch and call the cb fonction
301 s32 USBKeyboard_GetState(keyboard *key)
303 u8 i;
304 u8 bad_message[6] = {0x01, 0x01, 0x01, 0x01, 0x01, 0x01};
305 if (USBKeyboard_Get_InputReport_Intr(key)<0)
306 return -1;
308 if (memcmp(key->keyNew + 2, bad_message, 6) == 0)
309 return 0;
311 if(key->keyNew[0] != key->oldState) {
312 if ((key->keyNew[0] & 0x02) && !(key->oldState & 0x02)) {
313 USBKeyboard_SubmitEvent(key, USBKEYBOARD_PRESSED, 0xe1);
314 } else if ((key->oldState & 0x02) && !(key->keyNew[0] & 0x02)) {
315 USBKeyboard_SubmitEvent(key, USBKEYBOARD_RELEASED, 0xe1);
318 if ((key->keyNew[0] & 0x20) && !(key->oldState & 0x20)) {
319 USBKeyboard_SubmitEvent(key, USBKEYBOARD_PRESSED, 0xe5);
320 } else if ((key->oldState & 0x20) && !(key->keyNew[0] & 0x20)) {
321 USBKeyboard_SubmitEvent(key, USBKEYBOARD_RELEASED, 0xe5);
324 if ((key->keyNew[0] & 0x01) && !(key->oldState & 0x01)) {
325 USBKeyboard_SubmitEvent(key, USBKEYBOARD_PRESSED, 0xe0);
326 } else if ((key->oldState & 0x01) && !(key->keyNew[0] & 0x01)) {
327 USBKeyboard_SubmitEvent(key, USBKEYBOARD_RELEASED, 0xe0);
330 if ((key->keyNew[0] & 0x10) && !(key->oldState & 0x10)) {
331 USBKeyboard_SubmitEvent(key, USBKEYBOARD_PRESSED, 0xe4);
332 } else if ((key->oldState & 0x10) && !(key->keyNew[0] & 0x10)) {
333 USBKeyboard_SubmitEvent(key, USBKEYBOARD_RELEASED, 0xe4);
336 if ((key->keyNew[0] & 0x04) && !(key->oldState & 0x04)) {
337 USBKeyboard_SubmitEvent(key, USBKEYBOARD_PRESSED, 0xe2);
338 } else if ((key->oldState & 0x04) && !(key->keyNew[0] & 0x04)) {
339 USBKeyboard_SubmitEvent(key, USBKEYBOARD_RELEASED, 0xe2);
342 if ((key->keyNew[0] & 0x40) && !(key->oldState & 0x40)) {
343 USBKeyboard_SubmitEvent(key, USBKEYBOARD_PRESSED, 0xe6);
344 } else if ((key->oldState & 0x40) && !(key->keyNew[0] & 0x40)) {
345 USBKeyboard_SubmitEvent(key, USBKEYBOARD_RELEASED, 0xe6);
348 if ((key->keyNew[0] & 0x08) && !(key->oldState & 0x08)) {
349 USBKeyboard_SubmitEvent(key, USBKEYBOARD_PRESSED, 0xe3);
350 } else if ((key->oldState & 0x08) && !(key->keyNew[0] & 0x08)) {
351 USBKeyboard_SubmitEvent(key, USBKEYBOARD_RELEASED, 0xe3);
354 if ((key->keyNew[0] & 0x80) && !(key->oldState & 0x80)) {
355 USBKeyboard_SubmitEvent(key, USBKEYBOARD_PRESSED, 0xe7);
356 } else if ((key->oldState & 0x80) && !(key->keyNew[0] & 0x80)) {
357 USBKeyboard_SubmitEvent(key, USBKEYBOARD_RELEASED, 0xe7);
360 for (i = 2; i < 8; i++)
362 if (key->keyOld[i] > 3 && memchr(key->keyNew + 2, key->keyOld[i], 6) == NULL)
364 USBKeyboard_SubmitEvent(key, USBKEYBOARD_RELEASED, key->keyOld[i]);
366 if (key->keyNew[i] > 3 && memchr(key->keyOld + 2, key->keyNew[i], 6) == NULL)
368 USBKeyboard_SubmitEvent(key, USBKEYBOARD_PRESSED, key->keyNew[i]);
371 memcpy(key->keyOld, key->keyNew, 8);
372 key->oldState = key->keyNew[0];
373 return 0;
376 //Put on the led led
377 s32 USBKeyboard_PutOnLed(keyboard *key,USBKeyboard_led led)
379 key->leds = key->leds | (1 << led );
380 if (USBKeyboard_Set_OutputReport_Ctrl(key)<0)
381 return -2;
382 return 1;
385 //Put off the led led
386 s32 USBKeyboard_PutOffLed(keyboard *key,USBKeyboard_led led)
388 key->leds = key->leds & (255 ^ (1 << led));
389 if (USBKeyboard_Set_OutputReport_Ctrl(key)<0)
390 return -2;
391 return 1;
394 //Switch the led led, put on if off or put off if on
395 s32 USBKeyboard_SwitchLed(keyboard *key,USBKeyboard_led led)
397 key->leds = key->leds ^ (1 << led);
398 if (USBKeyboard_Set_OutputReport_Ctrl(key)<0)
399 return -2;
400 return 1;
403 //Add a callback function who will handlethe keyboard events
404 s32 USBKeyboard_Add_EventCB(keyboard* key,eventcallback cb, void* data)
406 if (key->numCB==CBEVENT_MAXNUM)
407 return -1;
408 key->cb[key->numCB] = cb;
409 key->cbData[key->numCB] = data;
410 key->numCB++;
411 return key->numCB;
414 //Add a callback function who will handlethe keyboard events
415 s32 USBKeyboard_Remove_EventCB(keyboard* key,u8 n)
417 if (n>=CBEVENT_MAXNUM)
418 return -1;
419 u8 i;
420 for (i=n;i<key->numCB-1;i++)
422 key->cb[i] = key->cb[i+1];
423 key->cbData[i] = key->cbData[i+1];
425 key->numCB--;
426 return key->numCB;