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_GETDEVLIST 12
63 #define USBV0_IOCTL_DEVREMOVALHOOK 26
64 #define USBV0_IOCTL_DEVINSERTHOOK 27
65 #define USBV0_IOCTL_DEVICECLASSCHANGE 28
67 #define USBV4_IOCTL_GETVERSION 6 // returns 0x40001
69 #define USBV5_IOCTL_GETVERSION 0 // should return 0x50001
70 #define USBV5_IOCTL_GETDEVICECHANGE 1
71 #define USBV5_IOCTL_SHUTDOWN 2
72 #define USBV5_IOCTL_GETDEVPARAMS 3
73 #define USBV5_IOCTL_ATTACHFINISH 6
74 #define USBV5_IOCTL_SETALTERNATE 7
75 #define USBV5_IOCTL_SUSPEND_RESUME 16
76 #define USBV5_IOCTL_CANCELENDPOINT 17
77 #define USBV5_IOCTL_CTRLMSG 18
78 #define USBV5_IOCTL_INTRMSG 19
79 #define USBV5_IOCTL_ISOMSG 20
80 #define USBV5_IOCTL_BULKMSG 21
82 #define USB_MAX_DEVICES 32
85 static const char __oh0_path
[] ATTRIBUTE_ALIGN(32) = "/dev/usb/oh0";
86 static const char __ven_path
[] ATTRIBUTE_ALIGN(32) = "/dev/usb/ven";
87 static const char __hid_path
[] ATTRIBUTE_ALIGN(32) = "/dev/usb/hid";
89 struct _usb_cb_removalnotify_list
{
96 usb_device_entry attached_devices
[USB_MAX_DEVICES
];
97 struct _usb_cb_removalnotify_list remove_cb
[USB_MAX_DEVICES
];
101 static struct _usbv5_host
* ven_host
= NULL
;
102 static struct _usbv5_host
* hid_host
= NULL
;
136 // not completely sure about this but this field must be 0 for reads
139 u32 align_pad
[4]; // pad to 24 bytes
146 static s32
__usbv5_devicechangeCB(s32 result
, void *p
);
148 static s32
__usbv5_attachfinishCB(s32 result
, void *p
)
150 struct _usbv5_host
* host
= (struct _usbv5_host
*)p
;
151 if(host
==NULL
) return IPC_EINVAL
;
154 IOS_IoctlAsync(host
->fd
, USBV5_IOCTL_GETDEVICECHANGE
, NULL
, 0, host
->attached_devices
, 0x180, __usbv5_devicechangeCB
, host
);
159 static s32
__usbv5_devicechangeCB(s32 result
, void *p
)
162 struct _usbv5_host
* host
= (struct _usbv5_host
*)p
;
164 if(host
==NULL
) return IPC_EINVAL
;
167 // can't check the remove callbacks only if the number of devices has decreased,
168 // because devices may have been inserted as well as removed
169 for (i
=0; i
<USB_MAX_DEVICES
; i
++) {
170 if (host
->remove_cb
[i
].cb
==NULL
)
172 for (j
=0; j
<result
; j
++) {
173 if (host
->remove_cb
[i
].device_id
== host
->attached_devices
[j
].device_id
)
177 if (j
==result
) { // execute callback and remove it
178 host
->remove_cb
[i
].cb(0, host
->remove_cb
[i
].userdata
);
179 host
->remove_cb
[i
].cb
= NULL
;
182 // wipe unused device entries
183 memset(host
->attached_devices
+result
, 0, sizeof(usb_device_entry
)*(32-result
));
185 IOS_IoctlAsync(host
->fd
, USBV5_IOCTL_ATTACHFINISH
, NULL
, 0, NULL
, 0, __usbv5_attachfinishCB
, host
);
192 static s32
__usb_messageCB(s32 result
,void *_msg
)
194 struct _usb_msg
*msg
= (struct _usb_msg
*)_msg
;
196 if(msg
==NULL
) return IPC_EINVAL
;
198 if(msg
->cb
!=NULL
) msg
->cb(result
, msg
->userdata
);
205 static s32
__find_device_on_host(struct _usbv5_host
*host
, s32 device_id
)
208 if (host
==NULL
) return -1;
210 for (i
=0; host
->attached_devices
[i
].device_id
; i
++) {
211 if (host
->attached_devices
[i
].device_id
== device_id
)
218 static s32
__usb_control_message(s32 device_id
,u8 bmRequestType
,u8 bmRequest
,u16 wValue
,u16 wIndex
,u16 wLength
,void *rpData
,usbcallback cb
,void *userdata
)
221 struct _usb_msg
*msg
;
223 if(((s32
)rpData
%32)!=0) return IPC_EINVAL
;
224 if(wLength
&& !rpData
) return IPC_EINVAL
;
225 if(!wLength
&& rpData
) return IPC_EINVAL
;
227 msg
= iosAlloc(hId
,sizeof(*msg
));
228 if(msg
==NULL
) return IPC_ENOMEM
;
230 memset(msg
, 0, sizeof(*msg
));
233 msg
->ctrl
.bmRequestType
= bmRequestType
;
234 msg
->ctrl
.bmRequest
= bmRequest
;
236 msg
->userdata
= userdata
;
238 if (device_id
>=0 && device_id
<0x20) {
239 msg
->ctrl
.wValue
= bswap16(wValue
);
240 msg
->ctrl
.wIndex
= bswap16(wIndex
);
241 msg
->ctrl
.wLength
= bswap16(wLength
);
243 msg
->vec
[0].data
= &msg
->ctrl
.bmRequestType
;
244 msg
->vec
[0].len
= sizeof(u8
);
245 msg
->vec
[1].data
= &msg
->ctrl
.bmRequest
;
246 msg
->vec
[1].len
= sizeof(u8
);
247 msg
->vec
[2].data
= &msg
->ctrl
.wValue
;
248 msg
->vec
[2].len
= sizeof(u16
);
249 msg
->vec
[3].data
= &msg
->ctrl
.wIndex
;
250 msg
->vec
[3].len
= sizeof(u16
);
251 msg
->vec
[4].data
= &msg
->ctrl
.wLength
;
252 msg
->vec
[4].len
= sizeof(u16
);
253 msg
->vec
[5].data
= &msg
->ctrl
.rpData
;
254 msg
->vec
[5].len
= sizeof(u8
);
255 msg
->vec
[6].data
= rpData
;
256 msg
->vec
[6].len
= wLength
;
259 ret
= IOS_Ioctlv(device_id
, USBV0_IOCTL_CTRLMSG
, 6, 1, msg
->vec
);
261 return IOS_IoctlvAsync(device_id
, USBV0_IOCTL_CTRLMSG
, 6, 1, msg
->vec
, __usb_messageCB
, msg
);
264 u8 adjust
= bmRequestType
>> 7;
265 s32 fd
= (device_id
<0) ? ven_host
->fd
: hid_host
->fd
;
266 msg
->ctrl
.wValue
= wValue
;
267 msg
->ctrl
.wIndex
= wIndex
;
268 msg
->ctrl
.wLength
= wLength
;
269 msg
->ctrl
.rpData
= rpData
;
271 msg
->vec
[0].data
= msg
;
272 msg
->vec
[0].len
= 64;
273 msg
->vec
[1].data
= rpData
;
274 msg
->vec
[1].len
= wLength
;
277 ret
= IOS_Ioctlv(fd
, USBV5_IOCTL_CTRLMSG
, 2-adjust
, adjust
, msg
->vec
);
279 return IOS_IoctlvAsync(fd
, USBV5_IOCTL_CTRLMSG
, 2-adjust
, adjust
, msg
->vec
, __usb_messageCB
, msg
);
282 if(msg
!=NULL
) iosFree(hId
,msg
);
287 static inline s32
__usb_interrupt_bulk_message(s32 device_id
,u8 ioctl
,u8 bEndpoint
,u16 wLength
,void *rpData
,usbcallback cb
,void *userdata
)
290 struct _usb_msg
*msg
;
292 if(((s32
)rpData
%32)!=0) return IPC_EINVAL
;
293 if(wLength
&& !rpData
) return IPC_EINVAL
;
294 if(!wLength
&& rpData
) return IPC_EINVAL
;
296 msg
= iosAlloc(hId
,sizeof(*msg
));
297 if(msg
==NULL
) return IPC_ENOMEM
;
299 memset(msg
, 0, sizeof(*msg
));
302 msg
->bulk
.wLength
= wLength
;
303 msg
->bulk
.rpData
= rpData
;
305 msg
->userdata
= userdata
;
307 if (device_id
>=0 && device_id
<0x20) {
308 msg
->bulk
.bEndpoint
= bEndpoint
;
309 msg
->vec
[0].data
= &msg
->bulk
.bEndpoint
;
310 msg
->vec
[0].len
= sizeof(u8
);
311 msg
->vec
[1].data
= &msg
->bulk
.wLength
;
312 msg
->vec
[1].len
= sizeof(u16
);
313 msg
->vec
[2].data
= rpData
;
314 msg
->vec
[2].len
= wLength
;
317 ret
= IOS_Ioctlv(device_id
,ioctl
,2,1,msg
->vec
);
319 return IOS_IoctlvAsync(device_id
,ioctl
,2,1,msg
->vec
,__usb_messageCB
,msg
);
322 u8 adjust
= bEndpoint
>> 7;
323 s32 fd
= (device_id
<0) ? ven_host
->fd
: hid_host
->fd
;
324 if (ioctl
== USBV0_IOCTL_INTRMSG
) {
325 msg
->intr
.bEndpoint
= bEndpoint
;
326 ioctl
= USBV5_IOCTL_INTRMSG
;
327 // HID does this a little bit differently
329 msg
->hid_intr_write
= !adjust
;
331 msg
->bulk
.bEndpoint
= bEndpoint
;
332 ioctl
= USBV5_IOCTL_BULKMSG
;
335 msg
->vec
[0].data
= msg
;
336 msg
->vec
[0].len
= 64;
337 msg
->vec
[1].data
= rpData
;
338 msg
->vec
[1].len
= wLength
;
341 ret
= IOS_Ioctlv(fd
, ioctl
, 2-adjust
, adjust
, msg
->vec
);
343 return IOS_IoctlvAsync(fd
, ioctl
, 2-adjust
, adjust
, msg
->vec
, __usb_messageCB
, msg
);
346 if(msg
!=NULL
) iosFree(hId
,msg
);
351 static inline s32
__usb_getdesc(s32 fd
, u8
*buffer
, u8 type
, u8 index
, u8 size
)
353 return __usb_control_message(fd
, USB_ENDPOINT_IN
,USB_REQ_GETDESCRIPTOR
, (type
<< 8) | index
, 0, size
, buffer
, NULL
, NULL
);
356 static u32
__find_next_endpoint(u8
*buffer
,u32 size
)
361 if(buffer
[1]==USB_DT_ENDPOINT
|| buffer
[1]==USB_DT_INTERFACE
)
368 return (buffer
- ptr
);
373 if(hId
==-1) hId
= iosCreateHeap(USB_HEAPSIZE
);
374 if(hId
<0) return IPC_ENOMEM
;
376 if (ven_host
==NULL
) {
377 s32 ven_fd
= IOS_Open(__ven_path
, IPC_OPEN_NONE
);
379 ven_host
= (struct _usbv5_host
*)iosAlloc(hId
, sizeof(*ven_host
));
380 if (ven_host
==NULL
) {
384 memset(ven_host
, 0, sizeof(*ven_host
));
385 ven_host
->fd
= ven_fd
;
387 u32
*ven_ver
= (u32
*)iosAlloc(hId
, 0x20);
388 if (ven_ver
==NULL
) goto mem_error
;
389 if (IOS_Ioctl(ven_fd
, USBV5_IOCTL_GETVERSION
, NULL
, 0, ven_ver
, 0x20)==0 && ven_ver
[0]==0x50001)
390 IOS_IoctlAsync(ven_fd
, USBV5_IOCTL_GETDEVICECHANGE
, NULL
, 0, ven_host
->attached_devices
, 0x180, __usbv5_devicechangeCB
, ven_host
);
394 iosFree(hId
, ven_host
);
398 iosFree(hId
, ven_ver
);
402 if (hid_host
==NULL
) {
403 s32 hid_fd
= IOS_Open(__hid_path
, IPC_OPEN_NONE
);
405 hid_host
= (struct _usbv5_host
*)iosAlloc(hId
, sizeof(*hid_host
));
406 if (hid_host
==NULL
) {
410 memset(hid_host
, 0, sizeof(*hid_host
));
411 hid_host
->fd
= hid_fd
;
413 u32
*hid_ver
= (u32
*)iosAlloc(hId
, 0x20);
414 if (hid_ver
==NULL
) goto mem_error
;
415 // have to call the USB4 version first, to be safe
416 if (IOS_Ioctl(hid_fd
, USBV4_IOCTL_GETVERSION
, NULL
, 0, NULL
, 0)==0x40001 || \
417 IOS_Ioctl(hid_fd
, USBV5_IOCTL_GETVERSION
, NULL
, 0, hid_ver
, 0x20) || hid_ver
[0]!=0x50001) {
420 iosFree(hId
, hid_host
);
423 IOS_IoctlAsync(hid_fd
, USBV5_IOCTL_GETDEVICECHANGE
, NULL
, 0, hid_host
->attached_devices
, 0x180, __usbv5_devicechangeCB
, hid_host
);
425 iosFree(hId
, hid_ver
);
436 s32
USB_Deinitialize()
440 IOS_Ioctl(hid_host
->fd
, USBV5_IOCTL_SHUTDOWN
, NULL
, 0, NULL
, 0);
441 IOS_Close(hid_host
->fd
);
443 iosFree(hId
, hid_host
);
448 if (ven_host
->fd
>=0) {
449 IOS_Ioctl(ven_host
->fd
, USBV5_IOCTL_SHUTDOWN
, NULL
, 0, NULL
, 0);
450 IOS_Close(ven_host
->fd
);
452 iosFree(hId
, ven_host
);
464 s32
USB_OpenDevice(s32 device_id
,u16 vid
,u16 pid
,s32
*fd
)
467 char *devicepath
= NULL
;
470 if (device_id
&& device_id
!=USB_OH1_DEVICE_ID
) {
473 i
= __find_device_on_host(ven_host
, device_id
);
475 i
= __find_device_on_host(hid_host
, device_id
);
478 return USB_ResumeDevice(device_id
);
482 devicepath
= iosAlloc(hId
,USB_MAXPATH
);
483 if(devicepath
==NULL
) return IPC_ENOMEM
;
485 if (device_id
==USB_OH1_DEVICE_ID
)
486 snprintf(devicepath
,USB_MAXPATH
,"/dev/usb/oh1/%x/%x",vid
,pid
);
488 snprintf(devicepath
,USB_MAXPATH
,"/dev/usb/oh0/%x/%x",vid
,pid
);
490 *fd
= IOS_Open(devicepath
,0);
493 if (devicepath
!=NULL
) iosFree(hId
,devicepath
);
497 s32
USBV5_CloseDevice(s32 device_id
)
500 struct _usbv5_host
* host
;
502 if (__find_device_on_host(ven_host
, device_id
)>=0)
504 else if (__find_device_on_host(hid_host
, device_id
)>=0)
509 for (i
=0; i
< USB_MAX_DEVICES
; i
++) {
510 if (host
->remove_cb
[i
].cb
==NULL
)
513 if (host
->remove_cb
[i
].device_id
==device_id
) {
514 host
->remove_cb
[i
].cb(0, host
->remove_cb
[i
].userdata
);
515 host
->remove_cb
[i
].cb
= NULL
;
520 return USB_SuspendDevice(device_id
);
523 s32
USB_CloseDevice(s32
*fd
)
525 s32 ret
= IPC_EINVAL
;
527 ret
= USBV5_CloseDevice(*fd
);
528 if (ret
==IPC_EINVAL
&& *fd
>0)
529 ret
= IOS_Close(*fd
);
530 if (ret
>=0) *fd
= -1;
536 s32
USB_CloseDeviceAsync(s32
*fd
,usbcallback cb
,void *userdata
)
538 s32 ret
= IPC_EINVAL
;
540 ret
= USBV5_CloseDevice(*fd
);
541 if (ret
!=IPC_EINVAL
) {
543 return cb(ret
, userdata
);
548 return IOS_CloseAsync(*fd
,cb
,userdata
);
554 s32
USB_GetDeviceDescription(s32 fd
,usb_devdesc
*devdesc
)
559 p
= iosAlloc(hId
,USB_DT_DEVICE_SIZE
);
560 if(p
==NULL
) return IPC_ENOMEM
;
562 ret
= __usb_control_message(fd
,USB_ENDPOINT_IN
,USB_REQ_GETDESCRIPTOR
,(USB_DT_DEVICE
<<8),0,USB_DT_DEVICE_SIZE
,p
,NULL
,NULL
);
563 if(ret
>=0) memcpy(devdesc
,p
,USB_DT_DEVICE_SIZE
);
564 devdesc
->configurations
= NULL
;
566 if(p
!=NULL
) iosFree(hId
,p
);
570 static s32
USBV5_GetDescriptors(s32 device_id
, usb_devdesc
*udd
)
572 s32 retval
= IPC_ENOMEM
;
573 u32
*io_buffer
= NULL
;
575 usb_configurationdesc
*ucd
= NULL
;
576 usb_interfacedesc
*uid
= NULL
;
577 usb_endpointdesc
*ued
= NULL
;
578 u32 iConf
, iEndpoint
;
580 u32 desc_out_size
, desc_start_offset
;
582 if (__find_device_on_host(ven_host
, device_id
)>=0) {
584 desc_out_size
= 0xC0;
585 desc_start_offset
= 20;
586 } else if (__find_device_on_host(hid_host
, device_id
)>=0) {
588 desc_out_size
= 0x60;
589 desc_start_offset
= 36;
593 io_buffer
= (u32
*)iosAlloc(hId
, 0x20);
594 buffer
= (u8
*)iosAlloc(hId
, desc_out_size
);
595 if (io_buffer
==NULL
|| buffer
==NULL
) goto free_bufs
;
597 io_buffer
[0] = device_id
;
599 retval
= IOS_Ioctl(fd
, USBV5_IOCTL_GETDEVPARAMS
, io_buffer
, 0x20, buffer
, desc_out_size
);
600 if (retval
==IPC_OK
) {
601 u8
*next
= buffer
+desc_start_offset
;
603 memcpy(udd
, next
, sizeof(*udd
));
604 udd
->configurations
= calloc(udd
->bNumConfigurations
, sizeof(*udd
->configurations
));
605 if(udd
->configurations
== NULL
) goto free_bufs
;
607 next
+= (udd
->bLength
+3)&~3;
608 for (iConf
= 0; iConf
< udd
->bNumConfigurations
; iConf
++)
610 ucd
= &udd
->configurations
[iConf
];
611 memcpy(ucd
, next
, USB_DT_CONFIG_SIZE
);
612 next
+= (USB_DT_CONFIG_SIZE
+3)&~3;
613 // IOS presents each interface as a different device
614 if (ucd
->bNumInterfaces
) ucd
->bNumInterfaces
= 1;
616 ucd
->interfaces
= calloc(ucd
->bNumInterfaces
, sizeof(*ucd
->interfaces
));
617 if (ucd
->interfaces
== NULL
) goto free_bufs
;
619 uid
= ucd
->interfaces
;
620 memcpy(uid
, next
, USB_DT_INTERFACE_SIZE
);
621 next
+= (uid
->bLength
+3)&~3;
623 uid
->endpoints
= calloc(uid
->bNumEndpoints
, sizeof(*uid
->endpoints
));
624 if (uid
->endpoints
== NULL
) goto free_bufs
;
626 memset(uid
->endpoints
,0,uid
->bNumEndpoints
*sizeof(*uid
->endpoints
));
627 for(iEndpoint
= 0; iEndpoint
< uid
->bNumEndpoints
; iEndpoint
++)
629 ued
= &uid
->endpoints
[iEndpoint
];
630 memcpy(ued
, next
, USB_DT_ENDPOINT_SIZE
);
631 next
+= (ued
->bLength
+3)&~3;
640 iosFree(hId
, io_buffer
);
642 iosFree(hId
, buffer
);
646 s32
USB_GetDescriptors(s32 fd
, usb_devdesc
*udd
)
650 usb_configurationdesc
*ucd
= NULL
;
651 usb_interfacedesc
*uid
= NULL
;
652 usb_endpointdesc
*ued
= NULL
;
655 u32 iConf
, iInterface
, iEndpoint
;
657 if (fd
>=0x20 || fd
<-1)
658 return USBV5_GetDescriptors(fd
, udd
);
660 buffer
= iosAlloc(hId
, sizeof(*udd
));
663 retval
= IPC_ENOHEAP
;
667 retval
= __usb_getdesc(fd
, buffer
, USB_DT_DEVICE
, 0, USB_DT_DEVICE_SIZE
);
670 memcpy(udd
, buffer
, USB_DT_DEVICE_SIZE
);
671 iosFree(hId
, buffer
);
673 udd
->bcdUSB
= bswap16(udd
->bcdUSB
);
674 udd
->idVendor
= bswap16(udd
->idVendor
);
675 udd
->idProduct
= bswap16(udd
->idProduct
);
676 udd
->bcdDevice
= bswap16(udd
->bcdDevice
);
678 udd
->configurations
= calloc(udd
->bNumConfigurations
, sizeof(*udd
->configurations
));
679 if(udd
->configurations
== NULL
)
684 for(iConf
= 0; iConf
< udd
->bNumConfigurations
; iConf
++)
686 buffer
= iosAlloc(hId
, USB_DT_CONFIG_SIZE
);
689 retval
= IPC_ENOHEAP
;
693 retval
= __usb_getdesc(fd
, buffer
, USB_DT_CONFIG
, iConf
, USB_DT_CONFIG_SIZE
);
694 ucd
= &udd
->configurations
[iConf
];
695 memcpy(ucd
, buffer
, USB_DT_CONFIG_SIZE
);
696 iosFree(hId
, buffer
);
698 ucd
->wTotalLength
= bswap16(ucd
->wTotalLength
);
699 size
= ucd
->wTotalLength
;
700 buffer
= iosAlloc(hId
, size
);
703 retval
= IPC_ENOHEAP
;
707 retval
= __usb_getdesc(fd
, buffer
, USB_DT_CONFIG
, iConf
, ucd
->wTotalLength
);
713 size
-= ucd
->bLength
;
716 ucd
->interfaces
= calloc(ucd
->bNumInterfaces
, sizeof(*ucd
->interfaces
));
717 if(ucd
->interfaces
== NULL
)
719 for(iInterface
= 0; iInterface
< ucd
->bNumInterfaces
; iInterface
++)
721 uid
= &ucd
->interfaces
[iInterface
];
722 memcpy(uid
, ptr
, USB_DT_INTERFACE_SIZE
);
724 size
-= uid
->bLength
;
726 if (uid
->bNumEndpoints
==0)
728 uid
->endpoints
= calloc(uid
->bNumEndpoints
, sizeof(*uid
->endpoints
));
729 if(uid
->endpoints
== NULL
)
732 /* This skips vendor and class specific descriptors */
733 i
= __find_next_endpoint(ptr
, size
);
737 uid
->extra
= malloc(i
);
738 if(uid
->extra
== NULL
)
740 memcpy(uid
->extra
, ptr
, i
);
744 memset(uid
->endpoints
,0,uid
->bNumEndpoints
* sizeof(*uid
->endpoints
));
745 for(iEndpoint
= 0; iEndpoint
< uid
->bNumEndpoints
; iEndpoint
++)
747 ued
= &uid
->endpoints
[iEndpoint
];
748 memcpy(ued
, ptr
, USB_DT_ENDPOINT_SIZE
);
750 ued
->wMaxPacketSize
= bswap16(ued
->wMaxPacketSize
);
753 iosFree(hId
, buffer
);
760 iosFree(hId
, buffer
);
762 USB_FreeDescriptors(udd
);
766 //TODO: Fix for /dev/usb/hid
767 s32
USB_GetHIDDescriptor(s32 fd
,usb_hiddesc
*uhd
)
772 buffer
= iosAlloc(hId
,sizeof(usb_hiddesc
));
778 retval
= __usb_getdesc(fd
,buffer
,USB_DT_HID
,0,USB_DT_HID_SIZE
);
779 if(retval
<0) goto free_and_error
;
781 memcpy(uhd
,buffer
,USB_DT_HID_SIZE
);
782 uhd
->bcdHID
= bswap16(uhd
->bcdHID
);
783 uhd
->descr
[0].wDescriptorLength
= bswap16(uhd
->descr
[0].wDescriptorLength
);
788 if(buffer
!=NULL
) iosFree(hId
,buffer
);
792 void USB_FreeDescriptors(usb_devdesc
*udd
)
794 int iConf
, iInterface
;
795 usb_configurationdesc
*ucd
;
796 usb_interfacedesc
*uid
;
797 if(udd
->configurations
!= NULL
)
799 for(iConf
= 0; iConf
< udd
->bNumConfigurations
; iConf
++)
801 ucd
= &udd
->configurations
[iConf
];
802 if(ucd
->interfaces
!= NULL
)
804 for(iInterface
= 0; iInterface
< ucd
->bNumInterfaces
; iInterface
++)
806 uid
= &ucd
->interfaces
[iInterface
];
807 if(uid
->endpoints
!= NULL
)
808 free(uid
->endpoints
);
809 if(uid
->extra
!= NULL
)
812 free(ucd
->interfaces
);
815 free(udd
->configurations
);
819 s32
USB_GetAsciiString(s32 fd
,u16 wIndex
,u16 wLangID
,u16 wLength
,void *rpData
)
824 u8
*rp
= (u8
*)rpData
;
829 buf
= iosAlloc(hId
, 255); /* 255 is the highest possible length of a descriptor */
833 ret
= __usb_control_message(fd
, USB_ENDPOINT_IN
, USB_REQ_GETDESCRIPTOR
, ((USB_DT_STRING
<< 8) + wIndex
), wLangID
, 255, buf
, NULL
, NULL
);
835 /* index 0 gets a list of supported languages */
839 memcpy(rpData
, buf
, wLength
);
848 while(ro
< (wLength
- 1) && bo
< buf
[0])
864 s32
USB_ReadIntrMsg(s32 fd
,u8 bEndpoint
,u16 wLength
,void *rpData
)
866 return __usb_interrupt_bulk_message(fd
,USBV0_IOCTL_INTRMSG
,bEndpoint
,wLength
,rpData
,NULL
,NULL
);
869 s32
USB_ReadIntrMsgAsync(s32 fd
,u8 bEndpoint
,u16 wLength
,void *rpData
,usbcallback cb
,void *userdata
)
871 return __usb_interrupt_bulk_message(fd
,USBV0_IOCTL_INTRMSG
,bEndpoint
,wLength
,rpData
,cb
,userdata
);
874 s32
USB_WriteIntrMsg(s32 fd
,u8 bEndpoint
,u16 wLength
,void *rpData
)
876 return __usb_interrupt_bulk_message(fd
,USBV0_IOCTL_INTRMSG
,bEndpoint
,wLength
,rpData
,NULL
,NULL
);
879 s32
USB_WriteIntrMsgAsync(s32 fd
,u8 bEndpoint
,u16 wLength
,void *rpData
,usbcallback cb
,void *userdata
)
881 return __usb_interrupt_bulk_message(fd
,USBV0_IOCTL_INTRMSG
,bEndpoint
,wLength
,rpData
,cb
,userdata
);
884 s32
USB_ReadBlkMsg(s32 fd
,u8 bEndpoint
,u16 wLength
,void *rpData
)
886 return __usb_interrupt_bulk_message(fd
,USBV0_IOCTL_BLKMSG
,bEndpoint
,wLength
,rpData
,NULL
,NULL
);
889 s32
USB_ReadBlkMsgAsync(s32 fd
,u8 bEndpoint
,u16 wLength
,void *rpData
,usbcallback cb
,void *userdata
)
891 return __usb_interrupt_bulk_message(fd
,USBV0_IOCTL_BLKMSG
,bEndpoint
,wLength
,rpData
,cb
,userdata
);
894 s32
USB_WriteBlkMsg(s32 fd
,u8 bEndpoint
,u16 wLength
,void *rpData
)
896 return __usb_interrupt_bulk_message(fd
,USBV0_IOCTL_BLKMSG
,bEndpoint
,wLength
,rpData
,NULL
,NULL
);
899 s32
USB_WriteBlkMsgAsync(s32 fd
,u8 bEndpoint
,u16 wLength
,void *rpData
,usbcallback cb
,void *userdata
)
901 return __usb_interrupt_bulk_message(fd
,USBV0_IOCTL_BLKMSG
,bEndpoint
,wLength
,rpData
,cb
,userdata
);
904 s32
USB_ReadCtrlMsg(s32 fd
,u8 bmRequestType
,u8 bmRequest
,u16 wValue
,u16 wIndex
,u16 wLength
,void *rpData
)
906 return __usb_control_message(fd
,bmRequestType
,bmRequest
,wValue
,wIndex
,wLength
,rpData
,NULL
,NULL
);
909 s32
USB_ReadCtrlMsgAsync(s32 fd
,u8 bmRequestType
,u8 bmRequest
,u16 wValue
,u16 wIndex
,u16 wLength
,void *rpData
,usbcallback cb
,void *userdata
)
911 return __usb_control_message(fd
,bmRequestType
,bmRequest
,wValue
,wIndex
,wLength
,rpData
,cb
,userdata
);
914 s32
USB_WriteCtrlMsg(s32 fd
,u8 bmRequestType
,u8 bmRequest
,u16 wValue
,u16 wIndex
,u16 wLength
,void *rpData
)
916 return __usb_control_message(fd
,bmRequestType
,bmRequest
,wValue
,wIndex
,wLength
,rpData
,NULL
,NULL
);
919 s32
USB_WriteCtrlMsgAsync(s32 fd
,u8 bmRequestType
,u8 bmRequest
,u16 wValue
,u16 wIndex
,u16 wLength
,void *rpData
,usbcallback cb
,void *userdata
)
921 return __usb_control_message(fd
,bmRequestType
,bmRequest
,wValue
,wIndex
,wLength
,rpData
,cb
,userdata
);
924 static s32
USB5_RegisterDeviceRemoval(struct _usbv5_host
*host
, s32 device_id
, usbcallback cb
, void *userdata
)
928 // check to make sure the device is present
929 if (__find_device_on_host(host
, device_id
)<0)
932 // now make sure it's not hooked already
933 for (i
=0; i
<USB_MAX_DEVICES
; i
++) {
934 if (host
->remove_cb
[i
].cb
&& host
->remove_cb
[i
].device_id
==device_id
)
938 // find a free entry and add it
939 for (i
=0; i
<USB_MAX_DEVICES
; i
++) {
940 if (host
->remove_cb
[i
].cb
==NULL
) {
941 host
->remove_cb
[i
].cb
= cb
;
942 host
->remove_cb
[i
].userdata
= userdata
;
943 host
->remove_cb
[i
].device_id
= device_id
;
950 s32
USB_DeviceRemovalNotifyAsync(s32 fd
,usbcallback cb
,void *userdata
)
953 if (fd
>=0 && fd
<0x20)
954 return IOS_IoctlAsync(fd
,USBV0_IOCTL_DEVREMOVALHOOK
,NULL
,0,NULL
,0,cb
,userdata
);
956 ret
= USB5_RegisterDeviceRemoval(ven_host
, fd
, cb
, userdata
);
957 if (ret
== IPC_ENOENT
)
958 ret
= USB5_RegisterDeviceRemoval(hid_host
, fd
, cb
, userdata
);
963 static s32
USBV5_SuspendResume(s32 device_id
, s32 resumed
)
968 if (__find_device_on_host(ven_host
, device_id
)>=0)
970 else if (__find_device_on_host(hid_host
, device_id
)>=0)
975 s32
*buf
= (s32
*)iosAlloc(hId
, 32);
976 if (buf
==NULL
) return IPC_ENOMEM
;
980 ret
= IOS_Ioctl(fd
, USBV5_IOCTL_SUSPEND_RESUME
, buf
, 32, NULL
, 0);
986 s32
USB_SuspendDevice(s32 fd
)
988 if (fd
>=0x20 || fd
<-1)
989 return USBV5_SuspendResume(fd
, 0);
991 return IOS_Ioctl(fd
,USBV0_IOCTL_SUSPENDDEV
,NULL
,0,NULL
,0);
994 s32
USB_ResumeDevice(s32 fd
)
996 if (fd
>=0x20 || fd
<-1)
997 return USBV5_SuspendResume(fd
, 1);
999 return IOS_Ioctl(fd
,USBV0_IOCTL_RESUMEDEV
,NULL
,0,NULL
,0);
1002 // TODO: Implement this for VEN and HID
1003 s32
USB_DeviceChangeNotifyAsync(u8 interface_class
, usbcallback cb
, void* userdata
)
1006 struct _usb_msg
*msg
;
1009 fd
= IOS_Open(__oh0_path
,IPC_OPEN_NONE
);
1010 if (fd
<0) return fd
;
1012 msg
= iosAlloc(hId
,sizeof(*msg
));
1019 msg
->userdata
= userdata
;
1020 msg
->class = interface_class
;
1022 msg
->vec
[0].data
= &msg
->class;
1023 msg
->vec
[0].len
= 1;
1025 ret
= IOS_IoctlvAsync(fd
,USBV0_IOCTL_DEVICECLASSCHANGE
,1,0,msg
->vec
,__usb_messageCB
,msg
);
1028 if (ret
<0) iosFree(hId
, msg
);
1033 s32
USB_GetDeviceList(usb_device_entry
*descr_buffer
,u8 num_descr
,u8 interface_class
,u8
*cnt_descr
)
1038 if (ven_host
==NULL
) {
1040 u32
*buf
= (u32
*)iosAlloc(hId
, num_descr
<<3);
1041 if (buf
==NULL
) return IPC_ENOMEM
;
1043 fd
= IOS_Open(__oh0_path
,IPC_OPEN_NONE
);
1050 i
= IOS_IoctlvFormat(hId
,fd
,USBV0_IOCTL_GETDEVLIST
,"bb:dd",num_descr
,interface_class
,&cntdevs
,sizeof(cntdevs
),buf
,(num_descr
<<3));
1051 if (cnt_descr
) *cnt_descr
= cntdevs
;
1054 descr_buffer
[cntdevs
].device_id
= 0;
1055 descr_buffer
[cntdevs
].vid
= (u16
)(buf
[cntdevs
*2+1]>>16);
1056 descr_buffer
[cntdevs
].pid
= (u16
)buf
[cntdevs
*2+1];
1064 // for ven_host, we can only exclude usb_hid class devices
1065 if (interface_class
!= USB_CLASS_HID
&& ven_host
) {
1067 while (cntdevs
<num_descr
&& ven_host
->attached_devices
[i
].device_id
) {
1068 descr_buffer
[cntdevs
++] = ven_host
->attached_devices
[i
++];
1073 if ((!interface_class
|| interface_class
==USB_CLASS_HID
) && hid_host
) {
1075 while (cntdevs
<num_descr
&& hid_host
->attached_devices
[i
].device_id
) {
1076 descr_buffer
[cntdevs
++] = hid_host
->attached_devices
[i
++];
1081 if (cnt_descr
) *cnt_descr
= cntdevs
;
1086 s32
USB_SetConfiguration(s32 fd
, u8 configuration
)
1088 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
);
1091 s32
USB_GetConfiguration(s32 fd
, u8
*configuration
)
1096 _configuration
= iosAlloc(hId
, 1);
1097 if(_configuration
== NULL
)
1100 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
);
1102 *configuration
= *_configuration
;
1103 iosFree(hId
, _configuration
);
1108 s32
USB_SetAlternativeInterface(s32 fd
, u8 interface
, u8 alternateSetting
)
1110 if(alternateSetting
== 0)
1112 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
);
1115 static s32
USBV5_CancelEndpoint(s32 device_id
, u8 endpoint
)
1120 if (__find_device_on_host(ven_host
, device_id
)>=0)
1122 else if (__find_device_on_host(hid_host
, device_id
)>=0)
1127 s32
*buf
= (s32
*)iosAlloc(hId
, 32);
1128 if (buf
==NULL
) return IPC_ENOMEM
;
1132 ret
= IOS_Ioctl(fd
, USBV5_IOCTL_CANCELENDPOINT
, buf
, 32, NULL
, 0);
1138 s32
USB_ClearHalt(s32 fd
, u8 endpoint
)
1140 if (fd
>=0x20 || fd
<-1)
1141 return USBV5_CancelEndpoint(fd
, endpoint
);
1142 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
);
1145 #endif /* defined(HW_RVL) */