Documented GVF_SAVE_VAR alongside other flags, and removed a query/doubt
[AROS.git] / rom / usb / vusbhc / vusbhci_bridge.c
blobbd64b9376a49a6671ba7977adce10c8760c6fe61
1 /*
2 Copyright © 2015-2016, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Virtual USB host controller
6 Lang: English
7 */
9 #ifdef DEBUG
10 #undef DEBUG
11 #endif
12 #define DEBUG 1
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"
25 APTR HostLibBase;
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;
46 int rc, speed;
48 mybug_unit(-1, ("Hotplug callback event!\n"));
50 switch(event) {
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"));
59 return 0;
60 } else {
61 mybug_unit(-1, ("Device attach: %04x:%04x\n", desc.idVendor, desc.idProduct));
63 rc = LIBUSBCALL(libusb_open, dev, &dev_handle);
64 if(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"));
72 } else {
73 mybug_unit(-1, ("Kernel driver NOT detached\n"));
75 } else {
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"));
84 } else {
85 mybug_unit(-1, ("Kernel driver NOT detached\n"));
87 } else {
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);
95 switch(speed) {
96 case LIBUSB_SPEED_LOW:
97 unit->roothub.portstatus.wPortStatus |= AROS_WORD2LE(UPSF_PORT_LOW_SPEED);
98 break;
99 case LIBUSB_SPEED_FULL:
100 unit->roothub.portstatus.wPortStatus &= ~(AROS_WORD2LE(UPSF_PORT_HIGH_SPEED)|AROS_WORD2LE(UPSF_PORT_LOW_SPEED));
101 break;
102 case LIBUSB_SPEED_HIGH:
103 unit->roothub.portstatus.wPortStatus |= AROS_WORD2LE(UPSF_PORT_HIGH_SPEED);
104 break;
105 //case LIBUSB_SPEED_SUPER:
106 //break;
109 unit->roothub.portstatus.wPortStatus |= AROS_WORD2LE(UPSF_PORT_CONNECTION);
110 unit->roothub.portstatus.wPortChange |= AROS_WORD2LE(UPSF_PORT_CONNECTION);
112 uhwCheckRootHubChanges(unit);
113 } else {
114 if(rc == LIBUSB_ERROR_ACCESS) {
115 mybug_unit(-1, ("libusb_open, access error, try running as superuser\n\n"));
120 break;
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);
135 dev_handle = NULL;
138 break;
140 default:
141 mybug_unit(-1, (" - Unknown event arrived\n"));
142 break;
146 return 0;
149 void *hostlib_load_so(const char *sofile, const char **names, int nfuncs, void **funcptr) {
150 void *handle;
151 char *err;
152 int i;
154 if ((handle = HostLib_Open(sofile, &err)) == NULL) {
155 (bug("[LIBUSB] failed to open '%s': %s\n", sofile, err));
156 return NULL;
157 }else{
158 bug("[LIBUSB] opened '%s'\n", sofile);
161 for (i = 0; i < nfuncs; i++) {
162 funcptr[i] = HostLib_GetPointer(handle, names[i], &err);
163 if (err != NULL) {
164 bug("[LIBUSB] failed to get symbol '%s' (%s)\n", names[i], err);
165 HostLib_Close(handle, NULL);
166 return NULL;
167 }else{
168 bug("[LIBUSB] managed to get symbol '%s'\n", names[i]);
172 return handle;
175 BOOL libusb_bridge_init(struct VUSBHCIBase *VUSBHCIBase) {
177 int rc;
179 HostLibBase = OpenResource("hostlib.resource");
181 if (!HostLibBase)
182 return FALSE;
184 libusbhandle = hostlib_load_so("libusb.so", libusb_func_names, LIBUSB_NUM_FUNCS, (void **)&libusb_func);
186 if (!libusbhandle)
187 return FALSE;
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,
196 NULL,
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,
203 (void *)VUSBHCIBase,
204 NULL)
207 if(rc == LIBUSB_SUCCESS) {
208 bug("[LIBUSB] - Hotplug callback installed rc = %d\n", rc);
209 return TRUE;
212 bug("[LIBUSB] - Hotplug callback installation failure! rc = %d\n", rc);
214 } else {
215 bug("[LIBUSB] - Hotplug not supported, failing...\n");
216 LIBUSBCALL(libusb_exit, NULL);
218 libusb_bridge_cleanup();
221 return FALSE;
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;
242 int rc;
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;
258 break;
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;
266 break;
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);
275 if(rc<0) {
276 rc = 0;
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) {
295 case UHDIR_IN:
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);
298 break;
300 case UHDIR_OUT:
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);
303 break;
306 mybug_unit(-1, ("libusb_interrupt_transfer rc = %d, transferred %d\n", rc, transferred));
308 switch(rc) {
309 case LIBUSB_SUCCESS:
310 mybug_unit(-1, ("Success (no error)\n"));
311 break;
313 case LIBUSB_ERROR_IO:
314 mybug_unit(-1, ("Input/output error\n"));
315 break;
317 case LIBUSB_ERROR_INVALID_PARAM:
318 mybug_unit(-1, ("Invalid parameter\n"));
319 break;
321 case LIBUSB_ERROR_ACCESS:
322 mybug_unit(-1, ("Access denied (insufficient permissions)\n"));
323 break;
325 case LIBUSB_ERROR_NO_DEVICE:
326 mybug_unit(-1, ("No such device (it may have been disconnected)\n"));
327 break;
329 case LIBUSB_ERROR_NOT_FOUND:
330 mybug_unit(-1, ("Entity not found\n"));
331 break;
333 case LIBUSB_ERROR_BUSY:
334 mybug_unit(-1, ("Resource busy\n"));
335 break;
337 case LIBUSB_ERROR_TIMEOUT:
338 mybug_unit(-1, ("Operation timed out\n"));
339 break;
341 case LIBUSB_ERROR_OVERFLOW:
342 mybug_unit(-1, ("Overflow\n"));
343 break;
345 case LIBUSB_ERROR_PIPE:
346 mybug_unit(-1, ("Pipe error */\n"));
347 break;
349 case LIBUSB_ERROR_INTERRUPTED:
350 mybug_unit(-1, ("System call interrupted (perhaps due to signal)\n"));
351 break;
353 case LIBUSB_ERROR_NO_MEM:
354 mybug_unit(-1, ("Insufficient memory\n"));
355 break;
357 case LIBUSB_ERROR_NOT_SUPPORTED:
358 mybug_unit(-1, ("Operation not supported or unimplemented on this platform\n"));
359 break;
361 case LIBUSB_ERROR_OTHER:
362 mybug_unit(-1, ("Other error\n"));
363 break;
366 if(rc<0) {
367 rc = 0;
368 } else {
369 if(transferred) {
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) {
388 case UHDIR_IN:
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);
391 break;
393 case UHDIR_OUT:
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);
396 break;
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
409 if(rc<0) {
410 rc = 0;
411 } else {
412 if(transferred) {
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"));
434 return 0;