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    *********************************************************************
11    *
12    *  Copyright 2000,2001,2002,2003
13    *  Broadcom Corporation. All rights reserved.
14    *
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.
21    *
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.
25    *
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.
31    *
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    ********************************************************************* */
46
47
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
64
65#include "lib_malloc.h"
66#include "lib_queue.h"
67#include "usbchap9.h"
68#include "usbd.h"
69#include "ohci.h"
70
71
72/*  *********************************************************************
73    *  Macros for dealing with hardware
74    *
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    ********************************************************************* */
79
80#if defined(_CFE_) && defined(__MIPSEB)
81#define BSWAP32(x) __swap32(x)
82static inline uint32_t __swap32(uint32_t x)
83{
84    uint32_t y;
85
86    y = ((x & 0xFF) << 24) |
87	((x & 0xFF00) << 8) |
88	((x & 0xFF0000) >> 8) |
89	((x & 0xFF000000) >> 24);
90
91    return y;
92}
93#else
94#define BSWAP32(x) (x)
95#endif
96
97
98#ifndef _CFE_
99extern uint32_t vtop(void *ptr);
100extern 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)))
109
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
115
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
121
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
128extern 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
132
133
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    ********************************************************************* */
139
140const 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
145};
146
147
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).
152    *
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.
156    *
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    ********************************************************************* */
163
164#define ohci_td_from_transfer(softc,transfer) \
165     ((softc)->ohci_hwtdpool + ((transfer) - (softc)->ohci_transfer_pool))
166
167#define ohci_transfer_from_td(softc,td) \
168     ((softc)->ohci_transfer_pool + ((td) - (softc)->ohci_hwtdpool))
169
170#define ohci_ed_from_endpoint(softc,endpoint) \
171     ((softc)->ohci_hwedpool + ((endpoint) - (softc)->ohci_endpoint_pool))
172
173#define ohci_endpoint_from_ed(softc,ed) \
174     ((softc)->ohci_endpoint_pool + ((ed) - (softc)->ohci_hwedpool))
175
176/*  *********************************************************************
177    *  Forward declarations
178    ********************************************************************* */
179
180static int ohci_roothub_xfer(usbbus_t *bus,usb_ept_t *uept,usbreq_t *ur);
181static void ohci_roothub_statchg(ohci_softc_t *softc);
182extern usb_hcdrv_t ohci_driver;
183
184/*  *********************************************************************
185    *  Globals
186    ********************************************************************* */
187
188int ohcidebug = 0;
189void ohci_dumprhstat(uint32_t reg);
190void ohci_dumpportstat(int idx,uint32_t reg);
191void ohci_dumptd(ohci_td_t *td);
192void ohci_dumptdchain(ohci_td_t *td);
193void ohci_dumped(ohci_ed_t *ed);
194void ohci_dumpedchain(ohci_ed_t *ed);
195
196
197/*  *********************************************************************
198    *  Some debug routines
199    ********************************************************************* */
200
201void ohci_dumprhstat(uint32_t reg)
202{
203    printf("HubStatus: %08X  ",reg);
204
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");
211
212}
213
214void ohci_dumpportstat(int idx,uint32_t reg)
215{
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");
230}
231
232void ohci_dumptd(ohci_td_t *td)
233{
234    uint32_t ctl;
235    static char *pids[4] = {"SETUP","OUT","IN","RSVD"};
236
237    ctl = BSWAP32(td->td_control);
238
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));
251}
252
253void ohci_dumptdchain(ohci_td_t *td)
254{
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++;
267	}
268}
269
270void ohci_dumped(ohci_ed_t *ed)
271{
272    uint32_t ctl;
273    static char *pids[4] = {"FTD","OUT","IN","FTD"};
274
275    ctl = BSWAP32(ed->ed_control),
276
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));
293}
294
295void ohci_dumpedchain(ohci_ed_t *ed)
296{
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++;
305	}
306}
307
308
309
310static void eptstats(ohci_softc_t *softc)
311{
312    int cnt;
313    ohci_endpoint_t *e;
314    cnt = 0;
315
316    e = softc->ohci_endpoint_freelist;
317    while (e) { e = e->ep_next; cnt++; }
318    printf("%d left, %d inuse\n",cnt,OHCI_EDPOOL_SIZE-cnt);
319}
320
321/*  *********************************************************************
322    *  _ohci_allocept(softc)
323    *
324    *  Allocate an endpoint data structure from the pool, and
325    *  make it ready for use.  The endpoint is NOT attached to
326    *  the hardware at this time.
327    *
328    *  Input parameters:
329    *  	   softc - our OHCI controller
330    *
331    *  Return value:
332    *  	   pointer to endpoint or NULL
333    ********************************************************************* */
334
335static ohci_endpoint_t *_ohci_allocept(ohci_softc_t *softc)
336{
337    ohci_endpoint_t *e;
338    ohci_ed_t *ed;
339
340    if (ohcidebug > 2) {
341	printf("AllocEpt: ");eptstats(softc);
342	}
343
344    e = softc->ohci_endpoint_freelist;
345
346    if (!e) {
347	printf("No endpoints left!\n");
348	return NULL;
349	}
350
351    softc->ohci_endpoint_freelist = e->ep_next;
352
353    ed = ohci_ed_from_endpoint(softc,e);
354
355    ed->ed_control = BSWAP32(M_OHCI_ED_SKIP);
356    ed->ed_tailp   = BSWAP32(0);
357    ed->ed_headp   = BSWAP32(0);
358    ed->ed_next_ed = BSWAP32(0);
359
360    e->ep_phys = OHCI_VTOP(ed);
361    e->ep_next = NULL;
362
363    return e;
364}
365
366/*  *********************************************************************
367    *  _ohci_allocxfer(softc)
368    *
369    *  Allocate a transfer descriptor.  It is prepared for use
370    *  but not attached to the hardware.
371    *
372    *  Input parameters:
373    *  	   softc - our OHCI controller
374    *
375    *  Return value:
376    *  	   transfer descriptor, or NULL
377    ********************************************************************* */
378
379static ohci_transfer_t *_ohci_allocxfer(ohci_softc_t *softc)
380{
381    ohci_transfer_t *t;
382    ohci_td_t *td;
383
384    if (ohcidebug > 2) {
385	int cnt;
386	cnt = 0;
387	t = softc->ohci_transfer_freelist;
388	while (t) { t = t->t_next; cnt++; }
389	printf("AllocXfer: %d left, %d inuse\n",cnt,OHCI_TDPOOL_SIZE-cnt);
390	}
391
392    t = softc->ohci_transfer_freelist;
393
394    if (!t) {
395	printf("No more transfer descriptors!\n");
396	return NULL;
397	}
398
399    softc->ohci_transfer_freelist = t->t_next;
400
401    td = ohci_td_from_transfer(softc,t);
402
403    td->td_control = BSWAP32(0);
404    td->td_cbp     = BSWAP32(0);
405    td->td_next_td = BSWAP32(0);
406    td->td_be      = BSWAP32(0);
407
408    t->t_ref  = NULL;
409    t->t_next = NULL;
410
411    return t;
412}
413
414/*  *********************************************************************
415    *  _ohci_freeept(softc,e)
416    *
417    *  Free an endpoint, returning it to the pool.
418    *
419    *  Input parameters:
420    *  	   softc - our OHCI controller
421    *  	   e - endpoint descriptor to return
422    *
423    *  Return value:
424    *  	   nothing
425    ********************************************************************* */
426
427static void _ohci_freeept(ohci_softc_t *softc,ohci_endpoint_t *e)
428{
429    if (ohcidebug > 2) {
430	int cnt;
431	ohci_endpoint_t *ee;
432	cnt = 0;
433	ee = softc->ohci_endpoint_freelist;
434	while (ee) { ee = ee->ep_next; cnt++; }
435	printf("FreeEpt[%p]: %d left, %d inuse\n",e,cnt,OHCI_EDPOOL_SIZE-cnt);
436	}
437
438    e->ep_next = softc->ohci_endpoint_freelist;
439    softc->ohci_endpoint_freelist = e;
440}
441
442/*  *********************************************************************
443    *  _ohci_freexfer(softc,t)
444    *
445    *  Free a transfer descriptor, returning it to the pool.
446    *
447    *  Input parameters:
448    *  	   softc - our OHCI controller
449    *  	   t - transfer descriptor to return
450    *
451    *  Return value:
452    *  	   nothing
453    ********************************************************************* */
454
455static void _ohci_freexfer(ohci_softc_t *softc,ohci_transfer_t *t)
456{
457    t->t_next = softc->ohci_transfer_freelist;
458    softc->ohci_transfer_freelist = t;
459}
460
461/*  *********************************************************************
462    *  _ohci_initpools(softc)
463    *
464    *  Allocate and initialize the various pools of things that
465    *  we use in the OHCI driver.  We do this by allocating some
466    *  big chunks from the heap and carving them up.
467    *
468    *  Input parameters:
469    *  	   softc - our OHCI controller
470    *
471    *  Return value:
472    *  	   0 if ok
473    *  	   else error code
474    ********************************************************************* */
475
476static int _ohci_initpools(ohci_softc_t *softc)
477{
478    int idx;
479
480    /*
481     * Do the transfer descriptor pool
482     */
483
484    softc->ohci_transfer_pool = KMALLOC(OHCI_TDPOOL_SIZE*sizeof(ohci_transfer_t),0);
485    softc->ohci_hwtdpool = KMALLOC(OHCI_TDPOOL_SIZE*sizeof(ohci_td_t),OHCI_TD_ALIGN);
486
487    /*
488     * In the case of noncoherent DMA, make these uncached addresses.
489     * This way all our descriptors will be uncached.  Makes life easier, as we
490     * do not need to worry about flushing descriptors, etc.
491     */
492
493#if !CPUCFG_COHERENT_DMA
494    softc->ohci_hwtdpool = (void *) UNCADDR(PHYSADDR((uint32_t)(softc->ohci_hwtdpool)));
495#endif
496
497    if (!softc->ohci_transfer_pool || !softc->ohci_hwtdpool) {
498	printf("Could not allocate transfer descriptors\n");
499	return -1;
500	}
501
502    softc->ohci_transfer_freelist = NULL;
503
504    for (idx = 0; idx < OHCI_TDPOOL_SIZE; idx++) {
505	_ohci_freexfer(softc,softc->ohci_transfer_pool+idx);
506	}
507
508    /*
509     * Do the endpoint descriptor pool
510     */
511
512    softc->ohci_endpoint_pool = KMALLOC(OHCI_EDPOOL_SIZE*sizeof(ohci_endpoint_t),0);
513
514    softc->ohci_hwedpool       = KMALLOC(OHCI_EDPOOL_SIZE*sizeof(ohci_ed_t),OHCI_ED_ALIGN);
515
516#if !CPUCFG_COHERENT_DMA
517    softc->ohci_hwedpool = (void *) UNCADDR(PHYSADDR((uint32_t)(softc->ohci_hwedpool)));
518#endif
519
520    if (!softc->ohci_endpoint_pool || !softc->ohci_hwedpool) {
521	printf("Could not allocate transfer descriptors\n");
522	return -1;
523	}
524
525    softc->ohci_endpoint_freelist = NULL;
526
527    for (idx = 0; idx < OHCI_EDPOOL_SIZE; idx++) {
528	_ohci_freeept(softc,softc->ohci_endpoint_pool+idx);
529	}
530
531    /*
532     * Finally the host communications area
533     */
534
535    softc->ohci_hcca = KMALLOC(sizeof(ohci_hcca_t),sizeof(ohci_hcca_t));
536
537#if !CPUCFG_COHERENT_DMA
538    softc->ohci_hcca = (void *) UNCADDR(PHYSADDR((uint32_t)(softc->ohci_hcca)));
539#endif
540
541    memset(softc->ohci_hcca,0,sizeof(ohci_hcca_t));
542
543    return 0;
544}
545
546
547/*  *********************************************************************
548    *  ohci_start(bus)
549    *
550    *  Start the OHCI controller.  After this routine is called,
551    *  the hardware will be operational and ready to accept
552    *  descriptors and interrupt calls.
553    *
554    *  Input parameters:
555    *  	   bus - bus structure, from ohci_create
556    *
557    *  Return value:
558    *  	   0 if ok
559    *  	   else error code
560    ********************************************************************* */
561
562static int ohci_start(usbbus_t *bus)
563{
564    ohci_softc_t *softc = (ohci_softc_t *) bus->ub_hwsoftc;
565    uint32_t frameint;
566    uint32_t reg;
567    int idx;
568
569    /*
570     * Force a reset to the controller, followed by a short delay
571     */
572
573    OHCI_WRITECSR(softc,R_OHCI_CONTROL,V_OHCI_CONTROL_HCFS(K_OHCI_HCFS_RESET));
574    usb_delay_ms(bus,OHCI_RESET_DELAY);
575
576    /* Host controller state is now "RESET" */
577
578    /*
579     * We need the frame interval later, so get a copy of it now.
580     */
581    frameint = G_OHCI_FMINTERVAL_FI(OHCI_READCSR(softc,R_OHCI_FMINTERVAL));
582
583    /*
584     * Reset the host controller.  When you set the HCR bit
585     * if self-clears when the reset is complete.
586     */
587
588    OHCI_WRITECSR(softc,R_OHCI_CMDSTATUS,M_OHCI_CMDSTATUS_HCR);
589    for (idx = 0; idx < 10000; idx++) {
590	if (!(OHCI_READCSR(softc,R_OHCI_CMDSTATUS) & M_OHCI_CMDSTATUS_HCR)) break;
591	}
592
593    if (OHCI_READCSR(softc,R_OHCI_CMDSTATUS) & M_OHCI_CMDSTATUS_HCR) {
594	/* controller never came out of reset */
595	return -1;
596	}
597
598    /*
599     * Host controller state is now "SUSPEND".  We must exit
600     * from this state within 2ms.  (5.1.1.4)
601     *
602     * Set up pointers to data structures.
603     */
604
605    OHCI_WRITECSR(softc,R_OHCI_HCCA,OHCI_VTOP(softc->ohci_hcca));
606    OHCI_WRITECSR(softc,R_OHCI_CONTROLHEADED,softc->ohci_ctl_list->ep_phys);
607    OHCI_WRITECSR(softc,R_OHCI_BULKHEADED,softc->ohci_bulk_list->ep_phys);
608
609    /*
610     * Our driver is polled, turn off interrupts
611     */
612
613    OHCI_WRITECSR(softc,R_OHCI_INTDISABLE,M_OHCI_INT_ALL);
614
615    /*
616     * Set up the control register.
617     */
618
619    reg = OHCI_READCSR(softc,R_OHCI_CONTROL);
620
621    reg = M_OHCI_CONTROL_PLE | M_OHCI_CONTROL_CLE | M_OHCI_CONTROL_BLE |
622	M_OHCI_CONTROL_IE |
623	V_OHCI_CONTROL_CBSR(K_OHCI_CBSR_41) |
624	V_OHCI_CONTROL_HCFS(K_OHCI_HCFS_OPERATIONAL);
625
626    OHCI_WRITECSR(softc,R_OHCI_CONTROL,reg);
627
628
629    /*
630     * controller state is now OPERATIONAL
631     */
632
633    reg = OHCI_READCSR(softc,R_OHCI_FMINTERVAL);
634    reg &= M_OHCI_FMINTERVAL_FIT;
635    reg ^= M_OHCI_FMINTERVAL_FIT;
636    reg |= V_OHCI_FMINTERVAL_FSMPS(OHCI_CALC_FSMPS(frameint)) |
637	V_OHCI_FMINTERVAL_FI(frameint);
638    OHCI_WRITECSR(softc,R_OHCI_FMINTERVAL,reg);
639
640    reg = frameint * 9 / 10;		/* calculate 90% */
641    OHCI_WRITECSR(softc,R_OHCI_PERIODICSTART,reg);
642
643    usb_delay_ms(softc->ohci_bus,10);
644
645    /*
646     * Remember how many ports we have
647     */
648
649    reg = OHCI_READCSR(softc,R_OHCI_RHDSCRA);
650    softc->ohci_ndp = G_OHCI_RHDSCRA_NDP(reg);
651
652
653    /*
654     * Enable port power
655     */
656
657    OHCI_WRITECSR(softc,R_OHCI_RHSTATUS,M_OHCI_RHSTATUS_LPSC);
658    usb_delay_ms(softc->ohci_bus,10);
659
660    return 0;
661}
662
663
664/*  *********************************************************************
665    *  _ohci_setupepts(softc)
666    *
667    *  Set up the endpoint tree, as described in the OHCI manual.
668    *  Basically the hardware knows how to scan lists of lists,
669    *  so we build a tree where each level is pointed to by two
670    *  parent nodes.  We can choose our scanning rate by attaching
671    *  endpoints anywhere within this tree.
672    *
673    *  Input parameters:
674    *  	   softc - our OHCI controller
675    *
676    *  Return value:
677    *  	   0 if ok
678    *  	   else error (out of descriptors)
679    ********************************************************************* */
680
681static int _ohci_setupepts(ohci_softc_t *softc)
682{
683    int idx;
684    ohci_endpoint_t *e;
685    ohci_ed_t *ed;
686    ohci_endpoint_t *child;
687
688    /*
689     * Set up the list heads for the isochronous, control,
690     * and bulk transfer lists.  They don't get the same "tree"
691     * treatment that the interrupt devices get.
692     *
693     * For the purposes of CFE, it's probably not necessary
694     * to be this fancy.  The only device we're planning to
695     * talk to is the keyboard and some hubs, which should
696     * have pretty minimal requirements.  It's conceivable
697     * that this firmware may find a new home in other
698     * devices, so we'll meet halfway and do some things
699     * "fancy."
700     */
701
702    softc->ohci_isoc_list = _ohci_allocept(softc);
703    softc->ohci_ctl_list  = _ohci_allocept(softc);
704    softc->ohci_bulk_list = _ohci_allocept(softc);
705
706    /*
707     * Set up a tree of empty endpoint descriptors.  This is
708     * tree is scanned by the hardware from the leaves up to
709     * the root.  Once a millisecond, the hardware picks the
710     * next leaf and starts scanning descriptors looking
711     * for something to do.  It traverses all of the endpoints
712     * along the way until it gets to the root.
713     *
714     * The idea here is if you put a transfer descriptor on the
715     * root node, the hardware will see it every millisecond,
716     * since the root will be examined each time.  If you
717     * put the TD on the leaf, it will be 1/32 millisecond.
718     * The tree therefore is six levels deep.
719     */
720
721    for (idx = 0; idx < OHCI_INTTREE_SIZE; idx++) {
722	e = _ohci_allocept(softc);		/* allocated with sKip bit set */
723	softc->ohci_edtable[idx] = e;
724	child = (idx == 0) ? softc->ohci_isoc_list : softc->ohci_edtable[(idx-1)/2];
725	ed = ohci_ed_from_endpoint(softc,e);
726	ed->ed_next_ed = BSWAP32(child->ep_phys);
727	e->ep_next = child;
728	}
729
730    /*
731     * We maintain both physical and virtual copies of the interrupt
732     * table (leaves of the tree).
733     */
734
735    for (idx = 0; idx < OHCI_INTTABLE_SIZE; idx++) {
736	child = softc->ohci_edtable[OHCI_INTTREE_SIZE-OHCI_INTTABLE_SIZE+idx];
737	softc->ohci_inttable[ohci_revbits[idx]] = child;
738	softc->ohci_hcca->hcca_inttable[ohci_revbits[idx]] = BSWAP32(child->ep_phys);
739	}
740
741    /*
742     * Okay, at this point the tree is built.
743     */
744    return 0;
745}
746
747/*  *********************************************************************
748    *  ohci_stop(bus)
749    *
750    *  Stop the OHCI hardware.
751    *
752    *  Input parameters:
753    *  	   bus - our bus structure
754    *
755    *  Return value:
756    *  	   nothing
757    ********************************************************************* */
758
759static void ohci_stop(usbbus_t *bus)
760{
761    ohci_softc_t *softc = (ohci_softc_t *) bus->ub_hwsoftc;
762
763    OHCI_WRITECSR(softc,R_OHCI_CONTROL,V_OHCI_CONTROL_HCFS(K_OHCI_HCFS_RESET));
764}
765
766
767/*  *********************************************************************
768    *  _ohci_queueept(softc,queue,e)
769    *
770    *  Add an endpoint to a list of endpoints.  This routine
771    *  does things in a particular way according to the OHCI
772    *  spec so we can add endpoints while the hardware is running.
773    *
774    *  Input parameters:
775    *  	   queue - endpoint descriptor for head of queue
776    *  	   e - endpoint to add to queue
777    *
778    *  Return value:
779    *  	   nothing
780    ********************************************************************* */
781
782static void _ohci_queueept(ohci_softc_t *softc,ohci_endpoint_t *queue,ohci_endpoint_t *newept)
783{
784    ohci_ed_t *qed;
785    ohci_ed_t *newed;
786
787    qed = ohci_ed_from_endpoint(softc,queue);
788    newed = ohci_ed_from_endpoint(softc,newept);
789
790    newept->ep_next = queue->ep_next;
791    newed->ed_next_ed = qed->ed_next_ed;
792
793    queue->ep_next = newept;
794    qed->ed_next_ed = BSWAP32(newept->ep_phys);
795
796    if (ohcidebug > 1) ohci_dumped(newed);
797
798}
799
800/*  *********************************************************************
801    *  _ohci_deqept(queue,e)
802    *
803    *  Remove and endpoint from the list of endpoints.  This
804    *  routine does things in a particular way according to
805    *  the OHCI specification, since we are operating on
806    *  a running list.
807    *
808    *  Input parameters:
809    *  	   queue - base of queue to look for endpoint on
810    *  	   e - endpoint to remove
811    *
812    *  Return value:
813    *  	   nothing
814    ********************************************************************* */
815
816static void _ohci_deqept(ohci_softc_t *softc,ohci_endpoint_t *queue,ohci_endpoint_t *e)
817{
818    ohci_endpoint_t *cur;
819    ohci_ed_t *cured;
820    ohci_ed_t *ed;
821
822    cur = queue;
823
824    while (cur && (cur->ep_next != e)) cur = cur->ep_next;
825
826    if (cur == NULL) {
827	printf("Could not remove EP %08X: not on the list!\n",(uint32_t) (intptr_t)e);
828	return;
829	}
830
831    /*
832     * Remove from our regular list
833     */
834
835    cur->ep_next = e->ep_next;
836
837    /*
838     * now remove from the hardware's list
839     */
840
841    cured = ohci_ed_from_endpoint(softc,cur);
842    ed = ohci_ed_from_endpoint(softc,e);
843
844    cured->ed_next_ed = ed->ed_next_ed;
845}
846
847
848/*  *********************************************************************
849    *  ohci_intr_procdoneq(softc)
850    *
851    *  Process the "done" queue for this ohci controller.  As
852    *  descriptors are retired, the hardware links them to the
853    *  "done" queue so we can examine the results.
854    *
855    *  Input parameters:
856    *  	   softc - our OHCI controller
857    *
858    *  Return value:
859    *  	   nothing
860    ********************************************************************* */
861
862static void ohci_intr_procdoneq(ohci_softc_t *softc)
863{
864    uint32_t doneq;
865    ohci_transfer_t *transfer;
866    ohci_td_t *td;
867    int val;
868    usbreq_t *ur;
869
870    /*
871     * Get the head of the queue
872     */
873
874    doneq = softc->ohci_hcca->hcca_donehead;
875    doneq = BSWAP32(doneq);
876
877    td = (ohci_td_t *) OHCI_PTOV(doneq);
878    transfer = ohci_transfer_from_td(softc,td);
879
880    /*
881     * Process all elements from the queue
882     */
883
884    while (doneq) {
885
886	ohci_ed_t *ed;
887	ohci_endpoint_t *ept;
888	usbreq_t *xur = transfer->t_ref;
889
890	if (ohcidebug > 1) {
891	    if (xur) {
892		ept = (ohci_endpoint_t *) xur->ur_pipe->up_hwendpoint;
893		ed = ohci_ed_from_endpoint(softc,ept);
894//		printf("ProcDoneQ:ED [%08X] -> ",ept->ep_phys);
895//		ohci_dumped(ed);
896		}
897	    }
898
899	/*
900	 * Get the pointer to next one before freeing this one
901	 */
902
903	if (ohcidebug > 1) {
904	    ur = transfer->t_ref;
905	    printf("Done(%d): ",ur ? ur->ur_tdcount : -1);
906	    ohci_dumptd(td);
907	    }
908
909	doneq = BSWAP32(td->td_next_td);
910
911	val = G_OHCI_TD_CC(BSWAP32(td->td_control));
912
913	if (val != 0) printf("[Transfer error: %d]\n",val);
914
915	/*
916	 * See if it's time to call the callback.
917	 */
918	ur = transfer->t_ref;
919	if (ur) {
920	    ur->ur_status = val;
921	    ur->ur_tdcount--;
922	    if (BSWAP32(td->td_cbp) == 0) {
923		ur->ur_xferred += transfer->t_length;
924		}
925	    else {
926		ur->ur_xferred += transfer->t_length -
927		    (BSWAP32(td->td_be) - BSWAP32(td->td_cbp) + 1);
928		}
929	    if (ur->ur_tdcount == 0) {
930		/* Noncoherent DMA: need to invalidate, since data is in phys mem */
931		OHCI_INVAL_RANGE(ur->ur_buffer,ur->ur_xferred);
932		usb_complete_request(ur,val);
933		}
934	    }
935
936
937	/*
938	 * Free up the request
939	 */
940	_ohci_freexfer(softc,transfer);
941
942
943	/*
944	 * Advance to the next request.
945	 */
946
947	td = (ohci_td_t *) OHCI_PTOV(doneq);
948	transfer = ohci_transfer_from_td(softc,td);
949	}
950
951}
952
953/*  *********************************************************************
954    *  ohci_intr(bus)
955    *
956    *  Process pending interrupts for the OHCI controller.
957    *
958    *  Input parameters:
959    *  	   bus - our bus structure
960    *
961    *  Return value:
962    *  	   0 if we did nothing
963    *  	   nonzero if we did something.
964    ********************************************************************* */
965
966static int ohci_intr(usbbus_t *bus)
967{
968    uint32_t reg;
969    ohci_softc_t *softc = (ohci_softc_t *) bus->ub_hwsoftc;
970
971    /*
972     * Read the interrupt status register.
973     */
974
975    reg = OHCI_READCSR(softc,R_OHCI_INTSTATUS);
976
977    /*
978     * Don't bother doing anything if nothing happened.
979     */
980    if (reg == 0) {
981	return 0;
982	}
983
984    /* Scheduling Overruns */
985    if (reg & M_OHCI_INT_SO) {
986	printf("SchedOverrun\n");
987	}
988
989    /* Done Queue */
990    if (reg & M_OHCI_INT_WDH) {
991	/* printf("DoneQueue\n"); */
992	ohci_intr_procdoneq(softc);
993	}
994
995    /* Start of Frame */
996    if (reg & M_OHCI_INT_SF) {
997	/* don't be noisy about this */
998	}
999
1000    /* Resume Detect */
1001    if (reg & M_OHCI_INT_RD) {
1002	printf("ResumeDetect\n");
1003	}
1004
1005    /* Unrecoverable errors */
1006    if (reg & M_OHCI_INT_UE) {
1007	printf("UnrecoverableError\n");
1008	}
1009
1010    /* Frame number overflow */
1011    if (reg & M_OHCI_INT_FNO) {
1012	/*printf("FrameNumberOverflow\n"); */
1013	}
1014
1015    /* Root Hub Status Change */
1016    if ((reg & ~softc->ohci_intdisable) & M_OHCI_INT_RHSC) {
1017	uint32_t reg;
1018	if (ohcidebug > 0) {
1019	    printf("RootHubStatusChange: ");
1020	    reg = OHCI_READCSR(softc,R_OHCI_RHSTATUS);
1021	    ohci_dumprhstat(reg);
1022	    reg = OHCI_READCSR(softc,R_OHCI_RHPORTSTATUS(1));
1023	    ohci_dumpportstat(1,reg);
1024	    reg = OHCI_READCSR(softc,R_OHCI_RHPORTSTATUS(2));
1025	    ohci_dumpportstat(2,reg);
1026	    }
1027	ohci_roothub_statchg(softc);
1028	}
1029
1030    /* Ownership Change */
1031    if (reg & M_OHCI_INT_OC) {
1032	printf("OwnershipChange\n");
1033	}
1034
1035    /*
1036     * Write the value back to the interrupt
1037     * register to clear the bits that were set.
1038     */
1039
1040    OHCI_WRITECSR(softc,R_OHCI_INTSTATUS,reg);
1041
1042    return 1;
1043}
1044
1045
1046/*  *********************************************************************
1047    *  ohci_delete(bus)
1048    *
1049    *  Remove an OHCI bus structure and all resources allocated to
1050    *  it (used when shutting down USB)
1051    *
1052    *  Input parameters:
1053    *  	   bus - our USB bus structure
1054    *
1055    *  Return value:
1056    *  	   nothing
1057    ********************************************************************* */
1058
1059static void ohci_delete(usbbus_t *bus)
1060{
1061    // xxx fill in later.
1062}
1063
1064
1065/*  *********************************************************************
1066    *  ohci_create(addr)
1067    *
1068    *  Create a USB bus structure and associate it with our OHCI
1069    *  controller device.
1070    *
1071    *  Input parameters:
1072    *  	   addr - physical address of controller
1073    *
1074    *  Return value:
1075    *  	   usbbus structure pointer
1076    ********************************************************************* */
1077
1078static usbbus_t *ohci_create(physaddr_t addr)
1079{
1080    int res;
1081    ohci_softc_t *softc;
1082    usbbus_t *bus;
1083
1084    softc = KMALLOC(sizeof(ohci_softc_t),0);
1085    if (!softc) return NULL;
1086
1087    bus = KMALLOC(sizeof(usbbus_t),0);
1088    if (!bus) return NULL;
1089
1090    memset(softc,0,sizeof(ohci_softc_t));
1091    memset(bus,0,sizeof(usbbus_t));
1092
1093    bus->ub_hwsoftc  = (usb_hc_t *) softc;
1094    bus->ub_hwdisp   = &ohci_driver;
1095
1096    q_init(&(softc->ohci_rh_intrq));
1097
1098#ifdef _CFE_
1099    softc->ohci_regs =  addr;
1100#else
1101    softc->ohci_regs = (volatile uint32_t *) addr;
1102#endif
1103
1104    softc->ohci_rh_newaddr = -1;
1105    softc->ohci_bus = bus;
1106
1107    if ((res = _ohci_initpools(softc)) != 0) goto error;
1108    if ((res = _ohci_setupepts(softc)) != 0) goto error;
1109
1110    OHCI_WRITECSR(softc,R_OHCI_CONTROL,V_OHCI_CONTROL_HCFS(K_OHCI_HCFS_RESET));
1111
1112    return bus;
1113
1114error:
1115    KFREE(softc);
1116    return NULL;
1117}
1118
1119
1120/*  *********************************************************************
1121    *  ohci_ept_create(bus,usbaddr,eptnum,mps,flags)
1122    *
1123    *  Create a hardware endpoint structure and attach it to
1124    *  the hardware's endpoint list.  The hardware manages lists
1125    *  of queues, and this routine adds a new queue to the appropriate
1126    *  list of queues for the endpoint in question.  It roughly
1127    *  corresponds to the information in the OHCI specification.
1128    *
1129    *  Input parameters:
1130    *  	   bus - the USB bus we're dealing with
1131    *  	   usbaddr - USB address (0 means default address)
1132    *  	   eptnum - the endpoint number
1133    *  	   mps - the packet size for this endpoint
1134    *  	   flags - various flags to control endpoint creation
1135    *
1136    *  Return value:
1137    *  	   endpoint structure poihter, or NULL
1138    ********************************************************************* */
1139
1140static usb_ept_t *ohci_ept_create(usbbus_t *bus,
1141				  int usbaddr,
1142				  int eptnum,
1143				  int mps,
1144				  int flags)
1145{
1146    uint32_t eptflags;
1147    ohci_endpoint_t *ept;
1148    ohci_ed_t *ed;
1149    ohci_transfer_t *tailtransfer;
1150    ohci_td_t *tailtd;
1151    ohci_softc_t *softc = (ohci_softc_t *) bus->ub_hwsoftc;
1152
1153    ept = _ohci_allocept(softc);
1154    ed = ohci_ed_from_endpoint(softc,ept);
1155
1156    tailtransfer = _ohci_allocxfer(softc);
1157    tailtd = ohci_td_from_transfer(softc,tailtransfer);
1158
1159    /*
1160     * Set up functional address, endpoint number, and packet size
1161     */
1162
1163    eptflags = V_OHCI_ED_FA(usbaddr) |
1164	V_OHCI_ED_EN(eptnum) |
1165	V_OHCI_ED_MPS(mps) |
1166	0;
1167
1168    /*
1169     * Set up the endpoint type based on the flags
1170     * passed to us
1171     */
1172
1173    if (flags & UP_TYPE_IN) {
1174	eptflags |= V_OHCI_ED_DIR(K_OHCI_ED_DIR_IN);
1175	}
1176    else if (flags & UP_TYPE_OUT) {
1177	eptflags |= V_OHCI_ED_DIR(K_OHCI_ED_DIR_OUT);
1178	}
1179    else {
1180	eptflags |= V_OHCI_ED_DIR(K_OHCI_ED_DIR_FROMTD);
1181	}
1182
1183    /*
1184     * Don't forget about lowspeed devices.
1185     */
1186
1187    if (flags & UP_TYPE_LOWSPEED) {
1188	eptflags |= M_OHCI_ED_LOWSPEED;
1189	}
1190
1191    if (ohcidebug > 0) {
1192	printf("Create endpoint %d addr %d flags %08X mps %d\n",
1193	   eptnum,usbaddr,eptflags,mps);
1194	}
1195
1196    /*
1197     * Transfer this info into the endpoint descriptor.
1198     * No need to flush the cache here, it'll get done when
1199     * we add to the hardware list.
1200     */
1201
1202    ed->ed_control = BSWAP32(eptflags);
1203    ed->ed_tailp   = BSWAP32(OHCI_VTOP(tailtd));
1204    ed->ed_headp   = BSWAP32(OHCI_VTOP(tailtd));
1205    ept->ep_flags = flags;
1206    ept->ep_mps = mps;
1207    ept->ep_num = eptnum;
1208
1209    /*
1210     * Put it on the right queue
1211     */
1212
1213    if (flags & UP_TYPE_CONTROL) {
1214	_ohci_queueept(softc,softc->ohci_ctl_list,ept);
1215	}
1216    else if (flags & UP_TYPE_BULK) {
1217	_ohci_queueept(softc,softc->ohci_bulk_list,ept);
1218	}
1219    else if (flags & UP_TYPE_INTR) {
1220	_ohci_queueept(softc,softc->ohci_inttable[0],ept);
1221	}
1222
1223    return (usb_ept_t *) ept;
1224}
1225
1226/*  *********************************************************************
1227    *  ohci_ept_setaddr(bus,ept,usbaddr)
1228    *
1229    *  Change the functional address for a USB endpoint.  We do this
1230    *  when we switch the device's state from DEFAULT to ADDRESSED
1231    *  and we've already got the default pipe open.  This
1232    *  routine mucks with the descriptor and changes its address
1233    *  bits.
1234    *
1235    *  Input parameters:
1236    *  	   bus - usb bus structure
1237    *  	   ept - an open endpoint descriptor
1238    *  	   usbaddr - new address for this endpoint
1239    *
1240    *  Return value:
1241    *  	   nothing
1242    ********************************************************************* */
1243
1244static void ohci_ept_setaddr(usbbus_t *bus,usb_ept_t *uept,int usbaddr)
1245{
1246    uint32_t eptflags;
1247    ohci_endpoint_t *ept = (ohci_endpoint_t *) uept;
1248    ohci_softc_t *softc = (ohci_softc_t *) bus->ub_hwsoftc;
1249    ohci_ed_t *ed = ohci_ed_from_endpoint(softc,ept);
1250
1251    eptflags = BSWAP32(ed->ed_control);
1252    eptflags &= ~M_OHCI_ED_FA;
1253    eptflags |= V_OHCI_ED_FA(usbaddr);
1254    ed->ed_control = BSWAP32(eptflags);
1255}
1256
1257
1258/*  *********************************************************************
1259    *  ohci_ept_setmps(bus,ept,mps)
1260    *
1261    *  Set the maximum packet size of this endpoint.  This is
1262    *  normally used during the processing of endpoint 0 (default
1263    *  pipe) after we find out how big ep0's packets can be.
1264    *
1265    *  Input parameters:
1266    *  	   bus - our USB bus structure
1267    *  	   ept - endpoint structure
1268    *  	   mps - new packet size
1269    *
1270    *  Return value:
1271    *  	   nothing
1272    ********************************************************************* */
1273
1274static void ohci_ept_setmps(usbbus_t *bus,usb_ept_t *uept,int mps)
1275{
1276    uint32_t eptflags;
1277    ohci_softc_t *softc = (ohci_softc_t *) bus->ub_hwsoftc;
1278    ohci_endpoint_t *ept = (ohci_endpoint_t *) uept;
1279    ohci_ed_t *ed = ohci_ed_from_endpoint(softc,ept);
1280
1281    eptflags = BSWAP32(ed->ed_control);
1282    eptflags &= ~M_OHCI_ED_MPS;
1283    eptflags |= V_OHCI_ED_MPS(mps);
1284    ed->ed_control = BSWAP32(eptflags);
1285    ept->ep_mps = mps;
1286
1287}
1288
1289/*  *********************************************************************
1290    *  ohci_ept_cleartoggle(bus,ept,mps)
1291    *
1292    *  Clear the data toggle for the specified endpoint.
1293    *
1294    *  Input parameters:
1295    *  	   bus - our USB bus structure
1296    *  	   ept - endpoint structure
1297    *
1298    *  Return value:
1299    *  	   nothing
1300    ********************************************************************* */
1301
1302static void ohci_ept_cleartoggle(usbbus_t *bus,usb_ept_t *uept)
1303{
1304    uint32_t eptflags;
1305    ohci_softc_t *softc = (ohci_softc_t *) bus->ub_hwsoftc;
1306    ohci_endpoint_t *ept = (ohci_endpoint_t *) uept;
1307    ohci_ed_t *ed = ohci_ed_from_endpoint(softc,ept);
1308
1309    eptflags = BSWAP32(ed->ed_headp);
1310    eptflags &= ~(M_OHCI_ED_HALT | M_OHCI_ED_TOGGLECARRY);
1311    ed->ed_headp = BSWAP32(eptflags);
1312
1313    OHCI_WRITECSR(softc,R_OHCI_CMDSTATUS,M_OHCI_CMDSTATUS_CLF);
1314}
1315
1316/*  *********************************************************************
1317    *  ohci_ept_delete(bus,ept)
1318    *
1319    *  Deletes an endpoint from the OHCI controller.  This
1320    *  routine also completes pending transfers for the
1321    *  endpoint and gets rid of the hardware ept (queue base).
1322    *
1323    *  Input parameters:
1324    *  	   bus - ohci bus structure
1325    *  	   ept - endpoint to remove
1326    *
1327    *  Return value:
1328    *  	   nothing
1329    ********************************************************************* */
1330
1331static void ohci_ept_delete(usbbus_t *bus,usb_ept_t *uept)
1332{
1333    ohci_endpoint_t *queue;
1334    ohci_softc_t *softc = (ohci_softc_t *) bus->ub_hwsoftc;
1335    ohci_endpoint_t *ept = (ohci_endpoint_t *) uept;
1336    ohci_ed_t *ed = ohci_ed_from_endpoint(softc,ept);
1337    uint32_t framenum;
1338    uint32_t tdphys;
1339    usbreq_t *ur;
1340    ohci_td_t *td;
1341    ohci_transfer_t *transfer;
1342
1343    if (ept->ep_flags & UP_TYPE_CONTROL) {
1344	queue = softc->ohci_ctl_list;
1345	}
1346    else if (ept->ep_flags & UP_TYPE_BULK) {
1347	queue = softc->ohci_bulk_list;
1348	}
1349    else if (ept->ep_flags & UP_TYPE_INTR) {
1350	queue = softc->ohci_inttable[0];
1351	}
1352    else {
1353	printf("Invalid endpoint\n");
1354	return;
1355	}
1356
1357
1358    /*
1359     * Set the SKIP bit on the endpoint and
1360     * wait for two SOFs to guarantee that we're
1361     * not processing this ED anymore.
1362     */
1363
1364    ((volatile uint32_t) ed->ed_control) |= BSWAP32(M_OHCI_ED_SKIP);
1365
1366    framenum = OHCI_READCSR(softc,R_OHCI_FMNUMBER) & 0xFFFF;
1367    while ((OHCI_READCSR(softc,R_OHCI_FMNUMBER) & 0xFFFF) == framenum) ; /* NULL LOOP */
1368
1369    framenum = OHCI_READCSR(softc,R_OHCI_FMNUMBER) & 0xFFFF;
1370    while ((OHCI_READCSR(softc,R_OHCI_FMNUMBER) & 0xFFFF) == framenum) ; /* NULL LOOP */
1371
1372    /*
1373     * Remove endpoint from queue
1374     */
1375
1376    _ohci_deqept(softc,queue,ept);
1377
1378    /*
1379     * Free/complete the TDs on the queue
1380     */
1381
1382    tdphys = BSWAP32(ed->ed_headp) & M_OHCI_ED_PTRMASK;
1383
1384    while (tdphys != BSWAP32(ed->ed_tailp)) {
1385	td = (ohci_td_t *) OHCI_PTOV(tdphys);
1386	tdphys = BSWAP32(td->td_next_td);
1387	transfer = ohci_transfer_from_td(softc,td);
1388
1389	ur = transfer->t_ref;
1390	if (ur) {
1391	    ur->ur_status = K_OHCI_CC_CANCELLED;
1392	    ur->ur_tdcount--;
1393	    if (ur->ur_tdcount == 0) {
1394		if (ohcidebug > 0) printf("Completing request due to closed pipe: %p\n",ur);
1395		usb_complete_request(ur,K_OHCI_CC_CANCELLED);
1396		}
1397	    }
1398
1399	_ohci_freexfer(softc,transfer);
1400	}
1401
1402    /*
1403     * tdphys now points at the tail TD.  Just free it.
1404     */
1405
1406    td = (ohci_td_t *) OHCI_PTOV(tdphys);
1407    _ohci_freexfer(softc,ohci_transfer_from_td(softc,td));
1408
1409    /*
1410     * Return endpoint to free pool
1411     */
1412
1413    _ohci_freeept(softc,ept);
1414}
1415
1416
1417
1418/*  *********************************************************************
1419    *  ohci_xfer(bus,ept,ur)
1420    *
1421    *  Queue a transfer for the specified endpoint.  Depending on
1422    *  the transfer type, the transfer may go on one of many queues.
1423    *  When the transfer completes, a callback will be called.
1424    *
1425    *  Input parameters:
1426    *  	   bus - bus structure
1427    *  	   ept - endpoint descriptor
1428    *  	   ur - request (includes pointer to user buffer)
1429    *
1430    *  Return value:
1431    *  	   0 if ok
1432    *  	   else error
1433    ********************************************************************* */
1434
1435static int ohci_xfer(usbbus_t *bus,usb_ept_t *uept,usbreq_t *ur)
1436{
1437    ohci_softc_t *softc = (ohci_softc_t *) bus->ub_hwsoftc;
1438    ohci_endpoint_t *ept = (ohci_endpoint_t *) uept;
1439    ohci_ed_t *ed = ohci_ed_from_endpoint(softc,ept);
1440    ohci_transfer_t *newtailtransfer = 0;
1441    ohci_td_t *newtailtd = NULL;
1442    ohci_transfer_t *curtransfer;
1443    ohci_td_t *curtd;
1444    uint8_t *ptr;
1445    int len;
1446    int amtcopy;
1447    int pktlen;
1448    uint32_t tdcontrol = 0;
1449
1450    /*
1451     * If the destination USB address matches
1452     * the address of the root hub, shunt the request
1453     * over to our root hub emulation.
1454     */
1455
1456    if (ur->ur_dev->ud_address == softc->ohci_rh_addr) {
1457	return ohci_roothub_xfer(bus,uept,ur);
1458	}
1459
1460    /*
1461     * Set up the TD flags based on the
1462     * request type.
1463     */
1464
1465//    pktlen = ept->ep_mps;
1466    pktlen = OHCI_TD_MAX_DATA - 16;
1467
1468    if (ur->ur_flags & UR_FLAG_SETUP) {
1469	tdcontrol = V_OHCI_TD_PID(K_OHCI_TD_SETUP) |
1470	    V_OHCI_TD_DT(K_OHCI_TD_DT_DATA0) |
1471	    V_OHCI_TD_CC(K_OHCI_CC_NOTACCESSED) |
1472	    V_OHCI_TD_DI(1);
1473	}
1474    else if (ur->ur_flags & UR_FLAG_IN) {
1475	tdcontrol = V_OHCI_TD_PID(K_OHCI_TD_IN) |
1476	    V_OHCI_TD_DT(K_OHCI_TD_DT_TCARRY) |
1477	    V_OHCI_TD_CC(K_OHCI_CC_NOTACCESSED) |
1478	    V_OHCI_TD_DI(1);
1479	}
1480    else if (ur->ur_flags & UR_FLAG_OUT) {
1481	tdcontrol = V_OHCI_TD_PID(K_OHCI_TD_OUT) |
1482	    V_OHCI_TD_DT(K_OHCI_TD_DT_TCARRY) |
1483	    V_OHCI_TD_CC(K_OHCI_CC_NOTACCESSED) |
1484	    V_OHCI_TD_DI(1);
1485	}
1486    else if (ur->ur_flags & UR_FLAG_STATUS_OUT) {
1487	tdcontrol = V_OHCI_TD_PID(K_OHCI_TD_OUT) |
1488	    V_OHCI_TD_DT(K_OHCI_TD_DT_DATA1) |
1489	    V_OHCI_TD_CC(K_OHCI_CC_NOTACCESSED) |
1490	    V_OHCI_TD_DI(1);
1491	}
1492    else if (ur->ur_flags & UR_FLAG_STATUS_IN) {
1493	tdcontrol = V_OHCI_TD_PID(K_OHCI_TD_IN) |
1494	    V_OHCI_TD_DT(K_OHCI_TD_DT_DATA1) |
1495	    V_OHCI_TD_CC(K_OHCI_CC_NOTACCESSED) |
1496	    V_OHCI_TD_DI(1);
1497	}
1498    else {
1499	printf("Shouldn't happen!\n");
1500	}
1501
1502    if (ur->ur_flags & UR_FLAG_SHORTOK) {
1503	tdcontrol |= M_OHCI_TD_SHORTOK;
1504	}
1505
1506
1507    ptr = ur->ur_buffer;
1508    len = ur->ur_length;
1509    ur->ur_tdcount = 0;
1510
1511    if (ohcidebug > 1) {
1512	printf(">> Queueing xfer addr %d pipe %d ED %08X ptr %016llX length %d\n",
1513	       ur->ur_dev->ud_address,
1514	       ur->ur_pipe->up_num,
1515	       ept->ep_phys,
1516	       (uint64_t) (uintptr_t) ptr,
1517	       len);
1518//	ohci_dumped(ed);
1519	}
1520
1521    curtd = OHCI_PTOV(BSWAP32(ed->ed_tailp));
1522    curtransfer = ohci_transfer_from_td(softc,curtd);
1523
1524    if (len == 0) {
1525	newtailtransfer = _ohci_allocxfer(softc);
1526	newtailtd = ohci_td_from_transfer(softc,newtailtransfer);
1527	curtd->td_cbp = 0;
1528	curtd->td_be = 0;
1529	curtd->td_next_td = BSWAP32(OHCI_VTOP(newtailtd));
1530	curtd->td_control = BSWAP32(tdcontrol);
1531	curtransfer->t_next = newtailtransfer;
1532	curtransfer->t_ref = ur;
1533	curtransfer->t_length = 0;
1534	if (ohcidebug > 1) { printf("QueueTD: "); ohci_dumptd(curtd); }
1535	ur->ur_tdcount++;
1536	}
1537    else {
1538	/* Noncoherent DMA: need to flush user buffer to real memory first */
1539	OHCI_FLUSH_RANGE(ptr,len);
1540	while (len > 0) {
1541	    amtcopy = len;
1542	    if (amtcopy > pktlen) amtcopy =  pktlen;
1543	    newtailtransfer = _ohci_allocxfer(softc);
1544	    newtailtd = ohci_td_from_transfer(softc,newtailtransfer);
1545	    curtd->td_cbp = BSWAP32(OHCI_VTOP(ptr));
1546	    curtd->td_be = BSWAP32(OHCI_VTOP(ptr+amtcopy)-1);
1547	    curtd->td_next_td = BSWAP32(OHCI_VTOP(newtailtd));
1548	    curtd->td_control = BSWAP32(tdcontrol);
1549	    curtransfer->t_next = newtailtransfer;
1550	    curtransfer->t_ref = ur;
1551	    curtransfer->t_length = amtcopy;
1552	    if (ohcidebug > 1) { printf("QueueTD: "); ohci_dumptd(curtd); }
1553	    curtd = newtailtd;
1554	    curtransfer = ohci_transfer_from_td(softc,curtd);
1555	    ptr += amtcopy;
1556	    len -= amtcopy;
1557	    ur->ur_tdcount++;
1558	    }
1559	}
1560
1561    curtd = OHCI_PTOV(BSWAP32(ed->ed_headp & M_OHCI_ED_PTRMASK));
1562    ed->ed_tailp = BSWAP32(OHCI_VTOP(newtailtd));
1563
1564    /*
1565     * Prod the controller depending on what type of list we put
1566     * a TD on.
1567     */
1568
1569    if (ept->ep_flags & UP_TYPE_BULK) {
1570	OHCI_WRITECSR(softc,R_OHCI_CMDSTATUS,M_OHCI_CMDSTATUS_BLF);
1571	}
1572    else {
1573	OHCI_WRITECSR(softc,R_OHCI_CMDSTATUS,M_OHCI_CMDSTATUS_CLF);
1574	}
1575
1576    return 0;
1577}
1578
1579/*  *********************************************************************
1580    *  Driver structure
1581    ********************************************************************* */
1582
1583usb_hcdrv_t ohci_driver = {
1584    ohci_create,
1585    ohci_delete,
1586    ohci_start,
1587    ohci_stop,
1588    ohci_intr,
1589    ohci_ept_create,
1590    ohci_ept_delete,
1591    ohci_ept_setmps,
1592    ohci_ept_setaddr,
1593    ohci_ept_cleartoggle,
1594    ohci_xfer
1595};
1596
1597/*  *********************************************************************
1598    *  Root Hub
1599    *
1600    *  Data structures and functions
1601    ********************************************************************* */
1602
1603/*
1604 * Data structures and routines to emulate the root hub.
1605 */
1606static usb_device_descr_t ohci_root_devdsc = {
1607    sizeof(usb_device_descr_t),		/* bLength */
1608    USB_DEVICE_DESCRIPTOR_TYPE,		/* bDescriptorType */
1609    USBWORD(0x0100),			/* bcdUSB */
1610    USB_DEVICE_CLASS_HUB,		/* bDeviceClass */
1611    0,					/* bDeviceSubClass */
1612    0,					/* bDeviceProtocol */
1613    64,					/* bMaxPacketSize0 */
1614    USBWORD(0),				/* idVendor */
1615    USBWORD(0),				/* idProduct */
1616    USBWORD(0x0100),			/* bcdDevice */
1617    1,					/* iManufacturer */
1618    2,					/* iProduct */
1619    0,					/* iSerialNumber */
1620    1					/* bNumConfigurations */
1621};
1622
1623static usb_config_descr_t ohci_root_cfgdsc = {
1624    sizeof(usb_config_descr_t),		/* bLength */
1625    USB_CONFIGURATION_DESCRIPTOR_TYPE,	/* bDescriptorType */
1626    USBWORD(
1627	sizeof(usb_config_descr_t) +
1628	sizeof(usb_interface_descr_t) +
1629	sizeof(usb_endpoint_descr_t)),	/* wTotalLength */
1630    1,					/* bNumInterfaces */
1631    1,					/* bConfigurationValue */
1632    0,					/* iConfiguration */
1633    USB_CONFIG_SELF_POWERED,		/* bmAttributes */
1634    0					/* MaxPower */
1635};
1636
1637static usb_interface_descr_t ohci_root_ifdsc = {
1638    sizeof(usb_interface_descr_t),	/* bLength */
1639    USB_INTERFACE_DESCRIPTOR_TYPE,	/* bDescriptorType */
1640    0,					/* bInterfaceNumber */
1641    0,					/* bAlternateSetting */
1642    1,					/* bNumEndpoints */
1643    USB_INTERFACE_CLASS_HUB,		/* bInterfaceClass */
1644    0,					/* bInterfaceSubClass */
1645    0,					/* bInterfaceProtocol */
1646    0					/* iInterface */
1647};
1648
1649static usb_endpoint_descr_t ohci_root_epdsc = {
1650    sizeof(usb_endpoint_descr_t),	/* bLength */
1651    USB_ENDPOINT_DESCRIPTOR_TYPE,	/* bDescriptorType */
1652    (USB_ENDPOINT_DIRECTION_IN | 1),	/* bEndpointAddress */
1653    USB_ENDPOINT_TYPE_INTERRUPT,	/* bmAttributes */
1654    USBWORD(8),				/* wMaxPacketSize */
1655    255					/* bInterval */
1656};
1657
1658static usb_hub_descr_t ohci_root_hubdsc = {
1659    USB_HUB_DESCR_SIZE,			/* bLength */
1660    USB_HUB_DESCRIPTOR_TYPE,		/* bDescriptorType */
1661    0,					/* bNumberOfPorts */
1662    USBWORD(0),				/* wHubCharacteristics */
1663    0,					/* bPowreOnToPowerGood */
1664    0,					/* bHubControl Current */
1665    {0}					/* bRemoveAndPowerMask */
1666};
1667
1668/*  *********************************************************************
1669    *  ohci_roothb_strdscr(ptr,str)
1670    *
1671    *  Construct a string descriptor for root hub requests
1672    *
1673    *  Input parameters:
1674    *  	   ptr - pointer to where to put descriptor
1675    *  	   str - regular string to put into descriptor
1676    *
1677    *  Return value:
1678    *  	   number of bytes written to descriptor
1679    ********************************************************************* */
1680
1681static int ohci_roothub_strdscr(uint8_t *ptr,char *str)
1682{
1683    uint8_t *p = ptr;
1684
1685    *p++ = strlen(str)*2 + 2;	/* Unicode strings */
1686    *p++ = USB_STRING_DESCRIPTOR_TYPE;
1687    while (*str) {
1688	*p++ = *str++;
1689	*p++ = 0;
1690	}
1691    return (p - ptr);
1692}
1693
1694/*  *********************************************************************
1695    *  ohci_roothub_req(softc,req)
1696    *
1697    *  Handle a descriptor request on the control pipe for the
1698    *  root hub.  We pretend to be a real root hub here and
1699    *  return all the standard descriptors.
1700    *
1701    *  Input parameters:
1702    *  	   softc - our OHCI controller
1703    *  	   req - a usb request (completed immediately)
1704    *
1705    *  Return value:
1706    *  	   0 if ok
1707    *  	   else error code
1708    ********************************************************************* */
1709
1710static int ohci_roothub_req(ohci_softc_t *softc,usb_device_request_t *req)
1711{
1712    uint8_t *ptr;
1713    uint16_t wLength;
1714    uint16_t wValue;
1715    uint16_t wIndex;
1716    usb_port_status_t ups;
1717    usb_hub_descr_t hdsc;
1718    uint32_t status;
1719    uint32_t statport;
1720    uint32_t tmpval;
1721    int res = 0;
1722
1723    ptr = softc->ohci_rh_buf;
1724
1725    wLength = GETUSBFIELD(req,wLength);
1726    wValue  = GETUSBFIELD(req,wValue);
1727    wIndex  = GETUSBFIELD(req,wIndex);
1728
1729    switch (REQSW(req->bRequest,req->bmRequestType)) {
1730
1731	case REQCODE(USB_REQUEST_GET_STATUS,USBREQ_DIR_IN,USBREQ_TYPE_STD,USBREQ_REC_DEVICE):
1732	    *ptr++ = (USB_GETSTATUS_SELF_POWERED & 0xFF);
1733	    *ptr++ = (USB_GETSTATUS_SELF_POWERED >> 8);
1734	    break;
1735
1736	case REQCODE(USB_REQUEST_GET_STATUS,USBREQ_DIR_IN,USBREQ_TYPE_STD,USBREQ_REC_ENDPOINT):
1737	case REQCODE(USB_REQUEST_GET_STATUS,USBREQ_DIR_IN,USBREQ_TYPE_STD,USBREQ_REC_INTERFACE):
1738	    *ptr++ = 0;
1739	    *ptr++ = 0;
1740	    break;
1741
1742	case REQCODE(USB_REQUEST_GET_STATUS,USBREQ_DIR_IN,USBREQ_TYPE_CLASS,USBREQ_REC_OTHER):
1743	    status = OHCI_READCSR(softc,(R_OHCI_RHPORTSTATUS(wIndex)));
1744	    if (ohcidebug > 0) { printf("RHGetStatus: "); ohci_dumpportstat(wIndex,status);}
1745	    PUTUSBFIELD((&ups),wPortStatus,(status & 0xFFFF));
1746	    PUTUSBFIELD((&ups),wPortChange,(status >> 16));
1747	    memcpy(ptr,&ups,sizeof(ups));
1748	    ptr += sizeof(ups);
1749	    break;
1750
1751	case REQCODE(USB_REQUEST_GET_STATUS,USBREQ_DIR_IN,USBREQ_TYPE_CLASS,USBREQ_REC_DEVICE):
1752	    *ptr++ = 0;
1753	    *ptr++ = 0;
1754	    *ptr++ = 0;
1755	    *ptr++ = 0;
1756	    break;
1757
1758	case REQCODE(USB_REQUEST_CLEAR_FEATURE,USBREQ_DIR_OUT,USBREQ_TYPE_STD,USBREQ_REC_DEVICE):
1759	case REQCODE(USB_REQUEST_CLEAR_FEATURE,USBREQ_DIR_OUT,USBREQ_TYPE_STD,USBREQ_REC_INTERFACE):
1760	case REQCODE(USB_REQUEST_CLEAR_FEATURE,USBREQ_DIR_OUT,USBREQ_TYPE_STD,USBREQ_REC_ENDPOINT):
1761	    /* do nothing, not supported */
1762	    break;
1763
1764	case REQCODE(USB_REQUEST_CLEAR_FEATURE,USBREQ_DIR_OUT,USBREQ_TYPE_CLASS,USBREQ_REC_OTHER):
1765	    statport = R_OHCI_RHPORTSTATUS(wIndex);
1766	    if (ohcidebug> 0) {
1767		printf("RHClearFeature(%d): ",wValue); ohci_dumpportstat(wIndex,OHCI_READCSR(softc,statport));
1768		}
1769	    switch (wValue) {
1770		case USB_PORT_FEATURE_CONNECTION:
1771		    break;
1772		case USB_PORT_FEATURE_ENABLE:
1773		    OHCI_WRITECSR(softc,statport,M_OHCI_RHPORTSTAT_CCS);
1774		    break;
1775		case USB_PORT_FEATURE_SUSPEND:
1776		    OHCI_WRITECSR(softc,statport,M_OHCI_RHPORTSTAT_POCI);
1777		    break;
1778		case USB_PORT_FEATURE_OVER_CURRENT:
1779		    break;
1780		case USB_PORT_FEATURE_RESET:
1781		    break;
1782		case USB_PORT_FEATURE_POWER:
1783		    OHCI_WRITECSR(softc,statport,M_OHCI_RHPORTSTAT_LSDA);
1784		    break;
1785		case USB_PORT_FEATURE_LOW_SPEED:
1786		    break;
1787		case USB_PORT_FEATURE_C_PORT_CONNECTION:
1788		    OHCI_WRITECSR(softc,statport,M_OHCI_RHPORTSTAT_CSC);
1789		    break;
1790		case USB_PORT_FEATURE_C_PORT_ENABLE:
1791		    OHCI_WRITECSR(softc,statport,M_OHCI_RHPORTSTAT_PESC);
1792		    break;
1793		case USB_PORT_FEATURE_C_PORT_SUSPEND:
1794		    OHCI_WRITECSR(softc,statport,M_OHCI_RHPORTSTAT_PSSC);
1795		    break;
1796		case USB_PORT_FEATURE_C_PORT_OVER_CURRENT:
1797		    OHCI_WRITECSR(softc,statport,M_OHCI_RHPORTSTAT_OCIC);
1798		    break;
1799		case USB_PORT_FEATURE_C_PORT_RESET:
1800		    OHCI_WRITECSR(softc,statport,M_OHCI_RHPORTSTAT_PRSC);
1801		    break;
1802
1803		}
1804
1805	    /*
1806	     * If we've cleared all of the conditions that
1807	     * want our attention on the port status,
1808	     * then we can accept port status interrupts again.
1809	     */
1810
1811	    if ((wValue >= USB_PORT_FEATURE_C_PORT_CONNECTION) &&
1812		(wValue <= USB_PORT_FEATURE_C_PORT_RESET)) {
1813		status = OHCI_READCSR(softc,statport);
1814		if ((status & M_OHCI_RHPORTSTAT_ALLC) == 0) {
1815		    softc->ohci_intdisable &= ~M_OHCI_INT_RHSC;
1816		    }
1817		}
1818	    break;
1819
1820	case REQCODE(USB_REQUEST_SET_FEATURE,USBREQ_DIR_OUT,USBREQ_TYPE_STD,USBREQ_REC_DEVICE):
1821	case REQCODE(USB_REQUEST_SET_FEATURE,USBREQ_DIR_OUT,USBREQ_TYPE_STD,USBREQ_REC_INTERFACE):
1822	case REQCODE(USB_REQUEST_SET_FEATURE,USBREQ_DIR_OUT,USBREQ_TYPE_STD,USBREQ_REC_ENDPOINT):
1823	    res = -1;
1824	    break;
1825
1826	case REQCODE(USB_REQUEST_SET_FEATURE,USBREQ_DIR_OUT,USBREQ_TYPE_CLASS,USBREQ_REC_DEVICE):
1827	    /* nothing */
1828	    break;
1829
1830	case REQCODE(USB_REQUEST_SET_FEATURE,USBREQ_DIR_OUT,USBREQ_TYPE_CLASS,USBREQ_REC_OTHER):
1831	    statport = R_OHCI_RHPORTSTATUS(wIndex);
1832	    switch (wValue) {
1833		case USB_PORT_FEATURE_CONNECTION:
1834		    break;
1835		case USB_PORT_FEATURE_ENABLE:
1836		    OHCI_WRITECSR(softc,statport,M_OHCI_RHPORTSTAT_PES);
1837		    break;
1838		case USB_PORT_FEATURE_SUSPEND:
1839		    OHCI_WRITECSR(softc,statport,M_OHCI_RHPORTSTAT_PSS);
1840		    break;
1841		case USB_PORT_FEATURE_OVER_CURRENT:
1842		    break;
1843		case USB_PORT_FEATURE_RESET:
1844		    OHCI_WRITECSR(softc,statport,M_OHCI_RHPORTSTAT_PRS);
1845		    for (;;) {
1846			usb_delay_ms(softc->ohci_bus,100);
1847			if (!(OHCI_READCSR(softc,statport) & M_OHCI_RHPORTSTAT_PRS)) break;
1848			}
1849		    break;
1850		case USB_PORT_FEATURE_POWER:
1851		    OHCI_WRITECSR(softc,statport,M_OHCI_RHPORTSTAT_PPS);
1852		    break;
1853		case USB_PORT_FEATURE_LOW_SPEED:
1854		    break;
1855		case USB_PORT_FEATURE_C_PORT_CONNECTION:
1856		    break;
1857		case USB_PORT_FEATURE_C_PORT_ENABLE:
1858		    break;
1859		case USB_PORT_FEATURE_C_PORT_SUSPEND:
1860		    break;
1861		case USB_PORT_FEATURE_C_PORT_OVER_CURRENT:
1862		    break;
1863		case USB_PORT_FEATURE_C_PORT_RESET:
1864		    break;
1865
1866		}
1867
1868	    break;
1869
1870	case REQCODE(USB_REQUEST_SET_ADDRESS,USBREQ_DIR_OUT,USBREQ_TYPE_STD,USBREQ_REC_DEVICE):
1871	    softc->ohci_rh_newaddr = wValue;
1872	    break;
1873
1874	case REQCODE(USB_REQUEST_GET_DESCRIPTOR,USBREQ_DIR_IN,USBREQ_TYPE_STD,USBREQ_REC_DEVICE):
1875	    switch (wValue >> 8) {
1876		case USB_DEVICE_DESCRIPTOR_TYPE:
1877		    memcpy(ptr,&ohci_root_devdsc,sizeof(ohci_root_devdsc));
1878		    ptr += sizeof(ohci_root_devdsc);
1879		    break;
1880		case USB_CONFIGURATION_DESCRIPTOR_TYPE:
1881		    memcpy(ptr,&ohci_root_cfgdsc,sizeof(ohci_root_cfgdsc));
1882		    ptr += sizeof(ohci_root_cfgdsc);
1883		    memcpy(ptr,&ohci_root_ifdsc,sizeof(ohci_root_ifdsc));
1884		    ptr += sizeof(ohci_root_ifdsc);
1885		    memcpy(ptr,&ohci_root_epdsc,sizeof(ohci_root_epdsc));
1886		    ptr += sizeof(ohci_root_epdsc);
1887		    break;
1888		case USB_STRING_DESCRIPTOR_TYPE:
1889		    switch (wValue & 0xFF) {
1890			case 1:
1891			    ptr += ohci_roothub_strdscr(ptr,"Generic");
1892			    break;
1893			case 2:
1894			    ptr += ohci_roothub_strdscr(ptr,"Root Hub");
1895			    break;
1896			default:
1897			    *ptr++ = 0;
1898			    break;
1899			}
1900		    break;
1901		default:
1902		    res = -1;
1903		    break;
1904		}
1905	    break;
1906
1907	case REQCODE(USB_REQUEST_GET_DESCRIPTOR,USBREQ_DIR_IN,USBREQ_TYPE_CLASS,USBREQ_REC_DEVICE):
1908	    memcpy(&hdsc,&ohci_root_hubdsc,sizeof(hdsc));
1909	    hdsc.bNumberOfPorts = softc->ohci_ndp;
1910	    status = OHCI_READCSR(softc,R_OHCI_RHDSCRA);
1911	    tmpval = 0;
1912	    if (status & M_OHCI_RHDSCRA_NPS) tmpval |= USB_HUBCHAR_PWR_NONE;
1913	    if (status & M_OHCI_RHDSCRA_PSM) tmpval |= USB_HUBCHAR_PWR_GANGED;
1914	    else tmpval |= USB_HUBCHAR_PWR_IND;
1915	    PUTUSBFIELD((&hdsc),wHubCharacteristics,tmpval);
1916	    tmpval = G_OHCI_RHDSCRA_POTPGT(status);
1917	    hdsc.bPowerOnToPowerGood = tmpval;
1918	    hdsc.bDescriptorLength = USB_HUB_DESCR_SIZE + 1;
1919	    status = OHCI_READCSR(softc,R_OHCI_RHDSCRB);
1920	    hdsc.bRemoveAndPowerMask[0] = (uint8_t) status;
1921	    memcpy(ptr,&hdsc,sizeof(hdsc));
1922	    ptr += sizeof(hdsc);
1923	    break;
1924
1925	case REQCODE(USB_REQUEST_SET_DESCRIPTOR,USBREQ_DIR_OUT,USBREQ_TYPE_CLASS,USBREQ_REC_DEVICE):
1926	    /* nothing */
1927	    break;
1928
1929	case REQCODE(USB_REQUEST_GET_CONFIGURATION,USBREQ_DIR_IN,USBREQ_TYPE_STD,USBREQ_REC_DEVICE):
1930	    *ptr++ = softc->ohci_rh_conf;
1931	    break;
1932
1933	case REQCODE(USB_REQUEST_SET_CONFIGURATION,USBREQ_DIR_OUT,USBREQ_TYPE_STD,USBREQ_REC_DEVICE):
1934	    softc->ohci_rh_conf = wValue;
1935	    break;
1936
1937	case REQCODE(USB_REQUEST_GET_INTERFACE,USBREQ_DIR_IN,USBREQ_TYPE_STD,USBREQ_REC_INTERFACE):
1938	    *ptr++ = 0;
1939	    break;
1940
1941	case REQCODE(USB_REQUEST_SET_INTERFACE,USBREQ_DIR_OUT,USBREQ_TYPE_STD,USBREQ_REC_INTERFACE):
1942	    /* nothing */
1943	    break;
1944
1945	case REQCODE(USB_REQUEST_SYNC_FRAME,USBREQ_DIR_OUT,USBREQ_TYPE_STD,USBREQ_REC_ENDPOINT):
1946	    /* nothing */
1947	    break;
1948	}
1949
1950    softc->ohci_rh_ptr = softc->ohci_rh_buf;
1951    softc->ohci_rh_len = ptr - softc->ohci_rh_buf;
1952
1953    return res;
1954}
1955
1956/*  *********************************************************************
1957    *  ohci_roothub_statchg(softc)
1958    *
1959    *  This routine is called from the interrupt service routine
1960    *  (well, polling routine) for the ohci controller.  If the
1961    *  controller notices a root hub status change, it dequeues an
1962    *  interrupt transfer from the root hub's queue and completes
1963    *  it here.
1964    *
1965    *  Input parameters:
1966    *  	   softc - our OHCI controller
1967    *
1968    *  Return value:
1969    *  	   nothing
1970    ********************************************************************* */
1971
1972static void ohci_roothub_statchg(ohci_softc_t *softc)
1973{
1974    usbreq_t *ur;
1975    uint32_t status;
1976    uint8_t portstat = 0;
1977    int idx;
1978
1979    /* Note: this only works up to 8 ports */
1980    for (idx = 1; idx <= softc->ohci_ndp; idx++) {
1981	status = OHCI_READCSR(softc,R_OHCI_RHPORTSTATUS(idx));
1982	if (status & M_OHCI_RHPORTSTAT_ALLC) {
1983	    portstat = (1<<idx);
1984	    }
1985	}
1986
1987    if (portstat != 0) {
1988	softc->ohci_intdisable |= M_OHCI_INT_RHSC;
1989	}
1990
1991    ur = (usbreq_t *) q_deqnext(&(softc->ohci_rh_intrq));
1992    if (!ur) return;		/* no requests pending, ignore it */
1993
1994    memset(ur->ur_buffer,0,ur->ur_length);
1995    ur->ur_buffer[0] = portstat;
1996    ur->ur_xferred = ur->ur_length;
1997
1998    usb_complete_request(ur,0);
1999}
2000
2001/*  *********************************************************************
2002    *  ohci_roothub_xfer(softc,req)
2003    *
2004    *  Handle a root hub xfer - ohci_xfer transfers control here
2005    *  if we detect the address of the root hub - no actual transfers
2006    *  go out on the wire, we just handle the requests directly to
2007    *  make it look like a hub is attached.
2008    *
2009    *  This seems to be common practice in the USB world, so we do
2010    *  it here too.
2011    *
2012    *  Input parameters:
2013    *  	   softc - our OHCI controller structure
2014    *  	   req - usb request destined for host controller
2015    *
2016    *  Return value:
2017    *  	   0 if ok
2018    *  	   else error
2019    ********************************************************************* */
2020
2021static int ohci_roothub_xfer(usbbus_t *bus,usb_ept_t *uept,usbreq_t *ur)
2022{
2023    ohci_softc_t *softc = (ohci_softc_t *) bus->ub_hwsoftc;
2024    ohci_endpoint_t *ept = (ohci_endpoint_t *) uept;
2025    int res;
2026
2027    switch (ept->ep_num) {
2028
2029	/*
2030	 * CONTROL ENDPOINT
2031	 */
2032	case 0:
2033
2034	    /*
2035	     * Three types of transfers:  OUT (SETUP), IN (data), or STATUS.
2036	     * figure out which is which.
2037	     */
2038
2039	    if (ur->ur_flags & UR_FLAG_SETUP) {
2040		/*
2041		 * SETUP packet - this is an OUT request to the control
2042		 * pipe.  We emulate the hub request here.
2043		 */
2044		usb_device_request_t *req;
2045
2046		req = (usb_device_request_t *) ur->ur_buffer;
2047
2048		res = ohci_roothub_req(softc,req);
2049		if (res != 0) printf("Root hub request returned an error\n");
2050
2051		ur->ur_xferred = ur->ur_length;
2052		ur->ur_status = 0;
2053		usb_complete_request(ur,0);
2054		}
2055
2056	    else if (ur->ur_flags & UR_FLAG_STATUS_IN) {
2057		/*
2058		 * STATUS IN : it's sort of like a dummy IN request
2059		 * to acknowledge a SETUP packet that otherwise has no
2060		 * status.  Just complete the usbreq.
2061		 */
2062
2063		if (softc->ohci_rh_newaddr != -1) {
2064		    softc->ohci_rh_addr = softc->ohci_rh_newaddr;
2065		    softc->ohci_rh_newaddr = -1;
2066		    }
2067
2068		ur->ur_status = 0;
2069		ur->ur_xferred = 0;
2070		usb_complete_request(ur,0);
2071		}
2072
2073	    else if (ur->ur_flags & UR_FLAG_STATUS_OUT) {
2074		/*
2075		 * STATUS OUT : it's sort of like a dummy OUT request
2076		 */
2077		ur->ur_status = 0;
2078		ur->ur_xferred = 0;
2079		usb_complete_request(ur,0);
2080		}
2081
2082	    else if (ur->ur_flags & UR_FLAG_IN) {
2083		/*
2084		 * IN : return data from the root hub
2085		 */
2086		int amtcopy;
2087
2088		amtcopy = softc->ohci_rh_len;
2089		if (amtcopy > ur->ur_length) amtcopy = ur->ur_length;
2090
2091		memcpy(ur->ur_buffer,softc->ohci_rh_ptr,amtcopy);
2092
2093		softc->ohci_rh_ptr += amtcopy;
2094		softc->ohci_rh_len -= amtcopy;
2095
2096		ur->ur_status = 0;
2097		ur->ur_xferred = amtcopy;
2098		usb_complete_request(ur,0);
2099		}
2100
2101	    else {
2102		printf("Unknown root hub transfer type\n");
2103		return -1;
2104		}
2105	    break;
2106
2107	/*
2108	 * INTERRUPT ENDPOINT
2109	 */
2110
2111	case 1:			/* interrupt pipe */
2112	    if (ur->ur_flags & UR_FLAG_IN) {
2113		q_enqueue(&(softc->ohci_rh_intrq),(queue_t *) ur);
2114		}
2115 	    break;
2116
2117	}
2118
2119
2120    return 0;
2121}
2122