2 Copyright (C) 2006 by Michal Schulz
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU Library General Public
16 License along with this program; if not, write to the
17 Free Software Foundation, Inc.,
18 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 #include <aros/symbolsets.h>
27 #include <aros/debug.h>
29 #include <exec/types.h>
30 #include <exec/lists.h>
31 #include <exec/interrupts.h>
32 #include <exec/errors.h>
35 #include <hidd/hidd.h>
42 #include <proto/oop.h>
43 #include <proto/utility.h>
52 OOP_AttrBase HiddUHCIAttrBase
;
54 static AROS_INTH1(HubInterrupt
, UHCIData
*, uhci
)
58 /* Signal the HUB process about incoming interrupt */
60 struct Interrupt
*intr
;
62 /* Remove itself from msg list */
65 if (uhci
->timereq
->tr_node
.io_Error
== IOERR_ABORTED
)
67 D(bug("[UHCI] INTR Aborted\n"));
71 if (inw(uhci
->iobase
+ UHCI_PORTSC1
) & (UHCI_PORTSC_CSC
|UHCI_PORTSC_OCIC
))
73 if (inw(uhci
->iobase
+ UHCI_PORTSC2
) & (UHCI_PORTSC_CSC
|UHCI_PORTSC_OCIC
))
76 D(bug("[UHCI.%04x] Status on port: 1=%04x, 2=%04x\n", uhci
->iobase
, inw(uhci
->iobase
+ UHCI_PORTSC1
), inw(uhci
->iobase
+ UHCI_PORTSC2
)));
79 (bug("[UHCI] Status change on port 1\n"));
81 (bug("[UHCI] Status change on port 2\n"));
83 if (sts
&& uhci
->running
)
85 D(bug("Causing interrupts from list %p\n", &uhci
->intList
));
86 ForeachNode(&uhci
->intList
, intr
)
92 uhci
->timereq
->tr_node
.io_Command
= TR_ADDREQUEST
;
93 uhci
->timereq
->tr_time
.tv_secs
= 0;
94 uhci
->timereq
->tr_time
.tv_micro
= 255000;
95 SendIO((struct IORequest
*)uhci
->timereq
);
102 static AROS_INTH1(uhci_Handler
, UHCIData
*, uhci
)
108 uint16_t status
= inw(uhci
->iobase
+ UHCI_STS
);
109 uint16_t frame
= inw(uhci
->iobase
+ UHCI_FRNUM
);
110 uint16_t port1
= inw(uhci
->iobase
+ UHCI_PORTSC1
);
111 uint16_t port2
= inw(uhci
->iobase
+ UHCI_PORTSC2
);
112 uint16_t cmd
= inw(uhci
->iobase
+ UHCI_CMD
);
113 uint16_t sof
= inb(uhci
->iobase
+ UHCI_SOF
);
115 (void)frame
; //unused;
116 (void)port1
; // unused
117 (void)port2
; // unused
118 (void)sof
; // unused;
119 (void)cmd
; // unused;
121 /* Check if there's really an interrupt for us */
122 if((status
& UHCI_STS_USBINT
) == 0)
124 outw(status
, uhci
->iobase
+ UHCI_STS
);
128 D(bug("[UHCI] INTR Cmd=%04x, SOF=%04x, Status = %04x, Frame=%04x, PortSC1=%04x, PortSC2=%04x\n",
129 cmd
, sof
, status
, frame
, port1
, port2
));
131 if (!IsListEmpty(&uhci
->Interrupts
))
134 ForeachNode(&uhci
->Interrupts
, p
)
136 /* If the Linkptr of queue does not point to the first transfer descriptor, an interrupt
137 * has occured. Unfortunately, only the first one, who has added the interrupt to this
138 * pipe may receive data */
139 if ((p
->p_Queue
->qh_VLink
& 0xfffffff1) != (uint32_t)p
->p_FirstTD
)
141 struct UHCI_Interrupt
*intr
;
143 if (!(p
->p_FirstTD
->td_Status
& UHCI_TD_NAK
))
145 D(bug("[UHCI] Interrupt!!! pipe %p, vlink=%p, FirstTD=%p\n", p
, p
->p_Queue
->qh_VLink
, p
->p_FirstTD
));
146 ForeachNode(&p
->p_Intr
, intr
)
148 D(bug("[UHCI] Issuing interrupt %p\n", intr
));
153 /* Reactivate the transfer descriptor */
154 p
->p_FirstTD
->td_Status
= UHCI_TD_ZERO_ACTLEN(UHCI_TD_SET_ERRCNT(3)
158 p
->p_FirstTD
->td_Token
^= 1 << 19;
161 p
->p_FirstTD
->td_Status
|= UHCI_TD_SPD
;
163 p
->p_FirstTD
->td_Status
|= UHCI_TD_LS
| UHCI_TD_SPD
;
165 /* Link the first TD to the Queue header */
166 p
->p_Queue
->qh_VLink
= (uint32_t)p
->p_FirstTD
| UHCI_PTR_TD
;
172 if (!IsListEmpty(&uhci
->ControlLS
))
175 ForeachNode(&uhci
->ControlLS
, p
)
177 UHCI_TransferDesc
*td
= (UHCI_TransferDesc
*)p
->p_FirstTD
;
178 BOOL changed
= FALSE
;
180 if (p
->p_Queue
->qh_VLink
== UHCI_PTR_T
)
181 p
->p_LastTD
= (APTR
)UHCI_PTR_T
;
184 UHCI_TransferDesc
*t
= (UHCI_TransferDesc
*)(p
->p_Queue
->qh_VLink
& 0xfffffff1);
185 bug("[UHCI] Control Low: p->p_Queue->qh_VLink=%p\n", p
->p_Queue
->qh_VLink
);
186 while ((uint32_t)t
!= UHCI_PTR_T
)
188 bug("[UHCI] TD=%p (%08x %08x %08x %08x)\n", t
,
189 t
->td_LinkPtr
, t
->td_Status
, t
->td_Token
, t
->td_Buffer
);
190 t
= (UHCI_TransferDesc
*)(t
->td_LinkPtr
& 0xfffffff1);
194 while ((uint32_t)td
!= (p
->p_Queue
->qh_VLink
& 0xfffffff1))
196 D(bug("[UHCI] TD=%p\n", td
));
197 UHCI_TransferDesc
*tnext
= (UHCI_TransferDesc
*)(td
->td_LinkPtr
& 0xfffffff1);
198 uhci_FreeTDQuick(uhci
, td
);
200 p
->p_FirstTD
= tnext
;
204 if (changed
&& p
->p_Queue
->qh_VLink
== UHCI_PTR_T
) {
205 D(bug("[UHCI] INTR Control pipe %p empty (slow)\n", p
));
209 Signal(p
->p_SigTask
, 1 << p
->p_Signal
);
215 if (!IsListEmpty(&uhci
->ControlFS
))
218 ForeachNode(&uhci
->ControlFS
, p
)
220 UHCI_TransferDesc
*td
= (UHCI_TransferDesc
*)p
->p_FirstTD
;
221 BOOL changed
= FALSE
;
223 if (p
->p_Queue
->qh_VLink
& UHCI_PTR_T
)
224 p
->p_LastTD
= (APTR
)UHCI_PTR_T
;
227 UHCI_TransferDesc
*t
= (UHCI_TransferDesc
*)(p
->p_Queue
->qh_VLink
& 0xfffffff1);
228 bug("[UHCI] Control Fast: p->p_Queue->qh_VLink=%p\n", p
->p_Queue
->qh_VLink
);
229 while (!((uint32_t)t
& UHCI_PTR_T
))
231 bug("[UHCI] TD=%p (%08x %08x %08x %08x)\n", t
,
232 t
->td_LinkPtr
, t
->td_Status
, t
->td_Token
, t
->td_Buffer
);
233 t
= (UHCI_TransferDesc
*)(t
->td_LinkPtr
& 0xfffffff1);
238 while ((uint32_t)td
!= (p
->p_Queue
->qh_VLink
& 0xfffffff1))
240 D(bug("[UHCI] TD=%p\n", td
));
242 UHCI_TransferDesc
*tnext
= (UHCI_TransferDesc
*)(td
->td_LinkPtr
& 0xfffffff1);
243 uhci_FreeTDQuick(uhci
, td
);
245 p
->p_FirstTD
= tnext
;
249 if (changed
&& p
->p_Queue
->qh_VLink
== UHCI_PTR_T
) {
250 D(bug("[UHCI] INTR Control pipe %p empty\n", p
));
254 Signal(p
->p_SigTask
, 1 << p
->p_Signal
);
256 /* Free the unused TD's */
261 if (!IsListEmpty(&uhci
->Bulk
))
264 ForeachNode(&uhci
->Bulk
, p
)
266 UHCI_TransferDesc
*td
= (UHCI_TransferDesc
*)p
->p_FirstTD
;
267 BOOL changed
= FALSE
;
269 if (p
->p_Queue
->qh_VLink
== UHCI_PTR_T
)
270 p
->p_LastTD
= (APTR
)UHCI_PTR_T
;
273 UHCI_TransferDesc
*t
= (UHCI_TransferDesc
*)(p
->p_Queue
->qh_VLink
& 0xfffffff1);
274 bug("[UHCI] Bulk: p=%p, p->p_Queue->qh_VLink=%p\n", p
, p
->p_Queue
->qh_VLink
);
275 while ((uint32_t)t
!= UHCI_PTR_T
)
277 bug("[UHCI] TD=%p (%08x %08x %08x %08x)\n", t
,
278 t
->td_LinkPtr
, t
->td_Status
, t
->td_Token
, t
->td_Buffer
);
279 t
= (UHCI_TransferDesc
*)(t
->td_LinkPtr
& 0xfffffff1);
283 while ((uint32_t)td
!= (p
->p_Queue
->qh_VLink
& 0xfffffff1))
285 UHCI_TransferDesc
*tnext
= (UHCI_TransferDesc
*)(td
->td_LinkPtr
& 0xfffffff1);
286 uhci_FreeTDQuick(uhci
, td
);
288 p
->p_FirstTD
= tnext
;
292 if (changed
&& p
->p_Queue
->qh_VLink
== UHCI_PTR_T
) {
293 D(bug("[UHCI] INTR Bulk pipe %p empty\n", p
));
297 Signal(p
->p_SigTask
, 1 << p
->p_Signal
);
303 outw(status
, uhci
->iobase
+ UHCI_STS
);
310 OOP_Object
*METHOD(UHCI
, Root
, New
)
312 D(bug("[UHCI] UHCI::New()\n"));
314 BASE(cl
->UserData
)->LibNode
.lib_OpenCnt
++;
316 o
= (OOP_Object
*)OOP_DoSuperMethod(cl
, o
, (OOP_Msg
) msg
);
320 UHCIData
*uhci
= OOP_INST_DATA(cl
, o
);
322 NEWLIST(&uhci
->mport
.mp_MsgList
);
323 uhci
->mport
.mp_Flags
= PA_SOFTINT
;
324 uhci
->mport
.mp_Node
.ln_Type
= NT_MSGPORT
;
325 uhci
->mport
.mp_SigTask
= &uhci
->timerint
;
326 uhci
->timerint
.is_Code
= (VOID_FUNC
)HubInterrupt
;
327 uhci
->timerint
.is_Data
= uhci
;
329 uhci
->timereq
= CreateIORequest(&uhci
->mport
, sizeof(struct timerequest
));
330 OpenDevice((STRPTR
)"timer.device", UNIT_VBLANK
, (struct IORequest
*)uhci
->timereq
, 0);
334 NEWLIST(&uhci
->Isochronous
);
335 NEWLIST(&uhci
->Interrupts
);
336 NEWLIST(&uhci
->ControlLS
);
337 NEWLIST(&uhci
->ControlFS
);
338 NEWLIST(&uhci
->Bulk
);
340 NEWLIST(&uhci
->intList
);
343 AddTail(&uhci
->intList
, (struct Node
*)uhci
->tmp
);
345 uhci
->tr
= (struct timerequest
*)CreateIORequest(
346 CreateMsgPort(), sizeof(struct timerequest
));
348 FreeSignal(uhci
->tr
->tr_node
.io_Message
.mn_ReplyPort
->mp_SigBit
);
349 uhci
->tr
->tr_node
.io_Message
.mn_ReplyPort
->mp_SigBit
= SIGBREAKB_CTRL_D
;
350 OpenDevice((STRPTR
)"timer.device", UNIT_MICROHZ
, (struct IORequest
*)uhci
->tr
, 0);
352 uhci
->iobase
= GetTagData(aHidd_UHCI_IOBase
, 0, msg
->attrList
);
353 uhci
->device
= (OOP_Object
*)GetTagData(aHidd_UHCI_PCIDevice
, 0, msg
->attrList
);
354 uhci
->pciDriver
= (OOP_Object
*)GetTagData(aHidd_UHCI_PCIDriver
, 0, msg
->attrList
);
357 uint32_t base
= inw(uhci
->iobase
+ UHCI_FLBASEADDR
);
358 uint16_t status
= inw(uhci
->iobase
+ UHCI_STS
);
359 uint16_t frame
= inw(uhci
->iobase
+ UHCI_FRNUM
);
360 uint16_t port1
= inw(uhci
->iobase
+ UHCI_PORTSC1
);
361 uint16_t port2
= inw(uhci
->iobase
+ UHCI_PORTSC2
);
362 uint16_t cmd
= inw(uhci
->iobase
+ UHCI_CMD
);
363 uint8_t sof
= inb(uhci
->iobase
+ UHCI_SOF
);
366 bug("[UHCI] Initial state: Base=%08x Cmd=%04x SOF=%02x Status=%04x Frame=%04x PortSC1=%04x PortSC2=%04x\n",
367 base
, cmd
, sof
, status
, frame
, port1
, port2
);
369 /* Windows-like BIOS detach procedure */
370 bug("[UHCI] Stopping UHCI\n");
373 * Clearing RS bit will stop the controller. Clearing CF bit will tell potential
374 * legacy USB BIOS that AROS takes over
376 outw(inw(uhci
->iobase
+ UHCI_CMD
) & ~(UHCI_CMD_RS
| UHCI_CMD_CF
), uhci
->iobase
+ UHCI_CMD
);
378 for (i
=0; i
< 10; i
++)
380 uhci_sleep(cl
, o
, 1);
381 if (inw(uhci
->iobase
+ UHCI_STS
) & UHCI_STS_HCH
)
383 bug("[UHCI] Host controller halted\n");
388 struct pHidd_PCIDevice_WriteConfigWord wcw
;
389 struct pHidd_PCIDevice_ReadConfigWord rcw
;
391 wcw
.mID
= OOP_GetMethodID((STRPTR
)IID_Hidd_PCIDevice
, moHidd_PCIDevice_WriteConfigWord
);
392 wcw
.reg
= PCI_LEGSUP
;
393 rcw
.mID
= OOP_GetMethodID((STRPTR
)IID_Hidd_PCIDevice
, moHidd_PCIDevice_ReadConfigWord
);
394 rcw
.reg
= PCI_LEGSUP
;
396 uint16_t reg
= OOP_DoMethod(uhci
->device
, (OOP_Msg
)&rcw
.mID
);
397 bug("[UHCI] PCI_LEGSUP=%04x -> ", reg
);
401 OOP_DoMethod(uhci
->device
, (OOP_Msg
)&wcw
.mID
);
402 reg
= OOP_DoMethod(uhci
->device
, (OOP_Msg
)&rcw
.mID
);
403 bug("[UHCI] PCI_LEGSUP=%04x\n", reg
);
405 OOP_DoMethod(uhci
->device
, (OOP_Msg
)&wcw
.mID
);
406 reg
= OOP_DoMethod(uhci
->device
, (OOP_Msg
)&rcw
.mID
);
407 bug("[UHCI] PCI_LEGSUP=%04x\n", reg
);
412 OOP_GetAttr(uhci
->device
, aHidd_PCIDevice_INTLine
, &uhci
->irq
);
414 D(bug("[UHCI] New driver with IOBase=%x, IRQ=%d, PCI device=%08x, PCI driver=%08x\n",
415 uhci
->iobase
, uhci
->irq
, uhci
->device
, uhci
->pciDriver
));
417 uhci
->Frame
= HIDD_PCIDriver_AllocPCIMem(uhci
->pciDriver
, 4096);
418 D(bug("[UHCI] Frame = %08x\n", uhci
->Frame
));
420 outl((uint32_t)uhci
->Frame
, uhci
->iobase
+ UHCI_FLBASEADDR
);
422 uhci
->irqHandler
.is_Node
.ln_Type
= NT_INTERRUPT
;
423 uhci
->irqHandler
.is_Node
.ln_Name
= "UHCI Intr";
424 uhci
->irqHandler
.is_Node
.ln_Pri
= 127;
425 uhci
->irqHandler
.is_Code
= (VOID_FUNC
)uhci_Handler
;
426 uhci
->irqHandler
.is_Data
= uhci
;
428 AddIntServer(INTB_KERNEL
+ uhci
->irq
, &uhci
->irqHandler
);
429 D(bug("[UHCI] IRQHandler = %08x\n", &uhci
->irqHandler
));
431 struct pHidd_PCIDevice_WriteConfigWord __msg
= {
432 OOP_GetMethodID((STRPTR
)IID_Hidd_PCIDevice
, moHidd_PCIDevice_WriteConfigWord
), 0xc0, 0x8f00
435 OOP_DoMethod(uhci
->device
, (OOP_Msg
)msg
);
437 D(bug("[UHCI] Preparing initial QH tree\n"));
439 uhci
->dummy_td
= uhci_AllocTD(cl
, o
);
440 uhci
->dummy_td
->td_Buffer
= 0;
441 uhci
->dummy_td
->td_LinkPtr
= 0;
442 uhci
->dummy_td
->td_Status
= 0;
443 uhci
->dummy_td
->td_Token
= 0;
445 uhci
->qh01
= uhci_AllocQH(cl
, o
);
446 uhci
->qh01
->qh_VLink
= UHCI_PTR_T
;
447 uhci
->qh01
->qh_HLink
= UHCI_PTR_T
;
449 for (i
=0; i
< 2; i
++)
451 uhci
->qh02
[i
] = uhci_AllocQH(cl
, o
);
452 uhci
->qh02
[i
]->qh_VLink
= UHCI_PTR_T
;
453 uhci
->qh02
[i
]->qh_HLink
= UHCI_PTR_QH
| (uint32_t)uhci
->qh01
;
456 for (i
=0; i
< 4; i
++)
458 uhci
->qh04
[i
] = uhci_AllocQH(cl
, o
);
459 uhci
->qh04
[i
]->qh_VLink
= UHCI_PTR_T
;
460 uhci
->qh04
[i
]->qh_HLink
= UHCI_PTR_QH
| (uint32_t)uhci
->qh02
[i
& 0x01];
463 for (i
=0; i
< 8; i
++)
465 uhci
->qh08
[i
] = uhci_AllocQH(cl
, o
);
466 uhci
->qh08
[i
]->qh_VLink
= UHCI_PTR_T
;
467 uhci
->qh08
[i
]->qh_HLink
= UHCI_PTR_QH
| (uint32_t)uhci
->qh04
[i
& 0x03];
470 for (i
=0; i
< 16; i
++)
472 uhci
->qh16
[i
] = uhci_AllocQH(cl
, o
);
473 uhci
->qh16
[i
]->qh_VLink
= UHCI_PTR_T
;
474 uhci
->qh16
[i
]->qh_HLink
= UHCI_PTR_QH
| (uint32_t)uhci
->qh08
[i
& 0x07];
477 for (i
=0; i
< 32; i
++)
479 uhci
->qh32
[i
] = uhci_AllocQH(cl
, o
);
480 uhci
->qh32
[i
]->qh_VLink
= UHCI_PTR_T
;
481 uhci
->qh32
[i
]->qh_HLink
= UHCI_PTR_QH
| (uint32_t)uhci
->qh16
[i
& 0x0f];
484 for (i
=0; i
< 1024; i
++) {
485 uhci
->Frame
[i
] = UHCI_PTR_QH
| (uint32_t)uhci
->qh32
[i
% 0x1f];
488 D(bug("[UHCI] Enabling the controller\n"));
490 outw(0, uhci
->iobase
+ UHCI_INTR
);
491 uhci_globalreset(cl
, o
);
494 struct pHidd_PCIDevice_WriteConfigWord __msg2
= {
495 OOP_GetMethodID((STRPTR
)IID_Hidd_PCIDevice
, moHidd_PCIDevice_WriteConfigWord
), 0xc0, 0x2000
498 OOP_DoMethod(uhci
->device
, (OOP_Msg
)msg2
);
500 outb(0x40, uhci
->iobase
+ UHCI_SOF
);
502 outw(0, uhci
->iobase
+ UHCI_FRNUM
);
503 outl((uint32_t)uhci
->Frame
, uhci
->iobase
+ UHCI_FLBASEADDR
);
505 outw(UHCI_CMD_MAXP
| UHCI_CMD_CF
, uhci
->iobase
+ UHCI_CMD
);
507 outw(UHCI_INTR_SPIE
| UHCI_INTR_IOCE
| UHCI_INTR_RIE
| UHCI_INTR_TOCRCIE
,
508 uhci
->iobase
+ UHCI_INTR
);
512 D(bug("[UHCI] UHCI::New() = %p\n",o
));
515 BASE(cl
->UserData
)->LibNode
.lib_OpenCnt
--;
520 void METHOD(UHCI
, Root
, Dispose
)
522 UHCIData
*uhci
= OOP_INST_DATA(cl
, o
);
523 struct uhcibase
*base
= BASE(cl
->UserData
);
525 D(bug("[UHCI] UHCI::Dispose\n"));
527 D(bug("[UHCI] Stopping USB transfer\n"));
528 outw(0, uhci
->iobase
+ UHCI_CMD
);
530 D(bug("[UHCI] Releasing USB ring\n"));
531 HIDD_PCIDriver_FreePCIMem(uhci
->pciDriver
, uhci
->Frame
);
533 D(bug("[UHCI] Removing IRQ handler\n"));
534 RemIntServer(INTB_KERNEL
+ uhci
->irq
, &uhci
->irqHandler
);
536 AbortIO((struct IORequest
*)uhci
->timereq
);
537 DeleteIORequest((struct IORequest
*)uhci
->timereq
);
539 struct MsgPort
*port
= uhci
->tr
->tr_node
.io_Message
.mn_ReplyPort
;
540 port
->mp_SigTask
= FindTask(NULL
);
541 CloseDevice((struct IORequest
*)uhci
->tr
);
542 DeleteIORequest((struct IORequest
*)uhci
->tr
);
543 port
->mp_SigBit
= AllocSignal(-1);
546 OOP_DoSuperMethod(cl
, o
, (OOP_Msg
)msg
);
548 base
->LibNode
.lib_OpenCnt
--;
551 void METHOD(UHCI
, Root
, Get
)
555 if (IS_USBDEVICE_ATTR(msg
->attrID
, idx
))
559 case aoHidd_USBDevice_Address
:
562 case aoHidd_USBDevice_Hub
:
565 case aoHidd_USBDevice_Bus
:
566 *msg
->storage
= (IPTR
)o
;
569 OOP_DoSuperMethod(cl
, o
, (OOP_Msg
)msg
);
572 else if (IS_USBDRV_ATTR(msg
->attrID
, idx
))
577 OOP_DoSuperMethod(cl
, o
, (OOP_Msg
)msg
);
580 void METHOD(UHCI
, Root
, Set
)
584 struct TagItem
*tags
= msg
->attrList
;
586 while ((tag
= NextTagItem(&tags
)))
588 if (IS_USBDEVICE_ATTR(tag
->ti_Tag
, idx
))
591 else if (IS_USBHUB_ATTR(tag
->ti_Tag
, idx
))
595 else if (IS_USBDRV_ATTR(tag
->ti_Tag
, idx
))
600 OOP_DoSuperMethod(cl
, o
, (OOP_Msg
)msg
);
604 APTR
METHOD(UHCI
, Hidd_USBDrv
, CreatePipe
)
606 return uhci_CreatePipe(cl
, o
, msg
->type
, msg
->fullspeed
, msg
->address
, msg
->endpoint
, msg
->period
, msg
->maxpacket
, msg
->timeout
);
609 void METHOD(UHCI
, Hidd_USBDrv
, DeletePipe
)
611 return uhci_DeletePipe(cl
, o
, msg
->pipe
);
614 void METHOD(UHCI
, Hidd_USBDrv
, SetTimeout
)
616 UHCI_Pipe
*p
= msg
->pipe
;
619 p
->p_TimeoutVal
= msg
->timeout
;
622 BOOL
METHOD(UHCI
, Hidd_USBDrv
, AddInterrupt
)
625 UHCI_Pipe
*p
= msg
->pipe
;
627 if (msg
->pipe
== (APTR
)0xdeadbeef)
629 UHCIData
*uhci
= OOP_INST_DATA(cl
, o
);
630 D(bug("[UHCI] AddInterrupt() local for the UHCI. Intr %p, list %p\n", msg
->interrupt
, &uhci
->intList
));
633 uhci
->tmp
= msg
->interrupt
;
635 AddTail(&uhci
->intList
, &msg
->interrupt
->is_Node
);
641 D(bug("[UHCI] AddInterrupt()\n"));
643 UHCI_Interrupt_t
*intr
= AllocVecPooled(SD(cl
)->MemPool
, sizeof(UHCI_Interrupt_t
));
645 D(bug("[UHCI::AddInterrupt] intr = %p\n", intr
));
649 intr
->i_intr
= msg
->interrupt
;
651 uhci_QueuedRead(cl
, o
, p
, msg
->buffer
, msg
->length
);
652 AddTail((struct List
*)&p
->p_Intr
, (struct Node
*)&intr
->i_node
);
655 intr->i_td = uhci_AllocTD(cl, o);
657 D(bug("[UHCI::AddInterrupt] intr->i_td = %p\n", intr->i_td));
661 intr->i_td->td_Buffer = (uint32_t)msg->buffer;
662 intr->i_td->td_Status = UHCI_TD_ZERO_ACTLEN(UHCI_TD_SET_ERRCNT(3) | UHCI_TD_ACTIVE);
663 intr->i_td->td_Token = UHCI_TD_IN(msg->length, p->p_EndPoint, p->p_DevAddr, p->p_NextToggle);
664 intr->i_td->td_Status |= UHCI_TD_SPD;
665 intr->i_td->td_LinkPtr = UHCI_PTR_T;
669 AddTail(&p->p_Intr, &intr->i_node);
671 if (p->p_FirstTD == (APTR)UHCI_PTR_T)
673 p->p_FirstTD = intr->i_td;
674 p->p_LastTD = intr->i_td;
678 p->p_LastTD->td_LinkPtr = (uint32_t)intr->i_td | UHCI_PTR_TD;
679 p->p_LastTD = intr->i_td;
682 if (p->p_Queue->qh_VLink == UHCI_PTR_T)
684 p->p_Queue->qh_VLink = (uint32_t)p->p_FirstTD | UHCI_PTR_TD;
689 bug("[UHCI::AddInterrupt] p->p_FirstTd = %p, vlink=%p\n", p->p_FirstTD, p->p_Queue->qh_VLink);
693 FreeVecPooled(SD(cl)->MemPool, intr);
697 D(bug("[UHCI::AddInterrupt] %s\n", retval
? "success":"failure"));
702 BOOL
METHOD(UHCI
, Hidd_USBDrv
, RemInterrupt
)
704 UHCI_Interrupt_t
*intr
;
705 UHCI_Pipe
*p
= msg
->pipe
;
707 if (p
== (UHCI_Pipe
*)0xdeadbeef)
709 Remove((struct Node
*)msg
->interrupt
);
714 ForeachNode(&p
->p_Intr
, intr
)
716 if (intr
->i_intr
== msg
->interrupt
)
723 Remove((struct Node
*)&intr
->i_node
);
726 uhci_FreeTD(cl
, o
, intr
->i_td
);
727 FreeVecPooled(SD(cl
)->MemPool
, intr
);
735 BOOL
METHOD(UHCI
, Hidd_USBDrv
, ControlTransfer
)
737 UHCI_Pipe
*p
= msg
->pipe
;
738 D(UHCIData
*uhci
= OOP_INST_DATA(cl
, o
));
743 uint16_t status
= inw(uhci
->iobase
+ UHCI_STS
);
744 uint16_t frame
= inw(uhci
->iobase
+ UHCI_FRNUM
);
745 uint16_t port1
= inw(uhci
->iobase
+ UHCI_PORTSC1
);
746 uint16_t port2
= inw(uhci
->iobase
+ UHCI_PORTSC2
);
747 uint16_t cmd
= inw(uhci
->iobase
+ UHCI_CMD
);
748 uint16_t sof
= inb(uhci
->iobase
+ UHCI_SOF
);
750 D(bug("[UHCI] Status check: Cmd=%04x, SOF=%04x, Status = %04x, Frame=%04x, PortSC1=%04x, PortSC2=%04x\n",
751 cmd
, sof
, status
, frame
, port1
, port2
));
754 int8_t sig
= AllocSignal(-1);
755 int8_t toutsig
= AllocSignal(-1);
756 int32_t msec
= p
->p_TimeoutVal
;
758 D(bug("[UHCI] ControlTransfer(pipe=%p, request=%p, buffer=%p, length=%d, timeout=%d, signal=%d, toutsig=%d)\n",
759 msg
->pipe
, msg
->request
, msg
->buffer
, msg
->length
, msec
, sig
, toutsig
));
761 if (sig
>= 0 && toutsig
>= 0)
764 p
->p_SigTask
= FindTask(NULL
);
766 if (p
->p_TimeoutVal
!= 0)
768 p
->p_Timeout
->tr_node
.io_Message
.mn_ReplyPort
->mp_SigBit
= toutsig
;
769 p
->p_Timeout
->tr_node
.io_Message
.mn_ReplyPort
->mp_SigTask
= FindTask(NULL
);
771 p
->p_Timeout
->tr_node
.io_Command
= TR_ADDREQUEST
;
772 p
->p_Timeout
->tr_time
.tv_secs
= msec
/ 1000;
773 p
->p_Timeout
->tr_time
.tv_micro
= 1000 * (msec
% 1000);
775 SendIO((struct IORequest
*)p
->p_Timeout
);
777 uhci_ControlTransfer(cl
, o
, msg
->pipe
, msg
->request
, msg
->buffer
, msg
->length
);
778 if (Wait((1 << sig
) | (1 << toutsig
)) & (1 << toutsig
))
780 bug("[UHCI] !!!TIMEOUT!!!\n");
781 p
->p_Queue
->qh_VLink
= UHCI_PTR_T
;
782 UHCI_TransferDesc
*td
= (UHCI_TransferDesc
*)p
->p_FirstTD
;
784 GetMsg(p
->p_Timeout
->tr_node
.io_Message
.mn_ReplyPort
);
786 while ((uint32_t)td
!= UHCI_PTR_T
)
788 bug("[UHCI] TD=%p (%08x %08x %08x %08x)\n", td
,
789 td
->td_LinkPtr
, td
->td_Status
, td
->td_Token
, td
->td_Buffer
);
790 UHCI_TransferDesc
*tnext
= (UHCI_TransferDesc
*)(td
->td_LinkPtr
& 0xfffffff1);
791 uhci_FreeTD(cl
, o
, td
);
793 p
->p_FirstTD
= tnext
;
795 p
->p_LastTD
=(APTR
)UHCI_PTR_T
;
801 if (!CheckIO((struct IORequest
*)p
->p_Timeout
))
802 AbortIO((struct IORequest
*)p
->p_Timeout
);
803 WaitIO((struct IORequest
*)p
->p_Timeout
);
804 SetSignal(0, 1 << toutsig
);
815 BOOL
METHOD(UHCI
, Hidd_USBDrv
, BulkTransfer
)
817 UHCI_Pipe
*p
= msg
->pipe
;
821 int8_t sig
= AllocSignal(-1);
822 int8_t toutsig
= AllocSignal(-1);
823 int32_t msec
= p
->p_TimeoutVal
;
825 D(bug("[UHCI] BulkTransfer(pipe=%p, buffer=%p, length=%d, timeout=%d, signal=%d, toutsig=%d)\n",
826 msg
->pipe
, msg
->buffer
, msg
->length
, msec
, sig
, toutsig
));
828 if (sig
>= 0 && toutsig
>= 0)
831 p
->p_SigTask
= FindTask(NULL
);
833 if (p
->p_TimeoutVal
!= 0)
835 p
->p_Timeout
->tr_node
.io_Message
.mn_ReplyPort
->mp_SigBit
= toutsig
;
836 p
->p_Timeout
->tr_node
.io_Message
.mn_ReplyPort
->mp_SigTask
= FindTask(NULL
);
838 p
->p_Timeout
->tr_node
.io_Command
= TR_ADDREQUEST
;
839 p
->p_Timeout
->tr_time
.tv_secs
= msec
/ 1000;
840 p
->p_Timeout
->tr_time
.tv_micro
= 1000 * (msec
% 1000);
842 SendIO((struct IORequest
*)p
->p_Timeout
);
845 uhci_QueuedTransfer(cl
, o
, p
, msg
->buffer
, msg
->length
, p
->p_EndPoint
& 0x80);
847 if (Wait((1 << sig
) | (1 << toutsig
)) & (1 << toutsig
))
849 bug("[UHCI] !!!TIMEOUT!!!\n");
850 p
->p_Queue
->qh_VLink
= UHCI_PTR_T
;
851 UHCI_TransferDesc
*td
= (UHCI_TransferDesc
*)p
->p_FirstTD
;
853 GetMsg(p
->p_Timeout
->tr_node
.io_Message
.mn_ReplyPort
);
855 while ((uint32_t)td
!= UHCI_PTR_T
)
857 bug("[UHCI] TD=%p (%08x %08x %08x %08x)\n", td
,
858 td
->td_LinkPtr
, td
->td_Status
, td
->td_Token
, td
->td_Buffer
);
859 UHCI_TransferDesc
*tnext
= (UHCI_TransferDesc
*)(td
->td_LinkPtr
& 0xfffffff1);
860 uhci_FreeTD(cl
, o
, td
);
862 p
->p_FirstTD
= tnext
;
864 p
->p_LastTD
=(APTR
)UHCI_PTR_T
;
870 if (!CheckIO((struct IORequest
*)p
->p_Timeout
))
871 AbortIO((struct IORequest
*)p
->p_Timeout
);
872 WaitIO((struct IORequest
*)p
->p_Timeout
);
873 SetSignal(0, 1 << toutsig
);
884 (bug("[UHCI] Transfer OK\n"));
886 (bug("[UHCI] Transfer FAILED\n"));
892 BOOL
METHOD(UHCI
, Hidd_USBHub
, OnOff
)
894 UHCIData
*uhci
= OOP_INST_DATA(cl
, o
);
896 D(bug("[UHCI] USBHub::OnOff(%d)\n", msg
->on
));
898 if (!CheckIO((struct IORequest
*)uhci
->timereq
))
899 AbortIO((struct IORequest
*)uhci
->timereq
);
900 GetMsg(&uhci
->mport
);
901 SetSignal(0, 1 << uhci
->mport
.mp_SigBit
);
903 uhci
->running
= msg
->on
;
907 uhci
->timereq
->tr_node
.io_Command
= TR_ADDREQUEST
;
908 uhci
->timereq
->tr_time
.tv_secs
= 1;
909 uhci
->timereq
->tr_time
.tv_micro
= 0;
910 SendIO((struct IORequest
*)uhci
->timereq
);
913 OOP_DoSuperMethod(cl
,o
,(OOP_Msg
)msg
);
915 retval
= uhci_run(cl
, o
, msg
->on
);
916 uhci_sleep(cl
, o
, 100);
921 BOOL
METHOD(UHCI
, Hidd_USBHub
, PortReset
)
923 UHCIData
*uhci
= OOP_INST_DATA(cl
, o
);
925 D(bug("[UHCI] USBHub::PortReset(%d)\n", msg
->portNummer
));
926 retval
= uhci_PortReset(cl
, o
, msg
->portNummer
);
927 uhci
->reset
|= (1 << (msg
->portNummer
- 1));
928 uhci_sleep(cl
, o
, 100);
932 BOOL
METHOD(UHCI
, Hidd_USBHub
, GetPortStatus
)
934 UHCIData
*uhci
= OOP_INST_DATA(cl
, o
);
935 uint16_t port
, x
, status
=0, change
=0;
939 else if (msg
->port
== 2)
943 x
= inw(uhci
->iobase
+ port
);
945 if (x
& UHCI_PORTSC_CCS
)
946 status
|= UPS_CURRENT_CONNECT_STATUS
;
947 if (x
& UHCI_PORTSC_CSC
)
948 change
|= UPS_C_CONNECT_STATUS
;
949 if (x
& UHCI_PORTSC_PE
)
950 status
|= UPS_PORT_ENABLED
;
951 if (x
& UHCI_PORTSC_POEDC
)
952 change
|= UPS_C_PORT_ENABLED
;
953 if (x
& UHCI_PORTSC_OCI
)
954 status
|= UPS_OVERCURRENT_INDICATOR
;
955 if (x
& UHCI_PORTSC_OCIC
)
956 change
|= UPS_C_OVERCURRENT_INDICATOR
;
957 if (x
& UHCI_PORTSC_SUSP
)
958 status
|= UPS_SUSPEND
;
959 if (x
& UHCI_PORTSC_LSDA
)
960 status
|= UPS_LOW_SPEED
;
962 status
|= UPS_PORT_POWER
;
964 if (uhci
->reset
& (1 << (msg
->port
- 1)))
965 status
|= UPS_C_PORT_RESET
;
967 msg
->status
->wPortStatus
= AROS_WORD2LE(status
);
968 msg
->status
->wPortChange
= AROS_WORD2LE(change
);
973 BOOL
METHOD(UHCI
, Hidd_USBHub
, GetHubStatus
)
978 BOOL
METHOD(UHCI
, Hidd_USBHub
, ClearHubFeature
)
983 BOOL
METHOD(UHCI
, Hidd_USBHub
, SetHubFeature
)
988 BOOL
METHOD(UHCI
, Hidd_USBHub
, ClearPortFeature
)
990 UHCIData
*uhci
= OOP_INST_DATA(cl
, o
);
996 else if (msg
->port
== 2)
1000 switch(msg
->feature
)
1002 case UHF_PORT_ENABLE
:
1003 x
= URWMASK(inw(uhci
->iobase
+ port
));
1004 outw(x
& ~UHCI_PORTSC_PE
, uhci
->iobase
+ port
);
1008 case UHF_PORT_SUSPEND
:
1009 x
= URWMASK(inw(uhci
->iobase
+ port
));
1010 outw(x
& ~UHCI_PORTSC_SUSP
, uhci
->iobase
+ port
);
1014 case UHF_PORT_RESET
:
1015 x
= URWMASK(inw(uhci
->iobase
+ port
));
1016 outw(x
& ~UHCI_PORTSC_PR
, uhci
->iobase
+ port
);
1020 case UHF_C_PORT_CONNECTION
:
1021 x
= URWMASK(inw(uhci
->iobase
+ port
));
1022 outw(x
| UHCI_PORTSC_CSC
, uhci
->iobase
+ port
);
1026 case UHF_C_PORT_ENABLE
:
1027 x
= URWMASK(inw(uhci
->iobase
+ port
));
1028 outw(x
| UHCI_PORTSC_POEDC
, uhci
->iobase
+ port
);
1032 case UHF_C_PORT_OVER_CURRENT
:
1033 x
= URWMASK(inw(uhci
->iobase
+ port
));
1034 outw(x
| UHCI_PORTSC_OCIC
, uhci
->iobase
+ port
);
1038 case UHF_C_PORT_RESET
:
1039 uhci
->reset
&= ~(1 << (msg
->port
- 1));
1051 BOOL
METHOD(UHCI
, Hidd_USBHub
, SetPortFeature
)
1053 UHCIData
*uhci
= OOP_INST_DATA(cl
, o
);
1055 BOOL retval
= FALSE
;
1058 port
= UHCI_PORTSC1
;
1059 else if (msg
->port
== 2)
1060 port
= UHCI_PORTSC2
;
1063 switch(msg
->feature
)
1065 case UHF_PORT_ENABLE
:
1066 x
= URWMASK(inw(uhci
->iobase
+ port
));
1067 outw(x
| UHCI_PORTSC_PE
, uhci
->iobase
+ port
);
1071 case UHF_PORT_SUSPEND
:
1072 x
= URWMASK(inw(uhci
->iobase
+ port
));
1073 outw(x
| UHCI_PORTSC_SUSP
, uhci
->iobase
+ port
);
1077 case UHF_PORT_RESET
:
1078 retval
= uhci_PortReset(cl
, o
, msg
->port
);
1081 case UHF_PORT_POWER
:
1093 static const char *string1
= "U\0H\0C\0I\0 \0R\0o\0o\0t\0 \0H\0U\0B";
1094 static const int string1_l
= sizeof("U\0H\0C\0I\0 \0R\0o\0o\0t\0 \0H\0U\0B");
1096 static const char *string2
= "T\0h\0e\0 \0A\0R\0O\0S\0 \0D\0e\0v\0e\0l\0o\0p\0m\0e\0n\0t\0 \0T\0e\0a\0m";
1097 static const int string2_l
= sizeof("T\0h\0e\0 \0A\0R\0O\0S\0 \0D\0e\0v\0e\0l\0o\0p\0m\0e\0n\0t\0 \0T\0e\0a\0m");
1099 BOOL
METHOD(UHCI
, Hidd_USBDevice
, GetString
)
1101 msg
->string
->bDescriptorType
= UDESC_STRING
;
1103 if (msg
->id
== USB_LANGUAGE_TABLE
)
1105 msg
->string
->bLength
= 4;
1106 msg
->string
->bString
[0] = 0x0409;
1108 else if (msg
->id
== 1)
1110 msg
->string
->bLength
= 2 + string1_l
;
1111 CopyMem(string1
, &msg
->string
->bString
[0], string1_l
);
1113 else if (msg
->id
== 2)
1115 msg
->string
->bLength
= 2 + string2_l
;
1116 CopyMem(string2
, &msg
->string
->bString
[0], string2_l
);
1118 else if (msg
->id
== 3)
1122 snprintf(buff
, 128, "%d.%d", VERSION_NUMBER
, REVISION_NUMBER
);
1123 msg
->string
->bLength
= 2 + 2*strlen(buff
);
1124 for (i
=0; i
< ((msg
->string
->bLength
- 2) >> 1); i
++)
1125 msg
->string
->bString
[i
] = AROS_WORD2LE(buff
[i
]);
1134 static const usb_device_descriptor_t device_descriptor
= {
1135 bLength
: sizeof(usb_device_descriptor_t
),
1136 bDescriptorType
: UDESC_DEVICE
,
1138 bDeviceClass
: UDCLASS_HUB
,
1139 bDeviceSubClass
: UDSUBCLASS_HUB
,
1140 bDeviceProtocol
: UDPROTO_FSHUB
,
1145 bNumConfigurations
: 1,
1148 static const usb_hub_descriptor_t hub_descriptor
= {
1149 bDescLength
: sizeof(usb_hub_descriptor_t
) - 31,
1150 bDescriptorType
: UDESC_HUB
,
1152 wHubCharacteristics
:0,
1154 bHubContrCurrent
: 0,
1155 DeviceRemovable
: {0,},
1158 static const usb_endpoint_descriptor_t endpoint_descriptor
= {
1159 bLength
: sizeof(usb_endpoint_descriptor_t
),
1160 bDescriptorType
: UDESC_ENDPOINT
,
1161 bEndpointAddress
: 0x81,
1167 usb_endpoint_descriptor_t
* METHOD(UHCI
, Hidd_USBDevice
, GetEndpoint
)
1169 if (msg
->interface
== 0 && msg
->endpoint
== 0)
1170 return (usb_endpoint_descriptor_t
*)&endpoint_descriptor
;
1175 BOOL
METHOD(UHCI
, Hidd_USBDevice
, GetDeviceDescriptor
)
1177 CopyMem(&device_descriptor
, msg
->descriptor
, sizeof(device_descriptor
));
1181 BOOL
METHOD(UHCI
, Hidd_USBHub
, GetHubDescriptor
)
1183 CopyMem(&hub_descriptor
, msg
->descriptor
, sizeof(hub_descriptor
));
1184 msg
->descriptor
->wHubCharacteristics
= AROS_WORD2LE(UHD_PWR_NO_SWITCH
| UHD_OC_INDIVIDUAL
);
1188 BOOL
METHOD(UHCI
, Hidd_USBDevice
, Configure
)
1190 D(bug("[UHCI] ::Configure(%d)", msg
->configNr
));
1194 APTR
METHOD(UHCI
, Hidd_USBDevice
, CreatePipe
)
1196 if ( (msg
->type
== PIPE_Interrupt
) &&
1197 (msg
->endpoint
== 0x81))
1198 return (APTR
)0xdeadbeef;
1203 void METHOD(UHCI
, Hidd_USBDevice
, DeletePipe
)
1207 void METHOD(UHCI
, Hidd_USBDevice
, SetTimeout
)
1211 /* Class initialization and destruction */
1214 #define SD(x) (&LIBBASE->sd)
1216 static int UHCI_InitClass(LIBBASETYPEPTR LIBBASE
)
1219 D(bug("[UHCI] InitClass\n"));
1221 HiddUHCIAttrBase
= OOP_ObtainAttrBase(IID_Drv_USB_UHCI
);
1223 if (HiddUHCIAttrBase
)
1225 struct TagItem tags
[] = {
1226 { aHidd_UHCI_IOBase
, 0UL },
1227 { aHidd_UHCI_PCIDevice
, 0UL },
1228 { aHidd_UHCI_PCIDriver
, 0UL },
1229 { aHidd_USBDevice_Address
, 1UL },
1230 { aHidd_USBHub_IsRoot
, 1UL },
1231 { aHidd_USBHub_NumPorts
, 2UL },
1235 for (i
=0; i
< LIBBASE
->sd
.num_devices
; i
++)
1237 tags
[0].ti_Data
= LIBBASE
->sd
.iobase
[i
];
1238 tags
[1].ti_Data
= (IPTR
)LIBBASE
->sd
.uhciDevice
[i
];
1239 tags
[2].ti_Data
= (IPTR
)LIBBASE
->sd
.uhciPCIDriver
[i
];
1240 LIBBASE
->sd
.uhciDevice
[i
] = OOP_NewObject(NULL
, CLID_Drv_USB_UHCI
, tags
);
1241 HIDD_USB_AttachDriver(LIBBASE
->sd
.usb
, LIBBASE
->sd
.uhciDevice
[i
]);
1248 static int UHCI_ExpungeClass(LIBBASETYPEPTR LIBBASE
)
1250 D(bug("[UHCI] ExpungeClass\n"));
1252 OOP_ReleaseAttrBase(IID_Drv_USB_UHCI
);
1257 ADD2INITLIB(UHCI_InitClass
, 0)
1258 ADD2EXPUNGELIB(UHCI_ExpungeClass
, 0)