usb fix (tueidj)
[libogc.git] / libogc / usb.c
blob7622ac5fd8db848587e541d52cf1a137cbce5b01
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;
107 static struct _usbv5_host* ven_host = NULL;
108 static struct _usbv5_host* hid_host = NULL;
110 struct _usb_msg {
111 s32 fd;
112 u32 heap_buffers;
113 union {
114 struct {
115 u8 bmRequestType;
116 u8 bmRequest;
117 u16 wValue;
118 u16 wIndex;
119 u16 wLength;
120 void *rpData;
121 } ctrl;
123 struct {
124 void *rpData;
125 u16 wLength;
126 u8 pad[4];
127 u8 bEndpoint;
128 } bulk;
130 struct {
131 void *rpData;
132 u16 wLength;
133 u8 bEndpoint;
134 } intr;
136 struct {
137 void *rpData;
138 void *rpPacketSizes;
139 u8 bPackets;
140 u8 bEndpoint;
141 } iso;
143 struct {
144 u16 pid;
145 u16 vid;
146 } notify;
148 u8 class;
149 u32 hid_intr_dir;
151 u32 align_pad[4]; // pad to 24 bytes
153 usbcallback cb;
154 void *userdata;
155 ioctlv vec[7];
158 static s32 __usbv5_devicechangeCB(s32 result, void *p);
160 static s32 __usbv5_attachfinishCB(s32 result, void *p)
162 struct _usbv5_host* host = (struct _usbv5_host*)p;
163 if(host==NULL) return IPC_EINVAL;
165 if (result==0)
166 IOS_IoctlAsync(host->fd, USBV5_IOCTL_GETDEVICECHANGE, NULL, 0, host->attached_devices, 0x180, __usbv5_devicechangeCB, host);
168 return IPC_OK;
171 static s32 __usbv5_devicechangeCB(s32 result, void *p)
173 int i, j;
174 struct _usbv5_host* host = (struct _usbv5_host*)p;
176 if(host==NULL) return IPC_EINVAL;
178 if (result>=0) {
179 // can't check the remove callbacks only if the number of devices has decreased,
180 // because devices may have been inserted as well as removed
181 for (i=0; i<USB_MAX_DEVICES; i++) {
182 if (host->remove_cb[i].cb==NULL)
183 continue;
184 for (j=0; j<result; j++) {
185 if (host->remove_cb[i].device_id == host->attached_devices[j].device_id)
186 break;
189 if (j==result) { // execute callback and remove it
190 host->remove_cb[i].cb(0, host->remove_cb[i].userdata);
191 host->remove_cb[i].cb = NULL;
194 // wipe unused device entries
195 memset(host->attached_devices+result, 0, sizeof(usb_device_entry)*(32-result));
197 IOS_IoctlAsync(host->fd, USBV5_IOCTL_ATTACHFINISH, NULL, 0, NULL, 0, __usbv5_attachfinishCB, host);
200 return IPC_OK;
204 static s32 __usbv5_messageCB(s32 result,void *_msg)
206 struct _usb_msg *msg = (struct _usb_msg*)_msg;
208 if(msg==NULL) return IPC_EINVAL;
210 if(msg->cb!=NULL) msg->cb(result, msg->userdata);
212 iosFree(hId,msg);
214 return IPC_OK;
217 static s32 __usbv0_messageCB(s32 result,void *usrdata)
219 u32 i;
220 struct _usb_msg *msg = (struct _usb_msg*)usrdata;
222 if(msg==NULL) return IPC_EINVAL;
224 if(msg->cb!=NULL) msg->cb(result, msg->userdata);
226 for(i=0; i<msg->heap_buffers; i++) {
227 if(msg->vec[i].data!=NULL)
228 iosFree(hId,msg->vec[i].data);
231 iosFree(hId,msg);
233 return IPC_OK;
236 static s32 __find_device_on_host(struct _usbv5_host *host, s32 device_id)
238 int i;
239 if (host==NULL) return -1;
241 for (i=0; host->attached_devices[i].device_id; i++) {
242 if (host->attached_devices[i].device_id == device_id)
243 return i;
246 return -1;
249 static s32 __usb_isochronous_message(s32 device_id,u8 bEndpoint,u8 bPackets,u16* rpPacketSizes,void* rpData,usbcallback cb,void *userdata)
251 s32 ret = IPC_ENOMEM;
252 struct _usb_msg *msg;
253 u16 wLength=0;
254 u8 i;
256 for (i=0; i<bPackets; i++)
257 wLength += rpPacketSizes[i];
259 if(wLength==0) return IPC_EINVAL;
260 if(((u32)rpData%32)!=0) return IPC_EINVAL;
261 if(((u32)rpPacketSizes%32)!=0) return IPC_EINVAL;
262 if(bPackets==0) return IPC_EINVAL;
263 if(rpPacketSizes==NULL || rpData==NULL) return IPC_EINVAL;
265 msg = (struct _usb_msg*)iosAlloc(hId,sizeof(struct _usb_msg));
266 if(msg==NULL) return IPC_ENOMEM;
268 memset(msg, 0, sizeof(struct _usb_msg));
270 msg->fd = device_id;
271 msg->cb = cb;
272 msg->userdata = userdata;
274 if (device_id>=0 && device_id<0x20) {
275 u8 *pEndp=NULL;
276 u16 *pLength=NULL;
277 u8 *pPackets=NULL;
279 pEndp = (u8*)iosAlloc(hId,32);
280 if(pEndp==NULL) goto done;
281 *pEndp = bEndpoint;
283 pLength = (u16*)iosAlloc(hId,32);
284 if(pLength==NULL) goto done;
285 // NOT byteswapped!
286 *pLength = wLength;
288 pPackets = (u8*)iosAlloc(hId,32);
289 if(pPackets==NULL) goto done;
290 *pPackets = bPackets;
292 msg->heap_buffers = 3;
294 msg->vec[0].data = pEndp;
295 msg->vec[0].len = sizeof(u8);
296 msg->vec[1].data = pLength;
297 msg->vec[1].len = sizeof(u16);
298 msg->vec[2].data = pPackets;
299 msg->vec[2].len = sizeof(u8);
300 msg->vec[3].data = rpPacketSizes;
301 msg->vec[3].len = sizeof(u16)*bPackets;
302 msg->vec[4].data = rpData;
303 msg->vec[4].len = wLength;
305 if (cb==NULL)
306 ret = IOS_Ioctlv(device_id, USBV0_IOCTL_ISOMSG, 3, 2, msg->vec);
307 else
308 return IOS_IoctlvAsync(device_id, USBV0_IOCTL_ISOMSG, 3, 2, msg->vec, __usbv0_messageCB, msg);
310 done:
311 if(pEndp) iosFree(hId,pEndp);
312 if(pLength) iosFree(hId,pLength);
313 if(pPackets) iosFree(hId,pPackets);
314 } else {
315 u8 endpoint_dir = !!(bEndpoint&USB_ENDPOINT_IN);
316 s32 fd = (device_id<0) ? ven_host->fd : hid_host->fd;
318 msg->iso.rpData = rpData;
319 msg->iso.rpPacketSizes = rpPacketSizes;
320 msg->iso.bEndpoint = bEndpoint;
321 msg->iso.bPackets = bPackets;
323 msg->vec[0].data = msg;
324 msg->vec[0].len = 64;
325 // block counts are used for both input and output
326 msg->vec[1].data = msg->vec[3].data = rpPacketSizes;
327 msg->vec[1].len = msg->vec[3].len = sizeof(u16)*bPackets;
328 msg->vec[2].data = rpData;
329 msg->vec[2].len = wLength;
331 if (cb==NULL)
332 ret = IOS_Ioctlv(fd, USBV5_IOCTL_ISOMSG, 2-endpoint_dir, 2+endpoint_dir, msg->vec);
333 else
334 return IOS_IoctlvAsync(fd, USBV5_IOCTL_ISOMSG, 2-endpoint_dir, 2+endpoint_dir, msg->vec, __usbv5_messageCB, msg);
337 if (msg!=NULL) iosFree(hId,msg);
339 return ret;
342 static s32 __usb_control_message(s32 device_id,u8 bmRequestType,u8 bmRequest,u16 wValue,u16 wIndex,u16 wLength,void *rpData,usbcallback cb,void *userdata)
344 s32 ret = IPC_ENOMEM;
345 struct _usb_msg *msg;
347 if(((s32)rpData%32)!=0) return IPC_EINVAL;
348 if(wLength && !rpData) return IPC_EINVAL;
349 if(!wLength && rpData) return IPC_EINVAL;
351 msg = (struct _usb_msg*)iosAlloc(hId,sizeof(struct _usb_msg));
352 if(msg==NULL) return IPC_ENOMEM;
354 memset(msg, 0, sizeof(struct _usb_msg));
356 msg->fd = device_id;
357 msg->cb = cb;
358 msg->userdata = userdata;
360 if (device_id>=0 && device_id<0x20) {
361 u8 *pRqType = NULL,*pRq = NULL,*pNull = NULL;
362 u16 *pValue = NULL,*pIndex = NULL,*pLength = NULL;
364 pRqType = (u8*)iosAlloc(hId,32);
365 if(pRqType==NULL) goto done;
366 *pRqType = bmRequestType;
368 pRq = (u8*)iosAlloc(hId,32);
369 if(pRq==NULL) goto done;
370 *pRq = bmRequest;
372 pValue = (u16*)iosAlloc(hId,32);
373 if(pValue==NULL) goto done;
374 *pValue = bswap16(wValue);
376 pIndex = (u16*)iosAlloc(hId,32);
377 if(pIndex==NULL) goto done;
378 *pIndex = bswap16(wIndex);
380 pLength = (u16*)iosAlloc(hId,32);
381 if(pLength==NULL) goto done;
382 *pLength = bswap16(wLength);
384 pNull = (u8*)iosAlloc(hId,32);
385 if(pNull==NULL) goto done;
386 *pNull = 0;
388 msg->heap_buffers = 6;
390 msg->vec[0].data = pRqType;
391 msg->vec[0].len = sizeof(u8);
392 msg->vec[1].data = pRq;
393 msg->vec[1].len = sizeof(u8);
394 msg->vec[2].data = pValue;
395 msg->vec[2].len = sizeof(u16);
396 msg->vec[3].data = pIndex;
397 msg->vec[3].len = sizeof(u16);
398 msg->vec[4].data = pLength;
399 msg->vec[4].len = sizeof(u16);
400 msg->vec[5].data = pNull;
401 msg->vec[5].len = sizeof(u8);
402 msg->vec[6].data = rpData;
403 msg->vec[6].len = wLength;
405 if (cb==NULL)
406 ret = IOS_Ioctlv(device_id, USBV0_IOCTL_CTRLMSG, 6, 1, msg->vec);
407 else
408 return IOS_IoctlvAsync(device_id, USBV0_IOCTL_CTRLMSG, 6, 1, msg->vec, __usbv0_messageCB, msg);
410 done:
411 if(pRqType!=NULL) iosFree(hId,pRqType);
412 if(pRq!=NULL) iosFree(hId,pRq);
413 if(pValue!=NULL) iosFree(hId,pValue);
414 if(pIndex!=NULL) iosFree(hId,pIndex);
415 if(pLength!=NULL) iosFree(hId,pLength);
416 if(pNull!=NULL) iosFree(hId,pNull);
418 } else {
419 u8 request_dir = !!(bmRequestType&USB_CTRLTYPE_DIR_DEVICE2HOST);
420 s32 fd = (device_id<0) ? ven_host->fd : hid_host->fd;
422 msg->ctrl.bmRequestType = bmRequestType;
423 msg->ctrl.bmRequest = bmRequest;
424 msg->ctrl.wValue = wValue;
425 msg->ctrl.wIndex = wIndex;
426 msg->ctrl.wLength = wLength;
427 msg->ctrl.rpData = rpData;
429 msg->vec[0].data = msg;
430 msg->vec[0].len = 64;
431 msg->vec[1].data = rpData;
432 msg->vec[1].len = wLength;
434 if (cb==NULL)
435 ret = IOS_Ioctlv(fd, USBV5_IOCTL_CTRLMSG, 2-request_dir, request_dir, msg->vec);
436 else
437 return IOS_IoctlvAsync(fd, USBV5_IOCTL_CTRLMSG, 2-request_dir, request_dir, msg->vec, __usbv5_messageCB, msg);
440 if(msg!=NULL) iosFree(hId,msg);
442 return ret;
445 static inline s32 __usb_interrupt_bulk_message(s32 device_id,u8 ioctl,u8 bEndpoint,u16 wLength,void *rpData,usbcallback cb,void *userdata)
447 s32 ret = IPC_ENOMEM;
448 struct _usb_msg *msg;
450 if(((s32)rpData%32)!=0) return IPC_EINVAL;
451 if(wLength && !rpData) return IPC_EINVAL;
452 if(!wLength && rpData) return IPC_EINVAL;
454 msg = (struct _usb_msg*)iosAlloc(hId,sizeof(struct _usb_msg));
455 if(msg==NULL) return IPC_ENOMEM;
457 memset(msg, 0, sizeof(struct _usb_msg));
459 msg->fd = device_id;
460 msg->cb = cb;
461 msg->userdata = userdata;
463 if (device_id>=0 && device_id<0x20) {
464 u8 *pEndP = NULL;
465 u16 *pLength = NULL;
467 pEndP = (u8*)iosAlloc(hId,32);
468 if(pEndP==NULL) goto done;
469 *pEndP = bEndpoint;
471 pLength = (u16*)iosAlloc(hId,32);
472 if(pLength==NULL) goto done;
473 *pLength = wLength;
475 msg->vec[0].data = pEndP;
476 msg->vec[0].len = sizeof(u8);
477 msg->vec[1].data = pLength;
478 msg->vec[1].len = sizeof(u16);
479 msg->vec[2].data = rpData;
480 msg->vec[2].len = wLength;
482 msg->heap_buffers = 2;
484 if (cb==NULL)
485 ret = IOS_Ioctlv(device_id,ioctl,2,1,msg->vec);
486 else
487 return IOS_IoctlvAsync(device_id,ioctl,2,1,msg->vec,__usbv0_messageCB,msg);
489 done:
490 if(pEndP!=NULL) iosFree(hId,pEndP);
491 if(pLength!=NULL) iosFree(hId,pLength);
493 } else {
494 u8 endpoint_dir = !!(bEndpoint&USB_ENDPOINT_IN);
495 s32 fd = (device_id<0) ? ven_host->fd : hid_host->fd;
497 if (ioctl == USBV0_IOCTL_INTRMSG) {
498 // HID does this a little bit differently
499 if (device_id>=0)
500 msg->hid_intr_dir = !endpoint_dir;
501 else {
502 msg->intr.rpData = rpData;
503 msg->intr.wLength = wLength;
504 msg->intr.bEndpoint = bEndpoint;
506 ioctl = USBV5_IOCTL_INTRMSG;
507 } else {
508 msg->bulk.rpData = rpData;
509 msg->bulk.wLength = wLength;
510 msg->bulk.bEndpoint = bEndpoint;
511 ioctl = USBV5_IOCTL_BULKMSG;
514 msg->vec[0].data = msg;
515 msg->vec[0].len = 64;
516 msg->vec[1].data = rpData;
517 msg->vec[1].len = wLength;
519 if (cb==NULL)
520 ret = IOS_Ioctlv(fd, ioctl, 2-endpoint_dir, endpoint_dir, msg->vec);
521 else
522 return IOS_IoctlvAsync(fd, ioctl, 2-endpoint_dir, endpoint_dir, msg->vec, __usbv5_messageCB, msg);
525 if(msg!=NULL) iosFree(hId,msg);
527 return ret;
530 static inline s32 __usb_getdesc(s32 fd, u8 *buffer, u8 valuehi, u8 valuelo, u16 index, u8 size)
532 u8 requestType = USB_CTRLTYPE_DIR_DEVICE2HOST;
534 if (valuehi==USB_DT_HID || valuehi==USB_DT_REPORT || valuehi==USB_DT_PHYSICAL)
535 requestType |= USB_CTRLTYPE_REC_INTERFACE;
537 return __usb_control_message(fd, requestType, USB_REQ_GETDESCRIPTOR, (valuehi << 8) | valuelo, index, size, buffer, NULL, NULL);
540 static u32 __find_next_endpoint(u8 *buffer,s32 size,u8 align)
542 u8 *ptr = buffer;
544 while(size>2 && buffer[0]) { // abort if buffer[0]==0 to avoid getting stuck
545 if(buffer[1]==USB_DT_ENDPOINT || buffer[1]==USB_DT_INTERFACE)
546 break;
548 size -= (buffer[0]+align)&~align;
549 buffer += (buffer[0]+align)&~align;
552 return (buffer - ptr);
555 s32 USB_Initialize()
557 if(hId==-1) hId = iosCreateHeap(USB_HEAPSIZE);
558 if(hId<0) return IPC_ENOMEM;
560 if (ven_host==NULL) {
561 s32 ven_fd = IOS_Open(__ven_path, IPC_OPEN_NONE);
562 if (ven_fd>=0) {
563 ven_host = (struct _usbv5_host*)iosAlloc(hId, sizeof(*ven_host));
564 if (ven_host==NULL) {
565 IOS_Close(ven_fd);
566 return IPC_ENOMEM;
568 memset(ven_host, 0, sizeof(*ven_host));
569 ven_host->fd = ven_fd;
571 u32 *ven_ver = (u32*)iosAlloc(hId, 0x20);
572 if (ven_ver==NULL) goto mem_error;
573 if (IOS_Ioctl(ven_fd, USBV5_IOCTL_GETVERSION, NULL, 0, ven_ver, 0x20)==0 && ven_ver[0]==0x50001)
574 IOS_IoctlAsync(ven_fd, USBV5_IOCTL_GETDEVICECHANGE, NULL, 0, ven_host->attached_devices, 0x180, __usbv5_devicechangeCB, ven_host);
575 else {
576 // wrong ven version
577 IOS_Close(ven_fd);
578 iosFree(hId, ven_host);
579 ven_host = NULL;
582 iosFree(hId, ven_ver);
586 if (hid_host==NULL) {
587 s32 hid_fd = IOS_Open(__hid_path, IPC_OPEN_NONE);
588 if (hid_fd>=0) {
589 hid_host = (struct _usbv5_host*)iosAlloc(hId, sizeof(*hid_host));
590 if (hid_host==NULL) {
591 IOS_Close(hid_fd);
592 goto mem_error;
594 memset(hid_host, 0, sizeof(*hid_host));
595 hid_host->fd = hid_fd;
597 u32 *hid_ver = (u32*)iosAlloc(hId, 0x20);
598 if (hid_ver==NULL) goto mem_error;
599 // have to call the USB4 version first, to be safe
600 if (IOS_Ioctl(hid_fd, USBV4_IOCTL_GETVERSION, NULL, 0, NULL, 0)==0x40001 || \
601 IOS_Ioctl(hid_fd, USBV5_IOCTL_GETVERSION, NULL, 0, hid_ver, 0x20) || hid_ver[0]!=0x50001) {
602 // wrong hid version
603 IOS_Close(hid_fd);
604 iosFree(hId, hid_host);
605 hid_host = NULL;
606 } else
607 IOS_IoctlAsync(hid_fd, USBV5_IOCTL_GETDEVICECHANGE, NULL, 0, hid_host->attached_devices, 0x180, __usbv5_devicechangeCB, hid_host);
609 iosFree(hId, hid_ver);
613 return IPC_OK;
615 mem_error:
616 USB_Deinitialize();
617 return IPC_ENOMEM;
620 s32 USB_Deinitialize()
622 if (hid_host) {
623 if (hid_host->fd>=0) {
624 IOS_Ioctl(hid_host->fd, USBV5_IOCTL_SHUTDOWN, NULL, 0, NULL, 0);
625 IOS_Close(hid_host->fd);
627 iosFree(hId, hid_host);
628 hid_host = NULL;
631 if (ven_host) {
632 if (ven_host->fd>=0) {
633 IOS_Ioctl(ven_host->fd, USBV5_IOCTL_SHUTDOWN, NULL, 0, NULL, 0);
634 IOS_Close(ven_host->fd);
636 iosFree(hId, ven_host);
637 ven_host = NULL;
640 return IPC_OK;
643 s32 USB_OpenDevice(s32 device_id,u16 vid,u16 pid,s32 *fd)
645 s32 ret = USB_OK;
646 char *devicepath = NULL;
647 *fd = -1;
649 if (device_id && device_id!=USB_OH1_DEVICE_ID) {
650 int i;
652 i = __find_device_on_host(ven_host, device_id);
653 if (i<0)
654 i = __find_device_on_host(hid_host, device_id);
655 if (i>=0) {
656 *fd = device_id;
657 USB_ResumeDevice(device_id);
658 return 0;
662 devicepath = iosAlloc(hId,USB_MAXPATH);
663 if(devicepath==NULL) return IPC_ENOMEM;
665 if (device_id==USB_OH1_DEVICE_ID)
666 snprintf(devicepath,USB_MAXPATH,"/dev/usb/oh1/%x/%x",vid,pid);
667 else
668 snprintf(devicepath,USB_MAXPATH,"/dev/usb/oh0/%x/%x",vid,pid);
670 *fd = IOS_Open(devicepath,0);
671 if(*fd<0) ret = *fd;
673 if (devicepath!=NULL) iosFree(hId,devicepath);
674 return ret;
677 s32 USBV5_CloseDevice(s32 device_id)
679 int i;
680 struct _usbv5_host* host;
682 if (__find_device_on_host(ven_host, device_id)>=0)
683 host = ven_host;
684 else if (__find_device_on_host(hid_host, device_id)>=0)
685 host = hid_host;
686 else
687 return IPC_EINVAL;
689 for (i=0; i < USB_MAX_DEVICES; i++) {
690 if (host->remove_cb[i].cb==NULL)
691 continue;
693 if (host->remove_cb[i].device_id==device_id) {
694 host->remove_cb[i].cb(0, host->remove_cb[i].userdata);
695 host->remove_cb[i].cb = NULL;
696 break;
699 //return USB_SuspendDevice(device_id);
700 return 0;
703 s32 USB_CloseDevice(s32 *fd)
705 s32 ret = IPC_EINVAL;
706 if (fd) {
707 ret = USBV5_CloseDevice(*fd);
708 if (ret==IPC_EINVAL && *fd>0)
709 ret = IOS_Close(*fd);
710 if (ret>=0) *fd = -1;
713 return ret;
716 s32 USB_CloseDeviceAsync(s32 *fd,usbcallback cb,void *userdata)
718 s32 ret = IPC_EINVAL;
719 if(fd) {
720 ret = USBV5_CloseDevice(*fd);
721 if (ret!=IPC_EINVAL) {
722 if (cb)
723 return cb(ret, userdata);
724 else
725 return ret;
727 if (*fd>0)
728 return IOS_CloseAsync(*fd,cb,userdata);
731 return ret;
734 s32 USB_GetDeviceDescription(s32 fd,usb_devdesc *devdesc)
736 s32 ret;
737 usb_devdesc *p;
739 p = iosAlloc(hId,USB_DT_DEVICE_SIZE);
740 if(p==NULL) return IPC_ENOMEM;
742 ret = __usb_control_message(fd,USB_CTRLTYPE_DIR_DEVICE2HOST,USB_REQ_GETDESCRIPTOR,(USB_DT_DEVICE<<8),0,USB_DT_DEVICE_SIZE,p,NULL,NULL);
743 if(ret>=0) memcpy(devdesc,p,USB_DT_DEVICE_SIZE);
744 devdesc->configurations = NULL;
746 if(p!=NULL) iosFree(hId,p);
747 return ret;
750 static s32 USBV5_GetDescriptors(s32 device_id, usb_devdesc *udd)
752 s32 retval = IPC_ENOMEM;
753 u32 *io_buffer = NULL;
754 u8 *buffer = NULL;
755 usb_configurationdesc *ucd = NULL;
756 usb_interfacedesc *uid = NULL;
757 usb_endpointdesc *ued = NULL;
758 u32 iConf, iEndpoint;
759 s32 fd;
760 u32 desc_out_size, desc_start_offset;
762 if (__find_device_on_host(ven_host, device_id)>=0) {
763 fd = ven_host->fd;
764 desc_out_size = 0xC0;
765 desc_start_offset = 20;
766 } else if (__find_device_on_host(hid_host, device_id)>=0) {
767 fd = hid_host->fd;
768 desc_out_size = 0x60;
769 desc_start_offset = 36;
770 } else
771 return IPC_EINVAL;
773 io_buffer = (u32*)iosAlloc(hId, 0x20);
774 buffer = (u8*)iosAlloc(hId, desc_out_size);
775 if (io_buffer==NULL || buffer==NULL) goto free_bufs;
777 io_buffer[0] = device_id;
778 io_buffer[2] = 0;
779 memset(buffer, 0, desc_out_size);
780 retval = IOS_Ioctl(fd, USBV5_IOCTL_GETDEVPARAMS, io_buffer, 0x20, buffer, desc_out_size);
781 if (retval==IPC_OK) {
782 u8 *next = buffer+desc_start_offset;
784 memcpy(udd, next, sizeof(*udd));
785 udd->configurations = calloc(udd->bNumConfigurations, sizeof(*udd->configurations));
786 if(udd->configurations == NULL) goto free_bufs;
788 next += (udd->bLength+3)&~3;
789 for (iConf = 0; iConf < udd->bNumConfigurations; iConf++)
791 ucd = &udd->configurations[iConf];
792 memcpy(ucd, next, USB_DT_CONFIG_SIZE);
793 next += (USB_DT_CONFIG_SIZE+3)&~3;
795 // ignore the actual value of bNumInterfaces; IOS presents each interface as a different device
796 // alternate settings will not show up here, if you want them you must explicitly request
797 // the interface descriptor
798 if (ucd->bNumInterfaces==0)
799 continue;
801 ucd->bNumInterfaces = 1;
802 ucd->interfaces = calloc(1, sizeof(*ucd->interfaces));
803 if (ucd->interfaces == NULL) goto free_bufs;
805 uid = ucd->interfaces;
806 memcpy(uid, next, USB_DT_INTERFACE_SIZE);
807 next += (uid->bLength+3)&~3;
809 /* This skips vendor and class specific descriptors */
810 uid->extra_size = __find_next_endpoint(next, buffer+desc_out_size-next, 3);
811 if(uid->extra_size>0)
813 uid->extra = malloc(uid->extra_size);
814 if(uid->extra == NULL)
815 goto free_bufs;
816 memcpy(uid->extra, next, uid->extra_size);
817 // already rounded
818 next += uid->extra_size;
821 if (uid->bNumEndpoints) {
822 uid->endpoints = calloc(uid->bNumEndpoints, sizeof(*uid->endpoints));
823 if (uid->endpoints == NULL) goto free_bufs;
825 for(iEndpoint = 0; iEndpoint < uid->bNumEndpoints; iEndpoint++)
827 ued = &uid->endpoints[iEndpoint];
828 memcpy(ued, next, USB_DT_ENDPOINT_SIZE);
829 next += (ued->bLength+3)&~3;
835 retval = IPC_OK;
838 free_bufs:
839 if (io_buffer!=NULL)
840 iosFree(hId, io_buffer);
841 if (buffer!=NULL)
842 iosFree(hId, buffer);
843 if (retval<0)
844 USB_FreeDescriptors(udd);
845 return retval;
848 s32 USB_GetDescriptors(s32 fd, usb_devdesc *udd)
850 u8 *buffer = NULL;
851 u8 *ptr = NULL;
852 usb_configurationdesc *ucd = NULL;
853 usb_interfacedesc *uid = NULL;
854 usb_endpointdesc *ued = NULL;
855 s32 retval = 0;
856 u32 size;
857 u32 iConf, iInterface, iEndpoint;
859 if (fd>=0x20 || fd<-1)
860 return USBV5_GetDescriptors(fd, udd);
862 buffer = iosAlloc(hId, sizeof(*udd));
863 if(buffer == NULL)
865 retval = IPC_ENOHEAP;
866 goto free_and_error;
869 retval = __usb_getdesc(fd, buffer, USB_DT_DEVICE, 0, 0, USB_DT_DEVICE_SIZE);
870 if(retval < 0)
871 goto free_and_error;
872 memcpy(udd, buffer, USB_DT_DEVICE_SIZE);
873 iosFree(hId, buffer);
875 udd->bcdUSB = bswap16(udd->bcdUSB);
876 udd->idVendor = bswap16(udd->idVendor);
877 udd->idProduct = bswap16(udd->idProduct);
878 udd->bcdDevice = bswap16(udd->bcdDevice);
880 udd->configurations = calloc(udd->bNumConfigurations, sizeof(*udd->configurations));
881 if(udd->configurations == NULL)
883 retval = IPC_ENOMEM;
884 goto free_and_error;
886 for(iConf = 0; iConf < udd->bNumConfigurations; iConf++)
888 buffer = iosAlloc(hId, USB_DT_CONFIG_SIZE);
889 if(buffer == NULL)
891 retval = IPC_ENOHEAP;
892 goto free_and_error;
895 retval = __usb_getdesc(fd, buffer, USB_DT_CONFIG, iConf, 0, USB_DT_CONFIG_SIZE);
896 ucd = &udd->configurations[iConf];
897 memcpy(ucd, buffer, USB_DT_CONFIG_SIZE);
898 iosFree(hId, buffer);
900 ucd->wTotalLength = bswap16(ucd->wTotalLength);
901 size = ucd->wTotalLength;
902 buffer = iosAlloc(hId, size);
903 if(buffer == NULL)
905 retval = IPC_ENOHEAP;
906 goto free_and_error;
909 retval = __usb_getdesc(fd, buffer, USB_DT_CONFIG, iConf, 0, ucd->wTotalLength);
910 if(retval < 0)
911 goto free_and_error;
913 ptr = buffer;
914 ptr += ucd->bLength;
915 size -= ucd->bLength;
917 retval = IPC_ENOMEM;
919 ucd->interfaces = calloc(ucd->bNumInterfaces, sizeof(*ucd->interfaces));
920 if(ucd->interfaces == NULL)
921 goto free_and_error;
922 for(iInterface = 0; iInterface < ucd->bNumInterfaces; iInterface++)
924 uid = ucd->interfaces+iInterface;
925 memcpy(uid, ptr, USB_DT_INTERFACE_SIZE);
926 ptr += uid->bLength;
927 size -= uid->bLength;
929 /* This skips vendor and class specific descriptors */
930 uid->extra_size = __find_next_endpoint(ptr, size, 0);
931 if(uid->extra_size>0)
933 uid->extra = malloc(uid->extra_size);
934 if(uid->extra == NULL)
935 goto free_and_error;
936 memcpy(uid->extra, ptr, uid->extra_size);
937 ptr += uid->extra_size;
938 size -= uid->extra_size;
941 if (uid->bNumEndpoints) {
942 uid->endpoints = calloc(uid->bNumEndpoints, sizeof(*uid->endpoints));
943 if(uid->endpoints == NULL)
944 goto free_and_error;
946 for(iEndpoint = 0; iEndpoint < uid->bNumEndpoints; iEndpoint++)
948 ued = &uid->endpoints[iEndpoint];
949 memcpy(ued, ptr, USB_DT_ENDPOINT_SIZE);
950 ptr += ued->bLength;
951 size -= ued->bLength;
952 ued->wMaxPacketSize = bswap16(ued->wMaxPacketSize);
956 if (iInterface==(ucd->bNumInterfaces-1) && size>2 && ptr[0]==USB_DT_INTERFACE_SIZE && ptr[1]==USB_DT_INTERFACE) {
957 // looks like there's interfaces with alternate settings on this device.
958 // grab them and make them look like separate interfaces
959 usb_interfacedesc *interfaces = realloc(ucd->interfaces, (iInterface+2)*sizeof(*interfaces));
960 if (interfaces == NULL)
961 goto free_and_error;
962 interfaces[iInterface+1].endpoints = NULL;
963 interfaces[iInterface+1].extra = NULL;
964 ucd->bNumInterfaces++;
965 ucd->interfaces = interfaces;
968 iosFree(hId, buffer);
969 buffer = NULL;
971 retval = IPC_OK;
973 free_and_error:
974 if(buffer != NULL)
975 iosFree(hId, buffer);
976 if(retval < 0)
977 USB_FreeDescriptors(udd);
978 return retval;
981 s32 USB_GetGenericDescriptor(s32 fd,u8 type,u8 index,u8 interface,void *data,u32 size) {
982 u8 *buffer;
983 s32 retval;
985 buffer = iosAlloc(hId,sizeof(size));
986 if(buffer==NULL) {
987 retval = IPC_ENOMEM;
988 goto free_and_error;
991 retval = __usb_getdesc(fd,buffer,type,index,interface,size);
992 if(retval<0) goto free_and_error;
994 memcpy(data,buffer,size);
995 retval = IPC_OK;
997 free_and_error:
998 if(buffer!=NULL) iosFree(hId,buffer);
999 return retval;
1002 s32 USB_GetHIDDescriptor(s32 fd,u8 interface,usb_hiddesc *uhd,u32 size)
1004 int i;
1005 s32 retval;
1007 if (size < USB_DT_HID_SIZE)
1008 return IPC_EINVAL;
1010 retval = USB_GetGenericDescriptor(fd, USB_DT_HID, 0, interface, uhd, size);
1011 if (retval != IPC_OK)
1012 return retval;
1014 uhd->bcdHID = bswap16(uhd->bcdHID);
1015 uhd->descr[0].wDescriptorLength = bswap16(uhd->descr[0].wDescriptorLength);
1016 size -= USB_DT_HID_SIZE;
1017 for (i=1; i<uhd->bNumDescriptors && size>=3; size -=3, i++)
1018 uhd->descr[i].wDescriptorLength = bswap16(uhd->descr[i].wDescriptorLength);
1020 return retval;
1023 void USB_FreeDescriptors(usb_devdesc *udd)
1025 int iConf, iInterface;
1026 usb_configurationdesc *ucd;
1027 usb_interfacedesc *uid;
1028 if(udd->configurations != NULL)
1030 for(iConf = 0; iConf < udd->bNumConfigurations; iConf++)
1032 ucd = &udd->configurations[iConf];
1033 if(ucd->interfaces != NULL)
1035 for(iInterface = 0; iInterface < ucd->bNumInterfaces; iInterface++)
1037 uid = ucd->interfaces+iInterface;
1038 free(uid->endpoints);
1039 free(uid->extra);
1041 free(ucd->interfaces);
1044 free(udd->configurations);
1048 s32 USB_GetAsciiString(s32 fd,u8 bIndex,u16 wLangID,u16 wLength,void *rpData)
1050 s32 ret;
1051 u8 bo, ro;
1052 u8 *buf;
1053 u8 *rp = (u8 *)rpData;
1055 if(wLength > 255)
1056 wLength = 255;
1058 buf = iosAlloc(hId, 255); /* 255 is the highest possible length of a descriptor */
1059 if(buf == NULL)
1060 return IPC_ENOMEM;
1062 ret = __usb_getdesc(fd, buf, USB_DT_STRING, bIndex, wLangID, 255);
1064 /* index 0 gets a list of supported languages */
1065 if(bIndex == 0)
1067 if(ret > 0)
1068 memcpy(rpData, buf, wLength);
1069 iosFree(hId, buf);
1070 return ret;
1073 if(ret > 0)
1075 bo = 2;
1076 ro = 0;
1077 while(ro < (wLength - 1) && bo < buf[0])
1079 if(buf[bo + 1])
1080 rp[ro++] = '?';
1081 else
1082 rp[ro++] = buf[bo];
1083 bo += 2;
1085 rp[ro] = 0;
1086 ret = ro - 1;
1089 iosFree(hId, buf);
1090 return ret;
1093 s32 USB_ReadIsoMsg(s32 fd,u8 bEndpoint,u8 bPackets,u16 *rpPacketSizes,void *rpData)
1095 return __usb_isochronous_message(fd,bEndpoint,bPackets,rpPacketSizes,rpData,NULL,NULL);
1098 s32 USB_ReadIsoMsgAsync(s32 fd,u8 bEndpoint,u8 bPackets,u16 *rpPacketSizes,void *rpData,usbcallback cb,void *userdata)
1100 return __usb_isochronous_message(fd,bEndpoint,bPackets,rpPacketSizes,rpData,cb,userdata);
1103 s32 USB_WriteIsoMsg(s32 fd,u8 bEndpoint,u8 bPackets,u16 *rpPacketSizes,void *rpData)
1105 return __usb_isochronous_message(fd,bEndpoint,bPackets,rpPacketSizes,rpData,NULL,NULL);
1108 s32 USB_WriteIsoMsgAsync(s32 fd,u8 bEndpoint,u8 bPackets,u16 *rpPacketSizes,void *rpData,usbcallback cb,void *userdata)
1110 return __usb_isochronous_message(fd,bEndpoint,bPackets,rpPacketSizes,rpData,cb,userdata);
1113 s32 USB_ReadIntrMsg(s32 fd,u8 bEndpoint,u16 wLength,void *rpData)
1115 return __usb_interrupt_bulk_message(fd,USBV0_IOCTL_INTRMSG,bEndpoint,wLength,rpData,NULL,NULL);
1118 s32 USB_ReadIntrMsgAsync(s32 fd,u8 bEndpoint,u16 wLength,void *rpData,usbcallback cb,void *userdata)
1120 return __usb_interrupt_bulk_message(fd,USBV0_IOCTL_INTRMSG,bEndpoint,wLength,rpData,cb,userdata);
1123 s32 USB_WriteIntrMsg(s32 fd,u8 bEndpoint,u16 wLength,void *rpData)
1125 return __usb_interrupt_bulk_message(fd,USBV0_IOCTL_INTRMSG,bEndpoint,wLength,rpData,NULL,NULL);
1128 s32 USB_WriteIntrMsgAsync(s32 fd,u8 bEndpoint,u16 wLength,void *rpData,usbcallback cb,void *userdata)
1130 return __usb_interrupt_bulk_message(fd,USBV0_IOCTL_INTRMSG,bEndpoint,wLength,rpData,cb,userdata);
1133 s32 USB_ReadBlkMsg(s32 fd,u8 bEndpoint,u16 wLength,void *rpData)
1135 return __usb_interrupt_bulk_message(fd,USBV0_IOCTL_BLKMSG,bEndpoint,wLength,rpData,NULL,NULL);
1138 s32 USB_ReadBlkMsgAsync(s32 fd,u8 bEndpoint,u16 wLength,void *rpData,usbcallback cb,void *userdata)
1140 return __usb_interrupt_bulk_message(fd,USBV0_IOCTL_BLKMSG,bEndpoint,wLength,rpData,cb,userdata);
1143 s32 USB_WriteBlkMsg(s32 fd,u8 bEndpoint,u16 wLength,void *rpData)
1145 return __usb_interrupt_bulk_message(fd,USBV0_IOCTL_BLKMSG,bEndpoint,wLength,rpData,NULL,NULL);
1148 s32 USB_WriteBlkMsgAsync(s32 fd,u8 bEndpoint,u16 wLength,void *rpData,usbcallback cb,void *userdata)
1150 return __usb_interrupt_bulk_message(fd,USBV0_IOCTL_BLKMSG,bEndpoint,wLength,rpData,cb,userdata);
1153 s32 USB_ReadCtrlMsg(s32 fd,u8 bmRequestType,u8 bmRequest,u16 wValue,u16 wIndex,u16 wLength,void *rpData)
1155 return __usb_control_message(fd,bmRequestType,bmRequest,wValue,wIndex,wLength,rpData,NULL,NULL);
1158 s32 USB_ReadCtrlMsgAsync(s32 fd,u8 bmRequestType,u8 bmRequest,u16 wValue,u16 wIndex,u16 wLength,void *rpData,usbcallback cb,void *userdata)
1160 return __usb_control_message(fd,bmRequestType,bmRequest,wValue,wIndex,wLength,rpData,cb,userdata);
1163 s32 USB_WriteCtrlMsg(s32 fd,u8 bmRequestType,u8 bmRequest,u16 wValue,u16 wIndex,u16 wLength,void *rpData)
1165 return __usb_control_message(fd,bmRequestType,bmRequest,wValue,wIndex,wLength,rpData,NULL,NULL);
1168 s32 USB_WriteCtrlMsgAsync(s32 fd,u8 bmRequestType,u8 bmRequest,u16 wValue,u16 wIndex,u16 wLength,void *rpData,usbcallback cb,void *userdata)
1170 return __usb_control_message(fd,bmRequestType,bmRequest,wValue,wIndex,wLength,rpData,cb,userdata);
1173 static s32 USB5_RegisterDeviceRemoval(struct _usbv5_host *host, s32 device_id, usbcallback cb, void *userdata)
1175 int i;
1177 // check to make sure the device is present
1178 if (__find_device_on_host(host, device_id)<0)
1179 return IPC_ENOENT;
1181 // now make sure it's not hooked already
1182 for (i=0; i<USB_MAX_DEVICES; i++) {
1183 if (host->remove_cb[i].cb && host->remove_cb[i].device_id==device_id)
1184 return IPC_EINVAL;
1187 // find a free entry and add it
1188 for (i=0; i<USB_MAX_DEVICES; i++) {
1189 if (host->remove_cb[i].cb==NULL) {
1190 host->remove_cb[i].cb = cb;
1191 host->remove_cb[i].userdata = userdata;
1192 host->remove_cb[i].device_id = device_id;
1193 return IPC_OK;
1196 return IPC_EINVAL;
1199 s32 USB_DeviceRemovalNotifyAsync(s32 fd,usbcallback cb,void *userdata)
1201 s32 ret;
1202 if (fd>=0 && fd<0x20)
1203 return IOS_IoctlAsync(fd,USBV0_IOCTL_DEVREMOVALHOOK,NULL,0,NULL,0,cb,userdata);
1205 ret = USB5_RegisterDeviceRemoval(ven_host, fd, cb, userdata);
1206 if (ret == IPC_ENOENT)
1207 ret = USB5_RegisterDeviceRemoval(hid_host, fd, cb, userdata);
1209 return ret;
1212 static s32 USBV5_SuspendResume(s32 device_id, s32 resumed)
1214 s32 ret;
1215 s32 fd;
1217 if (__find_device_on_host(ven_host, device_id)>=0)
1218 fd = ven_host->fd;
1219 else if (__find_device_on_host(hid_host, device_id)>=0)
1220 fd = hid_host->fd;
1221 else
1222 return IPC_ENOENT;
1224 s32 *buf = (s32*)iosAlloc(hId, 32);
1225 if (buf==NULL) return IPC_ENOMEM;
1227 buf[0] = device_id;
1228 buf[2] = resumed;
1229 ret = IOS_Ioctl(fd, USBV5_IOCTL_SUSPEND_RESUME, buf, 32, NULL, 0);
1230 iosFree(hId, buf);
1232 return ret;
1235 s32 USB_SuspendDevice(s32 fd)
1237 if (fd>=0x20 || fd<-1)
1238 return USBV5_SuspendResume(fd, 0);
1240 return IOS_Ioctl(fd,USBV0_IOCTL_SUSPENDDEV,NULL,0,NULL,0);
1243 s32 USB_ResumeDevice(s32 fd)
1245 if (fd>=0x20 || fd<-1)
1246 return USBV5_SuspendResume(fd, 1);
1248 return IOS_Ioctl(fd,USBV0_IOCTL_RESUMEDEV,NULL,0,NULL,0);
1251 // TODO: Implement this for VEN and HID
1252 s32 USB_DeviceChangeNotifyAsync(u8 interface_class, usbcallback cb, void* userdata)
1254 s32 fd;
1255 struct _usb_msg *msg;
1256 s32 ret;
1258 fd = IOS_Open(__oh0_path,IPC_OPEN_NONE);
1259 if (fd<0) return fd;
1261 msg = iosAlloc(hId,sizeof(*msg));
1262 if (msg==NULL) {
1263 IOS_Close(fd);
1264 return IPC_ENOMEM;
1267 msg->cb = cb;
1268 msg->userdata = userdata;
1269 msg->class = interface_class;
1271 msg->vec[0].data = &msg->class;
1272 msg->vec[0].len = 1;
1274 ret = IOS_IoctlvAsync(fd,USBV0_IOCTL_DEVICECLASSCHANGE,1,0,msg->vec,__usbv5_messageCB,msg);
1275 IOS_Close(fd);
1277 if (ret<0) iosFree(hId, msg);
1279 return ret;
1282 s32 USB_GetDeviceList(usb_device_entry *descr_buffer,u8 num_descr,u8 interface_class,u8 *cnt_descr)
1284 int i;
1285 u8 cntdevs=0;
1287 if (ven_host==NULL) {
1288 s32 fd;
1289 u32 *buf = (u32*)iosAlloc(hId, num_descr<<3);
1290 if (buf==NULL) return IPC_ENOMEM;
1292 fd = IOS_Open(__oh0_path,IPC_OPEN_NONE);
1293 if (fd<0) {
1294 iosFree(hId, buf);
1295 return fd;
1298 cntdevs = 0;
1299 i = IOS_IoctlvFormat(hId,fd,USBV0_IOCTL_GETDEVLIST,"bb:dd",num_descr,interface_class,&cntdevs,sizeof(cntdevs),buf,(num_descr<<3));
1300 if (cnt_descr) *cnt_descr = cntdevs;
1302 while (cntdevs--) {
1303 descr_buffer[cntdevs].device_id = 0;
1304 descr_buffer[cntdevs].vid = (u16)(buf[cntdevs*2+1]>>16);
1305 descr_buffer[cntdevs].pid = (u16)buf[cntdevs*2+1];
1308 IOS_Close(fd);
1309 iosFree(hId, buf);
1310 return i;
1313 // for ven_host, we can only exclude usb_hid class devices
1314 if (interface_class != USB_CLASS_HID && ven_host) {
1315 i=0;
1316 while (cntdevs<num_descr && ven_host->attached_devices[i].device_id) {
1317 descr_buffer[cntdevs++] = ven_host->attached_devices[i++];
1318 if (i>=32) break;
1322 if ((!interface_class || interface_class==USB_CLASS_HID) && hid_host) {
1323 i=0;
1324 while (cntdevs<num_descr && hid_host->attached_devices[i].device_id) {
1325 descr_buffer[cntdevs++] = hid_host->attached_devices[i++];
1326 if (i>32) break;
1330 if (cnt_descr) *cnt_descr = cntdevs;
1332 return IPC_OK;
1335 s32 USB_SetConfiguration(s32 fd, u8 configuration)
1337 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);
1340 s32 USB_GetConfiguration(s32 fd, u8 *configuration)
1342 u8 *_configuration;
1343 s32 retval;
1345 _configuration = iosAlloc(hId, 1);
1346 if(_configuration == NULL)
1347 return IPC_ENOMEM;
1349 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);
1350 if(retval >= 0)
1351 *configuration = *_configuration;
1352 iosFree(hId, _configuration);
1354 return retval;
1357 s32 USB_SetAlternativeInterface(s32 fd, u8 interface, u8 alternateSetting)
1359 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);
1362 static s32 USBV5_CancelEndpoint(s32 device_id, u8 endpoint)
1364 s32 ret;
1365 s32 fd;
1367 if (__find_device_on_host(ven_host, device_id)>=0)
1368 fd = ven_host->fd;
1369 else if (__find_device_on_host(hid_host, device_id)>=0)
1370 fd = hid_host->fd;
1371 else
1372 return IPC_ENOENT;
1374 s32 *buf = (s32*)iosAlloc(hId, 32);
1375 if (buf==NULL) return IPC_ENOMEM;
1377 buf[0] = device_id;
1378 buf[2] = endpoint;
1379 ret = IOS_Ioctl(fd, USBV5_IOCTL_CANCELENDPOINT, buf, 32, NULL, 0);
1380 iosFree(hId, buf);
1382 return ret;
1385 s32 USB_ClearHalt(s32 fd, u8 endpoint)
1387 if (fd>=0x20 || fd<-1)
1388 return USBV5_CancelEndpoint(fd, endpoint);
1389 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);
1392 #endif /* defined(HW_RVL) */