1 /*-------------------------------------------------------------
3 usbmouse.c -- USB mouse support
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
27 -------------------------------------------------------------*/
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
67 static lwp_queue _queue
;
68 static lwpq_t _mouse_queue
;
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
));
85 __lwp_queue_append(&_queue
, (lwp_node
*) n
);
91 static s32
_mouse_event_cb(s32 result
,void *usrdata
)
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);
105 _mouse
->connected
= false;
110 //Callback when the mouse is disconnected
111 static s32
_disconnect(s32 retval
, void *data
)
113 _mouse
->connected
= false;
118 static s32
USBMouse_Initialize(void)
123 hId
= iosCreateHeap(HEAP_SIZE
);
131 //Destroy the io heap
132 static s32
USBMouse_Deinitialize(void)
138 retval
= iosDestroyHeap(hId
);
145 static void USBMouse_Close(void)
147 if (_mouse
&& _mouse
->fd
!= -1) {
148 USB_CloseDevice(&_mouse
->fd
);
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
;
161 u32 iConf
, iInterface
, iEp
;
163 usb_configurationdesc
*ucd
;
164 usb_interfacedesc
*uid
;
165 usb_endpointdesc
*ued
;
167 buffer
= iosAlloc(hId
, DEVLIST_MAXSIZE
* sizeof(usb_device_entry
));
171 memset(buffer
, 0, DEVLIST_MAXSIZE
* sizeof(usb_device_entry
));
173 if (USB_GetDeviceList(buffer
, DEVLIST_MAXSIZE
, USB_CLASS_HID
, &device_count
) < 0)
179 for (i
= 0; i
< device_count
; i
++)
184 if ((vid
== 0) || (pid
== 0))
188 if (USB_OpenDevice(buffer
[i
].device_id
, vid
, pid
, &fd
) < 0)
191 if (USB_GetDescriptors(fd
, &udd
) < 0) {
192 USB_CloseDevice(&fd
);
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
)
215 if (!(ued
->bEndpointAddress
& USB_ENDPOINT_IN
))
218 if (ued
->wMaxPacketSize
> MOUSE_MAX_DATA
)
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
;
244 USB_FreeDescriptors(&udd
);
249 USB_CloseDevice(&fd
);
257 if (USB_DeviceRemovalNotifyAsync(_mouse
->fd
, &_disconnect
, NULL
) < 0)
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;
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())
286 usleep(MOUSE_THREAD_UDELAY
);
291 //Initialize USB and USB_MOUSE and the event queue
294 if(_mouse_is_inited
) return 0;
296 if (USB_Initialize() != IPC_OK
)
299 if (USBMouse_Initialize() != IPC_OK
) {
303 _mousedata
= (s8
*)iosAlloc(hId
,MOUSE_MAX_DATA
);
304 _mouse
= (struct umouse
*) malloc(sizeof(struct umouse
));
305 memset(_mouse
, 0, sizeof(struct umouse
));
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
,
322 USBMouse_Deinitialize();
323 _mouse_thread_running
= false;
326 _mouse_thread_running
= true;
329 __lwp_queue_init_empty(&_queue
);
330 LWP_InitQueue(&_mouse_queue
);
331 _mouse_is_inited
= true;
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
);
351 USBMouse_Deinitialize();
352 if(_mousedata
!=NULL
) iosFree(hId
,_mousedata
);
353 if(_mouse
!=NULL
) free(_mouse
);
354 _mouse_is_inited
= false;
358 //Get the first event of the event queue
359 s32
MOUSE_GetEvent(mouse_event
*event
)
361 _node
*n
= (_node
*) __lwp_queue_get(&_queue
);
373 //Flush all pending events
374 s32
MOUSE_FlushEvents(void)
381 n
= (_node
*) __lwp_queue_get(&_queue
);