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
];
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
;
153 u32 align_pad
[4]; // pad to 24 bytes
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
);
178 IOS_IoctlAsync(host
->fd
, USBV5_IOCTL_GETDEVICECHANGE
, NULL
, 0, host
->attached_devices
, 0x180, __usbv5_devicechangeCB
, host
);
183 static s32
__usbv5_devicechangeCB(s32 result
, void *p
)
186 struct _usbv5_host
* host
= (struct _usbv5_host
*)p
;
188 if(host
==NULL
) return IPC_EINVAL
;
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
)
196 for (j
=0; j
<result
; j
++) {
197 if (host
->remove_cb
[i
].device_id
== host
->attached_devices
[j
].device_id
)
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
);
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
);
229 static s32
__usbv0_messageCB(s32 result
,void *usrdata
)
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
);
248 static s32
__find_device_on_host(struct _usbv5_host
*host
, s32 device_id
)
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
)
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
;
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
));
284 msg
->userdata
= userdata
;
286 if (device_id
>=0 && device_id
<0x20) {
291 pEndp
= (u8
*)iosAlloc(hId
,32);
292 if(pEndp
==NULL
) goto done
;
295 pLength
= (u16
*)iosAlloc(hId
,32);
296 if(pLength
==NULL
) goto done
;
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
;
318 ret
= IOS_Ioctlv(device_id
, USBV0_IOCTL_ISOMSG
, 3, 2, msg
->vec
);
320 return IOS_IoctlvAsync(device_id
, USBV0_IOCTL_ISOMSG
, 3, 2, msg
->vec
, __usbv0_messageCB
, msg
);
323 if(pEndp
) iosFree(hId
,pEndp
);
324 if(pLength
) iosFree(hId
,pLength
);
325 if(pPackets
) iosFree(hId
,pPackets
);
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
;
344 ret
= IOS_Ioctlv(fd
, USBV5_IOCTL_ISOMSG
, 2-endpoint_dir
, 2+endpoint_dir
, msg
->vec
);
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
);
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
));
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
;
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
;
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
;
418 ret
= IOS_Ioctlv(device_id
, USBV0_IOCTL_CTRLMSG
, 6, 1, msg
->vec
);
420 return IOS_IoctlvAsync(device_id
, USBV0_IOCTL_CTRLMSG
, 6, 1, msg
->vec
, __usbv0_messageCB
, msg
);
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
);
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
;
447 ret
= IOS_Ioctlv(fd
, USBV5_IOCTL_CTRLMSG
, 2-request_dir
, request_dir
, msg
->vec
);
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
);
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
));
473 msg
->userdata
= userdata
;
475 if (device_id
>=0 && device_id
<0x20) {
479 pEndP
= (u8
*)iosAlloc(hId
,32);
480 if(pEndP
==NULL
) goto done
;
483 pLength
= (u16
*)iosAlloc(hId
,32);
484 if(pLength
==NULL
) goto done
;
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;
497 ret
= IOS_Ioctlv(device_id
,ioctl
,2,1,msg
->vec
);
499 return IOS_IoctlvAsync(device_id
,ioctl
,2,1,msg
->vec
,__usbv0_messageCB
,msg
);
502 if(pEndP
!=NULL
) iosFree(hId
,pEndP
);
503 if(pLength
!=NULL
) iosFree(hId
,pLength
);
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
512 msg
->hid_intr_dir
= !endpoint_dir
;
514 msg
->intr
.rpData
= rpData
;
515 msg
->intr
.wLength
= wLength
;
516 msg
->intr
.bEndpoint
= bEndpoint
;
518 ioctl
= USBV5_IOCTL_INTRMSG
;
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
;
532 ret
= IOS_Ioctlv(fd
, ioctl
, 2-endpoint_dir
, endpoint_dir
, msg
->vec
);
534 return IOS_IoctlvAsync(fd
, ioctl
, 2-endpoint_dir
, endpoint_dir
, msg
->vec
, __usbv5_messageCB
, msg
);
537 if(msg
!=NULL
) iosFree(hId
,msg
);
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
)
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
)
560 size
-= (buffer
[0]+align
)&~align
;
561 buffer
+= (buffer
[0]+align
)&~align
;
564 return (buffer
- ptr
);
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
);
575 ven_host
= (struct _usbv5_host
*)iosAlloc(hId
, sizeof(*ven_host
));
576 if (ven_host
==NULL
) {
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
);
590 iosFree(hId
, ven_host
);
594 iosFree(hId
, ven_ver
);
598 if (hid_host
==NULL
) {
599 s32 hid_fd
= IOS_Open(__hid_path
, IPC_OPEN_NONE
);
601 hid_host
= (struct _usbv5_host
*)iosAlloc(hId
, sizeof(*hid_host
));
602 if (hid_host
==NULL
) {
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) {
616 iosFree(hId
, hid_host
);
619 IOS_IoctlAsync(hid_fd
, USBV5_IOCTL_GETDEVICECHANGE
, NULL
, 0, hid_host
->attached_devices
, 0x180, __usbv5_devicechangeCB
, hid_host
);
621 iosFree(hId
, hid_ver
);
632 s32
USB_Deinitialize()
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
);
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
);
655 s32
USB_OpenDevice(s32 device_id
,u16 vid
,u16 pid
,s32
*fd
)
658 char *devicepath
= NULL
;
661 if (device_id
&& device_id
!=USB_OH1_DEVICE_ID
) {
664 i
= __find_device_on_host(ven_host
, device_id
);
666 USB_ResumeDevice(device_id
);
668 // HID V5 devices need their descriptors read before being used
670 i
= __find_device_on_host(hid_host
, device_id
);
672 USB_ResumeDevice(device_id
);
673 i
= USB_GetDescriptors(device_id
, &desc
);
675 USB_FreeDescriptors(&desc
);
677 USB_SuspendDevice(device_id
);
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
);
694 snprintf(devicepath
,USB_MAXPATH
,"/dev/usb/oh0/%x/%x",vid
,pid
);
696 *fd
= IOS_Open(devicepath
,0);
699 if (devicepath
!=NULL
) iosFree(hId
,devicepath
);
703 s32
USBV5_CloseDevice(s32 device_id
)
706 struct _usbv5_host
* host
;
708 if (__find_device_on_host(ven_host
, device_id
)>=0)
710 else if (__find_device_on_host(hid_host
, device_id
)>=0)
715 for (i
=0; i
< USB_MAX_DEVICES
; i
++) {
716 if (host
->remove_cb
[i
].cb
==NULL
)
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
;
725 //return USB_SuspendDevice(device_id);
729 s32
USB_CloseDevice(s32
*fd
)
731 s32 ret
= IPC_EINVAL
;
733 ret
= USBV5_CloseDevice(*fd
);
734 if (ret
==IPC_EINVAL
&& *fd
>0)
735 ret
= IOS_Close(*fd
);
736 if (ret
>=0) *fd
= -1;
742 s32
USB_CloseDeviceAsync(s32
*fd
,usbcallback cb
,void *userdata
)
744 s32 ret
= IPC_EINVAL
;
746 ret
= USBV5_CloseDevice(*fd
);
747 if (ret
!=IPC_EINVAL
) {
749 return cb(ret
, userdata
);
754 return IOS_CloseAsync(*fd
,cb
,userdata
);
760 s32
USB_GetDeviceDescription(s32 fd
,usb_devdesc
*devdesc
)
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
);
776 static s32
USBV5_GetDescriptors(s32 device_id
, usb_devdesc
*udd
)
778 s32 retval
= IPC_ENOMEM
;
779 u32
*io_buffer
= NULL
;
781 usb_configurationdesc
*ucd
= NULL
;
782 usb_interfacedesc
*uid
= NULL
;
783 usb_endpointdesc
*ued
= NULL
;
784 u32 iConf
, iEndpoint
;
786 u32 desc_out_size
, desc_start_offset
;
788 if (__find_device_on_host(ven_host
, device_id
)>=0) {
790 desc_out_size
= 0xC0;
791 desc_start_offset
= 20;
792 } else if (__find_device_on_host(hid_host
, device_id
)>=0) {
794 desc_out_size
= 0x60;
795 desc_start_offset
= 36;
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
;
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)
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
)
842 memcpy(uid
->extra
, next
, uid
->extra_size
);
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;
866 iosFree(hId
, io_buffer
);
868 iosFree(hId
, buffer
);
870 USB_FreeDescriptors(udd
);
874 s32
USB_GetDescriptors(s32 fd
, usb_devdesc
*udd
)
878 usb_configurationdesc
*ucd
= NULL
;
879 usb_interfacedesc
*uid
= NULL
;
880 usb_endpointdesc
*ued
= NULL
;
883 u32 iConf
, iInterface
, iEndpoint
;
887 memset(udd
, 0, sizeof(*udd
));
889 if (fd
>=0x20 || fd
<-1)
890 return USBV5_GetDescriptors(fd
, udd
);
892 buffer
= iosAlloc(hId
, sizeof(*udd
));
895 retval
= IPC_ENOHEAP
;
899 retval
= __usb_getdesc(fd
, buffer
, USB_DT_DEVICE
, 0, 0, USB_DT_DEVICE_SIZE
);
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
)
916 for(iConf
= 0; iConf
< udd
->bNumConfigurations
; iConf
++)
918 buffer
= iosAlloc(hId
, USB_DT_CONFIG_SIZE
);
921 retval
= IPC_ENOHEAP
;
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
);
935 retval
= IPC_ENOHEAP
;
939 retval
= __usb_getdesc(fd
, buffer
, USB_DT_CONFIG
, iConf
, 0, ucd
->wTotalLength
);
945 size
-= ucd
->bLength
;
949 ucd
->interfaces
= calloc(ucd
->bNumInterfaces
, sizeof(*ucd
->interfaces
));
950 if(ucd
->interfaces
== NULL
)
952 for(iInterface
= 0; iInterface
< ucd
->bNumInterfaces
; iInterface
++)
954 uid
= ucd
->interfaces
+iInterface
;
955 memcpy(uid
, ptr
, USB_DT_INTERFACE_SIZE
);
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
)
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
)
976 for(iEndpoint
= 0; iEndpoint
< uid
->bNumEndpoints
; iEndpoint
++)
978 ued
= &uid
->endpoints
[iEndpoint
];
979 memcpy(ued
, ptr
, USB_DT_ENDPOINT_SIZE
);
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
)
992 interfaces
[iInterface
+1].endpoints
= NULL
;
993 interfaces
[iInterface
+1].extra
= NULL
;
994 ucd
->bNumInterfaces
++;
995 ucd
->interfaces
= interfaces
;
998 iosFree(hId
, buffer
);
1005 iosFree(hId
, buffer
);
1007 USB_FreeDescriptors(udd
);
1011 s32
USB_GetGenericDescriptor(s32 fd
,u8 type
,u8 index
,u8 interface
,void *data
,u32 size
) {
1015 buffer
= iosAlloc(hId
,size
);
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
);
1028 if(buffer
!=NULL
) iosFree(hId
,buffer
);
1032 s32
USB_GetHIDDescriptor(s32 fd
,u8 interface
,usb_hiddesc
*uhd
,u32 size
)
1037 if (size
< USB_DT_HID_SIZE
)
1040 retval
= USB_GetGenericDescriptor(fd
, USB_DT_HID
, 0, interface
, uhd
, size
);
1041 if (retval
!= IPC_OK
)
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
);
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
);
1071 free(ucd
->interfaces
);
1074 free(udd
->configurations
);
1078 s32
USB_GetAsciiString(s32 fd
,u8 bIndex
,u16 wLangID
,u16 wLength
,void *rpData
)
1083 u8
*rp
= (u8
*)rpData
;
1088 buf
= iosAlloc(hId
, 255); /* 255 is the highest possible length of a descriptor */
1092 ret
= __usb_getdesc(fd
, buf
, USB_DT_STRING
, bIndex
, wLangID
, 255);
1094 /* index 0 gets a list of supported languages */
1098 memcpy(rpData
, buf
, wLength
);
1107 while(ro
< (wLength
- 1) && bo
< buf
[0])
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
)
1207 // check to make sure the device is present
1208 if (__find_device_on_host(host
, device_id
)<0)
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
)
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
;
1229 s32
USB_DeviceRemovalNotifyAsync(s32 fd
,usbcallback cb
,void *userdata
)
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
);
1242 static s32
USBV5_SuspendResume(s32 device_id
, s32 resumed
)
1247 if (__find_device_on_host(ven_host
, device_id
)>=0)
1249 else if (__find_device_on_host(hid_host
, device_id
)>=0)
1254 s32
*buf
= (s32
*)iosAlloc(hId
, 32);
1255 if (buf
==NULL
) return IPC_ENOMEM
;
1259 ret
= IOS_Ioctl(fd
, USBV5_IOCTL_SUSPEND_RESUME
, buf
, 32, NULL
, 0);
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
) {
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
));
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
);
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
) {
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
) {
1320 hid_host
->device_change_notify
= cb
;
1321 hid_host
->device_change_userdata
= userdata
;
1328 s32
USB_GetDeviceList(usb_device_entry
*descr_buffer
,u8 num_descr
,u8 interface_class
,u8
*cnt_descr
)
1333 if (ven_host
==NULL
) {
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
);
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
;
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];
1359 // for ven_host, we can only exclude usb_hid class devices
1360 if (interface_class
!= USB_CLASS_HID
&& ven_host
) {
1362 while (cntdevs
<num_descr
&& ven_host
->attached_devices
[i
].device_id
) {
1363 descr_buffer
[cntdevs
++] = ven_host
->attached_devices
[i
++];
1368 if ((!interface_class
|| interface_class
==USB_CLASS_HID
) && hid_host
) {
1370 while (cntdevs
<num_descr
&& hid_host
->attached_devices
[i
].device_id
) {
1371 descr_buffer
[cntdevs
++] = hid_host
->attached_devices
[i
++];
1376 if (cnt_descr
) *cnt_descr
= cntdevs
;
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
)
1391 _configuration
= iosAlloc(hId
, 1);
1392 if(_configuration
== NULL
)
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
);
1397 *configuration
= *_configuration
;
1398 iosFree(hId
, _configuration
);
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
)
1413 if (__find_device_on_host(ven_host
, device_id
)>=0)
1415 else if (__find_device_on_host(hid_host
, device_id
)>=0)
1420 s32
*buf
= (s32
*)iosAlloc(hId
, 32);
1421 if (buf
==NULL
) return IPC_ENOMEM
;
1425 ret
= IOS_Ioctl(fd
, USBV5_IOCTL_CANCELENDPOINT
, buf
, 32, NULL
, 0);
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) */