2 Copyright © 2015-2016, The AROS Development Team. All rights reserved.
5 Desc: Virtual USB host controller
14 #include <aros/debug.h>
16 #include <proto/exec.h>
17 #include <proto/hostlib.h>
19 #include <devices/usb.h>
20 #include <devices/usb_hub.h>
22 #include "vusbhci_device.h"
23 #include "vusbhci_bridge.h"
26 struct libusb_func libusb_func
;
28 static void *libusbhandle
;
30 static libusb_device_handle
*dev_handle
= NULL
;
32 void ctrl_callback_handler(struct libusb_transfer
*transfer
) {
34 struct IOUsbHWReq
*ioreq
= transfer
->user_data
;
35 struct VUSBHCIUnit
*unit
= (struct VUSBHCIUnit
*) ioreq
->iouh_Req
.io_Unit
;
37 mybug_unit(-1, ("ctrl_callback_handler!\n\n"));
40 int hotplug_callback_event_handler(libusb_context
*ctx
, libusb_device
*dev
, libusb_hotplug_event event
, void *user_data
) {
42 struct VUSBHCIBase
*VUSBHCIBase
= (struct VUSBHCIBase
*)user_data
;
43 struct VUSBHCIUnit
*unit
= VUSBHCIBase
->usbunit200
;
45 struct libusb_device_descriptor desc
;
48 mybug_unit(-1, ("Hotplug callback event!\n"));
52 case LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED
:
53 mybug_unit(-1, ("- Device attached\n"));
55 if(unit
->allocated
&& (!dev_handle
)) {
56 rc
= LIBUSBCALL(libusb_get_device_descriptor
, dev
, &desc
);
57 if (LIBUSB_SUCCESS
!= rc
) {
58 mybug_unit(-1, ("Failed to read device descriptor\n"));
61 mybug_unit(-1, ("Device attach: %04x:%04x\n", desc
.idVendor
, desc
.idProduct
));
63 rc
= LIBUSBCALL(libusb_open
, dev
, &dev_handle
);
66 LIBUSBCALL(libusb_set_auto_detach_kernel_driver
, dev_handle
, 0);
68 if ( LIBUSBCALL(libusb_kernel_driver_active
, dev_handle
, 0) ) {
69 mybug_unit(-1, ("Kernel driver active\n"));
70 if ( (LIBUSBCALL(libusb_detach_kernel_driver
, dev_handle
, 0) == 0) ) {
71 mybug_unit(-1, ("Kernel driver detached\n"));
73 mybug_unit(-1, ("Kernel driver NOT detached\n"));
76 mybug_unit(-1, ("Kernel driver doesn't appear to be active\n"));
79 /* Check again for debug purposes */
80 if ( LIBUSBCALL(libusb_kernel_driver_active
, dev_handle
, 0) ) {
81 mybug_unit(-1, ("Kernel driver active\n"));
82 if ( (LIBUSBCALL(libusb_detach_kernel_driver
, dev_handle
, 0) == 0) ) {
83 mybug_unit(-1, ("Kernel driver detached\n"));
85 mybug_unit(-1, ("Kernel driver NOT detached\n"));
88 mybug_unit(-1, ("Kernel driver doesn't appear to be active\n"));
91 LIBUSBCALL(libusb_set_configuration
, dev_handle
, 0);
92 LIBUSBCALL(libusb_claim_interface
, dev_handle
, 0);
94 speed
= LIBUSBCALL(libusb_get_device_speed
, dev
);
96 case LIBUSB_SPEED_LOW
:
97 unit
->roothub
.portstatus
.wPortStatus
|= AROS_WORD2LE(UPSF_PORT_LOW_SPEED
);
99 case LIBUSB_SPEED_FULL
:
100 unit
->roothub
.portstatus
.wPortStatus
&= ~(AROS_WORD2LE(UPSF_PORT_HIGH_SPEED
)|AROS_WORD2LE(UPSF_PORT_LOW_SPEED
));
102 case LIBUSB_SPEED_HIGH
:
103 unit
->roothub
.portstatus
.wPortStatus
|= AROS_WORD2LE(UPSF_PORT_HIGH_SPEED
);
105 //case LIBUSB_SPEED_SUPER:
109 unit
->roothub
.portstatus
.wPortStatus
|= AROS_WORD2LE(UPSF_PORT_CONNECTION
);
110 unit
->roothub
.portstatus
.wPortChange
|= AROS_WORD2LE(UPSF_PORT_CONNECTION
);
112 uhwCheckRootHubChanges(unit
);
114 if(rc
== LIBUSB_ERROR_ACCESS
) {
115 mybug_unit(-1, ("libusb_open, access error, try running as superuser\n\n"));
122 case LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT
:
123 mybug_unit(-1, (" - Device detached\n"));
125 if(unit
->allocated
) {
127 unit
->roothub
.portstatus
.wPortStatus
&= ~UPSF_PORT_CONNECTION
;
128 unit
->roothub
.portstatus
.wPortChange
|= UPSF_PORT_CONNECTION
;
130 uhwCheckRootHubChanges(unit
);
133 if(dev_handle
!= NULL
) {
134 LIBUSBCALL(libusb_close
, dev_handle
);
141 mybug_unit(-1, (" - Unknown event arrived\n"));
149 void *hostlib_load_so(const char *sofile
, const char **names
, int nfuncs
, void **funcptr
) {
154 if ((handle
= HostLib_Open(sofile
, &err
)) == NULL
) {
155 (bug("[LIBUSB] failed to open '%s': %s\n", sofile
, err
));
158 bug("[LIBUSB] opened '%s'\n", sofile
);
161 for (i
= 0; i
< nfuncs
; i
++) {
162 funcptr
[i
] = HostLib_GetPointer(handle
, names
[i
], &err
);
164 bug("[LIBUSB] failed to get symbol '%s' (%s)\n", names
[i
], err
);
165 HostLib_Close(handle
, NULL
);
168 bug("[LIBUSB] managed to get symbol '%s'\n", names
[i
]);
175 BOOL
libusb_bridge_init(struct VUSBHCIBase
*VUSBHCIBase
) {
179 HostLibBase
= OpenResource("hostlib.resource");
184 libusbhandle
= hostlib_load_so("libusb.so", libusb_func_names
, LIBUSB_NUM_FUNCS
, (void **)&libusb_func
);
189 if(!LIBUSBCALL(libusb_init
, NULL
)) {
190 LIBUSBCALL(libusb_set_debug
, NULL
, 1);
191 bug("[LIBUSB] Checking hotplug support of libusb\n");
192 if (LIBUSBCALL(libusb_has_capability
, LIBUSB_CAP_HAS_HOTPLUG
)) {
193 bug("[LIBUSB] - Hotplug supported\n");
195 rc
= (LIBUSBCALL(libusb_hotplug_register_callback
,
197 (LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED
|LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT
),
199 LIBUSB_HOTPLUG_MATCH_ANY
,
200 LIBUSB_HOTPLUG_MATCH_ANY
,
201 LIBUSB_HOTPLUG_MATCH_ANY
,
202 hotplug_callback_event_handler
,
207 if(rc
== LIBUSB_SUCCESS
) {
208 bug("[LIBUSB] - Hotplug callback installed rc = %d\n", rc
);
212 bug("[LIBUSB] - Hotplug callback installation failure! rc = %d\n", rc
);
215 bug("[LIBUSB] - Hotplug not supported, failing...\n");
216 LIBUSBCALL(libusb_exit
, NULL
);
218 libusb_bridge_cleanup();
224 VOID
libusb_bridge_cleanup() {
225 HostLib_Close(libusbhandle
, NULL
);
228 void call_libusb_event_handler() {
229 LIBUSBCALL(libusb_handle_events
, NULL
);
233 FIXME: libusb expects buffer to precede with enough space for setup data (8 bytes or LIBUSB_CONTROL_SETUP_SIZE)
234 - Copy buffer need to be used
236 IGNORE or CHECKME: LIBUSB_xxx_SETUP_SIZE is needed for asynchronous use of libusb
239 int do_libusb_ctrl_transfer(struct IOUsbHWReq
*ioreq
) {
240 struct VUSBHCIUnit
*unit
= (struct VUSBHCIUnit
*) ioreq
->iouh_Req
.io_Unit
;
244 UWORD bmRequestType
= (ioreq
->iouh_SetupData
.bmRequestType
);
245 UWORD bRequest
= (ioreq
->iouh_SetupData
.bRequest
);
246 UWORD wValue
= (ioreq
->iouh_SetupData
.wValue
);
247 UWORD wIndex
= (ioreq
->iouh_SetupData
.wIndex
);
248 UWORD wLength
= (ioreq
->iouh_SetupData
.wLength
);
250 switch(((ULONG
)ioreq
->iouh_SetupData
.bmRequestType
<<16)|((ULONG
)ioreq
->iouh_SetupData
.bRequest
)) {
252 /* FIXME: Keep track on device address (what poseidon thinks the address is and what Linux think it is) */
254 case ((((URTF_OUT
|URTF_STANDARD
|URTF_DEVICE
))<<16)|(USR_SET_ADDRESS
)):
255 mybug_unit(-1, ("Filtering out SET_ADDRESS\n\n"));
256 ioreq
->iouh_Actual
= ioreq
->iouh_Length
;
257 return UHIOERR_NO_ERROR
;
260 /* FIXME: Parse messages related to configurations and use related libusb calls directly */
262 case ((((URTF_OUT
|URTF_STANDARD
|URTF_DEVICE
))<<16)|(USR_SET_CONFIGURATION
)):
263 mybug_unit(-1, ("Filtering out SET_CONFIGURATION\n\n"));
264 ioreq
->iouh_Actual
= ioreq
->iouh_Length
;
265 return UHIOERR_NO_ERROR
;
270 mybug_unit(0, ("wLength %d\n", wLength
));
271 mybug_unit(0, ("ioreq->iouh_Length %d\n", ioreq
->iouh_Length
));
273 rc
= LIBUSBCALL(libusb_control_transfer
, dev_handle
, bmRequestType
, bRequest
, wValue
, wIndex
, ioreq
->iouh_Data
, ioreq
->iouh_Length
, ioreq
->iouh_NakTimeout
);
279 ioreq
->iouh_Actual
= rc
;
281 mybug_unit(0, ("Done!\n\n"));
282 return UHIOERR_NO_ERROR
;
285 int do_libusb_intr_transfer(struct IOUsbHWReq
*ioreq
) {
286 struct VUSBHCIUnit
*unit
= (struct VUSBHCIUnit
*) ioreq
->iouh_Req
.io_Unit
;
288 int rc
= 0, transferred
= 0;
289 UBYTE endpoint
= ioreq
->iouh_Endpoint
;
291 mybug_unit(-1, ("ioreq->iouh_Length %d\n", ioreq
->iouh_Length
));
292 mybug_unit(-1, ("direction %d\n", (ioreq
->iouh_Dir
)));
294 switch(ioreq
->iouh_Dir
) {
296 mybug_unit(-1, ("ioreq->iouh_Endpoint %d (IN)(%x)\n", endpoint
, (endpoint
|LIBUSB_ENDPOINT_IN
)));
297 rc
= LIBUSBCALL(libusb_interrupt_transfer
, dev_handle
, (endpoint
|LIBUSB_ENDPOINT_IN
), (UBYTE
*)ioreq
->iouh_Data
, ioreq
->iouh_Length
, &transferred
, ioreq
->iouh_NakTimeout
);
301 mybug_unit(-1, ("ioreq->iouh_Endpoint %d (OUT)(%x)\n", endpoint
, (endpoint
|LIBUSB_ENDPOINT_OUT
)));
302 rc
= LIBUSBCALL(libusb_interrupt_transfer
, dev_handle
, (endpoint
|LIBUSB_ENDPOINT_OUT
), (UBYTE
*)ioreq
->iouh_Data
, ioreq
->iouh_Length
, &transferred
, ioreq
->iouh_NakTimeout
);
306 mybug_unit(-1, ("libusb_interrupt_transfer rc = %d, transferred %d\n", rc
, transferred
));
310 mybug_unit(-1, ("Success (no error)\n"));
313 case LIBUSB_ERROR_IO
:
314 mybug_unit(-1, ("Input/output error\n"));
317 case LIBUSB_ERROR_INVALID_PARAM
:
318 mybug_unit(-1, ("Invalid parameter\n"));
321 case LIBUSB_ERROR_ACCESS
:
322 mybug_unit(-1, ("Access denied (insufficient permissions)\n"));
325 case LIBUSB_ERROR_NO_DEVICE
:
326 mybug_unit(-1, ("No such device (it may have been disconnected)\n"));
329 case LIBUSB_ERROR_NOT_FOUND
:
330 mybug_unit(-1, ("Entity not found\n"));
333 case LIBUSB_ERROR_BUSY
:
334 mybug_unit(-1, ("Resource busy\n"));
337 case LIBUSB_ERROR_TIMEOUT
:
338 mybug_unit(-1, ("Operation timed out\n"));
341 case LIBUSB_ERROR_OVERFLOW
:
342 mybug_unit(-1, ("Overflow\n"));
345 case LIBUSB_ERROR_PIPE
:
346 mybug_unit(-1, ("Pipe error */\n"));
349 case LIBUSB_ERROR_INTERRUPTED
:
350 mybug_unit(-1, ("System call interrupted (perhaps due to signal)\n"));
353 case LIBUSB_ERROR_NO_MEM
:
354 mybug_unit(-1, ("Insufficient memory\n"));
357 case LIBUSB_ERROR_NOT_SUPPORTED
:
358 mybug_unit(-1, ("Operation not supported or unimplemented on this platform\n"));
361 case LIBUSB_ERROR_OTHER
:
362 mybug_unit(-1, ("Other error\n"));
370 ioreq
->iouh_Actual
= transferred
;
374 mybug_unit(-1, ("Done!\n\n"));
375 return UHIOERR_NO_ERROR
;
378 int do_libusb_bulk_transfer(struct IOUsbHWReq
*ioreq
) {
379 struct VUSBHCIUnit
*unit
= (struct VUSBHCIUnit
*) ioreq
->iouh_Req
.io_Unit
;
381 int rc
= 0, transferred
= 0;
382 UBYTE endpoint
= ioreq
->iouh_Endpoint
;
384 mybug_unit(0, ("ioreq->iouh_Length %d\n", ioreq
->iouh_Length
));
385 mybug_unit(0, ("direction %d\n", (ioreq
->iouh_Dir
)));
387 switch(ioreq
->iouh_Dir
) {
389 mybug_unit(0, ("ioreq->iouh_Endpoint %d (IN)\n", endpoint
));
390 rc
= LIBUSBCALL(libusb_bulk_transfer
, dev_handle
, (endpoint
|LIBUSB_ENDPOINT_IN
), (UBYTE
*)ioreq
->iouh_Data
, ioreq
->iouh_Length
, &transferred
, ioreq
->iouh_NakTimeout
);
394 mybug_unit(0, ("ioreq->iouh_Endpoint %d (OUT)\n", endpoint
));
395 rc
= LIBUSBCALL(libusb_bulk_transfer
, dev_handle
, (endpoint
|LIBUSB_ENDPOINT_OUT
), (UBYTE
*)ioreq
->iouh_Data
, ioreq
->iouh_Length
, &transferred
, ioreq
->iouh_NakTimeout
);
399 mybug_unit(0, ("libusb_bulk_transfer rc = %d, transferred %d\n", rc
, transferred
));
402 0 on success (and populates transferred)
403 LIBUSB_ERROR_TIMEOUT if the transfer timed out (and populates transferred)
404 LIBUSB_ERROR_PIPE if the endpoint halted
405 LIBUSB_ERROR_OVERFLOW if the device offered more data, see Packets and overflows
406 LIBUSB_ERROR_NO_DEVICE if the device has been disconnected
407 another LIBUSB_ERROR code on other failures
413 ioreq
->iouh_Actual
= transferred
;
417 mybug_unit(0, ("Done!\n\n"));
418 return UHIOERR_NO_ERROR
;
421 int do_libusb_isoc_transfer(struct IOUsbHWReq
*ioreq
) {
422 struct VUSBHCIUnit
*unit
= (struct VUSBHCIUnit
*) ioreq
->iouh_Req
.io_Unit
;
424 //UWORD bmRequestType = (ioreq->iouh_SetupData.bmRequestType) & (URTF_STANDARD | URTF_CLASS | URTF_VENDOR);
425 //UWORD bmRequestDirection = (ioreq->iouh_SetupData.bmRequestType) & (URTF_IN | URTF_OUT);
426 //UWORD bmRequestRecipient = (ioreq->iouh_SetupData.bmRequestType) & (URTF_DEVICE | URTF_INTERFACE | URTF_ENDPOINT | URTF_OTHER);
428 //UWORD bRequest = (ioreq->iouh_SetupData.bRequest);
429 //UWORD wValue = AROS_WORD2LE(ioreq->iouh_SetupData.wValue);
430 //UWORD wIndex = AROS_WORD2LE(ioreq->iouh_SetupData.wIndex);
431 //UWORD wLength = AROS_WORD2LE(ioreq->iouh_SetupData.wLength);
433 mybug_unit(-1, ("Done!\n\n"));