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
, u16 size
)
544 u8 requestType
= USB_CTRLTYPE_DIR_DEVICE2HOST
;
546 if (valuehi
==USB_DT_HID
|| valuehi
==USB_DT_REPORT
|| valuehi
==USB_DT_PHYSICAL
)
547 requestType
|= USB_CTRLTYPE_REC_INTERFACE
;
549 return __usb_control_message(fd
, requestType
, USB_REQ_GETDESCRIPTOR
, (valuehi
<< 8) | valuelo
, index
, size
, buffer
, NULL
, NULL
);
552 static u32
__find_next_endpoint(u8
*buffer
,s32 size
,u8 align
)
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
);
929 ucd
= &udd
->configurations
[iConf
];
930 memcpy(ucd
, buffer
, USB_DT_CONFIG_SIZE
);
931 iosFree(hId
, buffer
);
933 ucd
->wTotalLength
= bswap16(ucd
->wTotalLength
);
934 size
= ucd
->wTotalLength
;
935 buffer
= iosAlloc(hId
, size
);
938 retval
= IPC_ENOHEAP
;
942 retval
= __usb_getdesc(fd
, buffer
, USB_DT_CONFIG
, iConf
, 0, ucd
->wTotalLength
);
948 size
-= ucd
->bLength
;
952 ucd
->interfaces
= calloc(ucd
->bNumInterfaces
, sizeof(*ucd
->interfaces
));
953 if(ucd
->interfaces
== NULL
)
955 for(iInterface
= 0; iInterface
< ucd
->bNumInterfaces
; iInterface
++)
957 retval
= __find_next_endpoint(ptr
, size
, 0);
959 // FIXME: do something with this data
964 uid
= ucd
->interfaces
+iInterface
;
965 memcpy(uid
, ptr
, USB_DT_INTERFACE_SIZE
);
967 size
-= uid
->bLength
;
969 /* This skips vendor and class specific descriptors */
970 uid
->extra_size
= __find_next_endpoint(ptr
, size
, 0);
971 if(uid
->extra_size
>0)
973 uid
->extra
= malloc(uid
->extra_size
);
974 if(uid
->extra
== NULL
)
976 memcpy(uid
->extra
, ptr
, uid
->extra_size
);
977 ptr
+= uid
->extra_size
;
978 size
-= uid
->extra_size
;
981 if (uid
->bNumEndpoints
) {
982 uid
->endpoints
= calloc(uid
->bNumEndpoints
, sizeof(*uid
->endpoints
));
983 if(uid
->endpoints
== NULL
)
986 for(iEndpoint
= 0; iEndpoint
< uid
->bNumEndpoints
; iEndpoint
++)
988 ued
= &uid
->endpoints
[iEndpoint
];
989 memcpy(ued
, ptr
, USB_DT_ENDPOINT_SIZE
);
991 size
-= ued
->bLength
;
992 ued
->wMaxPacketSize
= bswap16(ued
->wMaxPacketSize
);
996 if (iInterface
==(ucd
->bNumInterfaces
-1) && size
>2) {
997 // we've read all the interfaces but there's data left (probably alternate setting interfaces)
998 // see if we can find another interface descriptor
999 retval
= __find_next_endpoint(ptr
, size
, 0);
1000 if (size
-retval
>= USB_DT_INTERFACE_SIZE
&& ptr
[retval
+1] == USB_DT_INTERFACE
) {
1001 // found alternates, make room and loop
1002 usb_interfacedesc
*interfaces
= realloc(ucd
->interfaces
, (iInterface
+2)*sizeof(*interfaces
));
1003 if (interfaces
== NULL
)
1004 goto free_and_error
;
1005 interfaces
[iInterface
+1].endpoints
= NULL
;
1006 interfaces
[iInterface
+1].extra
= NULL
;
1007 ucd
->bNumInterfaces
++;
1008 ucd
->interfaces
= interfaces
;
1012 iosFree(hId
, buffer
);
1019 iosFree(hId
, buffer
);
1021 USB_FreeDescriptors(udd
);
1025 s32
USB_GetGenericDescriptor(s32 fd
,u8 type
,u8 index
,u8 interface
,void *data
,u32 size
) {
1029 buffer
= iosAlloc(hId
,size
);
1031 retval
= IPC_ENOMEM
;
1032 goto free_and_error
;
1035 retval
= __usb_getdesc(fd
,buffer
,type
,index
,interface
,size
);
1036 if(retval
<0) goto free_and_error
;
1038 memcpy(data
,buffer
,size
);
1042 if(buffer
!=NULL
) iosFree(hId
,buffer
);
1046 s32
USB_GetHIDDescriptor(s32 fd
,u8 interface
,usb_hiddesc
*uhd
,u32 size
)
1051 if (size
< USB_DT_HID_SIZE
)
1054 retval
= USB_GetGenericDescriptor(fd
, USB_DT_HID
, 0, interface
, uhd
, size
);
1055 if (retval
!= IPC_OK
)
1058 uhd
->bcdHID
= bswap16(uhd
->bcdHID
);
1059 uhd
->descr
[0].wDescriptorLength
= bswap16(uhd
->descr
[0].wDescriptorLength
);
1060 size
-= USB_DT_HID_SIZE
;
1061 for (i
=1; i
<uhd
->bNumDescriptors
&& size
>=3; size
-=3, i
++)
1062 uhd
->descr
[i
].wDescriptorLength
= bswap16(uhd
->descr
[i
].wDescriptorLength
);
1067 void USB_FreeDescriptors(usb_devdesc
*udd
)
1069 int iConf
, iInterface
;
1070 usb_configurationdesc
*ucd
;
1071 usb_interfacedesc
*uid
;
1072 if(udd
->configurations
!= NULL
)
1074 for(iConf
= 0; iConf
< udd
->bNumConfigurations
; iConf
++)
1076 ucd
= &udd
->configurations
[iConf
];
1077 if(ucd
->interfaces
!= NULL
)
1079 for(iInterface
= 0; iInterface
< ucd
->bNumInterfaces
; iInterface
++)
1081 uid
= ucd
->interfaces
+iInterface
;
1082 free(uid
->endpoints
);
1085 free(ucd
->interfaces
);
1088 free(udd
->configurations
);
1092 s32
USB_GetAsciiString(s32 fd
,u8 bIndex
,u16 wLangID
,u16 wLength
,void *rpData
)
1097 u8
*rp
= (u8
*)rpData
;
1102 buf
= iosAlloc(hId
, 255); /* 255 is the highest possible length of a descriptor */
1106 ret
= __usb_getdesc(fd
, buf
, USB_DT_STRING
, bIndex
, wLangID
, 255);
1108 /* index 0 gets a list of supported languages */
1112 memcpy(rpData
, buf
, wLength
);
1121 while(ro
< (wLength
- 1) && bo
< buf
[0])
1137 s32
USB_ReadIsoMsg(s32 fd
,u8 bEndpoint
,u8 bPackets
,u16
*rpPacketSizes
,void *rpData
)
1139 return __usb_isochronous_message(fd
,bEndpoint
,bPackets
,rpPacketSizes
,rpData
,NULL
,NULL
);
1142 s32
USB_ReadIsoMsgAsync(s32 fd
,u8 bEndpoint
,u8 bPackets
,u16
*rpPacketSizes
,void *rpData
,usbcallback cb
,void *userdata
)
1144 return __usb_isochronous_message(fd
,bEndpoint
,bPackets
,rpPacketSizes
,rpData
,cb
,userdata
);
1147 s32
USB_WriteIsoMsg(s32 fd
,u8 bEndpoint
,u8 bPackets
,u16
*rpPacketSizes
,void *rpData
)
1149 return __usb_isochronous_message(fd
,bEndpoint
,bPackets
,rpPacketSizes
,rpData
,NULL
,NULL
);
1152 s32
USB_WriteIsoMsgAsync(s32 fd
,u8 bEndpoint
,u8 bPackets
,u16
*rpPacketSizes
,void *rpData
,usbcallback cb
,void *userdata
)
1154 return __usb_isochronous_message(fd
,bEndpoint
,bPackets
,rpPacketSizes
,rpData
,cb
,userdata
);
1157 s32
USB_ReadIntrMsg(s32 fd
,u8 bEndpoint
,u16 wLength
,void *rpData
)
1159 return __usb_interrupt_bulk_message(fd
,USBV0_IOCTL_INTRMSG
,bEndpoint
,wLength
,rpData
,NULL
,NULL
);
1162 s32
USB_ReadIntrMsgAsync(s32 fd
,u8 bEndpoint
,u16 wLength
,void *rpData
,usbcallback cb
,void *userdata
)
1164 return __usb_interrupt_bulk_message(fd
,USBV0_IOCTL_INTRMSG
,bEndpoint
,wLength
,rpData
,cb
,userdata
);
1167 s32
USB_WriteIntrMsg(s32 fd
,u8 bEndpoint
,u16 wLength
,void *rpData
)
1169 return __usb_interrupt_bulk_message(fd
,USBV0_IOCTL_INTRMSG
,bEndpoint
,wLength
,rpData
,NULL
,NULL
);
1172 s32
USB_WriteIntrMsgAsync(s32 fd
,u8 bEndpoint
,u16 wLength
,void *rpData
,usbcallback cb
,void *userdata
)
1174 return __usb_interrupt_bulk_message(fd
,USBV0_IOCTL_INTRMSG
,bEndpoint
,wLength
,rpData
,cb
,userdata
);
1177 s32
USB_ReadBlkMsg(s32 fd
,u8 bEndpoint
,u16 wLength
,void *rpData
)
1179 return __usb_interrupt_bulk_message(fd
,USBV0_IOCTL_BLKMSG
,bEndpoint
,wLength
,rpData
,NULL
,NULL
);
1182 s32
USB_ReadBlkMsgAsync(s32 fd
,u8 bEndpoint
,u16 wLength
,void *rpData
,usbcallback cb
,void *userdata
)
1184 return __usb_interrupt_bulk_message(fd
,USBV0_IOCTL_BLKMSG
,bEndpoint
,wLength
,rpData
,cb
,userdata
);
1187 s32
USB_WriteBlkMsg(s32 fd
,u8 bEndpoint
,u16 wLength
,void *rpData
)
1189 return __usb_interrupt_bulk_message(fd
,USBV0_IOCTL_BLKMSG
,bEndpoint
,wLength
,rpData
,NULL
,NULL
);
1192 s32
USB_WriteBlkMsgAsync(s32 fd
,u8 bEndpoint
,u16 wLength
,void *rpData
,usbcallback cb
,void *userdata
)
1194 return __usb_interrupt_bulk_message(fd
,USBV0_IOCTL_BLKMSG
,bEndpoint
,wLength
,rpData
,cb
,userdata
);
1197 s32
USB_ReadCtrlMsg(s32 fd
,u8 bmRequestType
,u8 bmRequest
,u16 wValue
,u16 wIndex
,u16 wLength
,void *rpData
)
1199 return __usb_control_message(fd
,bmRequestType
,bmRequest
,wValue
,wIndex
,wLength
,rpData
,NULL
,NULL
);
1202 s32
USB_ReadCtrlMsgAsync(s32 fd
,u8 bmRequestType
,u8 bmRequest
,u16 wValue
,u16 wIndex
,u16 wLength
,void *rpData
,usbcallback cb
,void *userdata
)
1204 return __usb_control_message(fd
,bmRequestType
,bmRequest
,wValue
,wIndex
,wLength
,rpData
,cb
,userdata
);
1207 s32
USB_WriteCtrlMsg(s32 fd
,u8 bmRequestType
,u8 bmRequest
,u16 wValue
,u16 wIndex
,u16 wLength
,void *rpData
)
1209 return __usb_control_message(fd
,bmRequestType
,bmRequest
,wValue
,wIndex
,wLength
,rpData
,NULL
,NULL
);
1212 s32
USB_WriteCtrlMsgAsync(s32 fd
,u8 bmRequestType
,u8 bmRequest
,u16 wValue
,u16 wIndex
,u16 wLength
,void *rpData
,usbcallback cb
,void *userdata
)
1214 return __usb_control_message(fd
,bmRequestType
,bmRequest
,wValue
,wIndex
,wLength
,rpData
,cb
,userdata
);
1217 static s32
USB5_RegisterDeviceRemoval(struct _usbv5_host
*host
, s32 device_id
, usbcallback cb
, void *userdata
)
1221 // check to make sure the device is present
1222 if (__find_device_on_host(host
, device_id
)<0)
1225 // now make sure it's not hooked already
1226 for (i
=0; i
<USB_MAX_DEVICES
; i
++) {
1227 if (host
->remove_cb
[i
].cb
&& host
->remove_cb
[i
].device_id
==device_id
)
1231 // find a free entry and add it
1232 for (i
=0; i
<USB_MAX_DEVICES
; i
++) {
1233 if (host
->remove_cb
[i
].cb
==NULL
) {
1234 host
->remove_cb
[i
].cb
= cb
;
1235 host
->remove_cb
[i
].userdata
= userdata
;
1236 host
->remove_cb
[i
].device_id
= device_id
;
1243 s32
USB_DeviceRemovalNotifyAsync(s32 fd
,usbcallback cb
,void *userdata
)
1246 if (fd
>=0 && fd
<0x20)
1247 return IOS_IoctlAsync(fd
,USBV0_IOCTL_DEVREMOVALHOOK
,NULL
,0,NULL
,0,cb
,userdata
);
1249 ret
= USB5_RegisterDeviceRemoval(ven_host
, fd
, cb
, userdata
);
1250 if (ret
== IPC_ENOENT
)
1251 ret
= USB5_RegisterDeviceRemoval(hid_host
, fd
, cb
, userdata
);
1256 static s32
USBV5_SuspendResume(s32 device_id
, s32 resumed
)
1261 if (__find_device_on_host(ven_host
, device_id
)>=0)
1263 else if (__find_device_on_host(hid_host
, device_id
)>=0)
1268 s32
*buf
= (s32
*)iosAlloc(hId
, 32);
1269 if (buf
==NULL
) return IPC_ENOMEM
;
1273 ret
= IOS_Ioctl(fd
, USBV5_IOCTL_SUSPEND_RESUME
, buf
, 32, NULL
, 0);
1279 s32
USB_SuspendDevice(s32 fd
)
1281 if (fd
>=0x20 || fd
<-1)
1282 return USBV5_SuspendResume(fd
, 0);
1284 return IOS_Ioctl(fd
,USBV0_IOCTL_SUSPENDDEV
,NULL
,0,NULL
,0);
1287 s32
USB_ResumeDevice(s32 fd
)
1289 if (fd
>=0x20 || fd
<-1)
1290 return USBV5_SuspendResume(fd
, 1);
1292 return IOS_Ioctl(fd
,USBV0_IOCTL_RESUMEDEV
,NULL
,0,NULL
,0);
1295 s32
USB_DeviceChangeNotifyAsync(u8 interface_class
, usbcallback cb
, void* userdata
)
1297 s32 ret
=IPC_EQUEUEFULL
;
1299 if (ven_host
==NULL
) {
1301 struct _usb_msg
*msg
;
1303 fd
= IOS_Open(__oh0_path
,IPC_OPEN_NONE
);
1304 if (fd
<0) return fd
;
1306 msg
= iosAlloc(hId
,sizeof(*msg
));
1313 msg
->userdata
= userdata
;
1314 msg
->class = interface_class
;
1316 msg
->vec
[0].data
= &msg
->class;
1317 msg
->vec
[0].len
= 1;
1319 ret
= IOS_IoctlvAsync(fd
,USBV0_IOCTL_DEVICECLASSCHANGE
,1,0,msg
->vec
,__usbv5_messageCB
,msg
);
1322 if (ret
<0) iosFree(hId
, msg
);
1324 else if (interface_class
!= USB_CLASS_HID
&& ven_host
) {
1325 if (ven_host
->device_change_notify
== NULL
) {
1327 ven_host
->device_change_notify
= cb
;
1328 ven_host
->device_change_userdata
= userdata
;
1331 else if (interface_class
==USB_CLASS_HID
&& hid_host
) {
1332 if (hid_host
->device_change_notify
== NULL
) {
1334 hid_host
->device_change_notify
= cb
;
1335 hid_host
->device_change_userdata
= userdata
;
1342 s32
USB_GetDeviceList(usb_device_entry
*descr_buffer
,u8 num_descr
,u8 interface_class
,u8
*cnt_descr
)
1347 if (ven_host
==NULL
) {
1349 u32
*buf
= (u32
*)iosAlloc(hId
, num_descr
<<3);
1350 if (buf
==NULL
) return IPC_ENOMEM
;
1352 fd
= IOS_Open(__oh0_path
,IPC_OPEN_NONE
);
1359 i
= IOS_IoctlvFormat(hId
,fd
,USBV0_IOCTL_GETDEVLIST
,"bb:dd",num_descr
,interface_class
,&cntdevs
,sizeof(cntdevs
),buf
,(num_descr
<<3));
1360 if (cnt_descr
) *cnt_descr
= cntdevs
;
1363 descr_buffer
[cntdevs
].device_id
= 0;
1364 descr_buffer
[cntdevs
].vid
= (u16
)(buf
[cntdevs
*2+1]>>16);
1365 descr_buffer
[cntdevs
].pid
= (u16
)buf
[cntdevs
*2+1];
1373 // for ven_host, we can only exclude usb_hid class devices
1374 if (interface_class
!= USB_CLASS_HID
&& ven_host
) {
1376 while (cntdevs
<num_descr
&& ven_host
->attached_devices
[i
].device_id
) {
1377 descr_buffer
[cntdevs
++] = ven_host
->attached_devices
[i
++];
1382 if ((!interface_class
|| interface_class
==USB_CLASS_HID
) && hid_host
) {
1384 while (cntdevs
<num_descr
&& hid_host
->attached_devices
[i
].device_id
) {
1385 descr_buffer
[cntdevs
++] = hid_host
->attached_devices
[i
++];
1390 if (cnt_descr
) *cnt_descr
= cntdevs
;
1395 s32
USB_SetConfiguration(s32 fd
, u8 configuration
)
1397 return __usb_control_message(fd
, (USB_CTRLTYPE_DIR_HOST2DEVICE
| USB_CTRLTYPE_TYPE_STANDARD
| USB_CTRLTYPE_REC_DEVICE
), USB_REQ_SETCONFIG
, configuration
, 0, 0, NULL
, NULL
, NULL
);
1400 s32
USB_GetConfiguration(s32 fd
, u8
*configuration
)
1405 _configuration
= iosAlloc(hId
, 1);
1406 if(_configuration
== NULL
)
1409 retval
= __usb_control_message(fd
, (USB_CTRLTYPE_DIR_DEVICE2HOST
| USB_CTRLTYPE_TYPE_STANDARD
| USB_CTRLTYPE_REC_DEVICE
), USB_REQ_GETCONFIG
, 0, 0, 1, _configuration
, NULL
, NULL
);
1411 *configuration
= *_configuration
;
1412 iosFree(hId
, _configuration
);
1417 s32
USB_SetAlternativeInterface(s32 fd
, u8 interface
, u8 alternateSetting
)
1419 return __usb_control_message(fd
, (USB_CTRLTYPE_DIR_HOST2DEVICE
| USB_CTRLTYPE_TYPE_STANDARD
| USB_CTRLTYPE_REC_INTERFACE
), USB_REQ_SETINTERFACE
, alternateSetting
, interface
, 0, NULL
, NULL
, NULL
);
1422 static s32
USBV5_CancelEndpoint(s32 device_id
, u8 endpoint
)
1427 if (__find_device_on_host(ven_host
, device_id
)>=0)
1429 else if (__find_device_on_host(hid_host
, device_id
)>=0)
1434 s32
*buf
= (s32
*)iosAlloc(hId
, 32);
1435 if (buf
==NULL
) return IPC_ENOMEM
;
1439 ret
= IOS_Ioctl(fd
, USBV5_IOCTL_CANCELENDPOINT
, buf
, 32, NULL
, 0);
1445 s32
USB_ClearHalt(s32 fd
, u8 endpoint
)
1447 if (fd
>=0x20 || fd
<-1)
1448 return USBV5_CancelEndpoint(fd
, endpoint
);
1449 return __usb_control_message(fd
, (USB_CTRLTYPE_DIR_HOST2DEVICE
| USB_CTRLTYPE_TYPE_STANDARD
| USB_CTRLTYPE_REC_ENDPOINT
), USB_REQ_CLEARFEATURE
, USB_FEATURE_ENDPOINT_HALT
, endpoint
, 0, NULL
, NULL
, NULL
);
1452 #endif /* defined(HW_RVL) */