2 Copyright © 2015, The AROS Development Team. All rights reserved.
5 Desc: Virtual USB host controller
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]={'/','-','\\','|'};
42 struct VUSBHCIUnit
*unit
= VUSBHCIBase
->usbunit200
;
44 struct timerequest
*tr
= NULL
;
45 struct MsgPort
*mp
= NULL
;
49 tr
= (struct timerequest
*)CreateIORequest(mp
, sizeof(struct timerequest
));
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
) {
62 //mybug(-1,("%c\b", animate[(i++)%4]));
65 call_libusb_event_handler();
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);
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
)) {
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
,
101 VUSBHCIBase
->usbunit200
= VUSBHCI_AddNewUnit200();
103 if(VUSBHCIBase
->usbunit200
== NULL
) {
104 mybug(-1, ("[VUSBHCI] Init: Failed to create new USB unit!\n"));
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
;
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"));
139 unit
->allocated
= TRUE
;
140 ioreq
->iouh_Req
.io_Unit
= (struct Unit
*) unit
;
142 if(ioreq
->iouh_Req
.io_Unit
!= NULL
) {
144 ioreq
->iouh_Req
.io_Message
.mn_Node
.ln_Type
= NT_REPLYMSG
;
145 ioreq
->iouh_Req
.io_Error
= 0;
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
));
164 unit
->allocated
= FALSE
;
166 ioreq
->iouh_Req
.io_Unit
= (APTR
) -1;
167 ioreq
->iouh_Req
.io_Device
= (APTR
) -1;
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"));
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
) {
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"));
198 switch (ioreq
->iouh_Req
.io_Command
) {
200 mybug_unit(-1, ("CMD_RESET\n"));
203 mybug_unit(-1, ("CMD_FLUSH\n"));
205 case UHCMD_QUERYDEVICE
:
206 mybug_unit(0, ("UHCMD_QUERYDEVICE\n"));
207 ret
= cmdQueryDevice(ioreq
);
210 mybug_unit(0, ("UHCMD_USBRESET\n"));
211 ret
= cmdUsbReset(ioreq
);
213 case UHCMD_USBRESUME
:
214 mybug_unit(-1, ("UHCMD_USBRESUME\n"));
216 case UHCMD_USBSUSPEND
:
217 mybug_unit(-1, ("UHCMD_USBSUSPEND\n"));
220 mybug_unit(-1, ("UHCMD_USBOPER\n"));
221 //ret = cmdUsbOper(ioreq);
223 case UHCMD_CONTROLXFER
:
224 ret
= cmdControlXFer(ioreq
);
227 ret
= cmdIntXFer(ioreq
);
230 ret
= cmdBulkXFer(ioreq
);
233 ret
= cmdISOXFer(ioreq
);
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
,
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
;
264 mybug_unit(-1, ("IOERR_NOCMD\n"));
269 /* We have aborted the request as unit is invalid */
273 if(ret
!= RC_DONTREPLY
) {
274 /* Set error codes */
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
);
289 AROS_LH1(LONG
, AbortIO
, AROS_LHA(struct IOUsbHWReq
*, ioreq
, A1
), struct VUSBHCIBase
*, VUSBHCIBase
, 6, VUSBHCI
) {
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
)) {
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
;
312 while((tag
= LibNextTagItem(&taglist
)) != NULL
) {
313 switch (tag
->ti_Tag
) {
314 case UHA_Manufacturer
:
315 *((STRPTR
*) tag
->ti_Data
) = "The AROS Development Team";
319 *((ULONG
*) tag
->ti_Data
) = VERSION_NUMBER
;
323 *((ULONG
*) tag
->ti_Data
) = REVISION_NUMBER
;
327 *((STRPTR
*) tag
->ti_Data
) ="©2015 The AROS Development Team";
330 case UHA_ProductName
:
331 *((STRPTR
*) tag
->ti_Data
) ="VUSBHCI Host Controller";
334 case UHA_Description
:
335 *((STRPTR
*) tag
->ti_Data
) ="Hosted Host Controller Interface (libusb)";
338 case UHA_Capabilities
:
339 *((ULONG
*) tag
->ti_Data
) = (UHCF_USB20
|UHCF_ISO
);
347 mybug_unit(0, ("Done\n\n"));
349 ioreq
->iouh_Actual
= count
;
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
);
362 mybug(-1, ("[VUSBHCI] VUSBHCI_AddNewUnit: Failed to create new unit structure\n"));
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;