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 static s32
USBMouse_Deinitialize(void)
137 static void USBMouse_Close(void)
139 if (_mouse
&& _mouse
->fd
!= -1) {
140 USB_CloseDevice(&_mouse
->fd
);
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
;
153 u32 iConf
, iInterface
, iEp
;
155 usb_configurationdesc
*ucd
;
156 usb_interfacedesc
*uid
;
157 usb_endpointdesc
*ued
;
159 buffer
= iosAlloc(hId
, DEVLIST_MAXSIZE
* sizeof(usb_device_entry
));
163 memset(buffer
, 0, DEVLIST_MAXSIZE
* sizeof(usb_device_entry
));
165 if (USB_GetDeviceList(buffer
, DEVLIST_MAXSIZE
, USB_CLASS_HID
, &device_count
) < 0)
171 for (i
= 0; i
< device_count
; i
++)
176 if ((vid
== 0) || (pid
== 0))
180 if (USB_OpenDevice(buffer
[i
].device_id
, vid
, pid
, &fd
) < 0)
183 if (USB_GetDescriptors(fd
, &udd
) < 0) {
184 USB_CloseDevice(&fd
);
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
)
207 if (!(ued
->bEndpointAddress
& USB_ENDPOINT_IN
))
210 if (ued
->wMaxPacketSize
> MOUSE_MAX_DATA
)
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
;
236 USB_FreeDescriptors(&udd
);
241 USB_CloseDevice(&fd
);
249 if (USB_DeviceRemovalNotifyAsync(_mouse
->fd
, &_disconnect
, NULL
) < 0)
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;
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())
278 usleep(MOUSE_THREAD_UDELAY
);
283 //Initialize USB and USB_MOUSE and the event queue
286 if(_mouse_is_inited
) return 0;
288 if (USB_Initialize() != IPC_OK
)
291 if (USBMouse_Initialize() != IPC_OK
) {
295 _mousedata
= (s8
*)iosAlloc(hId
,MOUSE_MAX_DATA
);
296 _mouse
= (struct umouse
*) malloc(sizeof(struct umouse
));
297 memset(_mouse
, 0, sizeof(struct umouse
));
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
,
314 USBMouse_Deinitialize();
315 _mouse_thread_running
= false;
318 _mouse_thread_running
= true;
321 __lwp_queue_init_empty(&_queue
);
322 LWP_InitQueue(&_mouse_queue
);
323 _mouse_is_inited
= true;
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
);
343 USBMouse_Deinitialize();
344 if(_mousedata
!=NULL
) iosFree(hId
,_mousedata
);
345 if(_mouse
!=NULL
) free(_mouse
);
346 _mouse_is_inited
= false;
350 //Get the first event of the event queue
351 s32
MOUSE_GetEvent(mouse_event
*event
)
353 _node
*n
= (_node
*) __lwp_queue_get(&_queue
);
365 //Flush all pending events
366 s32
MOUSE_FlushEvents(void)
373 n
= (_node
*) __lwp_queue_get(&_queue
);