usb patches (tueidj)
[libogc.git] / libogc / usb.c
blobf3aee07779b591336b7254dca1d9de45063d4527
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, u8 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 ucd = &udd->configurations[iConf];
927 memcpy(ucd, buffer, USB_DT_CONFIG_SIZE);
928 iosFree(hId, buffer);
930 ucd->wTotalLength = bswap16(ucd->wTotalLength);
931 size = ucd->wTotalLength;
932 buffer = iosAlloc(hId, size);
933 if(buffer == NULL)
935 retval = IPC_ENOHEAP;
936 goto free_and_error;
939 retval = __usb_getdesc(fd, buffer, USB_DT_CONFIG, iConf, 0, ucd->wTotalLength);
940 if(retval < 0)
941 goto free_and_error;
943 ptr = buffer;
944 ptr += ucd->bLength;
945 size -= ucd->bLength;
947 retval = IPC_ENOMEM;
949 ucd->interfaces = calloc(ucd->bNumInterfaces, sizeof(*ucd->interfaces));
950 if(ucd->interfaces == NULL)
951 goto free_and_error;
952 for(iInterface = 0; iInterface < ucd->bNumInterfaces; iInterface++)
954 uid = ucd->interfaces+iInterface;
955 memcpy(uid, ptr, USB_DT_INTERFACE_SIZE);
956 ptr += uid->bLength;
957 size -= uid->bLength;
959 /* This skips vendor and class specific descriptors */
960 uid->extra_size = __find_next_endpoint(ptr, size, 0);
961 if(uid->extra_size>0)
963 uid->extra = malloc(uid->extra_size);
964 if(uid->extra == NULL)
965 goto free_and_error;
966 memcpy(uid->extra, ptr, uid->extra_size);
967 ptr += uid->extra_size;
968 size -= uid->extra_size;
971 if (uid->bNumEndpoints) {
972 uid->endpoints = calloc(uid->bNumEndpoints, sizeof(*uid->endpoints));
973 if(uid->endpoints == NULL)
974 goto free_and_error;
976 for(iEndpoint = 0; iEndpoint < uid->bNumEndpoints; iEndpoint++)
978 ued = &uid->endpoints[iEndpoint];
979 memcpy(ued, ptr, USB_DT_ENDPOINT_SIZE);
980 ptr += ued->bLength;
981 size -= ued->bLength;
982 ued->wMaxPacketSize = bswap16(ued->wMaxPacketSize);
986 if (iInterface==(ucd->bNumInterfaces-1) && size>2 && ptr[0]==USB_DT_INTERFACE_SIZE && ptr[1]==USB_DT_INTERFACE) {
987 // looks like there's interfaces with alternate settings on this device.
988 // grab them and make them look like separate interfaces
989 usb_interfacedesc *interfaces = realloc(ucd->interfaces, (iInterface+2)*sizeof(*interfaces));
990 if (interfaces == NULL)
991 goto free_and_error;
992 interfaces[iInterface+1].endpoints = NULL;
993 interfaces[iInterface+1].extra = NULL;
994 ucd->bNumInterfaces++;
995 ucd->interfaces = interfaces;
998 iosFree(hId, buffer);
999 buffer = NULL;
1001 retval = IPC_OK;
1003 free_and_error:
1004 if(buffer != NULL)
1005 iosFree(hId, buffer);
1006 if(retval < 0)
1007 USB_FreeDescriptors(udd);
1008 return retval;
1011 s32 USB_GetGenericDescriptor(s32 fd,u8 type,u8 index,u8 interface,void *data,u32 size) {
1012 u8 *buffer;
1013 s32 retval;
1015 buffer = iosAlloc(hId,size);
1016 if(buffer==NULL) {
1017 retval = IPC_ENOMEM;
1018 goto free_and_error;
1021 retval = __usb_getdesc(fd,buffer,type,index,interface,size);
1022 if(retval<0) goto free_and_error;
1024 memcpy(data,buffer,size);
1025 retval = IPC_OK;
1027 free_and_error:
1028 if(buffer!=NULL) iosFree(hId,buffer);
1029 return retval;
1032 s32 USB_GetHIDDescriptor(s32 fd,u8 interface,usb_hiddesc *uhd,u32 size)
1034 int i;
1035 s32 retval;
1037 if (size < USB_DT_HID_SIZE)
1038 return IPC_EINVAL;
1040 retval = USB_GetGenericDescriptor(fd, USB_DT_HID, 0, interface, uhd, size);
1041 if (retval != IPC_OK)
1042 return retval;
1044 uhd->bcdHID = bswap16(uhd->bcdHID);
1045 uhd->descr[0].wDescriptorLength = bswap16(uhd->descr[0].wDescriptorLength);
1046 size -= USB_DT_HID_SIZE;
1047 for (i=1; i<uhd->bNumDescriptors && size>=3; size -=3, i++)
1048 uhd->descr[i].wDescriptorLength = bswap16(uhd->descr[i].wDescriptorLength);
1050 return retval;
1053 void USB_FreeDescriptors(usb_devdesc *udd)
1055 int iConf, iInterface;
1056 usb_configurationdesc *ucd;
1057 usb_interfacedesc *uid;
1058 if(udd->configurations != NULL)
1060 for(iConf = 0; iConf < udd->bNumConfigurations; iConf++)
1062 ucd = &udd->configurations[iConf];
1063 if(ucd->interfaces != NULL)
1065 for(iInterface = 0; iInterface < ucd->bNumInterfaces; iInterface++)
1067 uid = ucd->interfaces+iInterface;
1068 free(uid->endpoints);
1069 free(uid->extra);
1071 free(ucd->interfaces);
1074 free(udd->configurations);
1078 s32 USB_GetAsciiString(s32 fd,u8 bIndex,u16 wLangID,u16 wLength,void *rpData)
1080 s32 ret;
1081 u8 bo, ro;
1082 u8 *buf;
1083 u8 *rp = (u8 *)rpData;
1085 if(wLength > 255)
1086 wLength = 255;
1088 buf = iosAlloc(hId, 255); /* 255 is the highest possible length of a descriptor */
1089 if(buf == NULL)
1090 return IPC_ENOMEM;
1092 ret = __usb_getdesc(fd, buf, USB_DT_STRING, bIndex, wLangID, 255);
1094 /* index 0 gets a list of supported languages */
1095 if(bIndex == 0)
1097 if(ret > 0)
1098 memcpy(rpData, buf, wLength);
1099 iosFree(hId, buf);
1100 return ret;
1103 if(ret > 0)
1105 bo = 2;
1106 ro = 0;
1107 while(ro < (wLength - 1) && bo < buf[0])
1109 if(buf[bo + 1])
1110 rp[ro++] = '?';
1111 else
1112 rp[ro++] = buf[bo];
1113 bo += 2;
1115 rp[ro] = 0;
1116 ret = ro - 1;
1119 iosFree(hId, buf);
1120 return ret;
1123 s32 USB_ReadIsoMsg(s32 fd,u8 bEndpoint,u8 bPackets,u16 *rpPacketSizes,void *rpData)
1125 return __usb_isochronous_message(fd,bEndpoint,bPackets,rpPacketSizes,rpData,NULL,NULL);
1128 s32 USB_ReadIsoMsgAsync(s32 fd,u8 bEndpoint,u8 bPackets,u16 *rpPacketSizes,void *rpData,usbcallback cb,void *userdata)
1130 return __usb_isochronous_message(fd,bEndpoint,bPackets,rpPacketSizes,rpData,cb,userdata);
1133 s32 USB_WriteIsoMsg(s32 fd,u8 bEndpoint,u8 bPackets,u16 *rpPacketSizes,void *rpData)
1135 return __usb_isochronous_message(fd,bEndpoint,bPackets,rpPacketSizes,rpData,NULL,NULL);
1138 s32 USB_WriteIsoMsgAsync(s32 fd,u8 bEndpoint,u8 bPackets,u16 *rpPacketSizes,void *rpData,usbcallback cb,void *userdata)
1140 return __usb_isochronous_message(fd,bEndpoint,bPackets,rpPacketSizes,rpData,cb,userdata);
1143 s32 USB_ReadIntrMsg(s32 fd,u8 bEndpoint,u16 wLength,void *rpData)
1145 return __usb_interrupt_bulk_message(fd,USBV0_IOCTL_INTRMSG,bEndpoint,wLength,rpData,NULL,NULL);
1148 s32 USB_ReadIntrMsgAsync(s32 fd,u8 bEndpoint,u16 wLength,void *rpData,usbcallback cb,void *userdata)
1150 return __usb_interrupt_bulk_message(fd,USBV0_IOCTL_INTRMSG,bEndpoint,wLength,rpData,cb,userdata);
1153 s32 USB_WriteIntrMsg(s32 fd,u8 bEndpoint,u16 wLength,void *rpData)
1155 return __usb_interrupt_bulk_message(fd,USBV0_IOCTL_INTRMSG,bEndpoint,wLength,rpData,NULL,NULL);
1158 s32 USB_WriteIntrMsgAsync(s32 fd,u8 bEndpoint,u16 wLength,void *rpData,usbcallback cb,void *userdata)
1160 return __usb_interrupt_bulk_message(fd,USBV0_IOCTL_INTRMSG,bEndpoint,wLength,rpData,cb,userdata);
1163 s32 USB_ReadBlkMsg(s32 fd,u8 bEndpoint,u16 wLength,void *rpData)
1165 return __usb_interrupt_bulk_message(fd,USBV0_IOCTL_BLKMSG,bEndpoint,wLength,rpData,NULL,NULL);
1168 s32 USB_ReadBlkMsgAsync(s32 fd,u8 bEndpoint,u16 wLength,void *rpData,usbcallback cb,void *userdata)
1170 return __usb_interrupt_bulk_message(fd,USBV0_IOCTL_BLKMSG,bEndpoint,wLength,rpData,cb,userdata);
1173 s32 USB_WriteBlkMsg(s32 fd,u8 bEndpoint,u16 wLength,void *rpData)
1175 return __usb_interrupt_bulk_message(fd,USBV0_IOCTL_BLKMSG,bEndpoint,wLength,rpData,NULL,NULL);
1178 s32 USB_WriteBlkMsgAsync(s32 fd,u8 bEndpoint,u16 wLength,void *rpData,usbcallback cb,void *userdata)
1180 return __usb_interrupt_bulk_message(fd,USBV0_IOCTL_BLKMSG,bEndpoint,wLength,rpData,cb,userdata);
1183 s32 USB_ReadCtrlMsg(s32 fd,u8 bmRequestType,u8 bmRequest,u16 wValue,u16 wIndex,u16 wLength,void *rpData)
1185 return __usb_control_message(fd,bmRequestType,bmRequest,wValue,wIndex,wLength,rpData,NULL,NULL);
1188 s32 USB_ReadCtrlMsgAsync(s32 fd,u8 bmRequestType,u8 bmRequest,u16 wValue,u16 wIndex,u16 wLength,void *rpData,usbcallback cb,void *userdata)
1190 return __usb_control_message(fd,bmRequestType,bmRequest,wValue,wIndex,wLength,rpData,cb,userdata);
1193 s32 USB_WriteCtrlMsg(s32 fd,u8 bmRequestType,u8 bmRequest,u16 wValue,u16 wIndex,u16 wLength,void *rpData)
1195 return __usb_control_message(fd,bmRequestType,bmRequest,wValue,wIndex,wLength,rpData,NULL,NULL);
1198 s32 USB_WriteCtrlMsgAsync(s32 fd,u8 bmRequestType,u8 bmRequest,u16 wValue,u16 wIndex,u16 wLength,void *rpData,usbcallback cb,void *userdata)
1200 return __usb_control_message(fd,bmRequestType,bmRequest,wValue,wIndex,wLength,rpData,cb,userdata);
1203 static s32 USB5_RegisterDeviceRemoval(struct _usbv5_host *host, s32 device_id, usbcallback cb, void *userdata)
1205 int i;
1207 // check to make sure the device is present
1208 if (__find_device_on_host(host, device_id)<0)
1209 return IPC_ENOENT;
1211 // now make sure it's not hooked already
1212 for (i=0; i<USB_MAX_DEVICES; i++) {
1213 if (host->remove_cb[i].cb && host->remove_cb[i].device_id==device_id)
1214 return IPC_EINVAL;
1217 // find a free entry and add it
1218 for (i=0; i<USB_MAX_DEVICES; i++) {
1219 if (host->remove_cb[i].cb==NULL) {
1220 host->remove_cb[i].cb = cb;
1221 host->remove_cb[i].userdata = userdata;
1222 host->remove_cb[i].device_id = device_id;
1223 return IPC_OK;
1226 return IPC_EINVAL;
1229 s32 USB_DeviceRemovalNotifyAsync(s32 fd,usbcallback cb,void *userdata)
1231 s32 ret;
1232 if (fd>=0 && fd<0x20)
1233 return IOS_IoctlAsync(fd,USBV0_IOCTL_DEVREMOVALHOOK,NULL,0,NULL,0,cb,userdata);
1235 ret = USB5_RegisterDeviceRemoval(ven_host, fd, cb, userdata);
1236 if (ret == IPC_ENOENT)
1237 ret = USB5_RegisterDeviceRemoval(hid_host, fd, cb, userdata);
1239 return ret;
1242 static s32 USBV5_SuspendResume(s32 device_id, s32 resumed)
1244 s32 ret;
1245 s32 fd;
1247 if (__find_device_on_host(ven_host, device_id)>=0)
1248 fd = ven_host->fd;
1249 else if (__find_device_on_host(hid_host, device_id)>=0)
1250 fd = hid_host->fd;
1251 else
1252 return IPC_ENOENT;
1254 s32 *buf = (s32*)iosAlloc(hId, 32);
1255 if (buf==NULL) return IPC_ENOMEM;
1257 buf[0] = device_id;
1258 buf[2] = resumed;
1259 ret = IOS_Ioctl(fd, USBV5_IOCTL_SUSPEND_RESUME, buf, 32, NULL, 0);
1260 iosFree(hId, buf);
1262 return ret;
1265 s32 USB_SuspendDevice(s32 fd)
1267 if (fd>=0x20 || fd<-1)
1268 return USBV5_SuspendResume(fd, 0);
1270 return IOS_Ioctl(fd,USBV0_IOCTL_SUSPENDDEV,NULL,0,NULL,0);
1273 s32 USB_ResumeDevice(s32 fd)
1275 if (fd>=0x20 || fd<-1)
1276 return USBV5_SuspendResume(fd, 1);
1278 return IOS_Ioctl(fd,USBV0_IOCTL_RESUMEDEV,NULL,0,NULL,0);
1281 s32 USB_DeviceChangeNotifyAsync(u8 interface_class, usbcallback cb, void* userdata)
1283 s32 ret=IPC_EQUEUEFULL;
1285 if (ven_host==NULL) {
1286 s32 fd;
1287 struct _usb_msg *msg;
1289 fd = IOS_Open(__oh0_path,IPC_OPEN_NONE);
1290 if (fd<0) return fd;
1292 msg = iosAlloc(hId,sizeof(*msg));
1293 if (msg==NULL) {
1294 IOS_Close(fd);
1295 return IPC_ENOMEM;
1298 msg->cb = cb;
1299 msg->userdata = userdata;
1300 msg->class = interface_class;
1302 msg->vec[0].data = &msg->class;
1303 msg->vec[0].len = 1;
1305 ret = IOS_IoctlvAsync(fd,USBV0_IOCTL_DEVICECLASSCHANGE,1,0,msg->vec,__usbv5_messageCB,msg);
1306 IOS_Close(fd);
1308 if (ret<0) iosFree(hId, msg);
1310 else if (interface_class != USB_CLASS_HID && ven_host) {
1311 if (ven_host->device_change_notify == NULL) {
1312 ret = 0;
1313 ven_host->device_change_notify = cb;
1314 ven_host->device_change_userdata = userdata;
1317 else if (interface_class==USB_CLASS_HID && hid_host) {
1318 if (hid_host->device_change_notify == NULL) {
1319 ret = 0;
1320 hid_host->device_change_notify = cb;
1321 hid_host->device_change_userdata = userdata;
1325 return ret;
1328 s32 USB_GetDeviceList(usb_device_entry *descr_buffer,u8 num_descr,u8 interface_class,u8 *cnt_descr)
1330 int i;
1331 u8 cntdevs=0;
1333 if (ven_host==NULL) {
1334 s32 fd;
1335 u32 *buf = (u32*)iosAlloc(hId, num_descr<<3);
1336 if (buf==NULL) return IPC_ENOMEM;
1338 fd = IOS_Open(__oh0_path,IPC_OPEN_NONE);
1339 if (fd<0) {
1340 iosFree(hId, buf);
1341 return fd;
1344 cntdevs = 0;
1345 i = IOS_IoctlvFormat(hId,fd,USBV0_IOCTL_GETDEVLIST,"bb:dd",num_descr,interface_class,&cntdevs,sizeof(cntdevs),buf,(num_descr<<3));
1346 if (cnt_descr) *cnt_descr = cntdevs;
1348 while (cntdevs--) {
1349 descr_buffer[cntdevs].device_id = 0;
1350 descr_buffer[cntdevs].vid = (u16)(buf[cntdevs*2+1]>>16);
1351 descr_buffer[cntdevs].pid = (u16)buf[cntdevs*2+1];
1354 IOS_Close(fd);
1355 iosFree(hId, buf);
1356 return i;
1359 // for ven_host, we can only exclude usb_hid class devices
1360 if (interface_class != USB_CLASS_HID && ven_host) {
1361 i=0;
1362 while (cntdevs<num_descr && ven_host->attached_devices[i].device_id) {
1363 descr_buffer[cntdevs++] = ven_host->attached_devices[i++];
1364 if (i>=32) break;
1368 if ((!interface_class || interface_class==USB_CLASS_HID) && hid_host) {
1369 i=0;
1370 while (cntdevs<num_descr && hid_host->attached_devices[i].device_id) {
1371 descr_buffer[cntdevs++] = hid_host->attached_devices[i++];
1372 if (i>32) break;
1376 if (cnt_descr) *cnt_descr = cntdevs;
1378 return IPC_OK;
1381 s32 USB_SetConfiguration(s32 fd, u8 configuration)
1383 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);
1386 s32 USB_GetConfiguration(s32 fd, u8 *configuration)
1388 u8 *_configuration;
1389 s32 retval;
1391 _configuration = iosAlloc(hId, 1);
1392 if(_configuration == NULL)
1393 return IPC_ENOMEM;
1395 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);
1396 if(retval >= 0)
1397 *configuration = *_configuration;
1398 iosFree(hId, _configuration);
1400 return retval;
1403 s32 USB_SetAlternativeInterface(s32 fd, u8 interface, u8 alternateSetting)
1405 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);
1408 static s32 USBV5_CancelEndpoint(s32 device_id, u8 endpoint)
1410 s32 ret;
1411 s32 fd;
1413 if (__find_device_on_host(ven_host, device_id)>=0)
1414 fd = ven_host->fd;
1415 else if (__find_device_on_host(hid_host, device_id)>=0)
1416 fd = hid_host->fd;
1417 else
1418 return IPC_ENOENT;
1420 s32 *buf = (s32*)iosAlloc(hId, 32);
1421 if (buf==NULL) return IPC_ENOMEM;
1423 buf[0] = device_id;
1424 buf[2] = endpoint;
1425 ret = IOS_Ioctl(fd, USBV5_IOCTL_CANCELENDPOINT, buf, 32, NULL, 0);
1426 iosFree(hId, buf);
1428 return ret;
1431 s32 USB_ClearHalt(s32 fd, u8 endpoint)
1433 if (fd>=0x20 || fd<-1)
1434 return USBV5_CancelEndpoint(fd, endpoint);
1435 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);
1438 #endif /* defined(HW_RVL) */