change PAD_ScanPads()s behaviour. the return value now contains a bitmask of the...
[libogc.git] / libogc / usb.c
blobcaa8831e6bf6afc18d01a6120ab01af625a97c21
1 /*-------------------------------------------------------------
3 usb.c -- USB lowlevel
5 Copyright (C) 2008
6 Michael Wiedenbauer (shagkur)
7 Dave Murphy (WinterMute)
8 tueidj
10 This software is provided 'as-is', without any express or implied
11 warranty. In no event will the authors be held liable for any
12 damages arising from the use of this software.
14 Permission is granted to anyone to use this software for any
15 purpose, including commercial applications, and to alter it and
16 redistribute it freely, subject to the following restrictions:
18 1. The origin of this software must not be misrepresented; you
19 must not claim that you wrote the original software. If you use
20 this software in a product, an acknowledgment in the product
21 documentation would be appreciated but is not required.
23 2. Altered source versions must be plainly marked as such, and
24 must not be misrepresented as being the original software.
26 3. This notice may not be removed or altered from any source
27 distribution.
29 -------------------------------------------------------------*/
32 /* Note: There are 3 types of USB interfaces here, the early ones
33 * (V0: /dev/usb/oh0 and /dev/usb/oh1) and two later ones (V5: /dev/usb/ven
34 * and /dev/usb/hid) which are similar but have some small
35 * differences. There is also an earlier version of /dev/usb/hid (V4)
36 * found in IOSes 37,61,56,etc. and /dev/usb/msc found in IOS 57.
37 * These interfaces aren't implemented here and you may find some
38 * devices don't show up if you're running under those IOSes.
41 #if defined(HW_RVL)
42 #include <stdlib.h>
43 #include <stdio.h>
44 #include <string.h>
45 #include <malloc.h>
46 #include <time.h>
47 #include <gcutil.h>
48 #include <ogcsys.h>
49 #include <ipc.h>
50 #include <asm.h>
51 #include <processor.h>
53 #include "usb.h"
55 #define USB_HEAPSIZE 16384
57 #define USBV0_IOCTL_CTRLMSG 0
58 #define USBV0_IOCTL_BLKMSG 1
59 #define USBV0_IOCTL_INTRMSG 2
60 #define USBV0_IOCTL_SUSPENDDEV 5
61 #define USBV0_IOCTL_RESUMEDEV 6
62 #define USBV0_IOCTL_ISOMSG 9
63 #define USBV0_IOCTL_GETDEVLIST 12
64 #define USBV0_IOCTL_DEVREMOVALHOOK 26
65 #define USBV0_IOCTL_DEVINSERTHOOK 27
66 #define USBV0_IOCTL_DEVICECLASSCHANGE 28
68 #define USBV4_IOCTL_GETVERSION 6 // returns 0x40001
70 #define USBV5_IOCTL_GETVERSION 0 // should return 0x50001
71 #define USBV5_IOCTL_GETDEVICECHANGE 1
72 #define USBV5_IOCTL_SHUTDOWN 2
73 #define USBV5_IOCTL_GETDEVPARAMS 3
74 #define USBV5_IOCTL_ATTACHFINISH 6
75 #define USBV5_IOCTL_SETALTERNATE 7
76 #define USBV5_IOCTL_SUSPEND_RESUME 16
77 #define USBV5_IOCTL_CANCELENDPOINT 17
78 #define USBV5_IOCTL_CTRLMSG 18
79 #define USBV5_IOCTL_INTRMSG 19
80 #define USBV5_IOCTL_ISOMSG 20
81 #define USBV5_IOCTL_BULKMSG 21
82 #define USBV5_IOCTL_MSC_READWRITE_ASYNC 32 /* unimplemented */
83 #define USBV5_IOCTL_MSC_READ_ASYNC 33 /* unimplemented */
84 #define USBV5_IOCTL_MSC_WRITE_ASYNC 34 /* unimplemented */
85 #define USBV5_IOCTL_MSC_READWRITE 35 /* unimplemented */
86 #define USBV5_IOCTL_MSC_RESET 36 /* unimplemented */
88 #define USB_MAX_DEVICES 32
90 static s32 hId = -1;
91 static const char __oh0_path[] ATTRIBUTE_ALIGN(32) = "/dev/usb/oh0";
92 static const char __ven_path[] ATTRIBUTE_ALIGN(32) = "/dev/usb/ven";
93 static const char __hid_path[] ATTRIBUTE_ALIGN(32) = "/dev/usb/hid";
95 struct _usb_cb_removalnotify_list {
96 usbcallback cb;
97 void *userdata;
98 s32 device_id;
101 struct _usbv5_host {
102 usb_device_entry attached_devices[USB_MAX_DEVICES];
103 struct _usb_cb_removalnotify_list remove_cb[USB_MAX_DEVICES];
104 s32 fd;
105 usbcallback device_change_notify;
106 void *device_change_userdata;
109 static struct _usbv5_host* ven_host = NULL;
110 static struct _usbv5_host* hid_host = NULL;
112 struct _usb_msg {
113 s32 fd;
114 u32 heap_buffers;
115 union {
116 struct {
117 u8 bmRequestType;
118 u8 bmRequest;
119 u16 wValue;
120 u16 wIndex;
121 u16 wLength;
122 void *rpData;
123 } ctrl;
125 struct {
126 void *rpData;
127 u16 wLength;
128 u8 pad[4];
129 u8 bEndpoint;
130 } bulk;
132 struct {
133 void *rpData;
134 u16 wLength;
135 u8 bEndpoint;
136 } intr;
138 struct {
139 void *rpData;
140 void *rpPacketSizes;
141 u8 bPackets;
142 u8 bEndpoint;
143 } iso;
145 struct {
146 u16 pid;
147 u16 vid;
148 } notify;
150 u8 class;
151 u32 hid_intr_dir;
153 u32 align_pad[4]; // pad to 24 bytes
155 usbcallback cb;
156 void *userdata;
157 ioctlv vec[7];
160 static s32 __usbv5_devicechangeCB(s32 result, void *p);
162 static s32 __usbv5_attachfinishCB(s32 result, void *p)
164 struct _usbv5_host* host = (struct _usbv5_host*)p;
165 if(host==NULL) return IPC_EINVAL;
167 if (host->device_change_notify) {
168 /* this callback function may attempt to set a new notify func,
169 * device_change_notify is set to NULL *before* calling it to
170 * avoid wiping out the new function
172 usbcallback cb = host->device_change_notify;
173 host->device_change_notify = NULL;
174 cb(result, host->device_change_userdata);
177 if (result==0)
178 IOS_IoctlAsync(host->fd, USBV5_IOCTL_GETDEVICECHANGE, NULL, 0, host->attached_devices, 0x180, __usbv5_devicechangeCB, host);
180 return IPC_OK;
183 static s32 __usbv5_devicechangeCB(s32 result, void *p)
185 int i, j;
186 struct _usbv5_host* host = (struct _usbv5_host*)p;
188 if(host==NULL) return IPC_EINVAL;
190 if (result>=0) {
191 // can't check the remove callbacks only if the number of devices has decreased,
192 // because devices may have been inserted as well as removed
193 for (i=0; i<USB_MAX_DEVICES; i++) {
194 if (host->remove_cb[i].cb==NULL)
195 continue;
196 for (j=0; j<result; j++) {
197 if (host->remove_cb[i].device_id == host->attached_devices[j].device_id)
198 break;
201 if (j==result) { // execute callback and remove it
202 host->remove_cb[i].cb(0, host->remove_cb[i].userdata);
203 host->remove_cb[i].cb = NULL;
206 // wipe unused device entries
207 memset(host->attached_devices+result, 0, sizeof(usb_device_entry)*(32-result));
209 IOS_IoctlAsync(host->fd, USBV5_IOCTL_ATTACHFINISH, NULL, 0, NULL, 0, __usbv5_attachfinishCB, host);
212 return IPC_OK;
216 static s32 __usbv5_messageCB(s32 result,void *_msg)
218 struct _usb_msg *msg = (struct _usb_msg*)_msg;
220 if(msg==NULL) return IPC_EINVAL;
222 if(msg->cb!=NULL) msg->cb(result, msg->userdata);
224 iosFree(hId,msg);
226 return IPC_OK;
229 static s32 __usbv0_messageCB(s32 result,void *usrdata)
231 u32 i;
232 struct _usb_msg *msg = (struct _usb_msg*)usrdata;
234 if(msg==NULL) return IPC_EINVAL;
236 if(msg->cb!=NULL) msg->cb(result, msg->userdata);
238 for(i=0; i<msg->heap_buffers; i++) {
239 if(msg->vec[i].data!=NULL)
240 iosFree(hId,msg->vec[i].data);
243 iosFree(hId,msg);
245 return IPC_OK;
248 static s32 __find_device_on_host(struct _usbv5_host *host, s32 device_id)
250 int i;
251 if (host==NULL) return -1;
253 for (i=0; host->attached_devices[i].device_id; i++) {
254 if (host->attached_devices[i].device_id == device_id)
255 return i;
258 return -1;
261 static s32 __usb_isochronous_message(s32 device_id,u8 bEndpoint,u8 bPackets,u16* rpPacketSizes,void* rpData,usbcallback cb,void *userdata)
263 s32 ret = IPC_ENOMEM;
264 struct _usb_msg *msg;
265 u16 wLength=0;
266 u8 i;
268 for (i=0; i<bPackets; i++)
269 wLength += rpPacketSizes[i];
271 if(wLength==0) return IPC_EINVAL;
272 if(((u32)rpData%32)!=0) return IPC_EINVAL;
273 if(((u32)rpPacketSizes%32)!=0) return IPC_EINVAL;
274 if(bPackets==0) return IPC_EINVAL;
275 if(rpPacketSizes==NULL || rpData==NULL) return IPC_EINVAL;
277 msg = (struct _usb_msg*)iosAlloc(hId,sizeof(struct _usb_msg));
278 if(msg==NULL) return IPC_ENOMEM;
280 memset(msg, 0, sizeof(struct _usb_msg));
282 msg->fd = device_id;
283 msg->cb = cb;
284 msg->userdata = userdata;
286 if (device_id>=0 && device_id<0x20) {
287 u8 *pEndp=NULL;
288 u16 *pLength=NULL;
289 u8 *pPackets=NULL;
291 pEndp = (u8*)iosAlloc(hId,32);
292 if(pEndp==NULL) goto done;
293 *pEndp = bEndpoint;
295 pLength = (u16*)iosAlloc(hId,32);
296 if(pLength==NULL) goto done;
297 // NOT byteswapped!
298 *pLength = wLength;
300 pPackets = (u8*)iosAlloc(hId,32);
301 if(pPackets==NULL) goto done;
302 *pPackets = bPackets;
304 msg->heap_buffers = 3;
306 msg->vec[0].data = pEndp;
307 msg->vec[0].len = sizeof(u8);
308 msg->vec[1].data = pLength;
309 msg->vec[1].len = sizeof(u16);
310 msg->vec[2].data = pPackets;
311 msg->vec[2].len = sizeof(u8);
312 msg->vec[3].data = rpPacketSizes;
313 msg->vec[3].len = sizeof(u16)*bPackets;
314 msg->vec[4].data = rpData;
315 msg->vec[4].len = wLength;
317 if (cb==NULL)
318 ret = IOS_Ioctlv(device_id, USBV0_IOCTL_ISOMSG, 3, 2, msg->vec);
319 else
320 return IOS_IoctlvAsync(device_id, USBV0_IOCTL_ISOMSG, 3, 2, msg->vec, __usbv0_messageCB, msg);
322 done:
323 if(pEndp) iosFree(hId,pEndp);
324 if(pLength) iosFree(hId,pLength);
325 if(pPackets) iosFree(hId,pPackets);
326 } else {
327 u8 endpoint_dir = !!(bEndpoint&USB_ENDPOINT_IN);
328 s32 fd = (device_id<0) ? ven_host->fd : hid_host->fd;
330 msg->iso.rpData = rpData;
331 msg->iso.rpPacketSizes = rpPacketSizes;
332 msg->iso.bEndpoint = bEndpoint;
333 msg->iso.bPackets = bPackets;
335 msg->vec[0].data = msg;
336 msg->vec[0].len = 64;
337 // block counts are used for both input and output
338 msg->vec[1].data = msg->vec[3].data = rpPacketSizes;
339 msg->vec[1].len = msg->vec[3].len = sizeof(u16)*bPackets;
340 msg->vec[2].data = rpData;
341 msg->vec[2].len = wLength;
343 if (cb==NULL)
344 ret = IOS_Ioctlv(fd, USBV5_IOCTL_ISOMSG, 2-endpoint_dir, 2+endpoint_dir, msg->vec);
345 else
346 return IOS_IoctlvAsync(fd, USBV5_IOCTL_ISOMSG, 2-endpoint_dir, 2+endpoint_dir, msg->vec, __usbv5_messageCB, msg);
349 if (msg!=NULL) iosFree(hId,msg);
351 return ret;
354 static s32 __usb_control_message(s32 device_id,u8 bmRequestType,u8 bmRequest,u16 wValue,u16 wIndex,u16 wLength,void *rpData,usbcallback cb,void *userdata)
356 s32 ret = IPC_ENOMEM;
357 struct _usb_msg *msg;
359 if(((s32)rpData%32)!=0) return IPC_EINVAL;
360 if(wLength && !rpData) return IPC_EINVAL;
361 if(!wLength && rpData) return IPC_EINVAL;
363 msg = (struct _usb_msg*)iosAlloc(hId,sizeof(struct _usb_msg));
364 if(msg==NULL) return IPC_ENOMEM;
366 memset(msg, 0, sizeof(struct _usb_msg));
368 msg->fd = device_id;
369 msg->cb = cb;
370 msg->userdata = userdata;
372 if (device_id>=0 && device_id<0x20) {
373 u8 *pRqType = NULL,*pRq = NULL,*pNull = NULL;
374 u16 *pValue = NULL,*pIndex = NULL,*pLength = NULL;
376 pRqType = (u8*)iosAlloc(hId,32);
377 if(pRqType==NULL) goto done;
378 *pRqType = bmRequestType;
380 pRq = (u8*)iosAlloc(hId,32);
381 if(pRq==NULL) goto done;
382 *pRq = bmRequest;
384 pValue = (u16*)iosAlloc(hId,32);
385 if(pValue==NULL) goto done;
386 *pValue = bswap16(wValue);
388 pIndex = (u16*)iosAlloc(hId,32);
389 if(pIndex==NULL) goto done;
390 *pIndex = bswap16(wIndex);
392 pLength = (u16*)iosAlloc(hId,32);
393 if(pLength==NULL) goto done;
394 *pLength = bswap16(wLength);
396 pNull = (u8*)iosAlloc(hId,32);
397 if(pNull==NULL) goto done;
398 *pNull = 0;
400 msg->heap_buffers = 6;
402 msg->vec[0].data = pRqType;
403 msg->vec[0].len = sizeof(u8);
404 msg->vec[1].data = pRq;
405 msg->vec[1].len = sizeof(u8);
406 msg->vec[2].data = pValue;
407 msg->vec[2].len = sizeof(u16);
408 msg->vec[3].data = pIndex;
409 msg->vec[3].len = sizeof(u16);
410 msg->vec[4].data = pLength;
411 msg->vec[4].len = sizeof(u16);
412 msg->vec[5].data = pNull;
413 msg->vec[5].len = sizeof(u8);
414 msg->vec[6].data = rpData;
415 msg->vec[6].len = wLength;
417 if (cb==NULL)
418 ret = IOS_Ioctlv(device_id, USBV0_IOCTL_CTRLMSG, 6, 1, msg->vec);
419 else
420 return IOS_IoctlvAsync(device_id, USBV0_IOCTL_CTRLMSG, 6, 1, msg->vec, __usbv0_messageCB, msg);
422 done:
423 if(pRqType!=NULL) iosFree(hId,pRqType);
424 if(pRq!=NULL) iosFree(hId,pRq);
425 if(pValue!=NULL) iosFree(hId,pValue);
426 if(pIndex!=NULL) iosFree(hId,pIndex);
427 if(pLength!=NULL) iosFree(hId,pLength);
428 if(pNull!=NULL) iosFree(hId,pNull);
430 } else {
431 u8 request_dir = !!(bmRequestType&USB_CTRLTYPE_DIR_DEVICE2HOST);
432 s32 fd = (device_id<0) ? ven_host->fd : hid_host->fd;
434 msg->ctrl.bmRequestType = bmRequestType;
435 msg->ctrl.bmRequest = bmRequest;
436 msg->ctrl.wValue = wValue;
437 msg->ctrl.wIndex = wIndex;
438 msg->ctrl.wLength = wLength;
439 msg->ctrl.rpData = rpData;
441 msg->vec[0].data = msg;
442 msg->vec[0].len = 64;
443 msg->vec[1].data = rpData;
444 msg->vec[1].len = wLength;
446 if (cb==NULL)
447 ret = IOS_Ioctlv(fd, USBV5_IOCTL_CTRLMSG, 2-request_dir, request_dir, msg->vec);
448 else
449 return IOS_IoctlvAsync(fd, USBV5_IOCTL_CTRLMSG, 2-request_dir, request_dir, msg->vec, __usbv5_messageCB, msg);
452 if(msg!=NULL) iosFree(hId,msg);
454 return ret;
457 static inline s32 __usb_interrupt_bulk_message(s32 device_id,u8 ioctl,u8 bEndpoint,u16 wLength,void *rpData,usbcallback cb,void *userdata)
459 s32 ret = IPC_ENOMEM;
460 struct _usb_msg *msg;
462 if(((s32)rpData%32)!=0) return IPC_EINVAL;
463 if(wLength && !rpData) return IPC_EINVAL;
464 if(!wLength && rpData) return IPC_EINVAL;
466 msg = (struct _usb_msg*)iosAlloc(hId,sizeof(struct _usb_msg));
467 if(msg==NULL) return IPC_ENOMEM;
469 memset(msg, 0, sizeof(struct _usb_msg));
471 msg->fd = device_id;
472 msg->cb = cb;
473 msg->userdata = userdata;
475 if (device_id>=0 && device_id<0x20) {
476 u8 *pEndP = NULL;
477 u16 *pLength = NULL;
479 pEndP = (u8*)iosAlloc(hId,32);
480 if(pEndP==NULL) goto done;
481 *pEndP = bEndpoint;
483 pLength = (u16*)iosAlloc(hId,32);
484 if(pLength==NULL) goto done;
485 *pLength = wLength;
487 msg->vec[0].data = pEndP;
488 msg->vec[0].len = sizeof(u8);
489 msg->vec[1].data = pLength;
490 msg->vec[1].len = sizeof(u16);
491 msg->vec[2].data = rpData;
492 msg->vec[2].len = wLength;
494 msg->heap_buffers = 2;
496 if (cb==NULL)
497 ret = IOS_Ioctlv(device_id,ioctl,2,1,msg->vec);
498 else
499 return IOS_IoctlvAsync(device_id,ioctl,2,1,msg->vec,__usbv0_messageCB,msg);
501 done:
502 if(pEndP!=NULL) iosFree(hId,pEndP);
503 if(pLength!=NULL) iosFree(hId,pLength);
505 } else {
506 u8 endpoint_dir = !!(bEndpoint&USB_ENDPOINT_IN);
507 s32 fd = (device_id<0) ? ven_host->fd : hid_host->fd;
509 if (ioctl == USBV0_IOCTL_INTRMSG) {
510 // HID does this a little bit differently
511 if (device_id>=0)
512 msg->hid_intr_dir = !endpoint_dir;
513 else {
514 msg->intr.rpData = rpData;
515 msg->intr.wLength = wLength;
516 msg->intr.bEndpoint = bEndpoint;
518 ioctl = USBV5_IOCTL_INTRMSG;
519 } else {
520 msg->bulk.rpData = rpData;
521 msg->bulk.wLength = wLength;
522 msg->bulk.bEndpoint = bEndpoint;
523 ioctl = USBV5_IOCTL_BULKMSG;
526 msg->vec[0].data = msg;
527 msg->vec[0].len = 64;
528 msg->vec[1].data = rpData;
529 msg->vec[1].len = wLength;
531 if (cb==NULL)
532 ret = IOS_Ioctlv(fd, ioctl, 2-endpoint_dir, endpoint_dir, msg->vec);
533 else
534 return IOS_IoctlvAsync(fd, ioctl, 2-endpoint_dir, endpoint_dir, msg->vec, __usbv5_messageCB, msg);
537 if(msg!=NULL) iosFree(hId,msg);
539 return ret;
542 static inline s32 __usb_getdesc(s32 fd, u8 *buffer, u8 valuehi, u8 valuelo, u16 index, u16 size)
544 u8 requestType = USB_CTRLTYPE_DIR_DEVICE2HOST;
546 if (valuehi==USB_DT_HID || valuehi==USB_DT_REPORT || valuehi==USB_DT_PHYSICAL)
547 requestType |= USB_CTRLTYPE_REC_INTERFACE;
549 return __usb_control_message(fd, requestType, USB_REQ_GETDESCRIPTOR, (valuehi << 8) | valuelo, index, size, buffer, NULL, NULL);
552 static u32 __find_next_endpoint(u8 *buffer,s32 size,u8 align)
554 u8 *ptr = buffer;
556 while(size>2 && buffer[0]) { // abort if buffer[0]==0 to avoid getting stuck
557 if(buffer[1]==USB_DT_ENDPOINT || buffer[1]==USB_DT_INTERFACE)
558 break;
560 size -= (buffer[0]+align)&~align;
561 buffer += (buffer[0]+align)&~align;
564 return (buffer - ptr);
567 s32 USB_Initialize()
569 if(hId==-1) hId = iosCreateHeap(USB_HEAPSIZE);
570 if(hId<0) return IPC_ENOMEM;
572 if (ven_host==NULL) {
573 s32 ven_fd = IOS_Open(__ven_path, IPC_OPEN_NONE);
574 if (ven_fd>=0) {
575 ven_host = (struct _usbv5_host*)iosAlloc(hId, sizeof(*ven_host));
576 if (ven_host==NULL) {
577 IOS_Close(ven_fd);
578 return IPC_ENOMEM;
580 memset(ven_host, 0, sizeof(*ven_host));
581 ven_host->fd = ven_fd;
583 u32 *ven_ver = (u32*)iosAlloc(hId, 0x20);
584 if (ven_ver==NULL) goto mem_error;
585 if (IOS_Ioctl(ven_fd, USBV5_IOCTL_GETVERSION, NULL, 0, ven_ver, 0x20)==0 && ven_ver[0]==0x50001)
586 IOS_IoctlAsync(ven_fd, USBV5_IOCTL_GETDEVICECHANGE, NULL, 0, ven_host->attached_devices, 0x180, __usbv5_devicechangeCB, ven_host);
587 else {
588 // wrong ven version
589 IOS_Close(ven_fd);
590 iosFree(hId, ven_host);
591 ven_host = NULL;
594 iosFree(hId, ven_ver);
598 if (hid_host==NULL) {
599 s32 hid_fd = IOS_Open(__hid_path, IPC_OPEN_NONE);
600 if (hid_fd>=0) {
601 hid_host = (struct _usbv5_host*)iosAlloc(hId, sizeof(*hid_host));
602 if (hid_host==NULL) {
603 IOS_Close(hid_fd);
604 goto mem_error;
606 memset(hid_host, 0, sizeof(*hid_host));
607 hid_host->fd = hid_fd;
609 u32 *hid_ver = (u32*)iosAlloc(hId, 0x20);
610 if (hid_ver==NULL) goto mem_error;
611 // have to call the USB4 version first, to be safe
612 if (IOS_Ioctl(hid_fd, USBV4_IOCTL_GETVERSION, NULL, 0, NULL, 0)==0x40001 || \
613 IOS_Ioctl(hid_fd, USBV5_IOCTL_GETVERSION, NULL, 0, hid_ver, 0x20) || hid_ver[0]!=0x50001) {
614 // wrong hid version
615 IOS_Close(hid_fd);
616 iosFree(hId, hid_host);
617 hid_host = NULL;
618 } else
619 IOS_IoctlAsync(hid_fd, USBV5_IOCTL_GETDEVICECHANGE, NULL, 0, hid_host->attached_devices, 0x180, __usbv5_devicechangeCB, hid_host);
621 iosFree(hId, hid_ver);
625 return IPC_OK;
627 mem_error:
628 USB_Deinitialize();
629 return IPC_ENOMEM;
632 s32 USB_Deinitialize()
634 if (hid_host) {
635 if (hid_host->fd>=0) {
636 IOS_Ioctl(hid_host->fd, USBV5_IOCTL_SHUTDOWN, NULL, 0, NULL, 0);
637 IOS_Close(hid_host->fd);
639 iosFree(hId, hid_host);
640 hid_host = NULL;
643 if (ven_host) {
644 if (ven_host->fd>=0) {
645 IOS_Ioctl(ven_host->fd, USBV5_IOCTL_SHUTDOWN, NULL, 0, NULL, 0);
646 IOS_Close(ven_host->fd);
648 iosFree(hId, ven_host);
649 ven_host = NULL;
652 return IPC_OK;
655 s32 USB_OpenDevice(s32 device_id,u16 vid,u16 pid,s32 *fd)
657 s32 ret = USB_OK;
658 char *devicepath = NULL;
659 *fd = -1;
661 if (device_id && device_id!=USB_OH1_DEVICE_ID) {
662 int i;
664 i = __find_device_on_host(ven_host, device_id);
665 if (i>=0)
666 USB_ResumeDevice(device_id);
667 else {
668 // HID V5 devices need their descriptors read before being used
669 usb_devdesc desc;
670 i = __find_device_on_host(hid_host, device_id);
671 if (i>=0) {
672 USB_ResumeDevice(device_id);
673 i = USB_GetDescriptors(device_id, &desc);
674 if (i>=0)
675 USB_FreeDescriptors(&desc);
676 else {
677 USB_SuspendDevice(device_id);
678 return i;
682 if (i>=0) {
683 *fd = device_id;
684 return 0;
688 devicepath = iosAlloc(hId,USB_MAXPATH);
689 if(devicepath==NULL) return IPC_ENOMEM;
691 if (device_id==USB_OH1_DEVICE_ID)
692 snprintf(devicepath,USB_MAXPATH,"/dev/usb/oh1/%x/%x",vid,pid);
693 else
694 snprintf(devicepath,USB_MAXPATH,"/dev/usb/oh0/%x/%x",vid,pid);
696 *fd = IOS_Open(devicepath,0);
697 if(*fd<0) ret = *fd;
699 if (devicepath!=NULL) iosFree(hId,devicepath);
700 return ret;
703 s32 USBV5_CloseDevice(s32 device_id)
705 int i;
706 struct _usbv5_host* host;
708 if (__find_device_on_host(ven_host, device_id)>=0)
709 host = ven_host;
710 else if (__find_device_on_host(hid_host, device_id)>=0)
711 host = hid_host;
712 else
713 return IPC_EINVAL;
715 for (i=0; i < USB_MAX_DEVICES; i++) {
716 if (host->remove_cb[i].cb==NULL)
717 continue;
719 if (host->remove_cb[i].device_id==device_id) {
720 host->remove_cb[i].cb(0, host->remove_cb[i].userdata);
721 host->remove_cb[i].cb = NULL;
722 break;
725 //return USB_SuspendDevice(device_id);
726 return 0;
729 s32 USB_CloseDevice(s32 *fd)
731 s32 ret = IPC_EINVAL;
732 if (fd) {
733 ret = USBV5_CloseDevice(*fd);
734 if (ret==IPC_EINVAL && *fd>0)
735 ret = IOS_Close(*fd);
736 if (ret>=0) *fd = -1;
739 return ret;
742 s32 USB_CloseDeviceAsync(s32 *fd,usbcallback cb,void *userdata)
744 s32 ret = IPC_EINVAL;
745 if(fd) {
746 ret = USBV5_CloseDevice(*fd);
747 if (ret!=IPC_EINVAL) {
748 if (cb)
749 return cb(ret, userdata);
750 else
751 return ret;
753 if (*fd>0)
754 return IOS_CloseAsync(*fd,cb,userdata);
757 return ret;
760 s32 USB_GetDeviceDescription(s32 fd,usb_devdesc *devdesc)
762 s32 ret;
763 usb_devdesc *p;
765 p = iosAlloc(hId,USB_DT_DEVICE_SIZE);
766 if(p==NULL) return IPC_ENOMEM;
768 ret = __usb_control_message(fd,USB_CTRLTYPE_DIR_DEVICE2HOST,USB_REQ_GETDESCRIPTOR,(USB_DT_DEVICE<<8),0,USB_DT_DEVICE_SIZE,p,NULL,NULL);
769 if(ret>=0) memcpy(devdesc,p,USB_DT_DEVICE_SIZE);
770 devdesc->configurations = NULL;
772 if(p!=NULL) iosFree(hId,p);
773 return ret;
776 static s32 USBV5_GetDescriptors(s32 device_id, usb_devdesc *udd)
778 s32 retval = IPC_ENOMEM;
779 u32 *io_buffer = NULL;
780 u8 *buffer = NULL;
781 usb_configurationdesc *ucd = NULL;
782 usb_interfacedesc *uid = NULL;
783 usb_endpointdesc *ued = NULL;
784 u32 iConf, iEndpoint;
785 s32 fd;
786 u32 desc_out_size, desc_start_offset;
788 if (__find_device_on_host(ven_host, device_id)>=0) {
789 fd = ven_host->fd;
790 desc_out_size = 0xC0;
791 desc_start_offset = 20;
792 } else if (__find_device_on_host(hid_host, device_id)>=0) {
793 fd = hid_host->fd;
794 desc_out_size = 0x60;
795 desc_start_offset = 36;
796 } else
797 return IPC_EINVAL;
799 io_buffer = (u32*)iosAlloc(hId, 0x20);
800 buffer = (u8*)iosAlloc(hId, desc_out_size);
801 if (io_buffer==NULL || buffer==NULL) goto free_bufs;
803 io_buffer[0] = device_id;
804 io_buffer[2] = 0;
805 memset(buffer, 0, desc_out_size);
806 retval = IOS_Ioctl(fd, USBV5_IOCTL_GETDEVPARAMS, io_buffer, 0x20, buffer, desc_out_size);
807 if (retval==IPC_OK) {
808 u8 *next = buffer+desc_start_offset;
810 memcpy(udd, next, sizeof(*udd));
811 udd->configurations = calloc(udd->bNumConfigurations, sizeof(*udd->configurations));
812 if(udd->configurations == NULL) goto free_bufs;
814 next += (udd->bLength+3)&~3;
815 for (iConf = 0; iConf < udd->bNumConfigurations; iConf++)
817 ucd = &udd->configurations[iConf];
818 memcpy(ucd, next, USB_DT_CONFIG_SIZE);
819 next += (USB_DT_CONFIG_SIZE+3)&~3;
821 // ignore the actual value of bNumInterfaces; IOS presents each interface as a different device
822 // alternate settings will not show up here, if you want them you must explicitly request
823 // the interface descriptor
824 if (ucd->bNumInterfaces==0)
825 continue;
827 ucd->bNumInterfaces = 1;
828 ucd->interfaces = calloc(1, sizeof(*ucd->interfaces));
829 if (ucd->interfaces == NULL) goto free_bufs;
831 uid = ucd->interfaces;
832 memcpy(uid, next, USB_DT_INTERFACE_SIZE);
833 next += (uid->bLength+3)&~3;
835 /* This skips vendor and class specific descriptors */
836 uid->extra_size = __find_next_endpoint(next, buffer+desc_out_size-next, 3);
837 if(uid->extra_size>0)
839 uid->extra = malloc(uid->extra_size);
840 if(uid->extra == NULL)
841 goto free_bufs;
842 memcpy(uid->extra, next, uid->extra_size);
843 // already rounded
844 next += uid->extra_size;
847 if (uid->bNumEndpoints) {
848 uid->endpoints = calloc(uid->bNumEndpoints, sizeof(*uid->endpoints));
849 if (uid->endpoints == NULL) goto free_bufs;
851 for(iEndpoint = 0; iEndpoint < uid->bNumEndpoints; iEndpoint++)
853 ued = &uid->endpoints[iEndpoint];
854 memcpy(ued, next, USB_DT_ENDPOINT_SIZE);
855 next += (ued->bLength+3)&~3;
861 retval = IPC_OK;
864 free_bufs:
865 if (io_buffer!=NULL)
866 iosFree(hId, io_buffer);
867 if (buffer!=NULL)
868 iosFree(hId, buffer);
869 if (retval<0)
870 USB_FreeDescriptors(udd);
871 return retval;
874 s32 USB_GetDescriptors(s32 fd, usb_devdesc *udd)
876 u8 *buffer = NULL;
877 u8 *ptr = NULL;
878 usb_configurationdesc *ucd = NULL;
879 usb_interfacedesc *uid = NULL;
880 usb_endpointdesc *ued = NULL;
881 s32 retval = 0;
882 u32 size;
883 u32 iConf, iInterface, iEndpoint;
885 if (udd==NULL)
886 return IPC_EINVAL;
887 memset(udd, 0, sizeof(*udd));
889 if (fd>=0x20 || fd<-1)
890 return USBV5_GetDescriptors(fd, udd);
892 buffer = iosAlloc(hId, sizeof(*udd));
893 if(buffer == NULL)
895 retval = IPC_ENOHEAP;
896 goto free_and_error;
899 retval = __usb_getdesc(fd, buffer, USB_DT_DEVICE, 0, 0, USB_DT_DEVICE_SIZE);
900 if(retval < 0)
901 goto free_and_error;
902 memcpy(udd, buffer, USB_DT_DEVICE_SIZE);
903 iosFree(hId, buffer);
905 udd->bcdUSB = bswap16(udd->bcdUSB);
906 udd->idVendor = bswap16(udd->idVendor);
907 udd->idProduct = bswap16(udd->idProduct);
908 udd->bcdDevice = bswap16(udd->bcdDevice);
910 udd->configurations = calloc(udd->bNumConfigurations, sizeof(*udd->configurations));
911 if(udd->configurations == NULL)
913 retval = IPC_ENOMEM;
914 goto free_and_error;
916 for(iConf = 0; iConf < udd->bNumConfigurations; iConf++)
918 buffer = iosAlloc(hId, USB_DT_CONFIG_SIZE);
919 if(buffer == NULL)
921 retval = IPC_ENOHEAP;
922 goto free_and_error;
925 retval = __usb_getdesc(fd, buffer, USB_DT_CONFIG, iConf, 0, USB_DT_CONFIG_SIZE);
926 if (retval < 0)
927 goto free_and_error;
929 ucd = &udd->configurations[iConf];
930 memcpy(ucd, buffer, USB_DT_CONFIG_SIZE);
931 iosFree(hId, buffer);
933 ucd->wTotalLength = bswap16(ucd->wTotalLength);
934 size = ucd->wTotalLength;
935 buffer = iosAlloc(hId, size);
936 if(buffer == NULL)
938 retval = IPC_ENOHEAP;
939 goto free_and_error;
942 retval = __usb_getdesc(fd, buffer, USB_DT_CONFIG, iConf, 0, ucd->wTotalLength);
943 if(retval < 0)
944 goto free_and_error;
946 ptr = buffer;
947 ptr += ucd->bLength;
948 size -= ucd->bLength;
950 retval = IPC_ENOMEM;
952 ucd->interfaces = calloc(ucd->bNumInterfaces, sizeof(*ucd->interfaces));
953 if(ucd->interfaces == NULL)
954 goto free_and_error;
955 for(iInterface = 0; iInterface < ucd->bNumInterfaces; iInterface++)
957 retval = __find_next_endpoint(ptr, size, 0);
958 if (retval>0) {
959 // FIXME: do something with this data
961 ptr += retval;
962 size -= retval;
964 uid = ucd->interfaces+iInterface;
965 memcpy(uid, ptr, USB_DT_INTERFACE_SIZE);
966 ptr += uid->bLength;
967 size -= uid->bLength;
969 /* This skips vendor and class specific descriptors */
970 uid->extra_size = __find_next_endpoint(ptr, size, 0);
971 if(uid->extra_size>0)
973 uid->extra = malloc(uid->extra_size);
974 if(uid->extra == NULL)
975 goto free_and_error;
976 memcpy(uid->extra, ptr, uid->extra_size);
977 ptr += uid->extra_size;
978 size -= uid->extra_size;
981 if (uid->bNumEndpoints) {
982 uid->endpoints = calloc(uid->bNumEndpoints, sizeof(*uid->endpoints));
983 if(uid->endpoints == NULL)
984 goto free_and_error;
986 for(iEndpoint = 0; iEndpoint < uid->bNumEndpoints; iEndpoint++)
988 ued = &uid->endpoints[iEndpoint];
989 memcpy(ued, ptr, USB_DT_ENDPOINT_SIZE);
990 ptr += ued->bLength;
991 size -= ued->bLength;
992 ued->wMaxPacketSize = bswap16(ued->wMaxPacketSize);
996 if (iInterface==(ucd->bNumInterfaces-1) && size>2) {
997 // we've read all the interfaces but there's data left (probably alternate setting interfaces)
998 // see if we can find another interface descriptor
999 retval = __find_next_endpoint(ptr, size, 0);
1000 if (size-retval >= USB_DT_INTERFACE_SIZE && ptr[retval+1] == USB_DT_INTERFACE) {
1001 // found alternates, make room and loop
1002 usb_interfacedesc *interfaces = realloc(ucd->interfaces, (iInterface+2)*sizeof(*interfaces));
1003 if (interfaces == NULL)
1004 goto free_and_error;
1005 interfaces[iInterface+1].endpoints = NULL;
1006 interfaces[iInterface+1].extra = NULL;
1007 ucd->bNumInterfaces++;
1008 ucd->interfaces = interfaces;
1012 iosFree(hId, buffer);
1013 buffer = NULL;
1015 retval = IPC_OK;
1017 free_and_error:
1018 if(buffer != NULL)
1019 iosFree(hId, buffer);
1020 if(retval < 0)
1021 USB_FreeDescriptors(udd);
1022 return retval;
1025 s32 USB_GetGenericDescriptor(s32 fd,u8 type,u8 index,u8 interface,void *data,u32 size) {
1026 u8 *buffer;
1027 s32 retval;
1029 buffer = iosAlloc(hId,size);
1030 if(buffer==NULL) {
1031 retval = IPC_ENOMEM;
1032 goto free_and_error;
1035 retval = __usb_getdesc(fd,buffer,type,index,interface,size);
1036 if(retval<0) goto free_and_error;
1038 memcpy(data,buffer,size);
1039 retval = IPC_OK;
1041 free_and_error:
1042 if(buffer!=NULL) iosFree(hId,buffer);
1043 return retval;
1046 s32 USB_GetHIDDescriptor(s32 fd,u8 interface,usb_hiddesc *uhd,u32 size)
1048 int i;
1049 s32 retval;
1051 if (size < USB_DT_HID_SIZE)
1052 return IPC_EINVAL;
1054 retval = USB_GetGenericDescriptor(fd, USB_DT_HID, 0, interface, uhd, size);
1055 if (retval != IPC_OK)
1056 return retval;
1058 uhd->bcdHID = bswap16(uhd->bcdHID);
1059 uhd->descr[0].wDescriptorLength = bswap16(uhd->descr[0].wDescriptorLength);
1060 size -= USB_DT_HID_SIZE;
1061 for (i=1; i<uhd->bNumDescriptors && size>=3; size -=3, i++)
1062 uhd->descr[i].wDescriptorLength = bswap16(uhd->descr[i].wDescriptorLength);
1064 return retval;
1067 void USB_FreeDescriptors(usb_devdesc *udd)
1069 int iConf, iInterface;
1070 usb_configurationdesc *ucd;
1071 usb_interfacedesc *uid;
1072 if(udd->configurations != NULL)
1074 for(iConf = 0; iConf < udd->bNumConfigurations; iConf++)
1076 ucd = &udd->configurations[iConf];
1077 if(ucd->interfaces != NULL)
1079 for(iInterface = 0; iInterface < ucd->bNumInterfaces; iInterface++)
1081 uid = ucd->interfaces+iInterface;
1082 free(uid->endpoints);
1083 free(uid->extra);
1085 free(ucd->interfaces);
1088 free(udd->configurations);
1092 s32 USB_GetAsciiString(s32 fd,u8 bIndex,u16 wLangID,u16 wLength,void *rpData)
1094 s32 ret;
1095 u8 bo, ro;
1096 u8 *buf;
1097 u8 *rp = (u8 *)rpData;
1099 if(wLength > 255)
1100 wLength = 255;
1102 buf = iosAlloc(hId, 255); /* 255 is the highest possible length of a descriptor */
1103 if(buf == NULL)
1104 return IPC_ENOMEM;
1106 ret = __usb_getdesc(fd, buf, USB_DT_STRING, bIndex, wLangID, 255);
1108 /* index 0 gets a list of supported languages */
1109 if(bIndex == 0)
1111 if(ret > 0)
1112 memcpy(rpData, buf, wLength);
1113 iosFree(hId, buf);
1114 return ret;
1117 if(ret > 0)
1119 bo = 2;
1120 ro = 0;
1121 while(ro < (wLength - 1) && bo < buf[0])
1123 if(buf[bo + 1])
1124 rp[ro++] = '?';
1125 else
1126 rp[ro++] = buf[bo];
1127 bo += 2;
1129 rp[ro] = 0;
1130 ret = ro - 1;
1133 iosFree(hId, buf);
1134 return ret;
1137 s32 USB_ReadIsoMsg(s32 fd,u8 bEndpoint,u8 bPackets,u16 *rpPacketSizes,void *rpData)
1139 return __usb_isochronous_message(fd,bEndpoint,bPackets,rpPacketSizes,rpData,NULL,NULL);
1142 s32 USB_ReadIsoMsgAsync(s32 fd,u8 bEndpoint,u8 bPackets,u16 *rpPacketSizes,void *rpData,usbcallback cb,void *userdata)
1144 return __usb_isochronous_message(fd,bEndpoint,bPackets,rpPacketSizes,rpData,cb,userdata);
1147 s32 USB_WriteIsoMsg(s32 fd,u8 bEndpoint,u8 bPackets,u16 *rpPacketSizes,void *rpData)
1149 return __usb_isochronous_message(fd,bEndpoint,bPackets,rpPacketSizes,rpData,NULL,NULL);
1152 s32 USB_WriteIsoMsgAsync(s32 fd,u8 bEndpoint,u8 bPackets,u16 *rpPacketSizes,void *rpData,usbcallback cb,void *userdata)
1154 return __usb_isochronous_message(fd,bEndpoint,bPackets,rpPacketSizes,rpData,cb,userdata);
1157 s32 USB_ReadIntrMsg(s32 fd,u8 bEndpoint,u16 wLength,void *rpData)
1159 return __usb_interrupt_bulk_message(fd,USBV0_IOCTL_INTRMSG,bEndpoint,wLength,rpData,NULL,NULL);
1162 s32 USB_ReadIntrMsgAsync(s32 fd,u8 bEndpoint,u16 wLength,void *rpData,usbcallback cb,void *userdata)
1164 return __usb_interrupt_bulk_message(fd,USBV0_IOCTL_INTRMSG,bEndpoint,wLength,rpData,cb,userdata);
1167 s32 USB_WriteIntrMsg(s32 fd,u8 bEndpoint,u16 wLength,void *rpData)
1169 return __usb_interrupt_bulk_message(fd,USBV0_IOCTL_INTRMSG,bEndpoint,wLength,rpData,NULL,NULL);
1172 s32 USB_WriteIntrMsgAsync(s32 fd,u8 bEndpoint,u16 wLength,void *rpData,usbcallback cb,void *userdata)
1174 return __usb_interrupt_bulk_message(fd,USBV0_IOCTL_INTRMSG,bEndpoint,wLength,rpData,cb,userdata);
1177 s32 USB_ReadBlkMsg(s32 fd,u8 bEndpoint,u16 wLength,void *rpData)
1179 return __usb_interrupt_bulk_message(fd,USBV0_IOCTL_BLKMSG,bEndpoint,wLength,rpData,NULL,NULL);
1182 s32 USB_ReadBlkMsgAsync(s32 fd,u8 bEndpoint,u16 wLength,void *rpData,usbcallback cb,void *userdata)
1184 return __usb_interrupt_bulk_message(fd,USBV0_IOCTL_BLKMSG,bEndpoint,wLength,rpData,cb,userdata);
1187 s32 USB_WriteBlkMsg(s32 fd,u8 bEndpoint,u16 wLength,void *rpData)
1189 return __usb_interrupt_bulk_message(fd,USBV0_IOCTL_BLKMSG,bEndpoint,wLength,rpData,NULL,NULL);
1192 s32 USB_WriteBlkMsgAsync(s32 fd,u8 bEndpoint,u16 wLength,void *rpData,usbcallback cb,void *userdata)
1194 return __usb_interrupt_bulk_message(fd,USBV0_IOCTL_BLKMSG,bEndpoint,wLength,rpData,cb,userdata);
1197 s32 USB_ReadCtrlMsg(s32 fd,u8 bmRequestType,u8 bmRequest,u16 wValue,u16 wIndex,u16 wLength,void *rpData)
1199 return __usb_control_message(fd,bmRequestType,bmRequest,wValue,wIndex,wLength,rpData,NULL,NULL);
1202 s32 USB_ReadCtrlMsgAsync(s32 fd,u8 bmRequestType,u8 bmRequest,u16 wValue,u16 wIndex,u16 wLength,void *rpData,usbcallback cb,void *userdata)
1204 return __usb_control_message(fd,bmRequestType,bmRequest,wValue,wIndex,wLength,rpData,cb,userdata);
1207 s32 USB_WriteCtrlMsg(s32 fd,u8 bmRequestType,u8 bmRequest,u16 wValue,u16 wIndex,u16 wLength,void *rpData)
1209 return __usb_control_message(fd,bmRequestType,bmRequest,wValue,wIndex,wLength,rpData,NULL,NULL);
1212 s32 USB_WriteCtrlMsgAsync(s32 fd,u8 bmRequestType,u8 bmRequest,u16 wValue,u16 wIndex,u16 wLength,void *rpData,usbcallback cb,void *userdata)
1214 return __usb_control_message(fd,bmRequestType,bmRequest,wValue,wIndex,wLength,rpData,cb,userdata);
1217 static s32 USB5_RegisterDeviceRemoval(struct _usbv5_host *host, s32 device_id, usbcallback cb, void *userdata)
1219 int i;
1221 // check to make sure the device is present
1222 if (__find_device_on_host(host, device_id)<0)
1223 return IPC_ENOENT;
1225 // now make sure it's not hooked already
1226 for (i=0; i<USB_MAX_DEVICES; i++) {
1227 if (host->remove_cb[i].cb && host->remove_cb[i].device_id==device_id)
1228 return IPC_EINVAL;
1231 // find a free entry and add it
1232 for (i=0; i<USB_MAX_DEVICES; i++) {
1233 if (host->remove_cb[i].cb==NULL) {
1234 host->remove_cb[i].cb = cb;
1235 host->remove_cb[i].userdata = userdata;
1236 host->remove_cb[i].device_id = device_id;
1237 return IPC_OK;
1240 return IPC_EINVAL;
1243 s32 USB_DeviceRemovalNotifyAsync(s32 fd,usbcallback cb,void *userdata)
1245 s32 ret;
1246 if (fd>=0 && fd<0x20)
1247 return IOS_IoctlAsync(fd,USBV0_IOCTL_DEVREMOVALHOOK,NULL,0,NULL,0,cb,userdata);
1249 ret = USB5_RegisterDeviceRemoval(ven_host, fd, cb, userdata);
1250 if (ret == IPC_ENOENT)
1251 ret = USB5_RegisterDeviceRemoval(hid_host, fd, cb, userdata);
1253 return ret;
1256 static s32 USBV5_SuspendResume(s32 device_id, s32 resumed)
1258 s32 ret;
1259 s32 fd;
1261 if (__find_device_on_host(ven_host, device_id)>=0)
1262 fd = ven_host->fd;
1263 else if (__find_device_on_host(hid_host, device_id)>=0)
1264 fd = hid_host->fd;
1265 else
1266 return IPC_ENOENT;
1268 s32 *buf = (s32*)iosAlloc(hId, 32);
1269 if (buf==NULL) return IPC_ENOMEM;
1271 buf[0] = device_id;
1272 buf[2] = resumed;
1273 ret = IOS_Ioctl(fd, USBV5_IOCTL_SUSPEND_RESUME, buf, 32, NULL, 0);
1274 iosFree(hId, buf);
1276 return ret;
1279 s32 USB_SuspendDevice(s32 fd)
1281 if (fd>=0x20 || fd<-1)
1282 return USBV5_SuspendResume(fd, 0);
1284 return IOS_Ioctl(fd,USBV0_IOCTL_SUSPENDDEV,NULL,0,NULL,0);
1287 s32 USB_ResumeDevice(s32 fd)
1289 if (fd>=0x20 || fd<-1)
1290 return USBV5_SuspendResume(fd, 1);
1292 return IOS_Ioctl(fd,USBV0_IOCTL_RESUMEDEV,NULL,0,NULL,0);
1295 s32 USB_DeviceChangeNotifyAsync(u8 interface_class, usbcallback cb, void* userdata)
1297 s32 ret=IPC_EQUEUEFULL;
1299 if (ven_host==NULL) {
1300 s32 fd;
1301 struct _usb_msg *msg;
1303 fd = IOS_Open(__oh0_path,IPC_OPEN_NONE);
1304 if (fd<0) return fd;
1306 msg = iosAlloc(hId,sizeof(*msg));
1307 if (msg==NULL) {
1308 IOS_Close(fd);
1309 return IPC_ENOMEM;
1312 msg->cb = cb;
1313 msg->userdata = userdata;
1314 msg->class = interface_class;
1316 msg->vec[0].data = &msg->class;
1317 msg->vec[0].len = 1;
1319 ret = IOS_IoctlvAsync(fd,USBV0_IOCTL_DEVICECLASSCHANGE,1,0,msg->vec,__usbv5_messageCB,msg);
1320 IOS_Close(fd);
1322 if (ret<0) iosFree(hId, msg);
1324 else if (interface_class != USB_CLASS_HID && ven_host) {
1325 if (ven_host->device_change_notify == NULL) {
1326 ret = 0;
1327 ven_host->device_change_notify = cb;
1328 ven_host->device_change_userdata = userdata;
1331 else if (interface_class==USB_CLASS_HID && hid_host) {
1332 if (hid_host->device_change_notify == NULL) {
1333 ret = 0;
1334 hid_host->device_change_notify = cb;
1335 hid_host->device_change_userdata = userdata;
1339 return ret;
1342 s32 USB_GetDeviceList(usb_device_entry *descr_buffer,u8 num_descr,u8 interface_class,u8 *cnt_descr)
1344 int i;
1345 u8 cntdevs=0;
1347 if (ven_host==NULL) {
1348 s32 fd;
1349 u32 *buf = (u32*)iosAlloc(hId, num_descr<<3);
1350 if (buf==NULL) return IPC_ENOMEM;
1352 fd = IOS_Open(__oh0_path,IPC_OPEN_NONE);
1353 if (fd<0) {
1354 iosFree(hId, buf);
1355 return fd;
1358 cntdevs = 0;
1359 i = IOS_IoctlvFormat(hId,fd,USBV0_IOCTL_GETDEVLIST,"bb:dd",num_descr,interface_class,&cntdevs,sizeof(cntdevs),buf,(num_descr<<3));
1360 if (cnt_descr) *cnt_descr = cntdevs;
1362 while (cntdevs--) {
1363 descr_buffer[cntdevs].device_id = 0;
1364 descr_buffer[cntdevs].vid = (u16)(buf[cntdevs*2+1]>>16);
1365 descr_buffer[cntdevs].pid = (u16)buf[cntdevs*2+1];
1368 IOS_Close(fd);
1369 iosFree(hId, buf);
1370 return i;
1373 // for ven_host, we can only exclude usb_hid class devices
1374 if (interface_class != USB_CLASS_HID && ven_host) {
1375 i=0;
1376 while (cntdevs<num_descr && ven_host->attached_devices[i].device_id) {
1377 descr_buffer[cntdevs++] = ven_host->attached_devices[i++];
1378 if (i>=32) break;
1382 if ((!interface_class || interface_class==USB_CLASS_HID) && hid_host) {
1383 i=0;
1384 while (cntdevs<num_descr && hid_host->attached_devices[i].device_id) {
1385 descr_buffer[cntdevs++] = hid_host->attached_devices[i++];
1386 if (i>32) break;
1390 if (cnt_descr) *cnt_descr = cntdevs;
1392 return IPC_OK;
1395 s32 USB_SetConfiguration(s32 fd, u8 configuration)
1397 return __usb_control_message(fd, (USB_CTRLTYPE_DIR_HOST2DEVICE | USB_CTRLTYPE_TYPE_STANDARD | USB_CTRLTYPE_REC_DEVICE), USB_REQ_SETCONFIG, configuration, 0, 0, NULL, NULL, NULL);
1400 s32 USB_GetConfiguration(s32 fd, u8 *configuration)
1402 u8 *_configuration;
1403 s32 retval;
1405 _configuration = iosAlloc(hId, 1);
1406 if(_configuration == NULL)
1407 return IPC_ENOMEM;
1409 retval = __usb_control_message(fd, (USB_CTRLTYPE_DIR_DEVICE2HOST | USB_CTRLTYPE_TYPE_STANDARD | USB_CTRLTYPE_REC_DEVICE), USB_REQ_GETCONFIG, 0, 0, 1, _configuration, NULL, NULL);
1410 if(retval >= 0)
1411 *configuration = *_configuration;
1412 iosFree(hId, _configuration);
1414 return retval;
1417 s32 USB_SetAlternativeInterface(s32 fd, u8 interface, u8 alternateSetting)
1419 return __usb_control_message(fd, (USB_CTRLTYPE_DIR_HOST2DEVICE | USB_CTRLTYPE_TYPE_STANDARD | USB_CTRLTYPE_REC_INTERFACE), USB_REQ_SETINTERFACE, alternateSetting, interface, 0, NULL, NULL, NULL);
1422 static s32 USBV5_CancelEndpoint(s32 device_id, u8 endpoint)
1424 s32 ret;
1425 s32 fd;
1427 if (__find_device_on_host(ven_host, device_id)>=0)
1428 fd = ven_host->fd;
1429 else if (__find_device_on_host(hid_host, device_id)>=0)
1430 fd = hid_host->fd;
1431 else
1432 return IPC_ENOENT;
1434 s32 *buf = (s32*)iosAlloc(hId, 32);
1435 if (buf==NULL) return IPC_ENOMEM;
1437 buf[0] = device_id;
1438 buf[2] = endpoint;
1439 ret = IOS_Ioctl(fd, USBV5_IOCTL_CANCELENDPOINT, buf, 32, NULL, 0);
1440 iosFree(hId, buf);
1442 return ret;
1445 s32 USB_ClearHalt(s32 fd, u8 endpoint)
1447 if (fd>=0x20 || fd<-1)
1448 return USBV5_CancelEndpoint(fd, endpoint);
1449 return __usb_control_message(fd, (USB_CTRLTYPE_DIR_HOST2DEVICE | USB_CTRLTYPE_TYPE_STANDARD | USB_CTRLTYPE_REC_ENDPOINT), USB_REQ_CLEARFEATURE, USB_FEATURE_ENDPOINT_HALT, endpoint, 0, NULL, NULL, NULL);
1452 #endif /* defined(HW_RVL) */