Fix libogc hardware lighting (GX_SetChanCtrl) - patch from https://sourceforge.net...
[libogc.git] / libogc / usbmouse.c
blob8be6c462a37a92d028c05cc139419041b0fe8899
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 //Destroy the io heap
132 static s32 USBMouse_Deinitialize(void)
134 if (hId < 0)
135 return -1;
137 s32 retval;
138 retval = iosDestroyHeap(hId);
139 hId = -1;
141 return retval;
144 //Close the device
145 static void USBMouse_Close(void)
147 if (_mouse && _mouse->fd != -1) {
148 USB_CloseDevice(&_mouse->fd);
149 _mouse->fd = -1;
153 //Search for a mouse connected to the wii usb port
154 //Thanks to Sven Peter usbstorage support
155 static s32 USBMouse_Open()
157 usb_device_entry *buffer;
158 u8 device_count, i;
159 u16 vid, pid;
160 bool found = false;
161 u32 iConf, iInterface, iEp;
162 usb_devdesc udd;
163 usb_configurationdesc *ucd;
164 usb_interfacedesc *uid;
165 usb_endpointdesc *ued;
167 buffer = iosAlloc(hId, DEVLIST_MAXSIZE * sizeof(usb_device_entry));
168 if(buffer == NULL)
169 return -1;
171 memset(buffer, 0, DEVLIST_MAXSIZE * sizeof(usb_device_entry));
173 if (USB_GetDeviceList(buffer, DEVLIST_MAXSIZE, USB_CLASS_HID, &device_count) < 0)
175 iosFree(hId,buffer);
176 return -2;
179 for (i = 0; i < device_count; i++)
181 vid = buffer[i].vid;
182 pid = buffer[i].pid;
184 if ((vid == 0) || (pid == 0))
185 continue;
187 s32 fd = 0;
188 if (USB_OpenDevice(buffer[i].device_id, vid, pid, &fd) < 0)
189 continue;
191 if (USB_GetDescriptors(fd, &udd) < 0) {
192 USB_CloseDevice(&fd);
193 continue;
196 for(iConf = 0; iConf < udd.bNumConfigurations; iConf++)
198 ucd = &udd.configurations[iConf];
200 for(iInterface = 0; iInterface < ucd->bNumInterfaces; iInterface++)
202 uid = &ucd->interfaces[iInterface];
204 if ((uid->bInterfaceClass == USB_CLASS_HID) &&
205 (uid->bInterfaceSubClass == USB_SUBCLASS_BOOT) &&
206 (uid->bInterfaceProtocol== USB_PROTOCOL_MOUSE))
208 for(iEp = 0; iEp < uid->bNumEndpoints; iEp++)
210 ued = &uid->endpoints[iEp];
212 if (ued->bmAttributes != USB_ENDPOINT_INTERRUPT)
213 continue;
215 if (!(ued->bEndpointAddress & USB_ENDPOINT_IN))
216 continue;
218 if (ued->wMaxPacketSize > MOUSE_MAX_DATA)
219 continue;
221 _mouse->fd = fd;
223 _mouse->configuration = ucd->bConfigurationValue;
224 _mouse->interface = uid->bInterfaceNumber;
225 _mouse->altInterface = uid->bAlternateSetting;
227 _mouse->ep = ued->bEndpointAddress;
228 _mouse->ep_size = ued->wMaxPacketSize;
230 found = true;
232 break;
236 if (found)
237 break;
240 if (found)
241 break;
244 USB_FreeDescriptors(&udd);
246 if (found)
247 break;
248 else
249 USB_CloseDevice(&fd);
252 iosFree(hId,buffer);
254 if (!found)
255 return -3;
257 if (USB_DeviceRemovalNotifyAsync(_mouse->fd, &_disconnect, NULL) < 0)
259 USBMouse_Close();
260 return -8;
263 //set boot protocol
264 USB_WriteCtrlMsg(_mouse->fd, USB_REQTYPE_SET, USB_REQ_SETPROTOCOL, 0, _mouse->interface, 0, NULL);
265 USB_ReadIntrMsgAsync(_mouse->fd, _mouse->ep, _mouse->ep_size, _mousedata, _mouse_event_cb, NULL);
266 _mouse->connected = true;
267 return 1;
270 bool MOUSE_IsConnected(void)
272 if (!_mouse) return false;
273 return _mouse->connected;
276 static void * _mouse_thread_func(void *arg)
278 while (!_mouse_thread_quit)
280 // scan for new attached mice
281 if (!MOUSE_IsConnected())
283 USBMouse_Close();
284 USBMouse_Open();
286 usleep(MOUSE_THREAD_UDELAY);
288 return NULL;
291 //Initialize USB and USB_MOUSE and the event queue
292 s32 MOUSE_Init(void)
294 if(_mouse_is_inited) return 0;
296 if (USB_Initialize() != IPC_OK)
297 return -1;
299 if (USBMouse_Initialize() != IPC_OK) {
300 return -2;
303 _mousedata = (s8*)iosAlloc(hId,MOUSE_MAX_DATA);
304 _mouse = (struct umouse *) malloc(sizeof(struct umouse));
305 memset(_mouse, 0, sizeof(struct umouse));
306 _mouse->fd = -1;
308 if (!_mouse_thread_running)
310 // start the mouse thread
311 _mouse_thread_quit = false;
312 memset(_mouse_stack, 0, MOUSE_THREAD_STACKSIZE);
314 s32 res = LWP_CreateThread(&_mouse_thread, _mouse_thread_func, NULL,
315 _mouse_stack, MOUSE_THREAD_STACKSIZE,
316 MOUSE_THREAD_PRIO);
318 if (res)
320 USBMouse_Close();
321 MOUSE_FlushEvents();
322 USBMouse_Deinitialize();
323 _mouse_thread_running = false;
324 return -6;
326 _mouse_thread_running = true;
329 __lwp_queue_init_empty(&_queue);
330 LWP_InitQueue(&_mouse_queue);
331 _mouse_is_inited = true;
332 return 0;
335 // Deinitialize USB_MOUSE and the event queue
336 s32 MOUSE_Deinit(void)
338 if(!_mouse_is_inited) return 1;
340 if (_mouse_thread_running) {
341 _mouse_thread_quit = true;
342 LWP_JoinThread(_mouse_thread, NULL);
343 _mouse_thread_running = false;
346 LWP_ThreadBroadcast(_mouse_queue);
347 LWP_CloseQueue(_mouse_queue);
349 USBMouse_Close();
350 MOUSE_FlushEvents();
351 USBMouse_Deinitialize();
352 if(_mousedata!=NULL) iosFree(hId,_mousedata);
353 if(_mouse!=NULL) free(_mouse);
354 _mouse_is_inited = false;
355 return 1;
358 //Get the first event of the event queue
359 s32 MOUSE_GetEvent(mouse_event *event)
361 _node *n = (_node *) __lwp_queue_get(&_queue);
363 if (!n)
364 return 0;
366 *event = n->event;
368 free(n);
370 return 1;
373 //Flush all pending events
374 s32 MOUSE_FlushEvents(void)
376 s32 res;
377 _node *n;
379 res = 0;
380 while (true) {
381 n = (_node *) __lwp_queue_get(&_queue);
383 if (!n)
384 break;
386 free(n);
387 res++;
390 return res;
393 #endif