- Oh... I might have mixed up data size needed for synchronous and asynchronous...
[AROS.git] / rom / usb / vusbhc / vusbhci_bridge.c
blob2d2309a885f4cd558115ee322d753d7f6090a8ba
1 /*
2 Copyright © 2015, 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) {
65 LIBUSBCALL(libusb_set_auto_detach_kernel_driver, dev_handle, 1);
66 LIBUSBCALL(libusb_set_configuration, dev_handle, 1);
67 LIBUSBCALL(libusb_claim_interface, dev_handle, 0);
69 speed = LIBUSBCALL(libusb_get_device_speed, dev);
70 switch(speed) {
71 case LIBUSB_SPEED_LOW:
72 unit->roothub.portstatus.wPortStatus |= AROS_WORD2LE(UPSF_PORT_LOW_SPEED);
73 break;
74 case LIBUSB_SPEED_FULL:
75 unit->roothub.portstatus.wPortStatus &= ~(AROS_WORD2LE(UPSF_PORT_HIGH_SPEED)|AROS_WORD2LE(UPSF_PORT_LOW_SPEED));
76 break;
77 case LIBUSB_SPEED_HIGH:
78 unit->roothub.portstatus.wPortStatus |= AROS_WORD2LE(UPSF_PORT_HIGH_SPEED);
79 break;
80 //case LIBUSB_SPEED_SUPER:
81 //break;
84 unit->roothub.portstatus.wPortStatus |= AROS_WORD2LE(UPSF_PORT_CONNECTION);
85 unit->roothub.portstatus.wPortChange |= AROS_WORD2LE(UPSF_PORT_CONNECTION);
87 uhwCheckRootHubChanges(unit);
88 } else {
89 if(rc == LIBUSB_ERROR_ACCESS) {
90 mybug_unit(-1, ("libusb_open, access error, try running as superuser\n\n"));
95 break;
97 case LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT:
98 mybug_unit(-1, (" - Device detached\n"));
100 if(unit->allocated) {
102 unit->roothub.portstatus.wPortStatus &= ~UPSF_PORT_CONNECTION;
103 unit->roothub.portstatus.wPortChange |= UPSF_PORT_CONNECTION;
105 uhwCheckRootHubChanges(unit);
108 if(dev_handle != NULL) {
109 LIBUSBCALL(libusb_close, dev_handle);
110 dev_handle = NULL;
113 break;
115 default:
116 mybug_unit(-1, (" - Unknown event arrived\n"));
117 break;
121 return 0;
124 void *hostlib_load_so(const char *sofile, const char **names, int nfuncs, void **funcptr) {
125 void *handle;
126 char *err;
127 int i;
129 if ((handle = HostLib_Open(sofile, &err)) == NULL) {
130 (bug("[LIBUSB] failed to open '%s': %s\n", sofile, err));
131 return NULL;
132 }else{
133 bug("[LIBUSB] opened '%s'\n", sofile);
136 for (i = 0; i < nfuncs; i++) {
137 funcptr[i] = HostLib_GetPointer(handle, names[i], &err);
138 if (err != NULL) {
139 bug("[LIBUSB] failed to get symbol '%s' (%s)\n", names[i], err);
140 HostLib_Close(handle, NULL);
141 return NULL;
142 }else{
143 bug("[LIBUSB] managed to get symbol '%s'\n", names[i]);
147 return handle;
150 BOOL libusb_bridge_init(struct VUSBHCIBase *VUSBHCIBase) {
152 int rc;
154 HostLibBase = OpenResource("hostlib.resource");
156 if (!HostLibBase)
157 return FALSE;
159 libusbhandle = hostlib_load_so("libusb.so", libusb_func_names, LIBUSB_NUM_FUNCS, (void **)&libusb_func);
161 if (!libusbhandle)
162 return FALSE;
164 if(!LIBUSBCALL(libusb_init, NULL)) {
165 LIBUSBCALL(libusb_set_debug, NULL, 1);
166 bug("[LIBUSB] Checking hotplug support of libusb\n");
167 if (LIBUSBCALL(libusb_has_capability, LIBUSB_CAP_HAS_HOTPLUG)) {
168 bug("[LIBUSB] - Hotplug supported\n");
170 rc = (LIBUSBCALL(libusb_hotplug_register_callback,
171 NULL,
172 (LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED|LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT),
174 LIBUSB_HOTPLUG_MATCH_ANY,
175 LIBUSB_HOTPLUG_MATCH_ANY,
176 LIBUSB_HOTPLUG_MATCH_ANY,
177 hotplug_callback_event_handler,
178 (void *)VUSBHCIBase,
179 NULL)
182 if(rc == LIBUSB_SUCCESS) {
183 bug("[LIBUSB] - Hotplug callback installed rc = %d\n", rc);
184 return TRUE;
187 bug("[LIBUSB] - Hotplug callback installation failure! rc = %d\n", rc);
189 } else {
190 bug("[LIBUSB] - Hotplug not supported, failing...\n");
191 LIBUSBCALL(libusb_exit, NULL);
193 libusb_bridge_cleanup();
196 return FALSE;
199 VOID libusb_bridge_cleanup() {
200 HostLib_Close(libusbhandle, NULL);
203 void call_libusb_event_handler() {
204 LIBUSBCALL(libusb_handle_events, NULL);
208 FIXME: libusb expects buffer to precede with enough space for setup data (8 bytes or LIBUSB_CONTROL_SETUP_SIZE)
209 - Copy buffer need to be used
211 IGNORE or CHECKME: LIBUSB_xxx_SETUP_SIZE is needed for asynchronous use of libusb
214 int do_libusb_ctrl_transfer(struct IOUsbHWReq *ioreq) {
215 struct VUSBHCIUnit *unit = (struct VUSBHCIUnit *) ioreq->iouh_Req.io_Unit;
217 int rc;
219 UWORD bmRequestType = (ioreq->iouh_SetupData.bmRequestType);
220 UWORD bRequest = (ioreq->iouh_SetupData.bRequest);
221 UWORD wValue = (ioreq->iouh_SetupData.wValue);
222 UWORD wIndex = (ioreq->iouh_SetupData.wIndex);
223 UWORD wLength = (ioreq->iouh_SetupData.wLength);
225 switch(((ULONG)ioreq->iouh_SetupData.bmRequestType<<16)|((ULONG)ioreq->iouh_SetupData.bRequest)) {
226 case ((((URTF_OUT|URTF_STANDARD|URTF_DEVICE))<<16)|(USR_SET_ADDRESS)):
227 mybug_unit(0, ("Filtering out SET_ADDRESS\n\n"));
228 ioreq->iouh_Actual = ioreq->iouh_Length;
229 return UHIOERR_NO_ERROR;
230 break;
233 mybug_unit(0, ("wLength %d\n", wLength));
234 mybug_unit(0, ("ioreq->iouh_Length %d\n", ioreq->iouh_Length));
236 rc = LIBUSBCALL(libusb_control_transfer, dev_handle, bmRequestType, bRequest, wValue, wIndex, ioreq->iouh_Data, ioreq->iouh_Length, ioreq->iouh_NakTimeout);
238 if(rc<0) {
239 rc = 0;
242 ioreq->iouh_Actual = rc;
244 mybug_unit(0, ("Done!\n\n"));
245 return UHIOERR_NO_ERROR;
248 int do_libusb_intr_transfer(struct IOUsbHWReq *ioreq) {
249 struct VUSBHCIUnit *unit = (struct VUSBHCIUnit *) ioreq->iouh_Req.io_Unit;
251 int rc = 0, transferred = 0;
252 UBYTE endpoint = ioreq->iouh_Endpoint;
254 mybug_unit(0, ("ioreq->iouh_Length %d\n", ioreq->iouh_Length));
255 mybug_unit(0, ("direction %d\n", (ioreq->iouh_Dir)));
257 switch(ioreq->iouh_Dir) {
258 case UHDIR_IN:
259 mybug_unit(0, ("ioreq->iouh_Endpoint %d (IN)\n", endpoint));
260 rc = LIBUSBCALL(libusb_interrupt_transfer, dev_handle, (endpoint|LIBUSB_ENDPOINT_IN), (UBYTE *)ioreq->iouh_Data, ioreq->iouh_Length, &transferred, ioreq->iouh_NakTimeout);
261 break;
263 case UHDIR_OUT:
264 mybug_unit(0, ("ioreq->iouh_Endpoint %d (OUT)\n", endpoint));
265 rc = LIBUSBCALL(libusb_interrupt_transfer, dev_handle, (endpoint|LIBUSB_ENDPOINT_OUT), (UBYTE *)ioreq->iouh_Data, ioreq->iouh_Length, &transferred, ioreq->iouh_NakTimeout);
266 break;
269 mybug_unit(0, ("libusb_interrupt_transfer rc = %d, transferred %d\n", rc, transferred));
272 0 on success (and populates transferred)
273 LIBUSB_ERROR_TIMEOUT if the transfer timed out (and populates transferred)
274 LIBUSB_ERROR_PIPE if the endpoint halted
275 LIBUSB_ERROR_OVERFLOW if the device offered more data, see Packets and overflows
276 LIBUSB_ERROR_NO_DEVICE if the device has been disconnected
277 another LIBUSB_ERROR code on other failures
279 if(rc<0) {
280 rc = 0;
281 } else {
282 if(transferred) {
283 ioreq->iouh_Actual = transferred;
287 mybug_unit(0, ("Done!\n\n"));
288 return UHIOERR_NO_ERROR;
291 int do_libusb_bulk_transfer(struct IOUsbHWReq *ioreq) {
292 struct VUSBHCIUnit *unit = (struct VUSBHCIUnit *) ioreq->iouh_Req.io_Unit;
294 int rc = 0, transferred = 0;
295 UBYTE endpoint = ioreq->iouh_Endpoint;
297 mybug_unit(0, ("ioreq->iouh_Length %d\n", ioreq->iouh_Length));
298 mybug_unit(0, ("direction %d\n", (ioreq->iouh_Dir)));
300 switch(ioreq->iouh_Dir) {
301 case UHDIR_IN:
302 mybug_unit(0, ("ioreq->iouh_Endpoint %d (IN)\n", endpoint));
303 rc = LIBUSBCALL(libusb_bulk_transfer, dev_handle, (endpoint|LIBUSB_ENDPOINT_IN), (UBYTE *)ioreq->iouh_Data, ioreq->iouh_Length, &transferred, ioreq->iouh_NakTimeout);
304 break;
306 case UHDIR_OUT:
307 mybug_unit(0, ("ioreq->iouh_Endpoint %d (OUT)\n", endpoint));
308 rc = LIBUSBCALL(libusb_bulk_transfer, dev_handle, (endpoint|LIBUSB_ENDPOINT_OUT), (UBYTE *)ioreq->iouh_Data, ioreq->iouh_Length, &transferred, ioreq->iouh_NakTimeout);
309 break;
312 mybug_unit(0, ("libusb_bulk_transfer rc = %d, transferred %d\n", rc, transferred));
315 0 on success (and populates transferred)
316 LIBUSB_ERROR_TIMEOUT if the transfer timed out (and populates transferred)
317 LIBUSB_ERROR_PIPE if the endpoint halted
318 LIBUSB_ERROR_OVERFLOW if the device offered more data, see Packets and overflows
319 LIBUSB_ERROR_NO_DEVICE if the device has been disconnected
320 another LIBUSB_ERROR code on other failures
322 if(rc<0) {
323 rc = 0;
324 } else {
325 if(transferred) {
326 ioreq->iouh_Actual = transferred;
330 mybug_unit(0, ("Done!\n\n"));
331 return UHIOERR_NO_ERROR;
334 int do_libusb_isoc_transfer(struct IOUsbHWReq *ioreq) {
335 struct VUSBHCIUnit *unit = (struct VUSBHCIUnit *) ioreq->iouh_Req.io_Unit;
337 //UWORD bmRequestType = (ioreq->iouh_SetupData.bmRequestType) & (URTF_STANDARD | URTF_CLASS | URTF_VENDOR);
338 //UWORD bmRequestDirection = (ioreq->iouh_SetupData.bmRequestType) & (URTF_IN | URTF_OUT);
339 //UWORD bmRequestRecipient = (ioreq->iouh_SetupData.bmRequestType) & (URTF_DEVICE | URTF_INTERFACE | URTF_ENDPOINT | URTF_OTHER);
341 //UWORD bRequest = (ioreq->iouh_SetupData.bRequest);
342 //UWORD wValue = AROS_WORD2LE(ioreq->iouh_SetupData.wValue);
343 //UWORD wIndex = AROS_WORD2LE(ioreq->iouh_SetupData.wIndex);
344 //UWORD wLength = AROS_WORD2LE(ioreq->iouh_SetupData.wLength);
346 mybug_unit(-1, ("Done!\n\n"));
347 return 0;