usb patches (tueidj)
[libogc.git] / libogc / usbmouse.c
blob571e69102f91f10df065059183aab70c2142e27d
1 /*-------------------------------------------------------------
3 usbmouse.c -- USB mouse support
5 Copyright (C) 2009
6 Daryl Borth (Tantric)
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 #if defined(HW_RVL)
31 #include <string.h>
32 #include <malloc.h>
33 #include <unistd.h>
35 #include <gccore.h>
36 #include <ogc/usb.h>
37 #include <ogc/lwp_queue.h>
38 #include <ogc/usbmouse.h>
40 #define MOUSE_THREAD_STACKSIZE (1024 * 4)
41 #define MOUSE_THREAD_PRIO 65
42 #define MOUSE_THREAD_UDELAY (1000 * 1000 * 3)
44 #define MOUSE_MAX_DATA 20
46 #define HEAP_SIZE 4096
47 #define DEVLIST_MAXSIZE 8
49 typedef struct {
50 lwp_node node;
51 mouse_event event;
52 } _node;
54 struct umouse {
55 bool connected;
57 s32 fd;
59 u8 configuration;
60 u32 interface;
61 u32 altInterface;
63 u8 ep;
64 u32 ep_size;
67 static lwp_queue _queue;
68 static lwpq_t _mouse_queue;
70 static s32 hId = -1;
71 static bool _mouse_is_inited = false;
72 static lwp_t _mouse_thread = LWP_THREAD_NULL;
73 static bool _mouse_thread_running = false;
74 static bool _mouse_thread_quit = false;
75 static struct umouse *_mouse = NULL;
76 static s8 *_mousedata = NULL;
78 static u8 _mouse_stack[MOUSE_THREAD_STACKSIZE] ATTRIBUTE_ALIGN(8);
80 //Add an event to the event queue
81 static s32 _mouse_addEvent(const mouse_event *event) {
82 _node *n = malloc(sizeof(_node));
83 n->event = *event;
85 __lwp_queue_append(&_queue, (lwp_node*) n);
87 return 1;
90 // Event callback
91 static s32 _mouse_event_cb(s32 result,void *usrdata)
93 mouse_event event;
95 if (result>0)
97 event.button = _mousedata[0];
98 event.rx = _mousedata[1];
99 event.ry = _mousedata[2];
100 _mouse_addEvent(&event);
101 USB_ReadIntrMsgAsync(_mouse->fd, _mouse->ep, _mouse->ep_size, _mousedata, _mouse_event_cb, 0);
103 else
105 _mouse->connected = false;
107 return 0;
110 //Callback when the mouse is disconnected
111 static s32 _disconnect(s32 retval, void *data)
113 _mouse->connected = false;
114 return 1;
117 //init the ioheap
118 static s32 USBMouse_Initialize(void)
120 if (hId > 0)
121 return 0;
123 hId = iosCreateHeap(HEAP_SIZE);
125 if (hId < 0)
126 return IPC_ENOHEAP;
128 return IPC_OK;
131 static s32 USBMouse_Deinitialize(void)
133 return IPC_OK;
136 //Close the device
137 static void USBMouse_Close(void)
139 if (_mouse && _mouse->fd != -1) {
140 USB_CloseDevice(&_mouse->fd);
141 _mouse->fd = -1;
145 //Search for a mouse connected to the wii usb port
146 //Thanks to Sven Peter usbstorage support
147 static s32 USBMouse_Open()
149 usb_device_entry *buffer;
150 u8 device_count, i;
151 u16 vid, pid;
152 bool found = false;
153 u32 iConf, iInterface, iEp;
154 usb_devdesc udd;
155 usb_configurationdesc *ucd;
156 usb_interfacedesc *uid;
157 usb_endpointdesc *ued;
159 buffer = iosAlloc(hId, DEVLIST_MAXSIZE * sizeof(usb_device_entry));
160 if(buffer == NULL)
161 return -1;
163 memset(buffer, 0, DEVLIST_MAXSIZE * sizeof(usb_device_entry));
165 if (USB_GetDeviceList(buffer, DEVLIST_MAXSIZE, USB_CLASS_HID, &device_count) < 0)
167 iosFree(hId,buffer);
168 return -2;
171 for (i = 0; i < device_count; i++)
173 vid = buffer[i].vid;
174 pid = buffer[i].pid;
176 if ((vid == 0) || (pid == 0))
177 continue;
179 s32 fd = 0;
180 if (USB_OpenDevice(buffer[i].device_id, vid, pid, &fd) < 0)
181 continue;
183 if (USB_GetDescriptors(fd, &udd) < 0) {
184 USB_CloseDevice(&fd);
185 continue;
188 for(iConf = 0; iConf < udd.bNumConfigurations; iConf++)
190 ucd = &udd.configurations[iConf];
192 for(iInterface = 0; iInterface < ucd->bNumInterfaces; iInterface++)
194 uid = &ucd->interfaces[iInterface];
196 if ((uid->bInterfaceClass == USB_CLASS_HID) &&
197 (uid->bInterfaceSubClass == USB_SUBCLASS_BOOT) &&
198 (uid->bInterfaceProtocol== USB_PROTOCOL_MOUSE))
200 for(iEp = 0; iEp < uid->bNumEndpoints; iEp++)
202 ued = &uid->endpoints[iEp];
204 if (ued->bmAttributes != USB_ENDPOINT_INTERRUPT)
205 continue;
207 if (!(ued->bEndpointAddress & USB_ENDPOINT_IN))
208 continue;
210 if (ued->wMaxPacketSize > MOUSE_MAX_DATA)
211 continue;
213 _mouse->fd = fd;
215 _mouse->configuration = ucd->bConfigurationValue;
216 _mouse->interface = uid->bInterfaceNumber;
217 _mouse->altInterface = uid->bAlternateSetting;
219 _mouse->ep = ued->bEndpointAddress;
220 _mouse->ep_size = ued->wMaxPacketSize;
222 found = true;
224 break;
228 if (found)
229 break;
232 if (found)
233 break;
236 USB_FreeDescriptors(&udd);
238 if (found)
239 break;
240 else
241 USB_CloseDevice(&fd);
244 iosFree(hId,buffer);
246 if (!found)
247 return -3;
249 if (USB_DeviceRemovalNotifyAsync(_mouse->fd, &_disconnect, NULL) < 0)
251 USBMouse_Close();
252 return -8;
255 //set boot protocol
256 USB_WriteCtrlMsg(_mouse->fd, USB_REQTYPE_INTERFACE_SET, USB_REQ_SETPROTOCOL, 0, _mouse->interface, 0, NULL);
257 USB_ReadIntrMsgAsync(_mouse->fd, _mouse->ep, _mouse->ep_size, _mousedata, _mouse_event_cb, NULL);
258 _mouse->connected = true;
259 return 1;
262 bool MOUSE_IsConnected(void)
264 if (!_mouse) return false;
265 return _mouse->connected;
268 static void * _mouse_thread_func(void *arg)
270 while (!_mouse_thread_quit)
272 // scan for new attached mice
273 if (!MOUSE_IsConnected())
275 USBMouse_Close();
276 USBMouse_Open();
278 usleep(MOUSE_THREAD_UDELAY);
280 return NULL;
283 //Initialize USB and USB_MOUSE and the event queue
284 s32 MOUSE_Init(void)
286 if(_mouse_is_inited) return 0;
288 if (USB_Initialize() != IPC_OK)
289 return -1;
291 if (USBMouse_Initialize() != IPC_OK) {
292 return -2;
295 _mousedata = (s8*)iosAlloc(hId,MOUSE_MAX_DATA);
296 _mouse = (struct umouse *) malloc(sizeof(struct umouse));
297 memset(_mouse, 0, sizeof(struct umouse));
298 _mouse->fd = -1;
300 if (!_mouse_thread_running)
302 // start the mouse thread
303 _mouse_thread_quit = false;
304 memset(_mouse_stack, 0, MOUSE_THREAD_STACKSIZE);
306 s32 res = LWP_CreateThread(&_mouse_thread, _mouse_thread_func, NULL,
307 _mouse_stack, MOUSE_THREAD_STACKSIZE,
308 MOUSE_THREAD_PRIO);
310 if (res)
312 USBMouse_Close();
313 MOUSE_FlushEvents();
314 USBMouse_Deinitialize();
315 _mouse_thread_running = false;
316 return -6;
318 _mouse_thread_running = true;
321 __lwp_queue_init_empty(&_queue);
322 LWP_InitQueue(&_mouse_queue);
323 _mouse_is_inited = true;
324 return 0;
327 // Deinitialize USB_MOUSE and the event queue
328 s32 MOUSE_Deinit(void)
330 if(!_mouse_is_inited) return 1;
332 if (_mouse_thread_running) {
333 _mouse_thread_quit = true;
334 LWP_JoinThread(_mouse_thread, NULL);
335 _mouse_thread_running = false;
338 LWP_ThreadBroadcast(_mouse_queue);
339 LWP_CloseQueue(_mouse_queue);
341 USBMouse_Close();
342 MOUSE_FlushEvents();
343 USBMouse_Deinitialize();
344 if(_mousedata!=NULL) iosFree(hId,_mousedata);
345 if(_mouse!=NULL) free(_mouse);
346 _mouse_is_inited = false;
347 return 1;
350 //Get the first event of the event queue
351 s32 MOUSE_GetEvent(mouse_event *event)
353 _node *n = (_node *) __lwp_queue_get(&_queue);
355 if (!n)
356 return 0;
358 *event = n->event;
360 free(n);
362 return 1;
365 //Flush all pending events
366 s32 MOUSE_FlushEvents(void)
368 s32 res;
369 _node *n;
371 res = 0;
372 while (true) {
373 n = (_node *) __lwp_queue_get(&_queue);
375 if (!n)
376 break;
378 free(n);
379 res++;
382 return res;
385 #endif