GUI: Fix Tomato RAF theme for all builds. Compilation typo.
[tomato.git] / release / src-rt-6.x.4708 / cfe / cfe / usb / ohci.c
blob696cda12709079d4ac7577cf9240c58eee00ffcf
1 /* *********************************************************************
2 * Broadcom Common Firmware Environment (CFE)
3 *
4 * OHCI device driver File: ohci.c
5 *
6 * Open Host Controller Interface low-level routines
7 *
8 * Author: Mitch Lichtenberg (mpl@broadcom.com)
9 *
10 *********************************************************************
12 * Copyright 2000,2001,2002,2003
13 * Broadcom Corporation. All rights reserved.
15 * This software is furnished under license and may be used and
16 * copied only in accordance with the following terms and
17 * conditions. Subject to these conditions, you may download,
18 * copy, install, use, modify and distribute modified or unmodified
19 * copies of this software in source and/or binary form. No title
20 * or ownership is transferred hereby.
22 * 1) Any source code used, modified or distributed must reproduce
23 * and retain this copyright notice and list of conditions
24 * as they appear in the source file.
26 * 2) No right is granted to use any trade name, trademark, or
27 * logo of Broadcom Corporation. The "Broadcom Corporation"
28 * name may not be used to endorse or promote products derived
29 * from this software without the prior written permission of
30 * Broadcom Corporation.
32 * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
33 * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
34 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
35 * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
36 * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
37 * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
38 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
39 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
40 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
41 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
42 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
43 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
44 * THE POSSIBILITY OF SUCH DAMAGE.
45 ********************************************************************* */
48 #ifndef _CFE_
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <unistd.h>
52 #include <string.h>
53 #include <stdint.h>
54 #include "usbhack.h"
55 #define CPUCFG_COHERENT_DMA 1 /* hack runs on a PC, PCs are coherent */
56 #else
57 #include "lib_types.h"
58 #include "lib_printf.h"
59 #include "lib_string.h"
60 #include "lib_physio.h"
61 #include "addrspace.h"
62 #include "cpu_config.h" /* for CPUCFG_COHERENT_DMA */
63 #endif
65 #include "lib_malloc.h"
66 #include "lib_queue.h"
67 #include "usbchap9.h"
68 #include "usbd.h"
69 #include "ohci.h"
72 /* *********************************************************************
73 * Macros for dealing with hardware
75 * This is all yucky stuff that needs to be made more
76 * processor-independent. It's mostly here now to help us with
77 * our test harness.
78 ********************************************************************* */
80 #if defined(_CFE_) && defined(__MIPSEB)
81 #define BSWAP32(x) __swap32(x)
82 static inline uint32_t __swap32(uint32_t x)
84 uint32_t y;
86 y = ((x & 0xFF) << 24) |
87 ((x & 0xFF00) << 8) |
88 ((x & 0xFF0000) >> 8) |
89 ((x & 0xFF000000) >> 24);
91 return y;
93 #else
94 #define BSWAP32(x) (x)
95 #endif
98 #ifndef _CFE_
99 extern uint32_t vtop(void *ptr);
100 extern void *ptov(uint32_t x);
101 #define OHCI_VTOP(ptr) vtop(ptr)
102 #define OHCI_PTOV(ptr) ptov(ptr)
103 #define OHCI_WRITECSR(softc,x,y) \
104 *((volatile uint32_t *) ((softc)->ohci_regs + ((x)/sizeof(uint32_t)))) = (y)
105 #define OHCI_READCSR(softc,x) \
106 *((volatile uint32_t *) ((softc)->ohci_regs + ((x)/sizeof(uint32_t))))
107 #else
108 #define OHCI_VTOP(ptr) ((uint32_t)PHYSADDR((long)(ptr)))
110 #if CPUCFG_COHERENT_DMA
111 #define OHCI_PTOV(ptr) ((void *)(KERNADDR(ptr)))
112 #else
113 #define OHCI_PTOV(ptr) ((void *)(UNCADDR(ptr)))
114 #endif
116 #define OHCI_WRITECSR(softc,x,y) \
117 phys_write32(((softc)->ohci_regs + (x)),(y))
118 #define OHCI_READCSR(softc,x) \
119 phys_read32(((softc)->ohci_regs + (x)))
120 #endif
122 #if CPUCFG_COHERENT_DMA
123 #define OHCI_INVAL_RANGE(s,l)
124 #define OHCI_FLUSH_RANGE(s,l)
125 #else /* not coherent */
126 #define CFE_CACHE_INVAL_RANGE 32
127 #define CFE_CACHE_FLUSH_RANGE 64
128 extern void _cfe_flushcache(int,uint8_t *,uint8_t *);
129 #define OHCI_INVAL_RANGE(s,l) _cfe_flushcache(CFE_CACHE_INVAL_RANGE,((uint8_t *) (s)),((uint8_t *) (s))+(l))
130 #define OHCI_FLUSH_RANGE(s,l) _cfe_flushcache(CFE_CACHE_FLUSH_RANGE,((uint8_t *) (s)),((uint8_t *) (s))+(l))
131 #endif
134 /* *********************************************************************
135 * Bit-reverse table - this table consists of the numbers
136 * at its index, listed in reverse. So, the reverse of 0000 0010
137 * is 0100 0000.
138 ********************************************************************* */
140 const static int ohci_revbits[OHCI_INTTABLE_SIZE] = {
141 0x00, 0x10, 0x08, 0x18, 0x04, 0x14, 0x0c, 0x1c,
142 0x02, 0x12, 0x0a, 0x1a, 0x06, 0x16, 0x0e, 0x1e,
143 0x01, 0x11, 0x09, 0x19, 0x05, 0x15, 0x0d, 0x1d,
144 0x03, 0x13, 0x0b, 0x1b, 0x07, 0x17, 0x0f, 0x1f
148 /* *********************************************************************
149 * Macros to convert from "hardware" endpoint and transfer
150 * descriptors (ohci_ed_t, ohci_td_t) to "software"
151 * data structures (ohci_transfer_t, ohci_endpoint_t).
153 * Basically, there are two tables, indexed by the same value
154 * By subtracting the base of one pool from a pointer, we get
155 * the index into the other table.
157 * We *could* have included the ed and td in the software
158 * data structures, but placing all the hardware stuff in one
159 * pool will make it easier for hardware that does not handle
160 * coherent DMA, since we can be less careful about what we flush
161 * and what we invalidate.
162 ********************************************************************* */
164 #define ohci_td_from_transfer(softc,transfer) \
165 ((softc)->ohci_hwtdpool + ((transfer) - (softc)->ohci_transfer_pool))
167 #define ohci_transfer_from_td(softc,td) \
168 ((softc)->ohci_transfer_pool + ((td) - (softc)->ohci_hwtdpool))
170 #define ohci_ed_from_endpoint(softc,endpoint) \
171 ((softc)->ohci_hwedpool + ((endpoint) - (softc)->ohci_endpoint_pool))
173 #define ohci_endpoint_from_ed(softc,ed) \
174 ((softc)->ohci_endpoint_pool + ((ed) - (softc)->ohci_hwedpool))
176 /* *********************************************************************
177 * Forward declarations
178 ********************************************************************* */
180 static int ohci_roothub_xfer(usbbus_t *bus,usb_ept_t *uept,usbreq_t *ur);
181 static void ohci_roothub_statchg(ohci_softc_t *softc);
182 extern usb_hcdrv_t ohci_driver;
184 /* *********************************************************************
185 * Globals
186 ********************************************************************* */
188 int ohcidebug = 0;
189 void ohci_dumprhstat(uint32_t reg);
190 void ohci_dumpportstat(int idx,uint32_t reg);
191 void ohci_dumptd(ohci_td_t *td);
192 void ohci_dumptdchain(ohci_td_t *td);
193 void ohci_dumped(ohci_ed_t *ed);
194 void ohci_dumpedchain(ohci_ed_t *ed);
197 /* *********************************************************************
198 * Some debug routines
199 ********************************************************************* */
201 void ohci_dumprhstat(uint32_t reg)
203 printf("HubStatus: %08X ",reg);
205 if (reg & M_OHCI_RHSTATUS_LPS) printf("LocalPowerStatus ");
206 if (reg & M_OHCI_RHSTATUS_OCI) printf("OverCurrent ");
207 if (reg & M_OHCI_RHSTATUS_DRWE) printf("DeviceRemoteWakeupEnable ");
208 if (reg & M_OHCI_RHSTATUS_LPSC) printf("LocalPowerStatusChange ");
209 if (reg & M_OHCI_RHSTATUS_OCIC) printf("OverCurrentIndicatorChange ");
210 printf("\n");
214 void ohci_dumpportstat(int idx,uint32_t reg)
216 printf("Port %d: %08X ",idx,reg);
217 if (reg & M_OHCI_RHPORTSTAT_CCS) printf("Connected ");
218 if (reg & M_OHCI_RHPORTSTAT_PES) printf("PortEnabled ");
219 if (reg & M_OHCI_RHPORTSTAT_PSS) printf("PortSuspended ");
220 if (reg & M_OHCI_RHPORTSTAT_POCI) printf("PortOverCurrent ");
221 if (reg & M_OHCI_RHPORTSTAT_PRS) printf("PortReset ");
222 if (reg & M_OHCI_RHPORTSTAT_PPS) printf("PortPowered ");
223 if (reg & M_OHCI_RHPORTSTAT_LSDA) printf("LowSpeed ");
224 if (reg & M_OHCI_RHPORTSTAT_CSC) printf("ConnectStatusChange ");
225 if (reg & M_OHCI_RHPORTSTAT_PESC) printf("PortEnableStatusChange ");
226 if (reg & M_OHCI_RHPORTSTAT_PSSC) printf("PortSuspendStatusChange ");
227 if (reg & M_OHCI_RHPORTSTAT_OCIC) printf("OverCurrentIndicatorChange ");
228 if (reg & M_OHCI_RHPORTSTAT_PRSC) printf("PortResetStatusChange ");
229 printf("\n");
232 void ohci_dumptd(ohci_td_t *td)
234 uint32_t ctl;
235 static char *pids[4] = {"SETUP","OUT","IN","RSVD"};
237 ctl = BSWAP32(td->td_control);
239 printf("[%08X] ctl=%08X (DP=%s,DI=%d,T=%d,EC=%d,CC=%d%s) cbp=%08X be=%08X next=%08X\n",
240 OHCI_VTOP(td),
241 ctl,
242 pids[G_OHCI_TD_PID(ctl)],
243 G_OHCI_TD_DI(ctl),
244 G_OHCI_TD_DT(ctl),
245 G_OHCI_TD_EC(ctl),
246 G_OHCI_TD_CC(ctl),
247 (ctl & M_OHCI_TD_SHORTOK) ? ",R" : "",
248 BSWAP32(td->td_cbp),
249 BSWAP32(td->td_be),
250 BSWAP32(td->td_next_td));
253 void ohci_dumptdchain(ohci_td_t *td)
255 int idx = 0;
256 for (;;) {
257 printf("%d:[%08X] ctl=%08X cbp=%08X be=%08X next=%08X\n",
258 idx,
259 OHCI_VTOP(td),
260 BSWAP32(td->td_control),
261 BSWAP32(td->td_cbp),
262 BSWAP32(td->td_be),
263 BSWAP32(td->td_next_td));
264 if (!td->td_next_td) break;
265 td = (ohci_td_t *) OHCI_PTOV(BSWAP32(td->td_next_td));
266 idx++;
270 void ohci_dumped(ohci_ed_t *ed)
272 uint32_t ctl;
273 static char *pids[4] = {"FTD","OUT","IN","FTD"};
275 ctl = BSWAP32(ed->ed_control),
277 printf("[%08X] Ctl=%08X (MPS=%d%s%s%s,EN=%d,FA=%d,D=%s) Tailp=%08X headp=%08X next=%08X %s\n",
278 OHCI_VTOP(ed),
279 ctl,
280 G_OHCI_ED_MPS(ctl),
281 (ctl & M_OHCI_ED_LOWSPEED) ? ",LS" : "",
282 (ctl & M_OHCI_ED_SKIP) ? ",SKIP" : "",
283 (ctl & M_OHCI_ED_ISOCFMT) ? ",ISOC" : "",
284 G_OHCI_ED_EN(ctl),
285 G_OHCI_ED_FA(ctl),
286 pids[G_OHCI_ED_DIR(ctl)],
287 BSWAP32(ed->ed_tailp),
288 BSWAP32(ed->ed_headp),
289 BSWAP32(ed->ed_next_ed),
290 BSWAP32(ed->ed_headp) & M_OHCI_ED_HALT ? "HALT" : "");
291 if ((ed->ed_headp & M_OHCI_ED_PTRMASK) == 0) return;
292 ohci_dumptdchain(OHCI_PTOV(BSWAP32(ed->ed_headp) & M_OHCI_ED_PTRMASK));
295 void ohci_dumpedchain(ohci_ed_t *ed)
297 int idx = 0;
298 for (;;) {
299 printf("---\nED#%d -> ",idx);
300 ohci_dumped(ed);
301 if (!ed->ed_next_ed) break;
302 if (idx > 50) break;
303 ed = (ohci_ed_t *) OHCI_PTOV(BSWAP32(ed->ed_next_ed));
304 idx++;
309 static void eptstats(ohci_softc_t *softc)
311 int cnt;
312 ohci_endpoint_t *e;
313 cnt = 0;
315 e = softc->ohci_endpoint_freelist;
316 while (e) { e = e->ep_next; cnt++; }
317 printf("%d left, %d inuse\n",cnt,OHCI_EDPOOL_SIZE-cnt);
320 /* *********************************************************************
321 * _ohci_allocept(softc)
323 * Allocate an endpoint data structure from the pool, and
324 * make it ready for use. The endpoint is NOT attached to
325 * the hardware at this time.
327 * Input parameters:
328 * softc - our OHCI controller
330 * Return value:
331 * pointer to endpoint or NULL
332 ********************************************************************* */
334 static ohci_endpoint_t *_ohci_allocept(ohci_softc_t *softc)
336 ohci_endpoint_t *e;
337 ohci_ed_t *ed;
339 if (ohcidebug > 2) {
340 printf("AllocEpt: ");eptstats(softc);
343 e = softc->ohci_endpoint_freelist;
345 if (!e) {
346 printf("No endpoints left!\n");
347 return NULL;
350 softc->ohci_endpoint_freelist = e->ep_next;
352 ed = ohci_ed_from_endpoint(softc,e);
354 ed->ed_control = BSWAP32(M_OHCI_ED_SKIP);
355 ed->ed_tailp = BSWAP32(0);
356 ed->ed_headp = BSWAP32(0);
357 ed->ed_next_ed = BSWAP32(0);
359 e->ep_phys = OHCI_VTOP(ed);
360 e->ep_next = NULL;
362 return e;
365 /* *********************************************************************
366 * _ohci_allocxfer(softc)
368 * Allocate a transfer descriptor. It is prepared for use
369 * but not attached to the hardware.
371 * Input parameters:
372 * softc - our OHCI controller
374 * Return value:
375 * transfer descriptor, or NULL
376 ********************************************************************* */
378 static ohci_transfer_t *_ohci_allocxfer(ohci_softc_t *softc)
380 ohci_transfer_t *t;
381 ohci_td_t *td;
383 if (ohcidebug > 2) {
384 int cnt;
385 cnt = 0;
386 t = softc->ohci_transfer_freelist;
387 while (t) { t = t->t_next; cnt++; }
388 printf("AllocXfer: %d left, %d inuse\n",cnt,OHCI_TDPOOL_SIZE-cnt);
391 t = softc->ohci_transfer_freelist;
393 if (!t) {
394 printf("No more transfer descriptors!\n");
395 return NULL;
398 softc->ohci_transfer_freelist = t->t_next;
400 td = ohci_td_from_transfer(softc,t);
402 td->td_control = BSWAP32(0);
403 td->td_cbp = BSWAP32(0);
404 td->td_next_td = BSWAP32(0);
405 td->td_be = BSWAP32(0);
407 t->t_ref = NULL;
408 t->t_next = NULL;
410 return t;
413 /* *********************************************************************
414 * _ohci_freeept(softc,e)
416 * Free an endpoint, returning it to the pool.
418 * Input parameters:
419 * softc - our OHCI controller
420 * e - endpoint descriptor to return
422 * Return value:
423 * nothing
424 ********************************************************************* */
426 static void _ohci_freeept(ohci_softc_t *softc,ohci_endpoint_t *e)
428 if (ohcidebug > 2) {
429 int cnt;
430 ohci_endpoint_t *ee;
431 cnt = 0;
432 ee = softc->ohci_endpoint_freelist;
433 while (ee) { ee = ee->ep_next; cnt++; }
434 printf("FreeEpt[%p]: %d left, %d inuse\n",e,cnt,OHCI_EDPOOL_SIZE-cnt);
437 e->ep_next = softc->ohci_endpoint_freelist;
438 softc->ohci_endpoint_freelist = e;
441 /* *********************************************************************
442 * _ohci_freexfer(softc,t)
444 * Free a transfer descriptor, returning it to the pool.
446 * Input parameters:
447 * softc - our OHCI controller
448 * t - transfer descriptor to return
450 * Return value:
451 * nothing
452 ********************************************************************* */
454 static void _ohci_freexfer(ohci_softc_t *softc,ohci_transfer_t *t)
456 t->t_next = softc->ohci_transfer_freelist;
457 softc->ohci_transfer_freelist = t;
460 /* *********************************************************************
461 * _ohci_initpools(softc)
463 * Allocate and initialize the various pools of things that
464 * we use in the OHCI driver. We do this by allocating some
465 * big chunks from the heap and carving them up.
467 * Input parameters:
468 * softc - our OHCI controller
470 * Return value:
471 * 0 if ok
472 * else error code
473 ********************************************************************* */
475 static int _ohci_initpools(ohci_softc_t *softc)
477 int idx;
480 * Do the transfer descriptor pool
483 softc->ohci_transfer_pool = KMALLOC(OHCI_TDPOOL_SIZE*sizeof(ohci_transfer_t),0);
484 softc->ohci_hwtdpool = KMALLOC(OHCI_TDPOOL_SIZE*sizeof(ohci_td_t),OHCI_TD_ALIGN);
487 * In the case of noncoherent DMA, make these uncached addresses.
488 * This way all our descriptors will be uncached. Makes life easier, as we
489 * do not need to worry about flushing descriptors, etc.
492 #if !CPUCFG_COHERENT_DMA
493 softc->ohci_hwtdpool = (void *) UNCADDR(PHYSADDR((uint32_t)(softc->ohci_hwtdpool)));
494 #endif
496 if (!softc->ohci_transfer_pool || !softc->ohci_hwtdpool) {
497 printf("Could not allocate transfer descriptors\n");
498 return -1;
501 softc->ohci_transfer_freelist = NULL;
503 for (idx = 0; idx < OHCI_TDPOOL_SIZE; idx++) {
504 _ohci_freexfer(softc,softc->ohci_transfer_pool+idx);
508 * Do the endpoint descriptor pool
511 softc->ohci_endpoint_pool = KMALLOC(OHCI_EDPOOL_SIZE*sizeof(ohci_endpoint_t),0);
513 softc->ohci_hwedpool = KMALLOC(OHCI_EDPOOL_SIZE*sizeof(ohci_ed_t),OHCI_ED_ALIGN);
515 #if !CPUCFG_COHERENT_DMA
516 softc->ohci_hwedpool = (void *) UNCADDR(PHYSADDR((uint32_t)(softc->ohci_hwedpool)));
517 #endif
519 if (!softc->ohci_endpoint_pool || !softc->ohci_hwedpool) {
520 printf("Could not allocate transfer descriptors\n");
521 return -1;
524 softc->ohci_endpoint_freelist = NULL;
526 for (idx = 0; idx < OHCI_EDPOOL_SIZE; idx++) {
527 _ohci_freeept(softc,softc->ohci_endpoint_pool+idx);
531 * Finally the host communications area
534 softc->ohci_hcca = KMALLOC(sizeof(ohci_hcca_t),sizeof(ohci_hcca_t));
536 #if !CPUCFG_COHERENT_DMA
537 softc->ohci_hcca = (void *) UNCADDR(PHYSADDR((uint32_t)(softc->ohci_hcca)));
538 #endif
540 memset(softc->ohci_hcca,0,sizeof(ohci_hcca_t));
542 return 0;
546 /* *********************************************************************
547 * ohci_start(bus)
549 * Start the OHCI controller. After this routine is called,
550 * the hardware will be operational and ready to accept
551 * descriptors and interrupt calls.
553 * Input parameters:
554 * bus - bus structure, from ohci_create
556 * Return value:
557 * 0 if ok
558 * else error code
559 ********************************************************************* */
561 static int ohci_start(usbbus_t *bus)
563 ohci_softc_t *softc = (ohci_softc_t *) bus->ub_hwsoftc;
564 uint32_t frameint;
565 uint32_t reg;
566 int idx;
569 * Force a reset to the controller, followed by a short delay
572 OHCI_WRITECSR(softc,R_OHCI_CONTROL,V_OHCI_CONTROL_HCFS(K_OHCI_HCFS_RESET));
573 usb_delay_ms(bus,OHCI_RESET_DELAY);
575 /* Host controller state is now "RESET" */
578 * We need the frame interval later, so get a copy of it now.
580 frameint = G_OHCI_FMINTERVAL_FI(OHCI_READCSR(softc,R_OHCI_FMINTERVAL));
583 * Reset the host controller. When you set the HCR bit
584 * if self-clears when the reset is complete.
587 OHCI_WRITECSR(softc,R_OHCI_CMDSTATUS,M_OHCI_CMDSTATUS_HCR);
588 for (idx = 0; idx < 10000; idx++) {
589 if (!(OHCI_READCSR(softc,R_OHCI_CMDSTATUS) & M_OHCI_CMDSTATUS_HCR)) break;
592 if (OHCI_READCSR(softc,R_OHCI_CMDSTATUS) & M_OHCI_CMDSTATUS_HCR) {
593 /* controller never came out of reset */
594 return -1;
598 * Host controller state is now "SUSPEND". We must exit
599 * from this state within 2ms. (5.1.1.4)
601 * Set up pointers to data structures.
604 OHCI_WRITECSR(softc,R_OHCI_HCCA,OHCI_VTOP(softc->ohci_hcca));
605 OHCI_WRITECSR(softc,R_OHCI_CONTROLHEADED,softc->ohci_ctl_list->ep_phys);
606 OHCI_WRITECSR(softc,R_OHCI_BULKHEADED,softc->ohci_bulk_list->ep_phys);
609 * Our driver is polled, turn off interrupts
612 OHCI_WRITECSR(softc,R_OHCI_INTDISABLE,M_OHCI_INT_ALL);
615 * Set up the control register.
618 reg = OHCI_READCSR(softc,R_OHCI_CONTROL);
620 reg = M_OHCI_CONTROL_PLE | M_OHCI_CONTROL_CLE | M_OHCI_CONTROL_BLE |
621 M_OHCI_CONTROL_IE |
622 V_OHCI_CONTROL_CBSR(K_OHCI_CBSR_41) |
623 V_OHCI_CONTROL_HCFS(K_OHCI_HCFS_OPERATIONAL);
625 OHCI_WRITECSR(softc,R_OHCI_CONTROL,reg);
629 * controller state is now OPERATIONAL
632 reg = OHCI_READCSR(softc,R_OHCI_FMINTERVAL);
633 reg &= M_OHCI_FMINTERVAL_FIT;
634 reg ^= M_OHCI_FMINTERVAL_FIT;
635 reg |= V_OHCI_FMINTERVAL_FSMPS(OHCI_CALC_FSMPS(frameint)) |
636 V_OHCI_FMINTERVAL_FI(frameint);
637 OHCI_WRITECSR(softc,R_OHCI_FMINTERVAL,reg);
639 reg = frameint * 9 / 10; /* calculate 90% */
640 OHCI_WRITECSR(softc,R_OHCI_PERIODICSTART,reg);
642 usb_delay_ms(softc->ohci_bus,10);
645 * Remember how many ports we have
648 reg = OHCI_READCSR(softc,R_OHCI_RHDSCRA);
649 softc->ohci_ndp = G_OHCI_RHDSCRA_NDP(reg);
653 * Enable port power
656 OHCI_WRITECSR(softc,R_OHCI_RHSTATUS,M_OHCI_RHSTATUS_LPSC);
657 usb_delay_ms(softc->ohci_bus,10);
659 return 0;
663 /* *********************************************************************
664 * _ohci_setupepts(softc)
666 * Set up the endpoint tree, as described in the OHCI manual.
667 * Basically the hardware knows how to scan lists of lists,
668 * so we build a tree where each level is pointed to by two
669 * parent nodes. We can choose our scanning rate by attaching
670 * endpoints anywhere within this tree.
672 * Input parameters:
673 * softc - our OHCI controller
675 * Return value:
676 * 0 if ok
677 * else error (out of descriptors)
678 ********************************************************************* */
680 static int _ohci_setupepts(ohci_softc_t *softc)
682 int idx;
683 ohci_endpoint_t *e;
684 ohci_ed_t *ed;
685 ohci_endpoint_t *child;
688 * Set up the list heads for the isochronous, control,
689 * and bulk transfer lists. They don't get the same "tree"
690 * treatment that the interrupt devices get.
692 * For the purposes of CFE, it's probably not necessary
693 * to be this fancy. The only device we're planning to
694 * talk to is the keyboard and some hubs, which should
695 * have pretty minimal requirements. It's conceivable
696 * that this firmware may find a new home in other
697 * devices, so we'll meet halfway and do some things
698 * "fancy."
701 softc->ohci_isoc_list = _ohci_allocept(softc);
702 softc->ohci_ctl_list = _ohci_allocept(softc);
703 softc->ohci_bulk_list = _ohci_allocept(softc);
706 * Set up a tree of empty endpoint descriptors. This is
707 * tree is scanned by the hardware from the leaves up to
708 * the root. Once a millisecond, the hardware picks the
709 * next leaf and starts scanning descriptors looking
710 * for something to do. It traverses all of the endpoints
711 * along the way until it gets to the root.
713 * The idea here is if you put a transfer descriptor on the
714 * root node, the hardware will see it every millisecond,
715 * since the root will be examined each time. If you
716 * put the TD on the leaf, it will be 1/32 millisecond.
717 * The tree therefore is six levels deep.
720 for (idx = 0; idx < OHCI_INTTREE_SIZE; idx++) {
721 e = _ohci_allocept(softc); /* allocated with sKip bit set */
722 softc->ohci_edtable[idx] = e;
723 child = (idx == 0) ? softc->ohci_isoc_list : softc->ohci_edtable[(idx-1)/2];
724 ed = ohci_ed_from_endpoint(softc,e);
725 ed->ed_next_ed = BSWAP32(child->ep_phys);
726 e->ep_next = child;
730 * We maintain both physical and virtual copies of the interrupt
731 * table (leaves of the tree).
734 for (idx = 0; idx < OHCI_INTTABLE_SIZE; idx++) {
735 child = softc->ohci_edtable[OHCI_INTTREE_SIZE-OHCI_INTTABLE_SIZE+idx];
736 softc->ohci_inttable[ohci_revbits[idx]] = child;
737 softc->ohci_hcca->hcca_inttable[ohci_revbits[idx]] = BSWAP32(child->ep_phys);
741 * Okay, at this point the tree is built.
743 return 0;
746 /* *********************************************************************
747 * ohci_stop(bus)
749 * Stop the OHCI hardware.
751 * Input parameters:
752 * bus - our bus structure
754 * Return value:
755 * nothing
756 ********************************************************************* */
758 static void ohci_stop(usbbus_t *bus)
760 ohci_softc_t *softc = (ohci_softc_t *) bus->ub_hwsoftc;
762 OHCI_WRITECSR(softc,R_OHCI_CONTROL,V_OHCI_CONTROL_HCFS(K_OHCI_HCFS_RESET));
766 /* *********************************************************************
767 * _ohci_queueept(softc,queue,e)
769 * Add an endpoint to a list of endpoints. This routine
770 * does things in a particular way according to the OHCI
771 * spec so we can add endpoints while the hardware is running.
773 * Input parameters:
774 * queue - endpoint descriptor for head of queue
775 * e - endpoint to add to queue
777 * Return value:
778 * nothing
779 ********************************************************************* */
781 static void _ohci_queueept(ohci_softc_t *softc,ohci_endpoint_t *queue,ohci_endpoint_t *newept)
783 ohci_ed_t *qed;
784 ohci_ed_t *newed;
786 qed = ohci_ed_from_endpoint(softc,queue);
787 newed = ohci_ed_from_endpoint(softc,newept);
789 newept->ep_next = queue->ep_next;
790 newed->ed_next_ed = qed->ed_next_ed;
792 queue->ep_next = newept;
793 qed->ed_next_ed = BSWAP32(newept->ep_phys);
795 if (ohcidebug > 1) ohci_dumped(newed);
799 /* *********************************************************************
800 * _ohci_deqept(queue,e)
802 * Remove and endpoint from the list of endpoints. This
803 * routine does things in a particular way according to
804 * the OHCI specification, since we are operating on
805 * a running list.
807 * Input parameters:
808 * queue - base of queue to look for endpoint on
809 * e - endpoint to remove
811 * Return value:
812 * nothing
813 ********************************************************************* */
815 static void _ohci_deqept(ohci_softc_t *softc,ohci_endpoint_t *queue,ohci_endpoint_t *e)
817 ohci_endpoint_t *cur;
818 ohci_ed_t *cured;
819 ohci_ed_t *ed;
821 cur = queue;
823 while (cur && (cur->ep_next != e)) cur = cur->ep_next;
825 if (cur == NULL) {
826 printf("Could not remove EP %08X: not on the list!\n",(uint32_t) (intptr_t)e);
827 return;
831 * Remove from our regular list
834 cur->ep_next = e->ep_next;
837 * now remove from the hardware's list
840 cured = ohci_ed_from_endpoint(softc,cur);
841 ed = ohci_ed_from_endpoint(softc,e);
843 cured->ed_next_ed = ed->ed_next_ed;
847 /* *********************************************************************
848 * ohci_intr_procdoneq(softc)
850 * Process the "done" queue for this ohci controller. As
851 * descriptors are retired, the hardware links them to the
852 * "done" queue so we can examine the results.
854 * Input parameters:
855 * softc - our OHCI controller
857 * Return value:
858 * nothing
859 ********************************************************************* */
861 static void ohci_intr_procdoneq(ohci_softc_t *softc)
863 uint32_t doneq;
864 ohci_transfer_t *transfer;
865 ohci_td_t *td;
866 int val;
867 usbreq_t *ur;
870 * Get the head of the queue
873 doneq = softc->ohci_hcca->hcca_donehead;
874 doneq = BSWAP32(doneq);
876 td = (ohci_td_t *) OHCI_PTOV(doneq);
877 transfer = ohci_transfer_from_td(softc,td);
880 * Process all elements from the queue
883 while (doneq) {
885 ohci_ed_t *ed;
886 ohci_endpoint_t *ept;
887 usbreq_t *xur = transfer->t_ref;
889 if (ohcidebug > 1) {
890 if (xur) {
891 ept = (ohci_endpoint_t *) xur->ur_pipe->up_hwendpoint;
892 ed = ohci_ed_from_endpoint(softc,ept);
893 // printf("ProcDoneQ:ED [%08X] -> ",ept->ep_phys);
894 // ohci_dumped(ed);
899 * Get the pointer to next one before freeing this one
902 if (ohcidebug > 1) {
903 ur = transfer->t_ref;
904 printf("Done(%d): ",ur ? ur->ur_tdcount : -1);
905 ohci_dumptd(td);
908 doneq = BSWAP32(td->td_next_td);
910 val = G_OHCI_TD_CC(BSWAP32(td->td_control));
912 if (val != 0) printf("[Transfer error: %d]\n",val);
915 * See if it's time to call the callback.
917 ur = transfer->t_ref;
918 if (ur) {
919 ur->ur_status = val;
920 ur->ur_tdcount--;
921 if (BSWAP32(td->td_cbp) == 0) {
922 ur->ur_xferred += transfer->t_length;
924 else {
925 ur->ur_xferred += transfer->t_length -
926 (BSWAP32(td->td_be) - BSWAP32(td->td_cbp) + 1);
928 if (ur->ur_tdcount == 0) {
929 /* Noncoherent DMA: need to invalidate, since data is in phys mem */
930 OHCI_INVAL_RANGE(ur->ur_buffer,ur->ur_xferred);
931 usb_complete_request(ur,val);
937 * Free up the request
939 _ohci_freexfer(softc,transfer);
943 * Advance to the next request.
946 td = (ohci_td_t *) OHCI_PTOV(doneq);
947 transfer = ohci_transfer_from_td(softc,td);
952 /* *********************************************************************
953 * ohci_intr(bus)
955 * Process pending interrupts for the OHCI controller.
957 * Input parameters:
958 * bus - our bus structure
960 * Return value:
961 * 0 if we did nothing
962 * nonzero if we did something.
963 ********************************************************************* */
965 static int ohci_intr(usbbus_t *bus)
967 uint32_t reg;
968 ohci_softc_t *softc = (ohci_softc_t *) bus->ub_hwsoftc;
971 * Read the interrupt status register.
974 reg = OHCI_READCSR(softc,R_OHCI_INTSTATUS);
977 * Don't bother doing anything if nothing happened.
979 if (reg == 0) {
980 return 0;
983 /* Scheduling Overruns */
984 if (reg & M_OHCI_INT_SO) {
985 printf("SchedOverrun\n");
988 /* Done Queue */
989 if (reg & M_OHCI_INT_WDH) {
990 /* printf("DoneQueue\n"); */
991 ohci_intr_procdoneq(softc);
994 /* Start of Frame */
995 if (reg & M_OHCI_INT_SF) {
996 /* don't be noisy about this */
999 /* Resume Detect */
1000 if (reg & M_OHCI_INT_RD) {
1001 printf("ResumeDetect\n");
1004 /* Unrecoverable errors */
1005 if (reg & M_OHCI_INT_UE) {
1006 printf("UnrecoverableError\n");
1009 /* Frame number overflow */
1010 if (reg & M_OHCI_INT_FNO) {
1011 /*printf("FrameNumberOverflow\n"); */
1014 /* Root Hub Status Change */
1015 if ((reg & ~softc->ohci_intdisable) & M_OHCI_INT_RHSC) {
1016 uint32_t reg;
1017 if (ohcidebug > 0) {
1018 printf("RootHubStatusChange: ");
1019 reg = OHCI_READCSR(softc,R_OHCI_RHSTATUS);
1020 ohci_dumprhstat(reg);
1021 reg = OHCI_READCSR(softc,R_OHCI_RHPORTSTATUS(1));
1022 ohci_dumpportstat(1,reg);
1023 reg = OHCI_READCSR(softc,R_OHCI_RHPORTSTATUS(2));
1024 ohci_dumpportstat(2,reg);
1026 ohci_roothub_statchg(softc);
1029 /* Ownership Change */
1030 if (reg & M_OHCI_INT_OC) {
1031 printf("OwnershipChange\n");
1035 * Write the value back to the interrupt
1036 * register to clear the bits that were set.
1039 OHCI_WRITECSR(softc,R_OHCI_INTSTATUS,reg);
1041 return 1;
1045 /* *********************************************************************
1046 * ohci_delete(bus)
1048 * Remove an OHCI bus structure and all resources allocated to
1049 * it (used when shutting down USB)
1051 * Input parameters:
1052 * bus - our USB bus structure
1054 * Return value:
1055 * nothing
1056 ********************************************************************* */
1058 static void ohci_delete(usbbus_t *bus)
1063 /* *********************************************************************
1064 * ohci_create(addr)
1066 * Create a USB bus structure and associate it with our OHCI
1067 * controller device.
1069 * Input parameters:
1070 * addr - physical address of controller
1072 * Return value:
1073 * usbbus structure pointer
1074 ********************************************************************* */
1076 static usbbus_t *ohci_create(physaddr_t addr)
1078 int res;
1079 ohci_softc_t *softc;
1080 usbbus_t *bus;
1082 softc = KMALLOC(sizeof(ohci_softc_t),0);
1083 if (!softc) return NULL;
1085 bus = KMALLOC(sizeof(usbbus_t),0);
1086 if (!bus) return NULL;
1088 memset(softc,0,sizeof(ohci_softc_t));
1089 memset(bus,0,sizeof(usbbus_t));
1091 bus->ub_hwsoftc = (usb_hc_t *) softc;
1092 bus->ub_hwdisp = &ohci_driver;
1094 q_init(&(softc->ohci_rh_intrq));
1096 #ifdef _CFE_
1097 softc->ohci_regs = addr;
1098 #else
1099 softc->ohci_regs = (volatile uint32_t *) addr;
1100 #endif
1102 softc->ohci_rh_newaddr = -1;
1103 softc->ohci_bus = bus;
1105 if ((res = _ohci_initpools(softc)) != 0) goto error;
1106 if ((res = _ohci_setupepts(softc)) != 0) goto error;
1108 OHCI_WRITECSR(softc,R_OHCI_CONTROL,V_OHCI_CONTROL_HCFS(K_OHCI_HCFS_RESET));
1110 return bus;
1112 error:
1113 KFREE(softc);
1114 return NULL;
1118 /* *********************************************************************
1119 * ohci_ept_create(bus,usbaddr,eptnum,mps,flags)
1121 * Create a hardware endpoint structure and attach it to
1122 * the hardware's endpoint list. The hardware manages lists
1123 * of queues, and this routine adds a new queue to the appropriate
1124 * list of queues for the endpoint in question. It roughly
1125 * corresponds to the information in the OHCI specification.
1127 * Input parameters:
1128 * bus - the USB bus we're dealing with
1129 * usbaddr - USB address (0 means default address)
1130 * eptnum - the endpoint number
1131 * mps - the packet size for this endpoint
1132 * flags - various flags to control endpoint creation
1134 * Return value:
1135 * endpoint structure poihter, or NULL
1136 ********************************************************************* */
1138 static usb_ept_t *ohci_ept_create(usbbus_t *bus,
1139 int usbaddr,
1140 int eptnum,
1141 int mps,
1142 int flags)
1144 uint32_t eptflags;
1145 ohci_endpoint_t *ept;
1146 ohci_ed_t *ed;
1147 ohci_transfer_t *tailtransfer;
1148 ohci_td_t *tailtd;
1149 ohci_softc_t *softc = (ohci_softc_t *) bus->ub_hwsoftc;
1151 ept = _ohci_allocept(softc);
1152 ed = ohci_ed_from_endpoint(softc,ept);
1154 tailtransfer = _ohci_allocxfer(softc);
1155 tailtd = ohci_td_from_transfer(softc,tailtransfer);
1158 * Set up functional address, endpoint number, and packet size
1161 eptflags = V_OHCI_ED_FA(usbaddr) |
1162 V_OHCI_ED_EN(eptnum) |
1163 V_OHCI_ED_MPS(mps) |
1167 * Set up the endpoint type based on the flags
1168 * passed to us
1171 if (flags & UP_TYPE_IN) {
1172 eptflags |= V_OHCI_ED_DIR(K_OHCI_ED_DIR_IN);
1174 else if (flags & UP_TYPE_OUT) {
1175 eptflags |= V_OHCI_ED_DIR(K_OHCI_ED_DIR_OUT);
1177 else {
1178 eptflags |= V_OHCI_ED_DIR(K_OHCI_ED_DIR_FROMTD);
1182 * Don't forget about lowspeed devices.
1185 if (flags & UP_TYPE_LOWSPEED) {
1186 eptflags |= M_OHCI_ED_LOWSPEED;
1189 if (ohcidebug > 0) {
1190 printf("Create endpoint %d addr %d flags %08X mps %d\n",
1191 eptnum,usbaddr,eptflags,mps);
1195 * Transfer this info into the endpoint descriptor.
1196 * No need to flush the cache here, it'll get done when
1197 * we add to the hardware list.
1200 ed->ed_control = BSWAP32(eptflags);
1201 ed->ed_tailp = BSWAP32(OHCI_VTOP(tailtd));
1202 ed->ed_headp = BSWAP32(OHCI_VTOP(tailtd));
1203 ept->ep_flags = flags;
1204 ept->ep_mps = mps;
1205 ept->ep_num = eptnum;
1208 * Put it on the right queue
1211 if (flags & UP_TYPE_CONTROL) {
1212 _ohci_queueept(softc,softc->ohci_ctl_list,ept);
1214 else if (flags & UP_TYPE_BULK) {
1215 _ohci_queueept(softc,softc->ohci_bulk_list,ept);
1217 else if (flags & UP_TYPE_INTR) {
1218 _ohci_queueept(softc,softc->ohci_inttable[0],ept);
1221 return (usb_ept_t *) ept;
1224 /* *********************************************************************
1225 * ohci_ept_setaddr(bus,ept,usbaddr)
1227 * Change the functional address for a USB endpoint. We do this
1228 * when we switch the device's state from DEFAULT to ADDRESSED
1229 * and we've already got the default pipe open. This
1230 * routine mucks with the descriptor and changes its address
1231 * bits.
1233 * Input parameters:
1234 * bus - usb bus structure
1235 * ept - an open endpoint descriptor
1236 * usbaddr - new address for this endpoint
1238 * Return value:
1239 * nothing
1240 ********************************************************************* */
1242 static void ohci_ept_setaddr(usbbus_t *bus,usb_ept_t *uept,int usbaddr)
1244 uint32_t eptflags;
1245 ohci_endpoint_t *ept = (ohci_endpoint_t *) uept;
1246 ohci_softc_t *softc = (ohci_softc_t *) bus->ub_hwsoftc;
1247 ohci_ed_t *ed = ohci_ed_from_endpoint(softc,ept);
1249 eptflags = BSWAP32(ed->ed_control);
1250 eptflags &= ~M_OHCI_ED_FA;
1251 eptflags |= V_OHCI_ED_FA(usbaddr);
1252 ed->ed_control = BSWAP32(eptflags);
1256 /* *********************************************************************
1257 * ohci_ept_setmps(bus,ept,mps)
1259 * Set the maximum packet size of this endpoint. This is
1260 * normally used during the processing of endpoint 0 (default
1261 * pipe) after we find out how big ep0's packets can be.
1263 * Input parameters:
1264 * bus - our USB bus structure
1265 * ept - endpoint structure
1266 * mps - new packet size
1268 * Return value:
1269 * nothing
1270 ********************************************************************* */
1272 static void ohci_ept_setmps(usbbus_t *bus,usb_ept_t *uept,int mps)
1274 uint32_t eptflags;
1275 ohci_softc_t *softc = (ohci_softc_t *) bus->ub_hwsoftc;
1276 ohci_endpoint_t *ept = (ohci_endpoint_t *) uept;
1277 ohci_ed_t *ed = ohci_ed_from_endpoint(softc,ept);
1279 eptflags = BSWAP32(ed->ed_control);
1280 eptflags &= ~M_OHCI_ED_MPS;
1281 eptflags |= V_OHCI_ED_MPS(mps);
1282 ed->ed_control = BSWAP32(eptflags);
1283 ept->ep_mps = mps;
1287 /* *********************************************************************
1288 * ohci_ept_cleartoggle(bus,ept,mps)
1290 * Clear the data toggle for the specified endpoint.
1292 * Input parameters:
1293 * bus - our USB bus structure
1294 * ept - endpoint structure
1296 * Return value:
1297 * nothing
1298 ********************************************************************* */
1300 static void ohci_ept_cleartoggle(usbbus_t *bus,usb_ept_t *uept)
1302 uint32_t eptflags;
1303 ohci_softc_t *softc = (ohci_softc_t *) bus->ub_hwsoftc;
1304 ohci_endpoint_t *ept = (ohci_endpoint_t *) uept;
1305 ohci_ed_t *ed = ohci_ed_from_endpoint(softc,ept);
1307 eptflags = BSWAP32(ed->ed_headp);
1308 eptflags &= ~(M_OHCI_ED_HALT | M_OHCI_ED_TOGGLECARRY);
1309 ed->ed_headp = BSWAP32(eptflags);
1311 OHCI_WRITECSR(softc,R_OHCI_CMDSTATUS,M_OHCI_CMDSTATUS_CLF);
1314 /* *********************************************************************
1315 * ohci_ept_delete(bus,ept)
1317 * Deletes an endpoint from the OHCI controller. This
1318 * routine also completes pending transfers for the
1319 * endpoint and gets rid of the hardware ept (queue base).
1321 * Input parameters:
1322 * bus - ohci bus structure
1323 * ept - endpoint to remove
1325 * Return value:
1326 * nothing
1327 ********************************************************************* */
1329 static void ohci_ept_delete(usbbus_t *bus,usb_ept_t *uept)
1331 ohci_endpoint_t *queue;
1332 ohci_softc_t *softc = (ohci_softc_t *) bus->ub_hwsoftc;
1333 ohci_endpoint_t *ept = (ohci_endpoint_t *) uept;
1334 ohci_ed_t *ed = ohci_ed_from_endpoint(softc,ept);
1335 uint32_t framenum;
1336 uint32_t tdphys;
1337 usbreq_t *ur;
1338 ohci_td_t *td;
1339 ohci_transfer_t *transfer;
1341 if (ept->ep_flags & UP_TYPE_CONTROL) {
1342 queue = softc->ohci_ctl_list;
1344 else if (ept->ep_flags & UP_TYPE_BULK) {
1345 queue = softc->ohci_bulk_list;
1347 else if (ept->ep_flags & UP_TYPE_INTR) {
1348 queue = softc->ohci_inttable[0];
1350 else {
1351 printf("Invalid endpoint\n");
1352 return;
1357 * Set the SKIP bit on the endpoint and
1358 * wait for two SOFs to guarantee that we're
1359 * not processing this ED anymore.
1362 ((volatile uint32_t) ed->ed_control) |= BSWAP32(M_OHCI_ED_SKIP);
1364 framenum = OHCI_READCSR(softc,R_OHCI_FMNUMBER) & 0xFFFF;
1365 while ((OHCI_READCSR(softc,R_OHCI_FMNUMBER) & 0xFFFF) == framenum) ; /* NULL LOOP */
1367 framenum = OHCI_READCSR(softc,R_OHCI_FMNUMBER) & 0xFFFF;
1368 while ((OHCI_READCSR(softc,R_OHCI_FMNUMBER) & 0xFFFF) == framenum) ; /* NULL LOOP */
1371 * Remove endpoint from queue
1374 _ohci_deqept(softc,queue,ept);
1377 * Free/complete the TDs on the queue
1380 tdphys = BSWAP32(ed->ed_headp) & M_OHCI_ED_PTRMASK;
1382 while (tdphys != BSWAP32(ed->ed_tailp)) {
1383 td = (ohci_td_t *) OHCI_PTOV(tdphys);
1384 tdphys = BSWAP32(td->td_next_td);
1385 transfer = ohci_transfer_from_td(softc,td);
1387 ur = transfer->t_ref;
1388 if (ur) {
1389 ur->ur_status = K_OHCI_CC_CANCELLED;
1390 ur->ur_tdcount--;
1391 if (ur->ur_tdcount == 0) {
1392 if (ohcidebug > 0) printf("Completing request due to closed pipe: %p\n",ur);
1393 usb_complete_request(ur,K_OHCI_CC_CANCELLED);
1397 _ohci_freexfer(softc,transfer);
1401 * tdphys now points at the tail TD. Just free it.
1404 td = (ohci_td_t *) OHCI_PTOV(tdphys);
1405 _ohci_freexfer(softc,ohci_transfer_from_td(softc,td));
1408 * Return endpoint to free pool
1411 _ohci_freeept(softc,ept);
1416 /* *********************************************************************
1417 * ohci_xfer(bus,ept,ur)
1419 * Queue a transfer for the specified endpoint. Depending on
1420 * the transfer type, the transfer may go on one of many queues.
1421 * When the transfer completes, a callback will be called.
1423 * Input parameters:
1424 * bus - bus structure
1425 * ept - endpoint descriptor
1426 * ur - request (includes pointer to user buffer)
1428 * Return value:
1429 * 0 if ok
1430 * else error
1431 ********************************************************************* */
1433 static int ohci_xfer(usbbus_t *bus,usb_ept_t *uept,usbreq_t *ur)
1435 ohci_softc_t *softc = (ohci_softc_t *) bus->ub_hwsoftc;
1436 ohci_endpoint_t *ept = (ohci_endpoint_t *) uept;
1437 ohci_ed_t *ed = ohci_ed_from_endpoint(softc,ept);
1438 ohci_transfer_t *newtailtransfer = 0;
1439 ohci_td_t *newtailtd = NULL;
1440 ohci_transfer_t *curtransfer;
1441 ohci_td_t *curtd;
1442 uint8_t *ptr;
1443 int len;
1444 int amtcopy;
1445 int pktlen;
1446 uint32_t tdcontrol = 0;
1449 * If the destination USB address matches
1450 * the address of the root hub, shunt the request
1451 * over to our root hub emulation.
1454 if (ur->ur_dev->ud_address == softc->ohci_rh_addr) {
1455 return ohci_roothub_xfer(bus,uept,ur);
1459 * Set up the TD flags based on the
1460 * request type.
1463 // pktlen = ept->ep_mps;
1464 pktlen = OHCI_TD_MAX_DATA - 16;
1466 if (ur->ur_flags & UR_FLAG_SETUP) {
1467 tdcontrol = V_OHCI_TD_PID(K_OHCI_TD_SETUP) |
1468 V_OHCI_TD_DT(K_OHCI_TD_DT_DATA0) |
1469 V_OHCI_TD_CC(K_OHCI_CC_NOTACCESSED) |
1470 V_OHCI_TD_DI(1);
1472 else if (ur->ur_flags & UR_FLAG_IN) {
1473 tdcontrol = V_OHCI_TD_PID(K_OHCI_TD_IN) |
1474 V_OHCI_TD_DT(K_OHCI_TD_DT_TCARRY) |
1475 V_OHCI_TD_CC(K_OHCI_CC_NOTACCESSED) |
1476 V_OHCI_TD_DI(1);
1478 else if (ur->ur_flags & UR_FLAG_OUT) {
1479 tdcontrol = V_OHCI_TD_PID(K_OHCI_TD_OUT) |
1480 V_OHCI_TD_DT(K_OHCI_TD_DT_TCARRY) |
1481 V_OHCI_TD_CC(K_OHCI_CC_NOTACCESSED) |
1482 V_OHCI_TD_DI(1);
1484 else if (ur->ur_flags & UR_FLAG_STATUS_OUT) {
1485 tdcontrol = V_OHCI_TD_PID(K_OHCI_TD_OUT) |
1486 V_OHCI_TD_DT(K_OHCI_TD_DT_DATA1) |
1487 V_OHCI_TD_CC(K_OHCI_CC_NOTACCESSED) |
1488 V_OHCI_TD_DI(1);
1490 else if (ur->ur_flags & UR_FLAG_STATUS_IN) {
1491 tdcontrol = V_OHCI_TD_PID(K_OHCI_TD_IN) |
1492 V_OHCI_TD_DT(K_OHCI_TD_DT_DATA1) |
1493 V_OHCI_TD_CC(K_OHCI_CC_NOTACCESSED) |
1494 V_OHCI_TD_DI(1);
1496 else {
1497 printf("Shouldn't happen!\n");
1500 if (ur->ur_flags & UR_FLAG_SHORTOK) {
1501 tdcontrol |= M_OHCI_TD_SHORTOK;
1505 ptr = ur->ur_buffer;
1506 len = ur->ur_length;
1507 ur->ur_tdcount = 0;
1509 if (ohcidebug > 1) {
1510 printf(">> Queueing xfer addr %d pipe %d ED %08X ptr %016llX length %d\n",
1511 ur->ur_dev->ud_address,
1512 ur->ur_pipe->up_num,
1513 ept->ep_phys,
1514 (uint64_t) (uintptr_t) ptr,
1515 len);
1516 // ohci_dumped(ed);
1519 curtd = OHCI_PTOV(BSWAP32(ed->ed_tailp));
1520 curtransfer = ohci_transfer_from_td(softc,curtd);
1522 if (len == 0) {
1523 newtailtransfer = _ohci_allocxfer(softc);
1524 newtailtd = ohci_td_from_transfer(softc,newtailtransfer);
1525 curtd->td_cbp = 0;
1526 curtd->td_be = 0;
1527 curtd->td_next_td = BSWAP32(OHCI_VTOP(newtailtd));
1528 curtd->td_control = BSWAP32(tdcontrol);
1529 curtransfer->t_next = newtailtransfer;
1530 curtransfer->t_ref = ur;
1531 curtransfer->t_length = 0;
1532 if (ohcidebug > 1) { printf("QueueTD: "); ohci_dumptd(curtd); }
1533 ur->ur_tdcount++;
1535 else {
1536 /* Noncoherent DMA: need to flush user buffer to real memory first */
1537 OHCI_FLUSH_RANGE(ptr,len);
1538 while (len > 0) {
1539 amtcopy = len;
1540 if (amtcopy > pktlen) amtcopy = pktlen;
1541 newtailtransfer = _ohci_allocxfer(softc);
1542 newtailtd = ohci_td_from_transfer(softc,newtailtransfer);
1543 curtd->td_cbp = BSWAP32(OHCI_VTOP(ptr));
1544 curtd->td_be = BSWAP32(OHCI_VTOP(ptr+amtcopy)-1);
1545 curtd->td_next_td = BSWAP32(OHCI_VTOP(newtailtd));
1546 curtd->td_control = BSWAP32(tdcontrol);
1547 curtransfer->t_next = newtailtransfer;
1548 curtransfer->t_ref = ur;
1549 curtransfer->t_length = amtcopy;
1550 if (ohcidebug > 1) { printf("QueueTD: "); ohci_dumptd(curtd); }
1551 curtd = newtailtd;
1552 curtransfer = ohci_transfer_from_td(softc,curtd);
1553 ptr += amtcopy;
1554 len -= amtcopy;
1555 ur->ur_tdcount++;
1559 curtd = OHCI_PTOV(BSWAP32(ed->ed_headp & M_OHCI_ED_PTRMASK));
1560 ed->ed_tailp = BSWAP32(OHCI_VTOP(newtailtd));
1563 * Prod the controller depending on what type of list we put
1564 * a TD on.
1567 if (ept->ep_flags & UP_TYPE_BULK) {
1568 OHCI_WRITECSR(softc,R_OHCI_CMDSTATUS,M_OHCI_CMDSTATUS_BLF);
1570 else {
1571 OHCI_WRITECSR(softc,R_OHCI_CMDSTATUS,M_OHCI_CMDSTATUS_CLF);
1574 return 0;
1577 /* *********************************************************************
1578 * Driver structure
1579 ********************************************************************* */
1581 usb_hcdrv_t ohci_driver = {
1582 ohci_create,
1583 ohci_delete,
1584 ohci_start,
1585 ohci_stop,
1586 ohci_intr,
1587 ohci_ept_create,
1588 ohci_ept_delete,
1589 ohci_ept_setmps,
1590 ohci_ept_setaddr,
1591 ohci_ept_cleartoggle,
1592 ohci_xfer
1595 /* *********************************************************************
1596 * Root Hub
1598 * Data structures and functions
1599 ********************************************************************* */
1602 * Data structures and routines to emulate the root hub.
1604 static usb_device_descr_t ohci_root_devdsc = {
1605 sizeof(usb_device_descr_t), /* bLength */
1606 USB_DEVICE_DESCRIPTOR_TYPE, /* bDescriptorType */
1607 USBWORD(0x0100), /* bcdUSB */
1608 USB_DEVICE_CLASS_HUB, /* bDeviceClass */
1609 0, /* bDeviceSubClass */
1610 0, /* bDeviceProtocol */
1611 64, /* bMaxPacketSize0 */
1612 USBWORD(0), /* idVendor */
1613 USBWORD(0), /* idProduct */
1614 USBWORD(0x0100), /* bcdDevice */
1615 1, /* iManufacturer */
1616 2, /* iProduct */
1617 0, /* iSerialNumber */
1618 1 /* bNumConfigurations */
1621 static usb_config_descr_t ohci_root_cfgdsc = {
1622 sizeof(usb_config_descr_t), /* bLength */
1623 USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType */
1624 USBWORD(
1625 sizeof(usb_config_descr_t) +
1626 sizeof(usb_interface_descr_t) +
1627 sizeof(usb_endpoint_descr_t)), /* wTotalLength */
1628 1, /* bNumInterfaces */
1629 1, /* bConfigurationValue */
1630 0, /* iConfiguration */
1631 USB_CONFIG_SELF_POWERED, /* bmAttributes */
1632 0 /* MaxPower */
1635 static usb_interface_descr_t ohci_root_ifdsc = {
1636 sizeof(usb_interface_descr_t), /* bLength */
1637 USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
1638 0, /* bInterfaceNumber */
1639 0, /* bAlternateSetting */
1640 1, /* bNumEndpoints */
1641 USB_INTERFACE_CLASS_HUB, /* bInterfaceClass */
1642 0, /* bInterfaceSubClass */
1643 0, /* bInterfaceProtocol */
1644 0 /* iInterface */
1647 static usb_endpoint_descr_t ohci_root_epdsc = {
1648 sizeof(usb_endpoint_descr_t), /* bLength */
1649 USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */
1650 (USB_ENDPOINT_DIRECTION_IN | 1), /* bEndpointAddress */
1651 USB_ENDPOINT_TYPE_INTERRUPT, /* bmAttributes */
1652 USBWORD(8), /* wMaxPacketSize */
1653 255 /* bInterval */
1656 static usb_hub_descr_t ohci_root_hubdsc = {
1657 USB_HUB_DESCR_SIZE, /* bLength */
1658 USB_HUB_DESCRIPTOR_TYPE, /* bDescriptorType */
1659 0, /* bNumberOfPorts */
1660 USBWORD(0), /* wHubCharacteristics */
1661 0, /* bPowreOnToPowerGood */
1662 0, /* bHubControl Current */
1663 {0} /* bRemoveAndPowerMask */
1666 /* *********************************************************************
1667 * ohci_roothb_strdscr(ptr,str)
1669 * Construct a string descriptor for root hub requests
1671 * Input parameters:
1672 * ptr - pointer to where to put descriptor
1673 * str - regular string to put into descriptor
1675 * Return value:
1676 * number of bytes written to descriptor
1677 ********************************************************************* */
1679 static int ohci_roothub_strdscr(uint8_t *ptr,char *str)
1681 uint8_t *p = ptr;
1683 *p++ = strlen(str)*2 + 2; /* Unicode strings */
1684 *p++ = USB_STRING_DESCRIPTOR_TYPE;
1685 while (*str) {
1686 *p++ = *str++;
1687 *p++ = 0;
1689 return (p - ptr);
1692 /* *********************************************************************
1693 * ohci_roothub_req(softc,req)
1695 * Handle a descriptor request on the control pipe for the
1696 * root hub. We pretend to be a real root hub here and
1697 * return all the standard descriptors.
1699 * Input parameters:
1700 * softc - our OHCI controller
1701 * req - a usb request (completed immediately)
1703 * Return value:
1704 * 0 if ok
1705 * else error code
1706 ********************************************************************* */
1708 static int ohci_roothub_req(ohci_softc_t *softc,usb_device_request_t *req)
1710 uint8_t *ptr;
1711 uint16_t wLength;
1712 uint16_t wValue;
1713 uint16_t wIndex;
1714 usb_port_status_t ups;
1715 usb_hub_descr_t hdsc;
1716 uint32_t status;
1717 uint32_t statport;
1718 uint32_t tmpval;
1719 int res = 0;
1721 ptr = softc->ohci_rh_buf;
1723 wLength = GETUSBFIELD(req,wLength);
1724 wValue = GETUSBFIELD(req,wValue);
1725 wIndex = GETUSBFIELD(req,wIndex);
1727 switch (REQSW(req->bRequest,req->bmRequestType)) {
1729 case REQCODE(USB_REQUEST_GET_STATUS,USBREQ_DIR_IN,USBREQ_TYPE_STD,USBREQ_REC_DEVICE):
1730 *ptr++ = (USB_GETSTATUS_SELF_POWERED & 0xFF);
1731 *ptr++ = (USB_GETSTATUS_SELF_POWERED >> 8);
1732 break;
1734 case REQCODE(USB_REQUEST_GET_STATUS,USBREQ_DIR_IN,USBREQ_TYPE_STD,USBREQ_REC_ENDPOINT):
1735 case REQCODE(USB_REQUEST_GET_STATUS,USBREQ_DIR_IN,USBREQ_TYPE_STD,USBREQ_REC_INTERFACE):
1736 *ptr++ = 0;
1737 *ptr++ = 0;
1738 break;
1740 case REQCODE(USB_REQUEST_GET_STATUS,USBREQ_DIR_IN,USBREQ_TYPE_CLASS,USBREQ_REC_OTHER):
1741 status = OHCI_READCSR(softc,(R_OHCI_RHPORTSTATUS(wIndex)));
1742 if (ohcidebug > 0) { printf("RHGetStatus: "); ohci_dumpportstat(wIndex,status);}
1743 PUTUSBFIELD((&ups),wPortStatus,(status & 0xFFFF));
1744 PUTUSBFIELD((&ups),wPortChange,(status >> 16));
1745 memcpy(ptr,&ups,sizeof(ups));
1746 ptr += sizeof(ups);
1747 break;
1749 case REQCODE(USB_REQUEST_GET_STATUS,USBREQ_DIR_IN,USBREQ_TYPE_CLASS,USBREQ_REC_DEVICE):
1750 *ptr++ = 0;
1751 *ptr++ = 0;
1752 *ptr++ = 0;
1753 *ptr++ = 0;
1754 break;
1756 case REQCODE(USB_REQUEST_CLEAR_FEATURE,USBREQ_DIR_OUT,USBREQ_TYPE_STD,USBREQ_REC_DEVICE):
1757 case REQCODE(USB_REQUEST_CLEAR_FEATURE,USBREQ_DIR_OUT,USBREQ_TYPE_STD,USBREQ_REC_INTERFACE):
1758 case REQCODE(USB_REQUEST_CLEAR_FEATURE,USBREQ_DIR_OUT,USBREQ_TYPE_STD,USBREQ_REC_ENDPOINT):
1759 /* do nothing, not supported */
1760 break;
1762 case REQCODE(USB_REQUEST_CLEAR_FEATURE,USBREQ_DIR_OUT,USBREQ_TYPE_CLASS,USBREQ_REC_OTHER):
1763 statport = R_OHCI_RHPORTSTATUS(wIndex);
1764 if (ohcidebug> 0) {
1765 printf("RHClearFeature(%d): ",wValue); ohci_dumpportstat(wIndex,OHCI_READCSR(softc,statport));
1767 switch (wValue) {
1768 case USB_PORT_FEATURE_CONNECTION:
1769 break;
1770 case USB_PORT_FEATURE_ENABLE:
1771 OHCI_WRITECSR(softc,statport,M_OHCI_RHPORTSTAT_CCS);
1772 break;
1773 case USB_PORT_FEATURE_SUSPEND:
1774 OHCI_WRITECSR(softc,statport,M_OHCI_RHPORTSTAT_POCI);
1775 break;
1776 case USB_PORT_FEATURE_OVER_CURRENT:
1777 break;
1778 case USB_PORT_FEATURE_RESET:
1779 break;
1780 case USB_PORT_FEATURE_POWER:
1781 OHCI_WRITECSR(softc,statport,M_OHCI_RHPORTSTAT_LSDA);
1782 break;
1783 case USB_PORT_FEATURE_LOW_SPEED:
1784 break;
1785 case USB_PORT_FEATURE_C_PORT_CONNECTION:
1786 OHCI_WRITECSR(softc,statport,M_OHCI_RHPORTSTAT_CSC);
1787 break;
1788 case USB_PORT_FEATURE_C_PORT_ENABLE:
1789 OHCI_WRITECSR(softc,statport,M_OHCI_RHPORTSTAT_PESC);
1790 break;
1791 case USB_PORT_FEATURE_C_PORT_SUSPEND:
1792 OHCI_WRITECSR(softc,statport,M_OHCI_RHPORTSTAT_PSSC);
1793 break;
1794 case USB_PORT_FEATURE_C_PORT_OVER_CURRENT:
1795 OHCI_WRITECSR(softc,statport,M_OHCI_RHPORTSTAT_OCIC);
1796 break;
1797 case USB_PORT_FEATURE_C_PORT_RESET:
1798 OHCI_WRITECSR(softc,statport,M_OHCI_RHPORTSTAT_PRSC);
1799 break;
1804 * If we've cleared all of the conditions that
1805 * want our attention on the port status,
1806 * then we can accept port status interrupts again.
1809 if ((wValue >= USB_PORT_FEATURE_C_PORT_CONNECTION) &&
1810 (wValue <= USB_PORT_FEATURE_C_PORT_RESET)) {
1811 status = OHCI_READCSR(softc,statport);
1812 if ((status & M_OHCI_RHPORTSTAT_ALLC) == 0) {
1813 softc->ohci_intdisable &= ~M_OHCI_INT_RHSC;
1816 break;
1818 case REQCODE(USB_REQUEST_SET_FEATURE,USBREQ_DIR_OUT,USBREQ_TYPE_STD,USBREQ_REC_DEVICE):
1819 case REQCODE(USB_REQUEST_SET_FEATURE,USBREQ_DIR_OUT,USBREQ_TYPE_STD,USBREQ_REC_INTERFACE):
1820 case REQCODE(USB_REQUEST_SET_FEATURE,USBREQ_DIR_OUT,USBREQ_TYPE_STD,USBREQ_REC_ENDPOINT):
1821 res = -1;
1822 break;
1824 case REQCODE(USB_REQUEST_SET_FEATURE,USBREQ_DIR_OUT,USBREQ_TYPE_CLASS,USBREQ_REC_DEVICE):
1825 /* nothing */
1826 break;
1828 case REQCODE(USB_REQUEST_SET_FEATURE,USBREQ_DIR_OUT,USBREQ_TYPE_CLASS,USBREQ_REC_OTHER):
1829 statport = R_OHCI_RHPORTSTATUS(wIndex);
1830 switch (wValue) {
1831 case USB_PORT_FEATURE_CONNECTION:
1832 break;
1833 case USB_PORT_FEATURE_ENABLE:
1834 OHCI_WRITECSR(softc,statport,M_OHCI_RHPORTSTAT_PES);
1835 break;
1836 case USB_PORT_FEATURE_SUSPEND:
1837 OHCI_WRITECSR(softc,statport,M_OHCI_RHPORTSTAT_PSS);
1838 break;
1839 case USB_PORT_FEATURE_OVER_CURRENT:
1840 break;
1841 case USB_PORT_FEATURE_RESET:
1842 OHCI_WRITECSR(softc,statport,M_OHCI_RHPORTSTAT_PRS);
1843 for (;;) {
1844 usb_delay_ms(softc->ohci_bus,100);
1845 if (!(OHCI_READCSR(softc,statport) & M_OHCI_RHPORTSTAT_PRS)) break;
1847 break;
1848 case USB_PORT_FEATURE_POWER:
1849 OHCI_WRITECSR(softc,statport,M_OHCI_RHPORTSTAT_PPS);
1850 break;
1851 case USB_PORT_FEATURE_LOW_SPEED:
1852 break;
1853 case USB_PORT_FEATURE_C_PORT_CONNECTION:
1854 break;
1855 case USB_PORT_FEATURE_C_PORT_ENABLE:
1856 break;
1857 case USB_PORT_FEATURE_C_PORT_SUSPEND:
1858 break;
1859 case USB_PORT_FEATURE_C_PORT_OVER_CURRENT:
1860 break;
1861 case USB_PORT_FEATURE_C_PORT_RESET:
1862 break;
1866 break;
1868 case REQCODE(USB_REQUEST_SET_ADDRESS,USBREQ_DIR_OUT,USBREQ_TYPE_STD,USBREQ_REC_DEVICE):
1869 softc->ohci_rh_newaddr = wValue;
1870 break;
1872 case REQCODE(USB_REQUEST_GET_DESCRIPTOR,USBREQ_DIR_IN,USBREQ_TYPE_STD,USBREQ_REC_DEVICE):
1873 switch (wValue >> 8) {
1874 case USB_DEVICE_DESCRIPTOR_TYPE:
1875 memcpy(ptr,&ohci_root_devdsc,sizeof(ohci_root_devdsc));
1876 ptr += sizeof(ohci_root_devdsc);
1877 break;
1878 case USB_CONFIGURATION_DESCRIPTOR_TYPE:
1879 memcpy(ptr,&ohci_root_cfgdsc,sizeof(ohci_root_cfgdsc));
1880 ptr += sizeof(ohci_root_cfgdsc);
1881 memcpy(ptr,&ohci_root_ifdsc,sizeof(ohci_root_ifdsc));
1882 ptr += sizeof(ohci_root_ifdsc);
1883 memcpy(ptr,&ohci_root_epdsc,sizeof(ohci_root_epdsc));
1884 ptr += sizeof(ohci_root_epdsc);
1885 break;
1886 case USB_STRING_DESCRIPTOR_TYPE:
1887 switch (wValue & 0xFF) {
1888 case 1:
1889 ptr += ohci_roothub_strdscr(ptr,"Generic");
1890 break;
1891 case 2:
1892 ptr += ohci_roothub_strdscr(ptr,"Root Hub");
1893 break;
1894 default:
1895 *ptr++ = 0;
1896 break;
1898 break;
1899 default:
1900 res = -1;
1901 break;
1903 break;
1905 case REQCODE(USB_REQUEST_GET_DESCRIPTOR,USBREQ_DIR_IN,USBREQ_TYPE_CLASS,USBREQ_REC_DEVICE):
1906 memcpy(&hdsc,&ohci_root_hubdsc,sizeof(hdsc));
1907 hdsc.bNumberOfPorts = softc->ohci_ndp;
1908 status = OHCI_READCSR(softc,R_OHCI_RHDSCRA);
1909 tmpval = 0;
1910 if (status & M_OHCI_RHDSCRA_NPS) tmpval |= USB_HUBCHAR_PWR_NONE;
1911 if (status & M_OHCI_RHDSCRA_PSM) tmpval |= USB_HUBCHAR_PWR_GANGED;
1912 else tmpval |= USB_HUBCHAR_PWR_IND;
1913 PUTUSBFIELD((&hdsc),wHubCharacteristics,tmpval);
1914 tmpval = G_OHCI_RHDSCRA_POTPGT(status);
1915 hdsc.bPowerOnToPowerGood = tmpval;
1916 hdsc.bDescriptorLength = USB_HUB_DESCR_SIZE + 1;
1917 status = OHCI_READCSR(softc,R_OHCI_RHDSCRB);
1918 hdsc.bRemoveAndPowerMask[0] = (uint8_t) status;
1919 memcpy(ptr,&hdsc,sizeof(hdsc));
1920 ptr += sizeof(hdsc);
1921 break;
1923 case REQCODE(USB_REQUEST_SET_DESCRIPTOR,USBREQ_DIR_OUT,USBREQ_TYPE_CLASS,USBREQ_REC_DEVICE):
1924 /* nothing */
1925 break;
1927 case REQCODE(USB_REQUEST_GET_CONFIGURATION,USBREQ_DIR_IN,USBREQ_TYPE_STD,USBREQ_REC_DEVICE):
1928 *ptr++ = softc->ohci_rh_conf;
1929 break;
1931 case REQCODE(USB_REQUEST_SET_CONFIGURATION,USBREQ_DIR_OUT,USBREQ_TYPE_STD,USBREQ_REC_DEVICE):
1932 softc->ohci_rh_conf = wValue;
1933 break;
1935 case REQCODE(USB_REQUEST_GET_INTERFACE,USBREQ_DIR_IN,USBREQ_TYPE_STD,USBREQ_REC_INTERFACE):
1936 *ptr++ = 0;
1937 break;
1939 case REQCODE(USB_REQUEST_SET_INTERFACE,USBREQ_DIR_OUT,USBREQ_TYPE_STD,USBREQ_REC_INTERFACE):
1940 /* nothing */
1941 break;
1943 case REQCODE(USB_REQUEST_SYNC_FRAME,USBREQ_DIR_OUT,USBREQ_TYPE_STD,USBREQ_REC_ENDPOINT):
1944 /* nothing */
1945 break;
1948 softc->ohci_rh_ptr = softc->ohci_rh_buf;
1949 softc->ohci_rh_len = ptr - softc->ohci_rh_buf;
1951 return res;
1954 /* *********************************************************************
1955 * ohci_roothub_statchg(softc)
1957 * This routine is called from the interrupt service routine
1958 * (well, polling routine) for the ohci controller. If the
1959 * controller notices a root hub status change, it dequeues an
1960 * interrupt transfer from the root hub's queue and completes
1961 * it here.
1963 * Input parameters:
1964 * softc - our OHCI controller
1966 * Return value:
1967 * nothing
1968 ********************************************************************* */
1970 static void ohci_roothub_statchg(ohci_softc_t *softc)
1972 usbreq_t *ur;
1973 uint32_t status;
1974 uint8_t portstat = 0;
1975 int idx;
1977 /* Note: this only works up to 8 ports */
1978 for (idx = 1; idx <= softc->ohci_ndp; idx++) {
1979 status = OHCI_READCSR(softc,R_OHCI_RHPORTSTATUS(idx));
1980 if (status & M_OHCI_RHPORTSTAT_ALLC) {
1981 portstat = (1<<idx);
1985 if (portstat != 0) {
1986 softc->ohci_intdisable |= M_OHCI_INT_RHSC;
1989 ur = (usbreq_t *) q_deqnext(&(softc->ohci_rh_intrq));
1990 if (!ur) return; /* no requests pending, ignore it */
1992 memset(ur->ur_buffer,0,ur->ur_length);
1993 ur->ur_buffer[0] = portstat;
1994 ur->ur_xferred = ur->ur_length;
1996 usb_complete_request(ur,0);
1999 /* *********************************************************************
2000 * ohci_roothub_xfer(softc,req)
2002 * Handle a root hub xfer - ohci_xfer transfers control here
2003 * if we detect the address of the root hub - no actual transfers
2004 * go out on the wire, we just handle the requests directly to
2005 * make it look like a hub is attached.
2007 * This seems to be common practice in the USB world, so we do
2008 * it here too.
2010 * Input parameters:
2011 * softc - our OHCI controller structure
2012 * req - usb request destined for host controller
2014 * Return value:
2015 * 0 if ok
2016 * else error
2017 ********************************************************************* */
2019 static int ohci_roothub_xfer(usbbus_t *bus,usb_ept_t *uept,usbreq_t *ur)
2021 ohci_softc_t *softc = (ohci_softc_t *) bus->ub_hwsoftc;
2022 ohci_endpoint_t *ept = (ohci_endpoint_t *) uept;
2023 int res;
2025 switch (ept->ep_num) {
2028 * CONTROL ENDPOINT
2030 case 0:
2033 * Three types of transfers: OUT (SETUP), IN (data), or STATUS.
2034 * figure out which is which.
2037 if (ur->ur_flags & UR_FLAG_SETUP) {
2039 * SETUP packet - this is an OUT request to the control
2040 * pipe. We emulate the hub request here.
2042 usb_device_request_t *req;
2044 req = (usb_device_request_t *) ur->ur_buffer;
2046 res = ohci_roothub_req(softc,req);
2047 if (res != 0) printf("Root hub request returned an error\n");
2049 ur->ur_xferred = ur->ur_length;
2050 ur->ur_status = 0;
2051 usb_complete_request(ur,0);
2054 else if (ur->ur_flags & UR_FLAG_STATUS_IN) {
2056 * STATUS IN : it's sort of like a dummy IN request
2057 * to acknowledge a SETUP packet that otherwise has no
2058 * status. Just complete the usbreq.
2061 if (softc->ohci_rh_newaddr != -1) {
2062 softc->ohci_rh_addr = softc->ohci_rh_newaddr;
2063 softc->ohci_rh_newaddr = -1;
2066 ur->ur_status = 0;
2067 ur->ur_xferred = 0;
2068 usb_complete_request(ur,0);
2071 else if (ur->ur_flags & UR_FLAG_STATUS_OUT) {
2073 * STATUS OUT : it's sort of like a dummy OUT request
2075 ur->ur_status = 0;
2076 ur->ur_xferred = 0;
2077 usb_complete_request(ur,0);
2080 else if (ur->ur_flags & UR_FLAG_IN) {
2082 * IN : return data from the root hub
2084 int amtcopy;
2086 amtcopy = softc->ohci_rh_len;
2087 if (amtcopy > ur->ur_length) amtcopy = ur->ur_length;
2089 memcpy(ur->ur_buffer,softc->ohci_rh_ptr,amtcopy);
2091 softc->ohci_rh_ptr += amtcopy;
2092 softc->ohci_rh_len -= amtcopy;
2094 ur->ur_status = 0;
2095 ur->ur_xferred = amtcopy;
2096 usb_complete_request(ur,0);
2099 else {
2100 printf("Unknown root hub transfer type\n");
2101 return -1;
2103 break;
2106 * INTERRUPT ENDPOINT
2109 case 1: /* interrupt pipe */
2110 if (ur->ur_flags & UR_FLAG_IN) {
2111 q_enqueue(&(softc->ohci_rh_intrq),(queue_t *) ur);
2113 break;
2118 return 0;