- Oh... I might have mixed up data size needed for synchronous and asynchronous...
[AROS.git] / rom / usb / vusbhc / vusbhci_device.c
blob5c680fafed706ceaec6b17c2799baa54c33269c3
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>
15 #include <aros/macros.h>
16 #include <aros/asmcall.h>
17 #include <aros/symbolsets.h>
19 #include <proto/exec.h>
20 #include <proto/arossupport.h>
22 #include <devices/usb.h>
23 #include <devices/usb_hub.h>
24 #include <devices/newstyle.h>
25 #include <devices/usbhardware.h>
26 #include <devices/timer.h>
28 #include "vusbhci_device.h"
30 #include LC_LIBDEFS_FILE
32 struct VUSBHCIUnit *VUSBHCI_AddNewUnit200(void);
34 static void handler_task(struct Task *parent, struct VUSBHCIBase *VUSBHCIBase) {
35 Signal(parent, SIGF_CHILD);
37 mybug(-1,("[handler_task] Starting\n"));
39 const char animate[4]={'/','-','\\','|'};
40 static ULONG i;
42 struct VUSBHCIUnit *unit = VUSBHCIBase->usbunit200;
44 struct timerequest *tr = NULL;
45 struct MsgPort *mp = NULL;
47 mp = CreateMsgPort();
48 if (mp) {
49 tr = (struct timerequest *)CreateIORequest(mp, sizeof(struct timerequest));
50 if (tr) {
51 FreeSignal(mp->mp_SigBit);
52 if (!OpenDevice((STRPTR)"timer.device", UNIT_MICROHZ, (struct IORequest *)tr, 0)) {
53 /* Allocate a signal within this task context */
54 tr->tr_node.io_Message.mn_ReplyPort->mp_SigBit = SIGB_SINGLE;
55 tr->tr_node.io_Message.mn_ReplyPort->mp_SigTask = FindTask(NULL);
56 /* Specify the request */
57 tr->tr_node.io_Command = TR_ADDREQUEST;
59 /* FIXME: Use signals */
60 while(VUSBHCIBase->handler_task_run) {
61 if(unit->allocated) {
62 //mybug(-1,("%c\b", animate[(i++)%4]));
65 call_libusb_event_handler();
67 /* Wait */
68 tr->tr_time.tv_secs = 1;
69 tr->tr_time.tv_micro = 0;
70 DoIO((struct IORequest *)tr);
72 CloseDevice((struct IORequest *)tr);
74 DeleteIORequest((struct IORequest *)tr);
75 mp->mp_SigBit = AllocSignal(-1);
77 DeleteMsgPort(mp);
80 mybug(-1,("[handler_task] Exiting\n"));
82 Signal(parent, SIGF_CHILD);
85 static int GM_UNIQUENAME(Init)(LIBBASETYPEPTR VUSBHCIBase) {
86 mybug(-1,("[VUSBHCI] Init: Entering function\n"));
88 if(!libusb_bridge_init(VUSBHCIBase)) {
89 return FALSE;
92 /* Create periodic handler task */
93 VUSBHCIBase->handler_task_run = TRUE;
94 VUSBHCIBase->handler_task = NewCreateTask(TASKTAG_NAME, "libusb handler task",
95 TASKTAG_PC, handler_task,
96 TASKTAG_ARG1, FindTask(NULL),
97 TASKTAG_ARG2, VUSBHCIBase,
98 TAG_END);
99 Wait(SIGF_CHILD);
101 VUSBHCIBase->usbunit200 = VUSBHCI_AddNewUnit200();
103 if(VUSBHCIBase->usbunit200 == NULL) {
104 mybug(-1, ("[VUSBHCI] Init: Failed to create new USB unit!\n"));
105 return FALSE;
108 return TRUE;
111 static int GM_UNIQUENAME(Open)(LIBBASETYPEPTR VUSBHCIBase, struct IOUsbHWReq *ioreq, ULONG unitnum, ULONG flags) {
112 mybug(-1, ("[VUSBHCI] Open: Entering function\n"));
113 mybug(-1, ("[VUSBHCI] Open: Unit %d\n", unitnum));
115 struct VUSBHCIUnit *unit;
117 /* Default to open failure. */
118 ioreq->iouh_Req.io_Error = IOERR_OPENFAIL;
119 ioreq->iouh_Req.io_Unit = NULL;
121 if(unitnum == 0) {
123 unit = VUSBHCIBase->usbunit200;
125 if(ioreq->iouh_Req.io_Message.mn_Length < sizeof(struct IOUsbHWReq)) {
126 mybug(-1, ("[VUSBHCI] Open: Invalid MN_LENGTH!\n"));
127 ioreq->iouh_Req.io_Error = IOERR_BADLENGTH;
130 ioreq->iouh_Req.io_Unit = NULL;
132 if(unit->allocated) {
133 ioreq->iouh_Req.io_Error = IOERR_UNITBUSY;
134 ioreq->iouh_Req.io_Unit = NULL;
135 mybug(-1, ("Unit 0 already in use!\n\n"));
136 return FALSE;
139 unit->allocated = TRUE;
140 ioreq->iouh_Req.io_Unit = (struct Unit *) unit;
142 if(ioreq->iouh_Req.io_Unit != NULL) {
143 /* Opened ok! */
144 ioreq->iouh_Req.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
145 ioreq->iouh_Req.io_Error = 0;
147 return TRUE;
148 } else {
149 return FALSE;
153 return FALSE;
156 static int GM_UNIQUENAME(Close)(LIBBASETYPEPTR VUSBHCIBase, struct IOUsbHWReq *ioreq) {
157 mybug(-1, ("[VUSBHCI] Close: Entering function\n"));
159 struct VUSBHCIUnit *unit = (struct VUSBHCIUnit *)ioreq->iouh_Req.io_Unit;
161 mybug_unit(-1, ("Closing unit %p\n", unit));
163 if(unit) {
164 unit->allocated = FALSE;
166 ioreq->iouh_Req.io_Unit = (APTR) -1;
167 ioreq->iouh_Req.io_Device = (APTR) -1;
169 return TRUE;
172 ioreq->iouh_Req.io_Error = IOERR_BADADDRESS;
173 ioreq->iouh_Req.io_Unit = (APTR) -1;
174 ioreq->iouh_Req.io_Device = (APTR) -1;
176 mybug(-1, (" Bad unit structure in ioreq, nothing done!\n\n"));
177 return FALSE;
180 ADD2INITLIB(GM_UNIQUENAME(Init), 0)
181 ADD2OPENDEV(GM_UNIQUENAME(Open), 0)
182 ADD2CLOSEDEV(GM_UNIQUENAME(Close), 0)
184 AROS_LH1(void, BeginIO, AROS_LHA(struct IOUsbHWReq *, ioreq, A1), struct VUSBHCIBase *, VUSBHCIBase, 5, VUSBHCI) {
185 AROS_LIBFUNC_INIT
187 WORD ret = RC_OK;
189 ioreq->iouh_Req.io_Message.mn_Node.ln_Type = NT_MESSAGE;
190 ioreq->iouh_Req.io_Error = UHIOERR_NO_ERROR;
192 struct VUSBHCIUnit *unit = (struct VUSBHCIUnit *) ioreq->iouh_Req.io_Unit;
194 mybug_unit(0, ("Entering function\n"));
196 if(unit != NULL) {
198 switch (ioreq->iouh_Req.io_Command) {
199 case CMD_RESET:
200 mybug_unit(-1, ("CMD_RESET\n"));
201 break;
202 case CMD_FLUSH:
203 mybug_unit(-1, ("CMD_FLUSH\n"));
204 break;
205 case UHCMD_QUERYDEVICE:
206 mybug_unit(0, ("UHCMD_QUERYDEVICE\n"));
207 ret = cmdQueryDevice(ioreq);
208 break;
209 case UHCMD_USBRESET:
210 mybug_unit(0, ("UHCMD_USBRESET\n"));
211 ret = cmdUsbReset(ioreq);
212 break;
213 case UHCMD_USBRESUME:
214 mybug_unit(-1, ("UHCMD_USBRESUME\n"));
215 break;
216 case UHCMD_USBSUSPEND:
217 mybug_unit(-1, ("UHCMD_USBSUSPEND\n"));
218 break;
219 case UHCMD_USBOPER:
220 mybug_unit(-1, ("UHCMD_USBOPER\n"));
221 //ret = cmdUsbOper(ioreq);
222 break;
223 case UHCMD_CONTROLXFER:
224 ret = cmdControlXFer(ioreq);
225 break;
226 case UHCMD_INTXFER:
227 ret = cmdIntXFer(ioreq);
228 break;
229 case UHCMD_BULKXFER:
230 ret = cmdBulkXFer(ioreq);
231 break;
232 case UHCMD_ISOXFER:
233 ret = cmdISOXFer(ioreq);
234 break;
236 /* Poseidon doesn't actually check this, ever... */
237 case NSCMD_DEVICEQUERY:
238 mybug_unit(-1, ("NSCMD_DEVICEQUERY\n"));
240 static const UWORD NSDSupported[] = {
241 CMD_FLUSH, CMD_RESET,
242 UHCMD_QUERYDEVICE,
243 UHCMD_USBRESET,
244 UHCMD_USBRESUME,
245 UHCMD_USBSUSPEND,
246 UHCMD_USBOPER,
247 UHCMD_CONTROLXFER ,
248 UHCMD_ISOXFER,
249 UHCMD_INTXFER,
250 UHCMD_BULKXFER,
251 NSCMD_DEVICEQUERY,
255 struct NSDeviceQueryResult *nsdq = (struct NSDeviceQueryResult *)((struct IOStdReq *)(ioreq))->io_Data;
256 nsdq->DevQueryFormat = 0;
257 nsdq->SizeAvailable = sizeof(struct NSDeviceQueryResult);
258 nsdq->DeviceType = NSDEVTYPE_USBHARDWARE;
259 nsdq->DeviceSubType = 0;
260 nsdq->SupportedCommands = (UWORD *)NSDSupported;
261 ret = RC_OK;
262 break;
263 default:
264 mybug_unit(-1, ("IOERR_NOCMD\n"));
265 ret = IOERR_NOCMD;
266 break;
268 } else {
269 /* We have aborted the request as unit is invalid */
270 ret = IOERR_ABORTED;
273 if(ret != RC_DONTREPLY) {
274 /* Set error codes */
275 if (ret != RC_OK) {
276 ioreq->iouh_Req.io_Error = ret & 0xff;
278 /* Terminate the iorequest */
279 ioreq->iouh_Req.io_Message.mn_Node.ln_Type = NT_FREEMSG;
280 /* If not quick I/O, reply the message */
281 if(!(ioreq->iouh_Req.io_Flags & IOF_QUICK)) {
282 ReplyMsg(&ioreq->iouh_Req.io_Message);
286 AROS_LIBFUNC_EXIT
289 AROS_LH1(LONG, AbortIO, AROS_LHA(struct IOUsbHWReq *, ioreq, A1), struct VUSBHCIBase *, VUSBHCIBase, 6, VUSBHCI) {
290 AROS_LIBFUNC_INIT
291 mybug(-1, ("[VUSBHCI] AbortIO: Entering function\n"));
293 if(ioreq->iouh_Req.io_Message.mn_Node.ln_Type == NT_MESSAGE) {
294 if(cmdAbortIO(ioreq)) {
295 return(0);
299 return(-1);
300 AROS_LIBFUNC_EXIT
303 WORD cmdQueryDevice(struct IOUsbHWReq *ioreq) {
304 struct VUSBHCIUnit *unit = (struct VUSBHCIUnit *) ioreq->iouh_Req.io_Unit;
306 mybug_unit(0, ("Entering function\n"));
308 struct TagItem *taglist = (struct TagItem *) ioreq->iouh_Data;
309 struct TagItem *tag;
310 ULONG count = 0;
312 while((tag = LibNextTagItem(&taglist)) != NULL) {
313 switch (tag->ti_Tag) {
314 case UHA_Manufacturer:
315 *((STRPTR *) tag->ti_Data) = "The AROS Development Team";
316 count++;
317 break;
318 case UHA_Version:
319 *((ULONG *) tag->ti_Data) = VERSION_NUMBER;
320 count++;
321 break;
322 case UHA_Revision:
323 *((ULONG *) tag->ti_Data) = REVISION_NUMBER;
324 count++;
325 break;
326 case UHA_Copyright:
327 *((STRPTR *) tag->ti_Data) ="©2015 The AROS Development Team";
328 count++;
329 break;
330 case UHA_ProductName:
331 *((STRPTR *) tag->ti_Data) ="VUSBHCI Host Controller";
332 count++;
333 break;
334 case UHA_Description:
335 *((STRPTR *) tag->ti_Data) ="Hosted Host Controller Interface (libusb)";
336 count++;
337 break;
338 case UHA_Capabilities:
339 *((ULONG *) tag->ti_Data) = (UHCF_USB20|UHCF_ISO);
340 count++;
341 break;
342 default:
343 break;
347 mybug_unit(0, ("Done\n\n"));
349 ioreq->iouh_Actual = count;
350 return RC_OK;
353 struct VUSBHCIUnit *VUSBHCI_AddNewUnit200(void) {
355 struct VUSBHCIUnit *unit;
357 static const char name[] = {"[VUSBHCI2.00]"};
359 unit = AllocVec(sizeof(struct VUSBHCIUnit), MEMF_ANY|MEMF_CLEAR);
361 if(unit == NULL) {
362 mybug(-1, ("[VUSBHCI] VUSBHCI_AddNewUnit: Failed to create new unit structure\n"));
363 return NULL;
364 } else {
365 unit->state = UHSF_SUSPENDED;
366 unit->allocated = FALSE;
368 NEWLIST(&unit->ctrlxfer_queue);
369 NEWLIST(&unit->intrxfer_queue);
370 NEWLIST(&unit->bulkxfer_queue);
371 NEWLIST(&unit->isocxfer_queue);
373 NEWLIST(&unit->roothub.intrxfer_queue);
375 /* This is our root hub device descriptor */
376 unit->roothub.devdesc.bLength = sizeof(struct UsbStdDevDesc);
377 unit->roothub.devdesc.bDescriptorType = UDT_DEVICE;
378 unit->roothub.devdesc.bcdUSB = AROS_WORD2LE(0x0200);
379 unit->roothub.devdesc.bDeviceClass = HUB_CLASSCODE;
380 unit->roothub.devdesc.bDeviceSubClass = 0;
381 unit->roothub.devdesc.bDeviceProtocol = 0;
382 unit->roothub.devdesc.bMaxPacketSize0 = 8; // Valid values are 8, 9(SuperSpeed), 16, 32, 64
383 unit->roothub.devdesc.idVendor = AROS_WORD2LE(0x0000);
384 unit->roothub.devdesc.idProduct = AROS_WORD2LE(0x0000);
385 unit->roothub.devdesc.bcdDevice = AROS_WORD2LE(0x0200);
386 unit->roothub.devdesc.iManufacturer = 1;
387 unit->roothub.devdesc.iProduct = 2;
388 unit->roothub.devdesc.iSerialNumber = 0;
389 unit->roothub.devdesc.bNumConfigurations = 1;
391 /* This is our root hub config descriptor */
392 unit->roothub.config.cfgdesc.bLength = sizeof(struct UsbStdCfgDesc);
393 unit->roothub.config.cfgdesc.bLength = sizeof(struct UsbStdCfgDesc);
394 unit->roothub.config.cfgdesc.bDescriptorType = UDT_CONFIGURATION;
395 unit->roothub.config.cfgdesc.wTotalLength = AROS_WORD2LE(sizeof(struct RHConfig));
396 unit->roothub.config.cfgdesc.bNumInterfaces = 1;
397 unit->roothub.config.cfgdesc.bConfigurationValue = 1;
398 unit->roothub.config.cfgdesc.iConfiguration = 0; //3;
399 unit->roothub.config.cfgdesc.bmAttributes = (USCAF_ONE|USCAF_SELF_POWERED|USCAF_REMOTE_WAKEUP);
400 unit->roothub.config.cfgdesc.bMaxPower = 0;
402 unit->roothub.config.ifdesc.bLength = sizeof(struct UsbStdIfDesc);
403 unit->roothub.config.ifdesc.bDescriptorType = UDT_INTERFACE;
404 unit->roothub.config.ifdesc.bInterfaceNumber = 0;
405 unit->roothub.config.ifdesc.bAlternateSetting = 0;
406 unit->roothub.config.ifdesc.bNumEndpoints = 1;
407 unit->roothub.config.ifdesc.bInterfaceClass = HUB_CLASSCODE;
408 unit->roothub.config.ifdesc.bInterfaceSubClass = 0;
409 unit->roothub.config.ifdesc.bInterfaceProtocol = 0;
410 unit->roothub.config.ifdesc.iInterface = 0; //4;
412 unit->roothub.config.epdesc.bLength = sizeof(struct UsbStdEPDesc);
413 unit->roothub.config.epdesc.bDescriptorType = UDT_ENDPOINT;
414 unit->roothub.config.epdesc.bEndpointAddress = (URTF_IN|1);
415 unit->roothub.config.epdesc.bmAttributes = USEAF_INTERRUPT;
416 unit->roothub.config.epdesc.wMaxPacketSize = AROS_WORD2LE(8);
417 unit->roothub.config.epdesc.bInterval = 12;
419 /* This is our root hub hub descriptor */
420 unit->roothub.hubdesc.bLength = sizeof(struct UsbHubDesc);
421 unit->roothub.hubdesc.bDescriptorType = UDT_HUB;
422 unit->roothub.hubdesc.bNbrPorts = 1;
423 unit->roothub.hubdesc.wHubCharacteristics = AROS_WORD2LE(UHCF_INDIVID_POWER|UHCF_INDIVID_OVP);
424 unit->roothub.hubdesc.bPwrOn2PwrGood = 1;
425 unit->roothub.hubdesc.bHubContrCurrent = 1;
426 unit->roothub.hubdesc.DeviceRemovable = 0;
427 unit->roothub.hubdesc.PortPwrCtrlMask = (1<<1);
429 //unit->roothub.portstatus.wPortStatus = 0;
430 //unit->roothub.portstatus.wPortChange = 0;
432 //unit->roothub.hubstatus->wHubStatus = 0;
433 //unit->roothub.hubstatus->wHubChange = 0;
435 unit->name = name;
437 return unit;