includes: AROS_UFIxx -> AROS_INTxx change
[AROS.git] / workbench / devs / USB / drivers / OHCI / ohcidriverclass.c
blob2d209836a4afd471b7f9a6f6eedcafc96e9a97ce
1 /*
2 Copyright (C) 2006 by Michal Schulz
3 $Id$
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.
21 #define DEBUG 0
23 #include <inttypes.h>
25 #include <exec/types.h>
26 #include <oop/oop.h>
27 #include <usb/usb.h>
28 #include <usb/usb_core.h>
29 #include <utility/tagitem.h>
30 #include <aros/debug.h>
31 #include <aros/symbolsets.h>
33 #include <devices/timer.h>
35 #include <hidd/hidd.h>
36 #include <hidd/pci.h>
38 #include <proto/oop.h>
39 #include <proto/utility.h>
41 #include <stdio.h>
43 #include "ohci.h"
46 * usb_delay() stops waits for specified amount of miliseconds. It uses the timerequest
47 * of specified USB device. No pre-allocation of signals is required.
49 void ohci_Delay(struct timerequest *tr, uint32_t msec)
51 /* Allocate a signal within this task context */
52 tr->tr_node.io_Message.mn_ReplyPort->mp_SigBit = SIGB_SINGLE;
53 tr->tr_node.io_Message.mn_ReplyPort->mp_SigTask = FindTask(NULL);
55 /* Specify the request */
56 tr->tr_node.io_Command = TR_ADDREQUEST;
57 tr->tr_time.tv_secs = msec / 1000;
58 tr->tr_time.tv_micro = 1000 * (msec % 1000);
60 /* Wait */
61 DoIO((struct IORequest *)tr);
63 tr->tr_node.io_Message.mn_ReplyPort->mp_SigTask = NULL;
67 struct timerequest *ohci_CreateTimer()
69 struct timerequest *tr = NULL;
70 struct MsgPort *mp = NULL;
72 mp = CreateMsgPort();
73 if (mp)
75 tr = (struct timerequest *)CreateIORequest(mp, sizeof(struct timerequest));
76 if (tr)
78 FreeSignal(mp->mp_SigBit);
79 if (!OpenDevice((STRPTR)"timer.device", UNIT_MICROHZ, (struct IORequest *)tr, 0))
80 return tr;
82 DeleteIORequest((struct IORequest *)tr);
83 mp->mp_SigBit = AllocSignal(-1);
85 DeleteMsgPort(mp);
88 return NULL;
91 void ohci_DeleteTimer(struct timerequest *tr)
93 if (tr)
95 tr->tr_node.io_Message.mn_ReplyPort->mp_SigBit = AllocSignal(-1);
96 CloseDevice((struct IORequest *)tr);
97 DeleteMsgPort(tr->tr_node.io_Message.mn_ReplyPort);
98 DeleteIORequest((struct IORequest *)tr);
103 * This function allocates a new 32-byte Transfer Descriptor from the
104 * pool of 4K-aligned PCI-accessible memory regions. Within each 4K page,
105 * a bitmap is used to determine which of the TD elements are available
106 * for use.
108 * This function returns NULL if no free TD's are found and no more memory
109 * is available.
111 ohci_td_t *ohci_AllocTD(OOP_Class *cl, OOP_Object *o)
113 ohci_data_t *ohci = OOP_INST_DATA(cl, o);
114 td_node_t *n;
115 uint8_t node_num = 32;
116 uint8_t bmp_pos = 4;
118 ObtainSemaphore(&SD(cl)->tdLock);
120 /* Walk through the list of already available 4K pages */
121 ForeachNode(&SD(cl)->tdList, n)
124 * For each 4K page, search the first free node (cleared bit) and alloc it.
126 for (bmp_pos=0; bmp_pos < 4; bmp_pos++)
128 if (n->tdBitmap[bmp_pos] != 0xffffffff)
130 for (node_num = 0; node_num < 32; node_num++)
132 /* Free TD */
133 if (!(n->tdBitmap[bmp_pos] & (1 << node_num)))
135 ohci_td_t * td = &n->tdPage[bmp_pos*32 + node_num];
136 /* Mark the TD as used and return a pointer to it */
137 n->tdBitmap[bmp_pos] |= 1 << node_num;
139 ReleaseSemaphore(&SD(cl)->tdLock);
141 return td;
149 * No free TDs have been found on the list of 4K pages. Create new Page node
150 * and alloc 4K PCI accessible memory region for it
152 if ((n = AllocPooled(SD(cl)->memPool, sizeof(td_node_t))))
154 if ((n->tdPage = HIDD_PCIDriver_AllocPCIMem(ohci->pciDriver, 4096)))
156 /* Make 4K node available for future allocations */
157 AddHead(&SD(cl)->tdList, (struct Node*)n);
158 ohci_td_t * td = &n->tdPage[0];
160 /* Mark first TD as used and return a pointer to it */
161 n->tdBitmap[0] |= 1;
163 ReleaseSemaphore(&SD(cl)->tdLock);
165 return td;
167 FreePooled(SD(cl)->memPool, n, sizeof(td_node_t));
170 ReleaseSemaphore(&SD(cl)->tdLock);
172 /* Everything failed? Out of memory, most likely */
173 return NULL;
177 * This function allocats new 16-byte Endpoint Descriptor aligned at the 16-byte boundary.
178 * See ohci_AllocTD for more details.
180 ohci_ed_t *ohci_AllocED(OOP_Class *cl, OOP_Object *o)
183 * Since the Endpoint Descriptors have to be aligned at the 16-byte boundary, they may
184 * be allocated from the same pool TD's are
186 return (ohci_ed_t *)ohci_AllocTD(cl, o);
190 * Mark the Transfer Descriptor free, so that it may be allocated by another one.
191 * A quick version which may be called from interrupts.
193 void ohci_FreeTDQuick(ohci_data_t *ohci, ohci_td_t *td)
195 td_node_t *t;
197 /* We're inside interrupt probably. Don't ObtainSemaphore. Just lock interrupts instead */
198 Disable();
200 /* traverse through the list of 4K pages */
201 ForeachNode(&ohci->sd->tdList, t)
203 /* Address match? */
204 if ((intptr_t)t->tdPage == ((intptr_t)td & ~0xfff))
206 /* extract the correct location of the TD within the bitmap */
207 int bmp = (((intptr_t)td & 0xc00) >> 10);
208 int node = (((intptr_t)td & 0x3e0) >> 5);
210 /* Free the node */
211 t->tdBitmap[bmp] &= ~(1 << node);
213 break;
217 Enable();
220 void ohci_FreeEDQuick(ohci_data_t *ohci, ohci_ed_t *ed)
222 ohci_FreeTDQuick(ohci, (ohci_td_t *)ed);
226 * Mark the Transfer Descriptor free, so that it may be allocated by another one.
227 * If the 4K page contains no used descriptors, the page will be freed
229 void ohci_FreeTD(OOP_Class *cl, OOP_Object *o, ohci_td_t *td)
231 td_node_t *t, *next;
232 ohci_data_t *ohci = OOP_INST_DATA(cl, o);
234 ObtainSemaphore(&SD(cl)->tdLock);
236 /* traverse through the list of 4K pages */
237 ForeachNodeSafe(&SD(cl)->tdList, t, next)
239 /* Address match? */
240 if ((intptr_t)t->tdPage == ((intptr_t)td & ~0xfff))
242 /* extract the correct location of the TD within the bitmap */
243 int bmp = (((intptr_t)td & 0xc00) >> 10);
244 int node = (((intptr_t)td & 0x3e0) >> 5);
246 /* Free the node */
247 t->tdBitmap[bmp] &= ~(1 << node);
249 /* Check, if all TD nodes are freee within the 4K page */
250 int i;
251 for (i=0; i < 4; i++)
252 if (t->tdBitmap[i] != 0)
253 break;
255 /* So is it. Free the 4K page */
256 if (i==4)
258 Remove((struct Node*)t);
259 HIDD_PCIDriver_FreePCIMem(ohci->pciDriver, t->tdPage);
260 FreePooled(SD(cl)->memPool, t, sizeof(td_node_t));
263 break;
266 ReleaseSemaphore(&SD(cl)->tdLock);
269 void ohci_FreeED(OOP_Class *cl, OOP_Object *o, ohci_ed_t *ed)
271 ohci_FreeTD(cl, o, (ohci_td_t *)ed);
274 AROS_INTH1(ohci_Handler, ohci_data_t *,ohci)
276 AROS_INTFUNC_INIT
278 uint32_t intrs = 0;
279 uint32_t done;
281 mmio(ohci->regs->HcInterruptDisable) = AROS_LONG2OHCI(HC_INTR_MIE);
283 CacheClearE((APTR)ohci->hcca, sizeof(ohci_hcca_t), CACRF_InvalidateD);
284 done = AROS_OHCI2LONG(ohci->hcca->hccaDoneHead);
286 if (done != 0)
288 if (done & ~1)
289 intrs = HC_INTR_WDH;
290 if (done & 1)
291 intrs |= AROS_OHCI2LONG(mmio(ohci->regs->HcInterruptStatus));
292 ohci->hcca->hccaDoneHead = 0;
294 else
296 intrs = AROS_OHCI2LONG(mmio(ohci->regs->HcInterruptStatus));
297 if (intrs & HC_INTR_WDH)
299 done = AROS_OHCI2LONG(ohci->hcca->hccaDoneHead);
300 ohci->hcca->hccaDoneHead = 0;
303 CacheClearE((APTR)ohci->hcca, sizeof(ohci_hcca_t), CACRF_ClearD);
305 intrs &= ~HC_INTR_MIE;
306 /* Ack interrupts */
307 mmio(ohci->regs->HcInterruptStatus) = AROS_LONG2OHCI(intrs);
309 /* Clear disabled interrupts */
310 intrs &= AROS_OHCI2LONG(mmio(ohci->regs->HcInterruptEnable));
312 if (intrs)
313 D(bug("[OHCI] Intr handler %08x, enabled %08x\n",
314 intrs,
315 AROS_OHCI2LONG(mmio(ohci->regs->HcInterruptEnable))));
317 if (intrs & HC_INTR_WDH)
319 D(bug("[OHCI] WDH Interrupt, hccaDoneHead=%p\n[OHCI] TD's in hccaDoneHead:\n", done));
320 ohci_td_t *td = (ohci_td_t*)(done & 0xfffffff0);
322 mmio(ohci->regs->HcInterruptStatus) = AROS_LONG2OHCI(HC_INTR_WDH);
324 while (td)
326 //CacheClearE(td, sizeof(ohci_td_t), CACRF_InvalidateD);
327 //CacheClearE(ohci->hcca, sizeof(ohci_hcca_t), CACRF_InvalidateD);
329 ohci_td_t *tmp = td;
332 * For each TD issue the signal for corresponding pipe if the
333 * edHeadP=edTailP (thus, the pipe is ready).
335 if (td->tdPipe)
337 ohci_pipe_t *pipe = td->tdPipe;
338 D(bug("[OHCI] Pipe=%08x HeadP=%08x TailP=%08x SigTask=%08x\n", pipe, AROS_OHCI2LONG(pipe->ed->edHeadP),
339 AROS_OHCI2LONG(pipe->ed->edTailP), pipe->sigTask));
341 //CacheClearE(pipe->ed, sizeof(ohci_ed_t), CACRF_InvalidateD);
342 if ((pipe->ed->edHeadP & AROS_OHCI2LONG(0xfffffff0)) == pipe->ed->edTailP)
344 if (pipe->sigTask)
345 Signal(pipe->sigTask, 1 << pipe->signal);
349 D(bug("[OHCI] TD @ %p (%08x %08x %08x %08x)\n", td, AROS_OHCI2LONG(td->tdFlags), AROS_OHCI2LONG(td->tdCurrentBufferPointer), AROS_OHCI2LONG(td->tdBufferEnd), AROS_OHCI2LONG(td->tdNextTD)));
351 td = (ohci_td_t *)AROS_OHCI2LONG(td->tdNextTD);
353 if (tmp->tdPipe->type == PIPE_Interrupt)
355 ohci_td_t *itd = (ohci_td_t *)AROS_OHCI2LONG(tmp->tdPipe->ed->edTailP);
357 //CacheClearE(itd, sizeof(ohci_td_t), CACRF_InvalidateD);
358 D(bug("[OHCI] TD belongs to the interrupt pipe. Intr = %p\n", tmp->tdPipe->interrupt));
360 D(bug("[OHCI] restarting TD\n"));
362 /* Restart the pipe's interrupt */
363 itd->tdFlags = tmp->tdFlags | AROS_LONG2OHCI(0xf0000000);
364 itd->tdPipe = tmp->tdPipe;
365 itd->tdBufferEnd = tmp->tdBufferEnd;
366 itd->tdCurrentBufferPointer = AROS_LONG2OHCI((uint32_t)(tmp->tdPipe->interrupt->buffer));
367 itd->tdNextTD = AROS_LONG2OHCI((uint32_t)tmp);
368 tmp->tdNextTD = 0;
369 tmp->tdFlags = 0;
370 tmp->tdCurrentBufferPointer = 0;
371 tmp->tdBufferEnd = 0;
372 itd->tdPipe->ed->edTailP = AROS_LONG2OHCI((uint32_t)tmp);
374 D(bug("[OHCI] TD @ %p (%08x %08x %08x %08x)\n", itd, AROS_OHCI2LONG(itd->tdFlags), AROS_OHCI2LONG(itd->tdCurrentBufferPointer), AROS_OHCI2LONG(itd->tdBufferEnd), AROS_OHCI2LONG(itd->tdNextTD)));
376 D(bug("[OHCI] Pipe=%p, HeadP=%p, TailP=%p\n", itd->tdPipe,
377 AROS_OHCI2LONG(itd->tdPipe->ed->edHeadP), AROS_OHCI2LONG(itd->tdPipe->ed->edTailP)));
378 D(bug("[OHCI] ED @ %p (%p %p %p %p)\n", itd->tdPipe->ed,
379 AROS_OHCI2LONG(itd->tdPipe->ed->edFlags),
380 AROS_OHCI2LONG(itd->tdPipe->ed->edHeadP),
381 AROS_OHCI2LONG(itd->tdPipe->ed->edTailP),
382 AROS_OHCI2LONG(itd->tdPipe->ed->edNextED)
385 // CacheClearE(tmp->tdPipe->ed, sizeof(ohci_ed_t), CACRF_ClearD);
386 // CacheClearE(tmp, sizeof(ohci_td_t), CACRF_ClearD);
387 // CacheClearE(itd, sizeof(ohci_td_t), CACRF_ClearD);
389 if (tmp->tdPipe->interrupt)
391 Cause(tmp->tdPipe->interrupt->intr);
394 else
395 ohci_FreeTDQuick(ohci, tmp);
399 //CacheClearE(ohci->hcca, sizeof(ohci_hcca_t), CACRF_ClearD);
401 intrs &= ~HC_INTR_WDH;
404 if (intrs & HC_INTR_RHSC)
406 D(bug("[OHCI] RHSC interrupt. Disabling it for 1 second\n"));
408 mmio(ohci->regs->HcInterruptDisable) = AROS_LONG2OHCI(HC_INTR_RHSC);
409 mmio(ohci->regs->HcInterruptStatus) = AROS_LONG2OHCI(HC_INTR_RHSC);
411 intrs &= ~HC_INTR_RHSC;
413 /* Restart the RHSC enable timer */
414 ohci->timerReq->tr_node.io_Command = TR_ADDREQUEST;
415 ohci->timerReq->tr_time.tv_secs = 1;
416 ohci->timerReq->tr_time.tv_micro = 0;
417 SendIO((struct IORequest *)ohci->timerReq);
419 if (ohci->running)
421 struct Interrupt *intr;
423 ForeachNode(&ohci->intList, intr)
425 Cause(intr);
428 else
431 * OHCI is not yet in running state, thus posting any interrupts
432 * down the classes is forbidden. The pending flag will be set in
433 * order to issue the interrupts as soon as the OHCI will be switched
434 * back to the running state
436 ohci->pendingRHSC = 1;
440 if (intrs)
442 mmio(ohci->regs->HcInterruptDisable) = AROS_OHCI2LONG(intrs);
443 D(bug("[OHCI] Disabling interrupts %p\n", intrs));
446 mmio(ohci->regs->HcInterruptEnable) = AROS_LONG2OHCI(HC_INTR_MIE);
448 return FALSE;
450 AROS_INTFUNC_EXIT
453 BOOL METHOD(OHCI, Hidd_USBDrv, AddInterrupt)
455 BOOL retval = FALSE;
457 if (msg->pipe == (void *)0xdeadbeef)
459 ohci_data_t *ohci = OOP_INST_DATA(cl, o);
460 D(bug("[OHCI] AddInterrupt() local for the OHCI. Intr %p, list %p\n", msg->interrupt, &ohci->intList));
462 if (!ohci->regs)
463 ohci->tmp = msg->interrupt;
464 else
465 AddTail(&ohci->intList, &msg->interrupt->is_Node);
467 retval = TRUE;
469 else
471 ohci_intr_t *intr = AllocVecPooled(SD(cl)->memPool, sizeof(ohci_intr_t));
472 ohci_pipe_t *pipe = msg->pipe;
473 ohci_td_t *tail;
475 D(bug("[OHCI] AddInterrupt() intr = %p\n", intr));
477 if (intr)
479 intr->intr = msg->interrupt;
481 tail = ohci_AllocTD(cl, o);
483 intr->td = pipe->tail;
484 intr->td->tdPipe = pipe;
485 intr->buffer = msg->buffer;
486 intr->length = msg->length;
487 pipe->tail = tail;
489 if (msg->buffer)
491 intr->td->tdCurrentBufferPointer = AROS_LONG2OHCI((uint32_t)msg->buffer);
492 intr->td->tdBufferEnd = AROS_LONG2OHCI((uint32_t)msg->buffer + msg->length - 1);
494 else
495 intr->td->tdBufferEnd = intr->td->tdCurrentBufferPointer = 0;
497 D(bug("[OHCI] AddInterrupt() buffer: %08x - %08x\n", AROS_OHCI2LONG(intr->td->tdCurrentBufferPointer), AROS_OHCI2LONG(intr->td->tdBufferEnd)));
499 if (UE_GET_DIR(pipe->endpoint) == UE_DIR_IN)
501 intr->td->tdFlags = AROS_LONG2OHCI(0xf0100000);
503 else
505 intr->td->tdFlags = AROS_LONG2OHCI(0xf0080000);
508 intr->td->tdNextTD = AROS_LONG2OHCI((uint32_t)tail);
510 D(bug("[OHCI] TD @ %p (%p %p %p %p)\n", intr->td, AROS_OHCI2LONG(intr->td->tdFlags), AROS_OHCI2LONG(intr->td->tdCurrentBufferPointer), AROS_OHCI2LONG(intr->td->tdBufferEnd), AROS_OHCI2LONG(intr->td->tdNextTD)));
512 CacheClearE(intr->td, sizeof(ohci_td_t), CACRF_ClearD);
514 retval = TRUE;
516 pipe->interrupt = intr;
517 pipe->ed->edTailP = AROS_LONG2OHCI((uint32_t)tail);
519 CacheClearE(pipe->ed, sizeof(ohci_ed_t), CACRF_ClearD);
521 D(bug("[OHCI] ED @ %p (%p %p %p %p)\n", pipe->ed,
522 AROS_OHCI2LONG(pipe->ed->edFlags),
523 AROS_OHCI2LONG(pipe->ed->edHeadP),
524 AROS_OHCI2LONG(pipe->ed->edTailP),
525 AROS_OHCI2LONG(pipe->ed->edNextED)
528 CacheClearE(intr->td, sizeof(ohci_td_t), CACRF_ClearD);
531 D(bug("[OHCI::AddInterrupt] %s\n", retval ? "success":"failure"));
533 return retval;
536 BOOL METHOD(OHCI, Hidd_USBDrv, RemInterrupt)
538 if (msg->pipe == (void *)0xdeadbeef)
540 Remove((struct Node *)msg->interrupt);
541 return TRUE;
543 else
545 // TODO:
546 return FALSE;
550 static ohci_ed_t *ohci_SelectIntrED(ohci_data_t *ohci, uint8_t interval)
552 ohci_ed_t **ed = NULL;
553 uint8_t i, count, minimum, bestat;
555 if (interval < 2)
557 ed = &ohci->int01;
558 count = 1;
560 else if (interval < 4)
562 ed = ohci->int02;
563 count = 2;
565 else if (interval < 8)
567 ed = ohci->int04;
568 count = 4;
570 else if (interval < 16)
572 ed = ohci->int08;
573 count = 8;
575 else if (interval < 32)
577 ed = ohci->int16;
578 count = 16;
580 else
582 ed = ohci->int32;
583 count = 32;
586 i=0;
587 minimum = ED_GET_USAGE(ed[0]);
588 bestat = 0;
589 do {
590 if (minimum > ED_GET_USAGE(ed[i]))
592 minimum = ED_GET_USAGE(ed[i]);
593 bestat = i;
595 } while (++i < count);
597 (bug("[OHCI] Best node (%d uses) %d from %d\n", minimum, bestat, count));
599 ED_SET_USAGE(ed[bestat], ED_GET_USAGE(ed[bestat]) + 1);
601 return ed[bestat];
604 void *METHOD(OHCI, Hidd_USBDrv, CreatePipe)
606 ohci_data_t *ohci = OOP_INST_DATA(cl, o);
607 ohci_pipe_t *pipe = NULL;
609 // if (msg->address == 2 && msg->endpoint==0x81)
610 // msg->maxpacket=4;
613 bug("[OHCI] CreatePipe(");
614 switch (msg->type)
616 case PIPE_Bulk:
617 bug("BULK");
618 break;
619 case PIPE_Control:
620 bug("CTRL");
621 break;
622 case PIPE_Interrupt:
623 bug("INTR");
624 break;
625 case PIPE_Isochronous:
626 bug("ISOC");
627 break;
628 default:
629 bug("????");
631 bug(", %s, %02x, %02x, %d, %dms)\n", msg->fullspeed ? "FAST":"SLOW",
632 msg->address, msg->endpoint, msg->maxpacket, msg->timeout);
635 pipe = AllocVecPooled(SD(cl)->memPool,sizeof(ohci_pipe_t));
637 if (pipe)
639 pipe->tail = ohci_AllocTD(cl, o);
640 pipe->tail->tdBufferEnd = 0;
641 pipe->tail->tdCurrentBufferPointer = 0;
642 pipe->tail->tdFlags = 0;
643 pipe->tail->tdNextTD = 0;
644 pipe->tail->tdPipe = pipe;
645 CacheClearE(pipe->tail, sizeof(ohci_td_t), CACRF_ClearD);
647 pipe->ed = ohci_AllocED(cl, o);
648 pipe->type = msg->type;
649 pipe->address = msg->address;
650 pipe->endpoint = msg->endpoint;
651 pipe->interval = msg->period;
652 pipe->maxpacket = msg->maxpacket;
654 pipe->ed->edPipe = pipe;
655 pipe->ed->edFlags = AROS_LONG2OHCI((msg->address & ED_FA_MASK) |
656 ((msg->endpoint << 7) & ED_EN_MASK) |
657 ((msg->maxpacket << 16) & ED_MPS_MASK) | ED_K);
659 if (!msg->fullspeed)
660 pipe->ed->edFlags |= AROS_LONG2OHCI(ED_S);
662 pipe->ed->edHeadP = pipe->ed->edTailP = AROS_LONG2OHCI((uint32_t)pipe->tail);
663 //pipe->ed->edHeadP |= AROS_LONG2OHCI(2);
665 CacheClearE(pipe->ed, sizeof(ohci_ed_t), CACRF_ClearD);
667 //NEWLIST(&pipe->intList);
668 InitSemaphore(&pipe->lock);
670 pipe->timeoutVal = msg->timeout;
671 pipe->timeout = (struct timerequest *)CreateIORequest(
672 CreateMsgPort(), sizeof(struct timerequest));
674 FreeSignal(pipe->timeout->tr_node.io_Message.mn_ReplyPort->mp_SigBit);
675 OpenDevice((STRPTR)"timer.device", UNIT_MICROHZ, (struct IORequest *)pipe->timeout, 0);
677 /* According to the pipe's type, add it to proper list */
678 switch (msg->type)
680 case PIPE_Bulk:
681 pipe->location = ohci->bulk_head;
682 break;
684 case PIPE_Control:
685 pipe->location = ohci->ctrl_head;
686 break;
688 case PIPE_Isochronous:
689 pipe->location = ohci->isoc_head;
690 pipe->ed->edFlags |= AROS_LONG2OHCI(ED_F);
691 CacheClearE(pipe->ed, sizeof(ohci_ed_t), CACRF_ClearD);
692 break;
694 case PIPE_Interrupt:
695 pipe->location = ohci_SelectIntrED(ohci, msg->period);
696 break;
699 if (pipe->location)
701 pipe->ed->edNextED = pipe->location->edNextED & AROS_LONG2OHCI(0xfffffff0);
702 pipe->location->edNextED = AROS_LONG2OHCI((AROS_OHCI2LONG(pipe->location->edNextED) & 0x0000000f) | (uint32_t)(pipe->ed));
704 D(bug("[OHCI] Master ED at %p\n", pipe->location));
707 pipe->ed->edFlags &= ~AROS_LONG2OHCI(ED_K);
708 pipe->location->edFlags &= ~AROS_LONG2OHCI(ED_K);
710 CacheClearE(pipe->location, sizeof(ohci_ed_t), CACRF_ClearD);
711 CacheClearE(pipe->ed, sizeof(ohci_ed_t), CACRF_ClearD);
714 D(bug("[OHCI] CreatePipe()=%p\n", pipe));
715 return pipe;
718 void METHOD(OHCI, Hidd_USBDrv, SetTimeout)
720 ohci_pipe_t *pipe = msg->pipe;
722 if (pipe)
723 pipe->timeoutVal = msg->timeout;
726 void METHOD(OHCI, Hidd_USBDrv, DeletePipe)
728 ohci_pipe_t *pipe = msg->pipe;
730 D(bug("[OHCI] DeletePipe(%p, ed=%p)\n", pipe, pipe->ed));
732 if (pipe)
734 ohci_ed_t *ed = pipe->location;
736 D(bug("[OHCI] ED @ %p (%p %p %p %p)\n", pipe->ed,
737 AROS_OHCI2LONG(pipe->ed->edFlags),
738 AROS_OHCI2LONG(pipe->ed->edHeadP),
739 AROS_OHCI2LONG(pipe->ed->edTailP),
740 AROS_OHCI2LONG(pipe->ed->edNextED)
743 D(bug("[OHCI] location=%p\n", ed));
745 D(bug("[OHCI] ED @ %p (%p %p %p %p)\n", ed,
746 AROS_OHCI2LONG(ed->edFlags),
747 AROS_OHCI2LONG(ed->edHeadP),
748 AROS_OHCI2LONG(ed->edTailP),
749 AROS_OHCI2LONG(ed->edNextED)
752 /* Stop pipe from being processed */
753 pipe->ed->edFlags |= AROS_LONG2OHCI(ED_K);
754 CacheClearE(pipe->ed, sizeof(ohci_ed_t), CACRF_ClearD);
756 if (pipe->type == PIPE_Interrupt)
758 Disable();
759 ED_SET_USAGE(ed, ED_GET_USAGE(ed) - 1);
760 CacheClearE(ed, sizeof(ohci_ed_t), CACRF_ClearD);
761 Enable();
764 /* Remove pipe from the proper list */
765 while ((uint32_t)ed & 0xfffffff0)
767 D(bug("[OHCI] ed->edNextED=%p\n", AROS_OHCI2LONG(ed->edNextED)));
769 if ((AROS_OHCI2LONG(ed->edNextED) & 0xfffffff0) == ((uint32_t)pipe->ed))
771 D(bug("[OHCI] ED match the pipe (pipe->edNextED=%p)\n", AROS_OHCI2LONG(pipe->ed->edNextED)));
772 Disable();
773 uint32_t next = (AROS_OHCI2LONG(ed->edNextED) & 0x0000000f) | (AROS_OHCI2LONG(pipe->ed->edNextED) & 0xfffffff0);
774 ed->edNextED = AROS_LONG2OHCI(next);
775 Enable();
777 D(bug("[OHCI] ed->edNextED=%p (fixed)\n", AROS_LONG2OHCI(ed->edNextED)));
779 CacheClearE(ed, sizeof(ohci_ed_t), CACRF_ClearD);
780 break;
783 ed = (ohci_ed_t *)(AROS_LONG2OHCI(ed->edNextED) & 0xfffffff0);
786 /* Remove any TD's pending */
787 while((AROS_OHCI2LONG(pipe->ed->edTailP) & 0xfffffff0) != (AROS_OHCI2LONG(pipe->ed->edHeadP) & 0xfffffff0))
789 ohci_td_t *t = (ohci_td_t*)(AROS_OHCI2LONG(pipe->ed->edHeadP) & 0xfffffff0);
790 pipe->ed->edHeadP = AROS_LONG2OHCI(AROS_OHCI2LONG(t->tdNextTD) & 0xfffffff0);
792 D(bug("[OHCI] TD @ %p (%p %p %p %p)\n", t, AROS_OHCI2LONG(t->tdFlags), AROS_OHCI2LONG(t->tdCurrentBufferPointer), AROS_OHCI2LONG(t->tdBufferEnd), AROS_OHCI2LONG(t->tdNextTD)));
794 ohci_FreeTD(cl, o, t);
797 if (pipe->ed->edTailP)
798 ohci_FreeTD(cl, o, (ohci_td_t *)AROS_OHCI2LONG(pipe->ed->edTailP));
800 /* Close timer device */
801 pipe->timeout->tr_node.io_Message.mn_ReplyPort->mp_SigBit = AllocSignal(-1);
802 CloseDevice((struct IORequest *)pipe->timeout);
803 DeleteMsgPort(pipe->timeout->tr_node.io_Message.mn_ReplyPort);
804 DeleteIORequest((struct IORequest *)pipe->timeout);
806 ohci_FreeED(cl, o, pipe->ed);
807 FreeVecPooled(SD(cl)->memPool, pipe);
813 BOOL METHOD(OHCI, Hidd_USBDrv, ControlTransfer)
815 ohci_data_t *ohci = OOP_INST_DATA(cl, o);
816 ohci_pipe_t *pipe = msg->pipe;
817 int8_t sig = AllocSignal(-1);
818 int8_t toutsig = AllocSignal(-1);
819 BOOL retval = FALSE;
820 ULONG length;
822 D(bug("[OHCI] ControlTransfer()\n"));
824 ObtainSemaphore(&pipe->lock);
826 if (sig >= 0 && toutsig >= 0)
828 ohci_td_t *setup;
829 ohci_td_t *status;
830 ohci_td_t *td, *tail;
831 void *request;
832 void *buffer;
834 pipe->signal = sig;
835 pipe->sigTask = FindTask(NULL);
837 tail = ohci_AllocTD(cl, o);
838 tail->tdFlags = 0;
839 tail->tdCurrentBufferPointer = 0;
840 tail->tdBufferEnd = 0;
841 tail->tdNextTD = 0;
842 tail->tdPipe = pipe;
844 length = sizeof(USBDevice_Request);
845 request = CachePreDMA(msg->request, &length, DMA_ReadFromRAM);
847 /* Do the right control transfer */
848 setup = td = pipe->tail;
849 setup->tdFlags = AROS_LONG2OHCI(0xf0000000 | 0x02000000 | 0x00e00000);
850 setup->tdCurrentBufferPointer = AROS_LONG2OHCI((uint32_t)request);
851 setup->tdBufferEnd = AROS_LONG2OHCI((uint32_t)request + sizeof(USBDevice_Request) - 1);
852 setup->tdPipe = pipe;
854 status = ohci_AllocTD(cl, o);
855 status->tdFlags = AROS_LONG2OHCI(0xf3000000 | ((msg->request->bmRequestType & UT_READ) ? 0x00080000 : 0x00100000));
856 status->tdBufferEnd = 0;
857 status->tdCurrentBufferPointer = 0;
858 status->tdNextTD = AROS_LONG2OHCI((uint32_t)tail);
859 status->tdPipe = pipe;
861 if (msg->buffer && msg->length < 8192)
863 length = msg->length;
864 if (msg->request->bmRequestType & UT_READ)
865 buffer = CachePreDMA(msg->buffer, &length, 0);
866 else
867 buffer = CachePreDMA(msg->buffer, &length, DMA_ReadFromRAM);
869 /* Get new TD and link it immediatelly with the previous one */
870 td->tdNextTD = AROS_LONG2OHCI((uint32_t)ohci_AllocTD(cl, o));
871 td = (ohci_td_t *)AROS_OHCI2LONG(td->tdNextTD);
873 td->tdFlags = AROS_LONG2OHCI(0xf3e00000 | ((msg->request->bmRequestType & UT_READ) ? 0x00100000 : 0x00080000));
874 td->tdCurrentBufferPointer = AROS_LONG2OHCI((uint32_t)buffer);
875 td->tdBufferEnd = AROS_LONG2OHCI((uint32_t)buffer + msg->length - 1);
876 td->tdPipe = pipe;
879 /* Link last TD with the status TD */
880 td->tdNextTD = AROS_LONG2OHCI((uint32_t)status);
882 D(bug("[OHCI] Transfer:\n[OHCI] SETUP=%p (%p %p %p %p)\n", setup, AROS_OHCI2LONG(setup->tdFlags), AROS_OHCI2LONG(setup->tdCurrentBufferPointer), AROS_OHCI2LONG(setup->tdBufferEnd), AROS_OHCI2LONG(setup->tdNextTD)));
883 if (td != setup)
884 D(bug("[OHCI] DATA=%p (%p %p %p %p)\n", td, AROS_OHCI2LONG(td->tdFlags), AROS_OHCI2LONG(td->tdCurrentBufferPointer), AROS_OHCI2LONG(td->tdBufferEnd), AROS_OHCI2LONG(td->tdNextTD)));
885 D(bug("[OHCI] STAT=%p (%p %p %p %p)\n", status, AROS_OHCI2LONG(status->tdFlags), AROS_OHCI2LONG(status->tdCurrentBufferPointer), AROS_OHCI2LONG(status->tdBufferEnd), AROS_OHCI2LONG(status->tdNextTD)));
887 pipe->errorCode = 0;
889 /* Link the first TD with end of the ED's transfer queue */
890 CacheClearE(setup, sizeof(ohci_td_t), CACRF_ClearD);
891 CacheClearE(status, sizeof(ohci_td_t), CACRF_ClearD);
892 CacheClearE(td, sizeof(ohci_td_t), CACRF_ClearD);
893 CacheClearE(tail, sizeof(ohci_td_t), CACRF_ClearD);
895 /* Fire the transfer */
896 if (pipe->timeoutVal != 0)
898 int32_t msec = pipe->timeoutVal + 10000;
899 pipe->timeout->tr_node.io_Message.mn_ReplyPort->mp_SigBit = toutsig;
900 pipe->timeout->tr_node.io_Message.mn_ReplyPort->mp_SigTask = FindTask(NULL);
902 pipe->timeout->tr_node.io_Command = TR_ADDREQUEST;
903 pipe->timeout->tr_time.tv_secs = msec / 1000;
904 pipe->timeout->tr_time.tv_micro = 1000 * (msec % 1000);
906 SendIO((struct IORequest *)pipe->timeout);
909 pipe->ed->edTailP = AROS_LONG2OHCI((uint32_t)tail);
910 pipe->tail = tail;
911 CacheClearE(pipe->ed, sizeof(ohci_ed_t), CACRF_ClearD);
913 mmio(ohci->regs->HcCommandStatus) |= AROS_LONG2OHCI(HC_CS_CLF);
915 /* Wait for completion signals */
916 if (Wait((1 << sig) | (1 << toutsig)) & (1 << toutsig))
918 /* Timeout. Pipe stall. */
919 bug("[OHCI] ControlTransfer() !!!TIMEOUT!!!\n");
921 GetMsg(pipe->timeout->tr_node.io_Message.mn_ReplyPort);
923 /* Remove any TD's pending */
925 D(bug("[OHCI] HeadP=%p TailP=%p\n", AROS_OHCI2LONG(pipe->ed->edHeadP), AROS_OHCI2LONG(pipe->ed->edTailP)));
926 D(bug("[OHCI] TD's in ED: \n"));
927 ohci_td_t *td = (ohci_td_t*)(AROS_OHCI2LONG(pipe->ed->edHeadP) & 0xfffffff0);
928 while (td)
930 D(bug("[OHCI] TD @ %p (%p %p %p %p)\n", td, AROS_OHCI2LONG(td->tdFlags), AROS_OHCI2LONG(td->tdCurrentBufferPointer), AROS_OHCI2LONG(td->tdBufferEnd), AROS_OHCI2LONG(td->tdNextTD)));
931 td = (ohci_td_t *)(AROS_OHCI2LONG(td->tdNextTD) & 0xfffffff0);
934 while((AROS_OHCI2LONG(pipe->ed->edTailP) & 0xfffffff0) != (AROS_OHCI2LONG(pipe->ed->edHeadP) & 0xfffffff0))
936 ohci_td_t *t = (ohci_td_t*)(AROS_OHCI2LONG(pipe->ed->edHeadP) & 0xfffffff0);
937 pipe->ed->edHeadP = AROS_LONG2OHCI(AROS_OHCI2LONG(t->tdNextTD) & 0xfffffff0);
938 ohci_FreeTD(cl, o, t);
941 /* Reenable the ED */
942 pipe->ed->edHeadP &= AROS_LONG2OHCI(0xfffffff0);
943 CacheClearE(pipe->ed, sizeof(ohci_ed_t), CACRF_ClearD);
945 retval = FALSE;
947 else
950 * No timeout occured. Remove the timeout request and report success. In this case,
951 * the TD's are freed automatically by the interrupt handler.
954 if (!CheckIO((struct IORequest *)pipe->timeout))
955 AbortIO((struct IORequest *)pipe->timeout);
956 WaitIO((struct IORequest *)pipe->timeout);
957 SetSignal(0, 1 << toutsig);
959 if (!pipe->errorCode)
960 retval = TRUE;
963 length = sizeof(USBDevice_Request);
964 CachePostDMA(msg->request, &length, DMA_ReadFromRAM);
965 if (msg->buffer && msg->length)
967 length = msg->length;
968 if (msg->request->bmRequestType & UT_READ)
969 CachePostDMA(msg->buffer, &length, 0);
970 else
971 CachePostDMA(msg->buffer, &length, DMA_ReadFromRAM);
975 FreeSignal(sig);
976 FreeSignal(toutsig);
979 D(bug("[OHCI] ControlTransfer() %s\n", retval?"OK":"FAILED"));
981 ReleaseSemaphore(&pipe->lock);
983 return retval;
986 BOOL METHOD(OHCI, Hidd_USBDrv, BulkTransfer)
988 ohci_data_t *ohci = OOP_INST_DATA(cl, o);
989 ohci_pipe_t *pipe = msg->pipe;
990 int8_t sig = AllocSignal(-1);
991 int8_t toutsig = AllocSignal(-1);
992 uint32_t length = msg->length;
993 uint8_t *buff;
994 BOOL retval = FALSE;
996 D(bug("[OHCI] BulkTransfer()\n"));
997 D(bug("[OHCI] Pipe %x %s endpoint %02x addr %02x\n", pipe, UE_GET_DIR(pipe->endpoint) == UE_DIR_IN ? "IN":"OUT",
998 pipe->endpoint, pipe->address));
1000 ObtainSemaphore(&pipe->lock);
1002 if (sig >= 0 && toutsig >= 0)
1004 ohci_td_t *td, *first_td, *tail;
1005 const uint32_t maxpacket = 4096; //(8192 / pipe->maxpacket) * pipe->maxpacket;
1007 pipe->signal = sig;
1008 pipe->sigTask = FindTask(NULL);
1010 first_td = td = pipe->tail;
1012 tail = ohci_AllocTD(cl, o);
1013 tail->tdFlags = 0;
1014 tail->tdCurrentBufferPointer = 0;
1015 tail->tdBufferEnd = 0;
1016 tail->tdNextTD = 0;
1017 tail->tdPipe = pipe;
1019 if (UE_GET_DIR(pipe->endpoint) == UE_DIR_IN)
1020 buff = CachePreDMA(msg->buffer, &length, 0);
1021 else
1022 buff = CachePreDMA(msg->buffer, &length, DMA_ReadFromRAM);
1024 while (length > 0)
1026 uint32_t len = length > maxpacket ? maxpacket : length;
1028 td->tdFlags = AROS_LONG2OHCI(0xf0000000);
1029 td->tdFlags |= AROS_LONG2OHCI(TD_R);
1031 if (length > len)
1032 td->tdFlags |= AROS_LONG2OHCI(0x00e00000);
1034 if (UE_GET_DIR(pipe->endpoint) == UE_DIR_IN)
1035 td->tdFlags |= AROS_LONG2OHCI(0x00100000);
1036 else
1037 td->tdFlags |= AROS_LONG2OHCI(0x00080000);
1039 td->tdPipe = pipe;
1040 td->tdCurrentBufferPointer = AROS_LONG2OHCI((IPTR)buff);
1041 td->tdBufferEnd = AROS_LONG2OHCI((IPTR)buff + len - 1);
1043 buff += len;
1044 length -= len;
1045 if (length)
1047 ohci_td_t *newtd = ohci_AllocTD(cl, o);
1048 td->tdNextTD = AROS_LONG2OHCI((uint32_t)newtd);
1049 CacheClearE(td, sizeof(ohci_td_t), CACRF_ClearD);
1050 td = newtd;
1053 td->tdNextTD = (IPTR)AROS_LONG2OHCI((IPTR)tail);
1054 CacheClearE(td, sizeof(ohci_td_t), CACRF_ClearD);
1056 D(bug("[OHCI] Transfer:\n"));
1057 for (td = first_td; td; td = (ohci_td_t *)AROS_OHCI2LONG(td->tdNextTD))
1059 D(bug("[OHCI] DATA=%p (%p %p %p %p)\n", td, AROS_OHCI2LONG(td->tdFlags), AROS_OHCI2LONG(td->tdCurrentBufferPointer), AROS_OHCI2LONG(td->tdBufferEnd), AROS_OHCI2LONG(td->tdNextTD)));
1061 pipe->errorCode = 0;
1063 length = msg->length;
1065 /* Fire the transfer */
1066 if (pipe->timeoutVal != 0)
1068 int32_t msec = pipe->timeoutVal + 10000;
1069 pipe->timeout->tr_node.io_Message.mn_ReplyPort->mp_SigBit = toutsig;
1070 pipe->timeout->tr_node.io_Message.mn_ReplyPort->mp_SigTask = FindTask(NULL);
1072 pipe->timeout->tr_node.io_Command = TR_ADDREQUEST;
1073 pipe->timeout->tr_time.tv_secs = msec / 1000;
1074 pipe->timeout->tr_time.tv_micro = 1000 * (msec % 1000);
1076 SendIO((struct IORequest *)pipe->timeout);
1079 pipe->ed->edTailP = AROS_LONG2OHCI((uint32_t)tail);
1080 pipe->tail = tail;
1081 CacheClearE(pipe->ed, sizeof(ohci_ed_t), CACRF_ClearD);
1083 mmio(ohci->regs->HcCommandStatus) |= AROS_LONG2OHCI(HC_CS_BLF);
1085 /* Wait for completion signals */
1086 if (Wait((1 << sig) | (1 << toutsig)) & (1 << toutsig))
1088 /* Timeout. Pipe stall. */
1089 bug("[OHCI] BulkTransfer() !!!TIMEOUT!!!\n");
1091 GetMsg(pipe->timeout->tr_node.io_Message.mn_ReplyPort);
1093 /* Remove any TD's pending */
1095 D(bug("[OHCI] HeadP=%p TailP=%p\n", AROS_OHCI2LONG(pipe->ed->edHeadP), AROS_OHCI2LONG(pipe->ed->edTailP)));
1096 D(bug("[OHCI] TD's in ED: \n"));
1097 ohci_td_t *td = (ohci_td_t*)(AROS_OHCI2LONG(pipe->ed->edHeadP) & 0xfffffff0);
1098 while (td)
1100 D(bug("[OHCI] TD @ %p (%p %p %p %p)\n", td, AROS_OHCI2LONG(td->tdFlags), AROS_OHCI2LONG(td->tdCurrentBufferPointer), AROS_OHCI2LONG(td->tdBufferEnd), AROS_OHCI2LONG(td->tdNextTD)));
1101 td = (ohci_td_t *)(AROS_OHCI2LONG(td->tdNextTD) & 0xfffffff0);
1104 while((AROS_OHCI2LONG(pipe->ed->edTailP) & 0xfffffff0) != (AROS_OHCI2LONG(pipe->ed->edHeadP) & 0xfffffff0))
1106 ohci_td_t *t = (ohci_td_t*)(AROS_OHCI2LONG(pipe->ed->edHeadP) & 0xfffffff0);
1107 pipe->ed->edHeadP = AROS_LONG2OHCI(AROS_OHCI2LONG(t->tdNextTD) & 0xfffffff0);
1108 ohci_FreeTD(cl, o, t);
1111 /* Reenable the ED */
1112 pipe->ed->edHeadP &= AROS_LONG2OHCI(0xfffffff0);
1113 CacheClearE(pipe->ed, sizeof(ohci_ed_t), CACRF_ClearD);
1115 retval = FALSE;
1117 else
1120 * No timeout occured. Remove the timeout request and report success. In this case,
1121 * the TD's are freed automatically by the interrupt handler.
1124 if (!CheckIO((struct IORequest *)pipe->timeout))
1125 AbortIO((struct IORequest *)pipe->timeout);
1126 WaitIO((struct IORequest *)pipe->timeout);
1127 SetSignal(0, 1 << toutsig);
1129 if (!pipe->errorCode)
1130 retval = TRUE;
1133 length = msg->length;
1134 if (UE_GET_DIR(pipe->endpoint) == UE_DIR_IN)
1135 CachePostDMA(msg->buffer, &length, 0);
1136 else
1137 CachePostDMA(msg->buffer, &length, DMA_ReadFromRAM);
1139 FreeSignal(sig);
1140 FreeSignal(toutsig);
1143 D(bug("[OHCI] BulkTransfer() %s\n", retval?"OK":"FAILED"));
1145 ReleaseSemaphore(&pipe->lock);
1147 return retval;