1 /*-------------------------------------------------------------
6 Michael Wiedenbauer (shagkur)
7 Dave Murphy (WinterMute)
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
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.
51 #include <processor.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
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
{
102 usb_device_entry attached_devices
[USB_MAX_DEVICES
];
103 struct _usb_cb_removalnotify_list remove_cb
[USB_MAX_DEVICES
];
107 static struct _usbv5_host
* ven_host
= NULL
;
108 static struct _usbv5_host
* hid_host
= NULL
;
151 u32 align_pad
[4]; // pad to 24 bytes
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
;
166 IOS_IoctlAsync(host
->fd
, USBV5_IOCTL_GETDEVICECHANGE
, NULL
, 0, host
->attached_devices
, 0x180, __usbv5_devicechangeCB
, host
);
171 static s32
__usbv5_devicechangeCB(s32 result
, void *p
)
174 struct _usbv5_host
* host
= (struct _usbv5_host
*)p
;
176 if(host
==NULL
) return IPC_EINVAL
;
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
)
184 for (j
=0; j
<result
; j
++) {
185 if (host
->remove_cb
[i
].device_id
== host
->attached_devices
[j
].device_id
)
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
);
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
);
217 static s32
__usbv0_messageCB(s32 result
,void *usrdata
)
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
);
236 static s32
__find_device_on_host(struct _usbv5_host
*host
, s32 device_id
)
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
)
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
;
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
));
272 msg
->userdata
= userdata
;
274 if (device_id
>=0 && device_id
<0x20) {
279 pEndp
= (u8
*)iosAlloc(hId
,32);
280 if(pEndp
==NULL
) goto done
;
283 pLength
= (u16
*)iosAlloc(hId
,32);
284 if(pLength
==NULL
) goto done
;
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
;
306 ret
= IOS_Ioctlv(device_id
, USBV0_IOCTL_ISOMSG
, 3, 2, msg
->vec
);
308 return IOS_IoctlvAsync(device_id
, USBV0_IOCTL_ISOMSG
, 3, 2, msg
->vec
, __usbv0_messageCB
, msg
);
311 if(pEndp
) iosFree(hId
,pEndp
);
312 if(pLength
) iosFree(hId
,pLength
);
313 if(pPackets
) iosFree(hId
,pPackets
);
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
;
332 ret
= IOS_Ioctlv(fd
, USBV5_IOCTL_ISOMSG
, 2-endpoint_dir
, 2+endpoint_dir
, msg
->vec
);
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
);
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
));
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
;
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
;
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
;
406 ret
= IOS_Ioctlv(device_id
, USBV0_IOCTL_CTRLMSG
, 6, 1, msg
->vec
);
408 return IOS_IoctlvAsync(device_id
, USBV0_IOCTL_CTRLMSG
, 6, 1, msg
->vec
, __usbv0_messageCB
, msg
);
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
);
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
;
435 ret
= IOS_Ioctlv(fd
, USBV5_IOCTL_CTRLMSG
, 2-request_dir
, request_dir
, msg
->vec
);
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
);
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
));
461 msg
->userdata
= userdata
;
463 if (device_id
>=0 && device_id
<0x20) {
467 pEndP
= (u8
*)iosAlloc(hId
,32);
468 if(pEndP
==NULL
) goto done
;
471 pLength
= (u16
*)iosAlloc(hId
,32);
472 if(pLength
==NULL
) goto done
;
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;
485 ret
= IOS_Ioctlv(device_id
,ioctl
,2,1,msg
->vec
);
487 return IOS_IoctlvAsync(device_id
,ioctl
,2,1,msg
->vec
,__usbv0_messageCB
,msg
);
490 if(pEndP
!=NULL
) iosFree(hId
,pEndP
);
491 if(pLength
!=NULL
) iosFree(hId
,pLength
);
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
500 msg
->hid_intr_dir
= !endpoint_dir
;
502 msg
->intr
.rpData
= rpData
;
503 msg
->intr
.wLength
= wLength
;
504 msg
->intr
.bEndpoint
= bEndpoint
;
506 ioctl
= USBV5_IOCTL_INTRMSG
;
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
;
520 ret
= IOS_Ioctlv(fd
, ioctl
, 2-endpoint_dir
, endpoint_dir
, msg
->vec
);
522 return IOS_IoctlvAsync(fd
, ioctl
, 2-endpoint_dir
, endpoint_dir
, msg
->vec
, __usbv5_messageCB
, msg
);
525 if(msg
!=NULL
) iosFree(hId
,msg
);
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
)
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
)
548 size
-= (buffer
[0]+align
)&~align
;
549 buffer
+= (buffer
[0]+align
)&~align
;
552 return (buffer
- ptr
);
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
);
563 ven_host
= (struct _usbv5_host
*)iosAlloc(hId
, sizeof(*ven_host
));
564 if (ven_host
==NULL
) {
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
);
578 iosFree(hId
, ven_host
);
582 iosFree(hId
, ven_ver
);
586 if (hid_host
==NULL
) {
587 s32 hid_fd
= IOS_Open(__hid_path
, IPC_OPEN_NONE
);
589 hid_host
= (struct _usbv5_host
*)iosAlloc(hId
, sizeof(*hid_host
));
590 if (hid_host
==NULL
) {
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) {
604 iosFree(hId
, hid_host
);
607 IOS_IoctlAsync(hid_fd
, USBV5_IOCTL_GETDEVICECHANGE
, NULL
, 0, hid_host
->attached_devices
, 0x180, __usbv5_devicechangeCB
, hid_host
);
609 iosFree(hId
, hid_ver
);
620 s32
USB_Deinitialize()
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
);
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
);
643 s32
USB_OpenDevice(s32 device_id
,u16 vid
,u16 pid
,s32
*fd
)
646 char *devicepath
= NULL
;
649 if (device_id
&& device_id
!=USB_OH1_DEVICE_ID
) {
652 i
= __find_device_on_host(ven_host
, device_id
);
654 i
= __find_device_on_host(hid_host
, device_id
);
657 USB_ResumeDevice(device_id
);
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
);
668 snprintf(devicepath
,USB_MAXPATH
,"/dev/usb/oh0/%x/%x",vid
,pid
);
670 *fd
= IOS_Open(devicepath
,0);
673 if (devicepath
!=NULL
) iosFree(hId
,devicepath
);
677 s32
USBV5_CloseDevice(s32 device_id
)
680 struct _usbv5_host
* host
;
682 if (__find_device_on_host(ven_host
, device_id
)>=0)
684 else if (__find_device_on_host(hid_host
, device_id
)>=0)
689 for (i
=0; i
< USB_MAX_DEVICES
; i
++) {
690 if (host
->remove_cb
[i
].cb
==NULL
)
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
;
699 //return USB_SuspendDevice(device_id);
703 s32
USB_CloseDevice(s32
*fd
)
705 s32 ret
= IPC_EINVAL
;
707 ret
= USBV5_CloseDevice(*fd
);
708 if (ret
==IPC_EINVAL
&& *fd
>0)
709 ret
= IOS_Close(*fd
);
710 if (ret
>=0) *fd
= -1;
716 s32
USB_CloseDeviceAsync(s32
*fd
,usbcallback cb
,void *userdata
)
718 s32 ret
= IPC_EINVAL
;
720 ret
= USBV5_CloseDevice(*fd
);
721 if (ret
!=IPC_EINVAL
) {
723 return cb(ret
, userdata
);
728 return IOS_CloseAsync(*fd
,cb
,userdata
);
734 s32
USB_GetDeviceDescription(s32 fd
,usb_devdesc
*devdesc
)
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
);
750 static s32
USBV5_GetDescriptors(s32 device_id
, usb_devdesc
*udd
)
752 s32 retval
= IPC_ENOMEM
;
753 u32
*io_buffer
= NULL
;
755 usb_configurationdesc
*ucd
= NULL
;
756 usb_interfacedesc
*uid
= NULL
;
757 usb_endpointdesc
*ued
= NULL
;
758 u32 iConf
, iEndpoint
;
760 u32 desc_out_size
, desc_start_offset
;
762 if (__find_device_on_host(ven_host
, device_id
)>=0) {
764 desc_out_size
= 0xC0;
765 desc_start_offset
= 20;
766 } else if (__find_device_on_host(hid_host
, device_id
)>=0) {
768 desc_out_size
= 0x60;
769 desc_start_offset
= 36;
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
;
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)
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
)
816 memcpy(uid
->extra
, next
, uid
->extra_size
);
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;
840 iosFree(hId
, io_buffer
);
842 iosFree(hId
, buffer
);
844 USB_FreeDescriptors(udd
);
848 s32
USB_GetDescriptors(s32 fd
, usb_devdesc
*udd
)
852 usb_configurationdesc
*ucd
= NULL
;
853 usb_interfacedesc
*uid
= NULL
;
854 usb_endpointdesc
*ued
= NULL
;
857 u32 iConf
, iInterface
, iEndpoint
;
859 if (fd
>=0x20 || fd
<-1)
860 return USBV5_GetDescriptors(fd
, udd
);
862 buffer
= iosAlloc(hId
, sizeof(*udd
));
865 retval
= IPC_ENOHEAP
;
869 retval
= __usb_getdesc(fd
, buffer
, USB_DT_DEVICE
, 0, 0, USB_DT_DEVICE_SIZE
);
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
)
886 for(iConf
= 0; iConf
< udd
->bNumConfigurations
; iConf
++)
888 buffer
= iosAlloc(hId
, USB_DT_CONFIG_SIZE
);
891 retval
= IPC_ENOHEAP
;
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
);
905 retval
= IPC_ENOHEAP
;
909 retval
= __usb_getdesc(fd
, buffer
, USB_DT_CONFIG
, iConf
, 0, ucd
->wTotalLength
);
915 size
-= ucd
->bLength
;
919 ucd
->interfaces
= calloc(ucd
->bNumInterfaces
, sizeof(*ucd
->interfaces
));
920 if(ucd
->interfaces
== NULL
)
922 for(iInterface
= 0; iInterface
< ucd
->bNumInterfaces
; iInterface
++)
924 uid
= ucd
->interfaces
+iInterface
;
925 memcpy(uid
, ptr
, USB_DT_INTERFACE_SIZE
);
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
)
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
)
946 for(iEndpoint
= 0; iEndpoint
< uid
->bNumEndpoints
; iEndpoint
++)
948 ued
= &uid
->endpoints
[iEndpoint
];
949 memcpy(ued
, ptr
, USB_DT_ENDPOINT_SIZE
);
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
)
962 interfaces
[iInterface
+1].endpoints
= NULL
;
963 interfaces
[iInterface
+1].extra
= NULL
;
964 ucd
->bNumInterfaces
++;
965 ucd
->interfaces
= interfaces
;
968 iosFree(hId
, buffer
);
975 iosFree(hId
, buffer
);
977 USB_FreeDescriptors(udd
);
981 s32
USB_GetGenericDescriptor(s32 fd
,u8 type
,u8 index
,u8 interface
,void *data
,u32 size
) {
985 buffer
= iosAlloc(hId
,sizeof(size
));
991 retval
= __usb_getdesc(fd
,buffer
,type
,index
,interface
,size
);
992 if(retval
<0) goto free_and_error
;
994 memcpy(data
,buffer
,size
);
998 if(buffer
!=NULL
) iosFree(hId
,buffer
);
1002 s32
USB_GetHIDDescriptor(s32 fd
,u8 interface
,usb_hiddesc
*uhd
,u32 size
)
1007 if (size
< USB_DT_HID_SIZE
)
1010 retval
= USB_GetGenericDescriptor(fd
, USB_DT_HID
, 0, interface
, uhd
, size
);
1011 if (retval
!= IPC_OK
)
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
);
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
);
1041 free(ucd
->interfaces
);
1044 free(udd
->configurations
);
1048 s32
USB_GetAsciiString(s32 fd
,u8 bIndex
,u16 wLangID
,u16 wLength
,void *rpData
)
1053 u8
*rp
= (u8
*)rpData
;
1058 buf
= iosAlloc(hId
, 255); /* 255 is the highest possible length of a descriptor */
1062 ret
= __usb_getdesc(fd
, buf
, USB_DT_STRING
, bIndex
, wLangID
, 255);
1064 /* index 0 gets a list of supported languages */
1068 memcpy(rpData
, buf
, wLength
);
1077 while(ro
< (wLength
- 1) && bo
< buf
[0])
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
)
1177 // check to make sure the device is present
1178 if (__find_device_on_host(host
, device_id
)<0)
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
)
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
;
1199 s32
USB_DeviceRemovalNotifyAsync(s32 fd
,usbcallback cb
,void *userdata
)
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
);
1212 static s32
USBV5_SuspendResume(s32 device_id
, s32 resumed
)
1217 if (__find_device_on_host(ven_host
, device_id
)>=0)
1219 else if (__find_device_on_host(hid_host
, device_id
)>=0)
1224 s32
*buf
= (s32
*)iosAlloc(hId
, 32);
1225 if (buf
==NULL
) return IPC_ENOMEM
;
1229 ret
= IOS_Ioctl(fd
, USBV5_IOCTL_SUSPEND_RESUME
, buf
, 32, NULL
, 0);
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
)
1255 struct _usb_msg
*msg
;
1258 fd
= IOS_Open(__oh0_path
,IPC_OPEN_NONE
);
1259 if (fd
<0) return fd
;
1261 msg
= iosAlloc(hId
,sizeof(*msg
));
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
);
1277 if (ret
<0) iosFree(hId
, msg
);
1282 s32
USB_GetDeviceList(usb_device_entry
*descr_buffer
,u8 num_descr
,u8 interface_class
,u8
*cnt_descr
)
1287 if (ven_host
==NULL
) {
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
);
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
;
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];
1313 // for ven_host, we can only exclude usb_hid class devices
1314 if (interface_class
!= USB_CLASS_HID
&& ven_host
) {
1316 while (cntdevs
<num_descr
&& ven_host
->attached_devices
[i
].device_id
) {
1317 descr_buffer
[cntdevs
++] = ven_host
->attached_devices
[i
++];
1322 if ((!interface_class
|| interface_class
==USB_CLASS_HID
) && hid_host
) {
1324 while (cntdevs
<num_descr
&& hid_host
->attached_devices
[i
].device_id
) {
1325 descr_buffer
[cntdevs
++] = hid_host
->attached_devices
[i
++];
1330 if (cnt_descr
) *cnt_descr
= cntdevs
;
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
)
1345 _configuration
= iosAlloc(hId
, 1);
1346 if(_configuration
== NULL
)
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
);
1351 *configuration
= *_configuration
;
1352 iosFree(hId
, _configuration
);
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
)
1367 if (__find_device_on_host(ven_host
, device_id
)>=0)
1369 else if (__find_device_on_host(hid_host
, device_id
)>=0)
1374 s32
*buf
= (s32
*)iosAlloc(hId
, 32);
1375 if (buf
==NULL
) return IPC_ENOMEM
;
1379 ret
= IOS_Ioctl(fd
, USBV5_IOCTL_CANCELENDPOINT
, buf
, 32, NULL
, 0);
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) */