Bug #1010 » freebsd.usb.diff
| /root/src/sys/dev/usb/ehci.c 2008-05-13 20:58:08 +0000 | ||
|---|---|---|
| 
     /*	$NetBSD: ehci.c,v 1.91 2005/02/27 00:27:51 perry Exp $ */ 
   | 
||
| 
     /*	$FreeBSD: src/sys/dev/usb/ehci.c,v 1.36.2.3 2006/09/24 13:39:04 iedowse Exp $	*/ 
   | 
||
| 
     /*	$DragonFly: src/sys/bus/usb/ehci.c,v 1.32 2007/06/29 22:56:31 hasso Exp $	*/ 
   | 
||
| 
     /* 
   | 
||
| 
     /*- 
   | 
||
| 
      * Copyright (c) 2004 The NetBSD Foundation, Inc. 
   | 
||
| 
      * All rights reserved. 
   | 
||
| 
      * 
   | 
||
| ... | ... | |
| 
      * 3) Command failures are not recovered correctly. 
   | 
||
| 
      */ 
   | 
||
| 
     #include <sys/cdefs.h> 
   | 
||
| 
     __FBSDID("$FreeBSD: src/sys/dev/usb/ehci.c,v 1.63 2008/05/13 20:58:08 marius Exp $"); 
   | 
||
| 
     #include <sys/param.h> 
   | 
||
| 
     #include <sys/systm.h> 
   | 
||
| 
     #include <sys/malloc.h> 
   | 
||
| ... | ... | |
| 
     #include <sys/module.h> 
   | 
||
| 
     #include <sys/bus.h> 
   | 
||
| 
     #include <sys/lock.h> 
   | 
||
| 
     #include <sys/lockmgr.h> 
   | 
||
| 
     #if defined(DIAGNOSTIC) && defined(__i386__) && defined(__FreeBSD__) 
   | 
||
| 
     #include <machine/cpu.h> 
   | 
||
| 
     #endif 
   | 
||
| 
     #include <sys/proc.h> 
   | 
||
| 
     #include <sys/queue.h> 
   | 
||
| 
     #include <sys/sysctl.h> 
   | 
||
| 
     #include <sys/thread2.h> 
   | 
||
| 
     #include <machine/cpu.h> 
   | 
||
| 
     #include <machine/bus.h> 
   | 
||
| 
     #include <machine/endian.h> 
   | 
||
| 
     #include <bus/usb/usb.h> 
   | 
||
| 
     #include <bus/usb/usbdi.h> 
   | 
||
| 
     #include <bus/usb/usbdivar.h> 
   | 
||
| 
     #include <bus/usb/usb_mem.h> 
   | 
||
| 
     #include <bus/usb/usb_quirks.h> 
   | 
||
| 
     #include <dev/usb/usb.h> 
   | 
||
| 
     #include <dev/usb/usbdi.h> 
   | 
||
| 
     #include <dev/usb/usbdivar.h> 
   | 
||
| 
     #include <dev/usb/usb_mem.h> 
   | 
||
| 
     #include <dev/usb/usb_quirks.h> 
   | 
||
| 
     #include <bus/usb/ehcireg.h> 
   | 
||
| 
     #include <bus/usb/ehcivar.h> 
   | 
||
| 
     #include <dev/usb/ehcireg.h> 
   | 
||
| 
     #include <dev/usb/ehcivar.h> 
   | 
||
| 
     #define delay(d)                DELAY(d) 
   | 
||
| 
     #ifdef USB_DEBUG 
   | 
||
| 
     #define EHCI_DEBUG USB_DEBUG 
   | 
||
| 
     #define DPRINTF(x)	do { if (ehcidebug) kprintf x; } while (0) 
   | 
||
| 
     #define DPRINTFN(n,x)	do { if (ehcidebug>(n)) kprintf x; } while (0) 
   | 
||
| 
     #define DPRINTF(x)	do { if (ehcidebug) printf x; } while (0) 
   | 
||
| 
     #define DPRINTFN(n,x)	do { if (ehcidebug>(n)) printf x; } while (0) 
   | 
||
| 
     int ehcidebug = 0; 
   | 
||
| 
     SYSCTL_NODE(_hw_usb, OID_AUTO, ehci, CTLFLAG_RW, 0, "USB ehci"); 
   | 
||
| 
     SYSCTL_INT(_hw_usb_ehci, OID_AUTO, debug, CTLFLAG_RW, 
   | 
||
| 
     	   &ehcidebug, 0, "ehci debug level"); 
   | 
||
| 
     #define bitmask_snprintf(q,f,b,l) ksnprintf((b), (l), "%b", (q), (f)) 
   | 
||
| 
     #define bitmask_snprintf(q,f,b,l) snprintf((b), (l), "%b", (q), (f)) 
   | 
||
| 
     #else 
   | 
||
| 
     #define DPRINTF(x) 
   | 
||
| 
     #define DPRINTFN(n,x) 
   | 
||
| ... | ... | |
| 
                      * Table 2-9 in the EHCI spec says this will result 
   | 
||
| 
                      * in undefined behavior. 
   | 
||
| 
                      */ 
   | 
||
| 
     		kprintf("%s: stop timeout\n", 
   | 
||
| 
     		printf("%s: stop timeout\n", 
   | 
||
| 
     		       device_get_nameunit(sc->sc_bus.bdev)); 
   | 
||
| 
     	EOWRITE4(sc, EHCI_USBCMD, EHCI_CMD_HCRESET); 
   | 
||
| ... | ... | |
| 
     		if (!hcr) 
   | 
||
| 
     			return (USBD_NORMAL_COMPLETION); 
   | 
||
| 
     	} 
   | 
||
| 
     	kprintf("%s: reset timeout\n", device_get_nameunit(sc->sc_bus.bdev)); 
   | 
||
| 
     	printf("%s: reset timeout\n", device_get_nameunit(sc->sc_bus.bdev)); 
   | 
||
| 
     	return (USBD_IOERROR); 
   | 
||
| 
     } 
   | 
||
| ... | ... | |
| 
     	sc->sc_offs = EREAD1(sc, EHCI_CAPLENGTH); 
   | 
||
| 
     	version = EREAD2(sc, EHCI_HCIVERSION); 
   | 
||
| 
     	kprintf("%s: EHCI version %x.%x\n", device_get_nameunit(sc->sc_bus.bdev), 
   | 
||
| 
     	printf("%s: EHCI version %x.%x\n", device_get_nameunit(sc->sc_bus.bdev), 
   | 
||
| 
     	       version >> 8, version & 0xff); 
   | 
||
| 
     	sparams = EREAD4(sc, EHCI_HCSPARAMS); 
   | 
||
| ... | ... | |
| 
     	sc->sc_npcomp = EHCI_HCS_N_PCC(sparams); 
   | 
||
| 
     	ncomp = EHCI_HCS_N_CC(sparams); 
   | 
||
| 
     	if (ncomp != sc->sc_ncomp) { 
   | 
||
| 
     		kprintf("%s: wrong number of companions (%d != %d)\n", 
   | 
||
| 
     		printf("%s: wrong number of companions (%d != %d)\n", 
   | 
||
| 
     		       device_get_nameunit(sc->sc_bus.bdev), 
   | 
||
| 
     		       ncomp, sc->sc_ncomp); 
   | 
||
| 
     		if (ncomp < sc->sc_ncomp) 
   | 
||
| 
     			sc->sc_ncomp = ncomp; 
   | 
||
| 
     	} 
   | 
||
| 
     	if (sc->sc_ncomp > 0) { 
   | 
||
| 
     		kprintf("%s: companion controller%s, %d port%s each:", 
   | 
||
| 
     		printf("%s: companion controller%s, %d port%s each:", 
   | 
||
| 
     		    device_get_nameunit(sc->sc_bus.bdev), sc->sc_ncomp!=1 ? "s" : "", 
   | 
||
| 
     		    EHCI_HCS_N_PCC(sparams), 
   | 
||
| 
     		    EHCI_HCS_N_PCC(sparams)!=1 ? "s" : ""); 
   | 
||
| 
     		for (i = 0; i < sc->sc_ncomp; i++) 
   | 
||
| 
     			kprintf(" %s", device_get_nameunit(sc->sc_comps[i]->bdev)); 
   | 
||
| 
     		kprintf("\n"); 
   | 
||
| 
     			printf(" %s", device_get_nameunit(sc->sc_comps[i]->bdev)); 
   | 
||
| 
     		printf("\n"); 
   | 
||
| 
     	} 
   | 
||
| 
     	sc->sc_noport = EHCI_HCS_N_PORTS(sparams); 
   | 
||
| 
     	cparams = EREAD4(sc, EHCI_HCCPARAMS); 
   | 
||
| ... | ... | |
| 
     	case 3: return (USBD_IOERROR); 
   | 
||
| 
     	} 
   | 
||
| 
     	err = usb_allocmem(&sc->sc_bus, sc->sc_flsize * sizeof(ehci_link_t), 
   | 
||
| 
     			   EHCI_FLALIGN_ALIGN, &sc->sc_fldma); 
   | 
||
| 
     	    EHCI_FLALIGN_ALIGN, &sc->sc_fldma); 
   | 
||
| 
     	if (err) 
   | 
||
| 
     		return (err); 
   | 
||
| 
     	DPRINTF(("%s: flsize=%d\n", device_get_nameunit(sc->sc_bus.bdev),sc->sc_flsize)); 
   | 
||
| ... | ... | |
| 
     	sc->sc_bus.methods = &ehci_bus_methods; 
   | 
||
| 
     	sc->sc_bus.pipe_size = sizeof(struct ehci_pipe); 
   | 
||
| 
     #if defined(__NetBSD__) || defined(__OpenBSD__) 
   | 
||
| 
     	sc->sc_powerhook = powerhook_establish(ehci_power, sc); 
   | 
||
| 
     	sc->sc_shutdownhook = shutdownhook_establish(ehci_shutdown, sc); 
   | 
||
| 
     #endif 
   | 
||
| 
     	sc->sc_eintrs = EHCI_NORMAL_INTRS; 
   | 
||
| 
     	/* 
   | 
||
| ... | ... | |
| 
     	sc->sc_async_head = sqh; 
   | 
||
| 
     	EOWRITE4(sc, EHCI_ASYNCLISTADDR, sqh->physaddr | EHCI_LINK_QH); 
   | 
||
| 
     	callout_init(&sc->sc_tmo_pcd); 
   | 
||
| 
     	callout_init(&sc->sc_tmo_intrlist); 
   | 
||
| 
     	callout_init(&sc->sc_tmo_pcd, 0); 
   | 
||
| 
     	callout_init(&sc->sc_tmo_intrlist, 0); 
   | 
||
| 
     	lockinit(&sc->sc_doorbell_lock, "ehcidb", 0, 0); 
   | 
||
| 
     	lockinit(&sc->sc_doorbell_lock, PZERO, "ehcidb", 0, 0); 
   | 
||
| 
     	/* Enable interrupts */ 
   | 
||
| 
     	EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs); 
   | 
||
| ... | ... | |
| 
     			break; 
   | 
||
| 
     	} 
   | 
||
| 
     	if (hcr) { 
   | 
||
| 
     		kprintf("%s: run timeout\n", device_get_nameunit(sc->sc_bus.bdev)); 
   | 
||
| 
     		printf("%s: run timeout\n", device_get_nameunit(sc->sc_bus.bdev)); 
   | 
||
| 
     		return (USBD_IOERROR); 
   | 
||
| 
     	} 
   | 
||
| ... | ... | |
| 
     	/* In case the interrupt occurs before initialization has completed. */ 
   | 
||
| 
     	if (sc == NULL) { 
   | 
||
| 
     #ifdef DIAGNOSTIC 
   | 
||
| 
     		kprintf("ehci_intr1: sc == NULL\n"); 
   | 
||
| 
     		printf("ehci_intr1: sc == NULL\n"); 
   | 
||
| 
     #endif 
   | 
||
| 
     		return (0); 
   | 
||
| 
     	} 
   | 
||
| ... | ... | |
| 
     		eintrs &= ~(EHCI_STS_INT | EHCI_STS_ERRINT); 
   | 
||
| 
     	} 
   | 
||
| 
     	if (eintrs & EHCI_STS_HSE) { 
   | 
||
| 
     		kprintf("%s: unrecoverable error, controller halted\n", 
   | 
||
| 
     		printf("%s: unrecoverable error, controller halted\n", 
   | 
||
| 
     		       device_get_nameunit(sc->sc_bus.bdev)); 
   | 
||
| 
     		/* XXX what else */ 
   | 
||
| 
     	} 
   | 
||
| ... | ... | |
| 
     		/* Block unprocessed interrupts. */ 
   | 
||
| 
     		sc->sc_eintrs &= ~eintrs; 
   | 
||
| 
     		EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs); 
   | 
||
| 
     		kprintf("%s: blocking intrs 0x%x\n", 
   | 
||
| 
     		printf("%s: blocking intrs 0x%x\n", 
   | 
||
| 
     		       device_get_nameunit(sc->sc_bus.bdev), eintrs); 
   | 
||
| 
     	} 
   | 
||
| ... | ... | |
| 
     	DPRINTFN(/*15*/2, ("ehci_check_intr: ex=%p\n", ex)); 
   | 
||
| 
     	if (ex->sqtdstart == NULL) { 
   | 
||
| 
     		kprintf("ehci_check_intr: sqtdstart=NULL\n"); 
   | 
||
| 
     		printf("ehci_check_intr: sqtdstart=NULL\n"); 
   | 
||
| 
     		return; 
   | 
||
| 
     	} 
   | 
||
| 
     	lsqtd = ex->sqtdend; 
   | 
||
| 
     #ifdef DIAGNOSTIC 
   | 
||
| 
     	if (lsqtd == NULL) { 
   | 
||
| 
     		kprintf("ehci_check_intr: lsqtd==0\n"); 
   | 
||
| 
     		printf("ehci_check_intr: lsqtd==0\n"); 
   | 
||
| 
     		return; 
   | 
||
| 
     	} 
   | 
||
| 
     #endif 
   | 
||
| ... | ... | |
| 
     	DPRINTFN(/*12*/2, ("ehci_idone: ex=%p\n", ex)); 
   | 
||
| 
     #ifdef DIAGNOSTIC 
   | 
||
| 
     	{ 
   | 
||
| 
     		crit_enter(); 
   | 
||
| 
     		int s = splhigh(); 
   | 
||
| 
     		if (ex->isdone) { 
   | 
||
| 
     			crit_exit(); 
   | 
||
| 
     			splx(s); 
   | 
||
| 
     #ifdef EHCI_DEBUG 
   | 
||
| 
     			kprintf("ehci_idone: ex is done!\n   "); 
   | 
||
| 
     			printf("ehci_idone: ex is done!\n   "); 
   | 
||
| 
     			ehci_dump_exfer(ex); 
   | 
||
| 
     #else 
   | 
||
| 
     			kprintf("ehci_idone: ex=%p is done!\n", ex); 
   | 
||
| 
     			printf("ehci_idone: ex=%p is done!\n", ex); 
   | 
||
| 
     #endif 
   | 
||
| 
     			return; 
   | 
||
| 
     		} 
   | 
||
| 
     		ex->isdone = 1; 
   | 
||
| 
     		crit_exit(); 
   | 
||
| 
     		splx(s); 
   | 
||
| 
     	} 
   | 
||
| 
     #endif 
   | 
||
| ... | ... | |
| 
     	callout_stop(&sc->sc_tmo_intrlist); 
   | 
||
| 
     	callout_stop(&sc->sc_tmo_pcd); 
   | 
||
| 
     #if defined(__NetBSD__) || defined(__OpenBSD__) 
   | 
||
| 
     	if (sc->sc_powerhook != NULL) 
   | 
||
| 
     		powerhook_disestablish(sc->sc_powerhook); 
   | 
||
| 
     	if (sc->sc_shutdownhook != NULL) 
   | 
||
| 
     		shutdownhook_disestablish(sc->sc_shutdownhook); 
   | 
||
| 
     #endif 
   | 
||
| 
     	usb_delay_ms(&sc->sc_bus, 300); /* XXX let stray task complete */ 
   | 
||
| 
     	usb_freemem(&sc->sc_bus, &sc->sc_fldma); 
   | 
||
| ... | ... | |
| 
     { 
   | 
||
| 
     	ehci_softc_t *sc = v; 
   | 
||
| 
     	u_int32_t cmd, hcr; 
   | 
||
| 
     	int i; 
   | 
||
| 
     	int s, i; 
   | 
||
| 
     #ifdef EHCI_DEBUG 
   | 
||
| 
     	DPRINTF(("ehci_power: sc=%p, why=%d\n", sc, why)); 
   | 
||
| ... | ... | |
| 
     		ehci_dump_regs(sc); 
   | 
||
| 
     #endif 
   | 
||
| 
     	crit_enter(); 
   | 
||
| 
     	s = splhardusb(); 
   | 
||
| 
     	switch (why) { 
   | 
||
| 
     	case PWR_SUSPEND: 
   | 
||
| 
     	case PWR_STANDBY: 
   | 
||
| ... | ... | |
| 
     			usb_delay_ms(&sc->sc_bus, 1); 
   | 
||
| 
     		} 
   | 
||
| 
     		if (hcr != 0) { 
   | 
||
| 
     			kprintf("%s: reset timeout\n", 
   | 
||
| 
     			printf("%s: reset timeout\n", 
   | 
||
| 
     			    device_get_nameunit(sc->sc_bus.bdev)); 
   | 
||
| 
     		} 
   | 
||
| ... | ... | |
| 
     			usb_delay_ms(&sc->sc_bus, 1); 
   | 
||
| 
     		} 
   | 
||
| 
     		if (hcr != EHCI_STS_HCH) { 
   | 
||
| 
     			kprintf("%s: config timeout\n", 
   | 
||
| 
     			printf("%s: config timeout\n", 
   | 
||
| 
     			    device_get_nameunit(sc->sc_bus.bdev)); 
   | 
||
| 
     		} 
   | 
||
| ... | ... | |
| 
     			usb_delay_ms(&sc->sc_bus, 1); 
   | 
||
| 
     		} 
   | 
||
| 
     		if (hcr == EHCI_STS_HCH) { 
   | 
||
| 
     			kprintf("%s: config timeout\n", 
   | 
||
| 
     			printf("%s: config timeout\n", 
   | 
||
| 
     			    device_get_nameunit(sc->sc_bus.bdev)); 
   | 
||
| 
     		} 
   | 
||
| ... | ... | |
| 
     	case PWR_SOFTRESUME: 
   | 
||
| 
     		break; 
   | 
||
| 
     	} 
   | 
||
| 
     	crit_exit(); 
   | 
||
| 
     	splx(s); 
   | 
||
| 
     #ifdef EHCI_DEBUG 
   | 
||
| 
     	DPRINTF(("ehci_power: sc=%p\n", sc)); 
   | 
||
| ... | ... | |
| 
     	err = usb_allocmem(bus, size, 0, dma); 
   | 
||
| 
     #ifdef EHCI_DEBUG 
   | 
||
| 
     	if (err) 
   | 
||
| 
     		kprintf("ehci_allocm: usb_allocmem()=%d\n", err); 
   | 
||
| 
     		printf("ehci_allocm: usb_allocmem()=%d\n", err); 
   | 
||
| 
     #endif 
   | 
||
| 
     	return (err); 
   | 
||
| 
     } 
   | 
||
| ... | ... | |
| 
     		STAILQ_REMOVE_HEAD(&sc->sc_free_xfers, next); 
   | 
||
| 
     #ifdef DIAGNOSTIC 
   | 
||
| 
     		if (xfer->busy_free != XFER_FREE) { 
   | 
||
| 
     			kprintf("ehci_allocx: xfer=%p not free, 0x%08x\n", xfer, 
   | 
||
| 
     			printf("ehci_allocx: xfer=%p not free, 0x%08x\n", xfer, 
   | 
||
| 
     			       xfer->busy_free); 
   | 
||
| 
     		} 
   | 
||
| 
     #endif 
   | 
||
| 
     	} else { 
   | 
||
| 
     		xfer = kmalloc(sizeof(struct ehci_xfer), M_USB, M_NOWAIT); 
   | 
||
| 
     		xfer = malloc(sizeof(struct ehci_xfer), M_USB, M_NOWAIT); 
   | 
||
| 
     	} 
   | 
||
| 
     	if (xfer != NULL) { 
   | 
||
| 
     		memset(xfer, 0, sizeof(struct ehci_xfer)); 
   | 
||
| ... | ... | |
| 
     #ifdef DIAGNOSTIC 
   | 
||
| 
     	if (xfer->busy_free != XFER_BUSY) { 
   | 
||
| 
     		kprintf("ehci_freex: xfer=%p not busy, 0x%08x\n", xfer, 
   | 
||
| 
     		printf("ehci_freex: xfer=%p not busy, 0x%08x\n", xfer, 
   | 
||
| 
     		       xfer->busy_free); 
   | 
||
| 
     		return; 
   | 
||
| 
     	} 
   | 
||
| 
     	xfer->busy_free = XFER_FREE; 
   | 
||
| 
     	if (!EXFER(xfer)->isdone) { 
   | 
||
| 
     		kprintf("ehci_freex: !isdone\n"); 
   | 
||
| 
     		printf("ehci_freex: !isdone\n"); 
   | 
||
| 
     		return; 
   | 
||
| 
     	} 
   | 
||
| 
     #endif 
   | 
||
| ... | ... | |
| 
     ehci_dump_regs(ehci_softc_t *sc) 
   | 
||
| 
     { 
   | 
||
| 
     	int i; 
   | 
||
| 
     	kprintf("cmd=0x%08x, sts=0x%08x, ien=0x%08x\n", 
   | 
||
| 
     	printf("cmd=0x%08x, sts=0x%08x, ien=0x%08x\n", 
   | 
||
| 
     	       EOREAD4(sc, EHCI_USBCMD), 
   | 
||
| 
     	       EOREAD4(sc, EHCI_USBSTS), 
   | 
||
| 
     	       EOREAD4(sc, EHCI_USBINTR)); 
   | 
||
| 
     	kprintf("frindex=0x%08x ctrdsegm=0x%08x periodic=0x%08x async=0x%08x\n", 
   | 
||
| 
     	printf("frindex=0x%08x ctrdsegm=0x%08x periodic=0x%08x async=0x%08x\n", 
   | 
||
| 
     	       EOREAD4(sc, EHCI_FRINDEX), 
   | 
||
| 
     	       EOREAD4(sc, EHCI_CTRLDSSEGMENT), 
   | 
||
| 
     	       EOREAD4(sc, EHCI_PERIODICLISTBASE), 
   | 
||
| 
     	       EOREAD4(sc, EHCI_ASYNCLISTADDR)); 
   | 
||
| 
     	for (i = 1; i <= sc->sc_noport; i++) 
   | 
||
| 
     		kprintf("port %d status=0x%08x\n", i, 
   | 
||
| 
     		printf("port %d status=0x%08x\n", i, 
   | 
||
| 
     		       EOREAD4(sc, EHCI_PORTSC(i))); 
   | 
||
| 
     } 
   | 
||
| ... | ... | |
| 
     ehci_dump_link(ehci_link_t link, int type) 
   | 
||
| 
     { 
   | 
||
| 
     	link = le32toh(link); 
   | 
||
| 
     	kprintf("0x%08x", link); 
   | 
||
| 
     	printf("0x%08x", link); 
   | 
||
| 
     	if (link & EHCI_LINK_TERMINATE) 
   | 
||
| 
     		kprintf("<T>"); 
   | 
||
| 
     		printf("<T>"); 
   | 
||
| 
     	else { 
   | 
||
| 
     		kprintf("<"); 
   | 
||
| 
     		printf("<"); 
   | 
||
| 
     		if (type) { 
   | 
||
| 
     			switch (EHCI_LINK_TYPE(link)) { 
   | 
||
| 
     			case EHCI_LINK_ITD: kprintf("ITD"); break; 
   | 
||
| 
     			case EHCI_LINK_QH: kprintf("QH"); break; 
   | 
||
| 
     			case EHCI_LINK_SITD: kprintf("SITD"); break; 
   | 
||
| 
     			case EHCI_LINK_FSTN: kprintf("FSTN"); break; 
   | 
||
| 
     			case EHCI_LINK_ITD: printf("ITD"); break; 
   | 
||
| 
     			case EHCI_LINK_QH: printf("QH"); break; 
   | 
||
| 
     			case EHCI_LINK_SITD: printf("SITD"); break; 
   | 
||
| 
     			case EHCI_LINK_FSTN: printf("FSTN"); break; 
   | 
||
| 
     			} 
   | 
||
| 
     		} 
   | 
||
| 
     		kprintf(">"); 
   | 
||
| 
     		printf(">"); 
   | 
||
| 
     	} 
   | 
||
| 
     } 
   | 
||
| ... | ... | |
| 
     		stop = sqtd->qtd.qtd_next & htole32(EHCI_LINK_TERMINATE); 
   | 
||
| 
     	} 
   | 
||
| 
     	if (sqtd) 
   | 
||
| 
     		kprintf("dump aborted, too many TDs\n"); 
   | 
||
| 
     		printf("dump aborted, too many TDs\n"); 
   | 
||
| 
     } 
   | 
||
| 
     void 
   | 
||
| 
     ehci_dump_sqtd(ehci_soft_qtd_t *sqtd) 
   | 
||
| 
     { 
   | 
||
| 
     	kprintf("QTD(%p) at 0x%08x:\n", sqtd, sqtd->physaddr); 
   | 
||
| 
     	printf("QTD(%p) at 0x%08x:\n", sqtd, sqtd->physaddr); 
   | 
||
| 
     	ehci_dump_qtd(&sqtd->qtd); 
   | 
||
| 
     } 
   | 
||
| ... | ... | |
| 
     	u_int32_t s; 
   | 
||
| 
     	char sbuf[128]; 
   | 
||
| 
     	kprintf("  next="); ehci_dump_link(qtd->qtd_next, 0); 
   | 
||
| 
     	kprintf(" altnext="); ehci_dump_link(qtd->qtd_altnext, 0); 
   | 
||
| 
     	kprintf("\n"); 
   | 
||
| 
     	printf("  next="); ehci_dump_link(qtd->qtd_next, 0); 
   | 
||
| 
     	printf(" altnext="); ehci_dump_link(qtd->qtd_altnext, 0); 
   | 
||
| 
     	printf("\n"); 
   | 
||
| 
     	s = le32toh(qtd->qtd_status); 
   | 
||
| 
     	bitmask_snprintf(EHCI_QTD_GET_STATUS(s), 
   | 
||
| 
     			 "\20\10ACTIVE\7HALTED\6BUFERR\5BABBLE\4XACTERR" 
   | 
||
| 
     			 "\3MISSED\2SPLIT\1PING", sbuf, sizeof(sbuf)); 
   | 
||
| 
     	kprintf("  status=0x%08x: toggle=%d bytes=0x%x ioc=%d c_page=0x%x\n", 
   | 
||
| 
     	printf("  status=0x%08x: toggle=%d bytes=0x%x ioc=%d c_page=0x%x\n", 
   | 
||
| 
     	       s, EHCI_QTD_GET_TOGGLE(s), EHCI_QTD_GET_BYTES(s), 
   | 
||
| 
     	       EHCI_QTD_GET_IOC(s), EHCI_QTD_GET_C_PAGE(s)); 
   | 
||
| 
     	kprintf("    cerr=%d pid=%d stat=0x%s\n", EHCI_QTD_GET_CERR(s), 
   | 
||
| 
     	printf("    cerr=%d pid=%d stat=0x%s\n", EHCI_QTD_GET_CERR(s), 
   | 
||
| 
     	       EHCI_QTD_GET_PID(s), sbuf); 
   | 
||
| 
     	for (s = 0; s < 5; s++) 
   | 
||
| 
     		kprintf("  buffer[%d]=0x%08x\n", s, le32toh(qtd->qtd_buffer[s])); 
   | 
||
| 
     		printf("  buffer[%d]=0x%08x\n", s, le32toh(qtd->qtd_buffer[s])); 
   | 
||
| 
     } 
   | 
||
| 
     void 
   | 
||
| ... | ... | |
| 
     	ehci_qh_t *qh = &sqh->qh; 
   | 
||
| 
     	u_int32_t endp, endphub; 
   | 
||
| 
     	kprintf("QH(%p) at 0x%08x:\n", sqh, sqh->physaddr); 
   | 
||
| 
     	kprintf("  sqtd=%p inactivesqtd=%p\n", sqh->sqtd, sqh->inactivesqtd); 
   | 
||
| 
     	kprintf("  link="); ehci_dump_link(qh->qh_link, 1); kprintf("\n"); 
   | 
||
| 
     	printf("QH(%p) at 0x%08x:\n", sqh, sqh->physaddr); 
   | 
||
| 
     	printf("  sqtd=%p inactivesqtd=%p\n", sqh->sqtd, sqh->inactivesqtd); 
   | 
||
| 
     	printf("  link="); ehci_dump_link(qh->qh_link, 1); printf("\n"); 
   | 
||
| 
     	endp = le32toh(qh->qh_endp); 
   | 
||
| 
     	kprintf("  endp=0x%08x\n", endp); 
   | 
||
| 
     	kprintf("    addr=0x%02x inact=%d endpt=%d eps=%d dtc=%d hrecl=%d\n", 
   | 
||
| 
     	printf("  endp=0x%08x\n", endp); 
   | 
||
| 
     	printf("    addr=0x%02x inact=%d endpt=%d eps=%d dtc=%d hrecl=%d\n", 
   | 
||
| 
     	       EHCI_QH_GET_ADDR(endp), EHCI_QH_GET_INACT(endp), 
   | 
||
| 
     	       EHCI_QH_GET_ENDPT(endp),  EHCI_QH_GET_EPS(endp), 
   | 
||
| 
     	       EHCI_QH_GET_DTC(endp), EHCI_QH_GET_HRECL(endp)); 
   | 
||
| 
     	kprintf("    mpl=0x%x ctl=%d nrl=%d\n", 
   | 
||
| 
     	printf("    mpl=0x%x ctl=%d nrl=%d\n", 
   | 
||
| 
     	       EHCI_QH_GET_MPL(endp), EHCI_QH_GET_CTL(endp), 
   | 
||
| 
     	       EHCI_QH_GET_NRL(endp)); 
   | 
||
| 
     	endphub = le32toh(qh->qh_endphub); 
   | 
||
| 
     	kprintf("  endphub=0x%08x\n", endphub); 
   | 
||
| 
     	kprintf("    smask=0x%02x cmask=0x%02x huba=0x%02x port=%d mult=%d\n", 
   | 
||
| 
     	printf("  endphub=0x%08x\n", endphub); 
   | 
||
| 
     	printf("    smask=0x%02x cmask=0x%02x huba=0x%02x port=%d mult=%d\n", 
   | 
||
| 
     	       EHCI_QH_GET_SMASK(endphub), EHCI_QH_GET_CMASK(endphub), 
   | 
||
| 
     	       EHCI_QH_GET_HUBA(endphub), EHCI_QH_GET_PORT(endphub), 
   | 
||
| 
     	       EHCI_QH_GET_MULT(endphub)); 
   | 
||
| 
     	kprintf("  curqtd="); ehci_dump_link(qh->qh_curqtd, 0); kprintf("\n"); 
   | 
||
| 
     	kprintf("Overlay qTD:\n"); 
   | 
||
| 
     	printf("  curqtd="); ehci_dump_link(qh->qh_curqtd, 0); printf("\n"); 
   | 
||
| 
     	printf("Overlay qTD:\n"); 
   | 
||
| 
     	ehci_dump_qtd(&qh->qh_qtd); 
   | 
||
| 
     } 
   | 
||
| ... | ... | |
| 
     static void 
   | 
||
| 
     ehci_dump_exfer(struct ehci_xfer *ex) 
   | 
||
| 
     { 
   | 
||
| 
     	kprintf("ehci_dump_exfer: ex=%p\n", ex); 
   | 
||
| 
     	printf("ehci_dump_exfer: ex=%p\n", ex); 
   | 
||
| 
     } 
   | 
||
| 
     #endif 
   | 
||
| 
     #endif 
   | 
||
| ... | ... | |
| 
     	struct ehci_pipe *epipe = (struct ehci_pipe *)pipe; 
   | 
||
| 
     	ehci_soft_qh_t *sqh; 
   | 
||
| 
     	usbd_status err; 
   | 
||
| 
     	int s; 
   | 
||
| 
     	int ival, speed, naks; 
   | 
||
| 
     	int hshubaddr, hshubport; 
   | 
||
| ... | ... | |
| 
     	default: panic("ehci_open: bad device speed %d", dev->speed); 
   | 
||
| 
     	} 
   | 
||
| 
     	if (speed != EHCI_QH_SPEED_HIGH && xfertype == UE_ISOCHRONOUS) { 
   | 
||
| 
     		kprintf("%s: *** WARNING: opening low/full speed device, this " 
   | 
||
| 
     		printf("%s: *** WARNING: opening low/full speed device, this " 
   | 
||
| 
     		       "does not work yet.\n", 
   | 
||
| 
     		       device_get_nameunit(sc->sc_bus.bdev)); 
   | 
||
| 
     		DPRINTFN(1,("ehci_open: hshubaddr=%d hshubport=%d\n", 
   | 
||
| ... | ... | |
| 
     				   0, &epipe->u.ctl.reqdma); 
   | 
||
| 
     #ifdef EHCI_DEBUG 
   | 
||
| 
     		if (err) 
   | 
||
| 
     			kprintf("ehci_open: usb_allocmem()=%d\n", err); 
   | 
||
| 
     			printf("ehci_open: usb_allocmem()=%d\n", err); 
   | 
||
| 
     #endif 
   | 
||
| 
     		if (err) 
   | 
||
| 
     			goto bad1; 
   | 
||
| 
     		pipe->methods = &ehci_device_ctrl_methods; 
   | 
||
| 
     		crit_enter(); 
   | 
||
| 
     		s = splusb(); 
   | 
||
| 
     		ehci_add_qh(sqh, sc->sc_async_head); 
   | 
||
| 
     		crit_exit(); 
   | 
||
| 
     		splx(s); 
   | 
||
| 
     		break; 
   | 
||
| 
     	case UE_BULK: 
   | 
||
| 
     		pipe->methods = &ehci_device_bulk_methods; 
   | 
||
| 
     		crit_enter(); 
   | 
||
| 
     		s = splusb(); 
   | 
||
| 
     		ehci_add_qh(sqh, sc->sc_async_head); 
   | 
||
| 
     		crit_exit(); 
   | 
||
| 
     		splx(s); 
   | 
||
| 
     		break; 
   | 
||
| 
     	case UE_INTERRUPT: 
   | 
||
| 
     		pipe->methods = &ehci_device_intr_methods; 
   | 
||
| ... | ... | |
| 
     } 
   | 
||
| 
     /* 
   | 
||
| 
      * Add an ED to the schedule.  Called while in a critical section. 
   | 
||
| 
      * Add an ED to the schedule.  Called at splusb(). 
   | 
||
| 
      * If in the async schedule, it will always have a next. 
   | 
||
| 
      * If in the intr schedule it may not. 
   | 
||
| 
      */ 
   | 
||
| 
     void 
   | 
||
| 
     ehci_add_qh(ehci_soft_qh_t *sqh, ehci_soft_qh_t *head) 
   | 
||
| 
     { 
   | 
||
| 
     	SPLUSBCHECK; 
   | 
||
| 
     	sqh->next = head->next; 
   | 
||
| 
     	sqh->prev = head; 
   | 
||
| 
     	sqh->qh.qh_link = head->qh.qh_link; 
   | 
||
| ... | ... | |
| 
     #ifdef EHCI_DEBUG 
   | 
||
| 
     	if (ehcidebug > 5) { 
   | 
||
| 
     		kprintf("ehci_add_qh:\n"); 
   | 
||
| 
     		printf("ehci_add_qh:\n"); 
   | 
||
| 
     		ehci_dump_sqh(sqh); 
   | 
||
| 
     	} 
   | 
||
| 
     #endif 
   | 
||
| 
     } 
   | 
||
| 
     /* 
   | 
||
| 
      * Remove an ED from the schedule.  Called while in a critical section. 
   | 
||
| 
      * Remove an ED from the schedule.  Called at splusb(). 
   | 
||
| 
      * Will always have a 'next' if it's in the async list as it's circular. 
   | 
||
| 
      */ 
   | 
||
| 
     void 
   | 
||
| 
     ehci_rem_qh(ehci_softc_t *sc, ehci_soft_qh_t *sqh, ehci_soft_qh_t *head) 
   | 
||
| 
     { 
   | 
||
| 
     	SPLUSBCHECK; 
   | 
||
| 
     	/* XXX */ 
   | 
||
| 
     	sqh->prev->qh.qh_link = sqh->qh.qh_link; 
   | 
||
| 
     	sqh->prev->next = sqh->next; 
   | 
||
| ... | ... | |
| 
     		if (EHCI_LINK_ADDR(le32toh(sqh->qh.qh_qtd.qtd_next)) != 
   | 
||
| 
     		    sqtd->physaddr) { 
   | 
||
| 
     #ifdef EHCI_DEBUG 
   | 
||
| 
     			kprintf("ehci_activate_qh: unexpected next ptr\n"); 
   | 
||
| 
     			printf("ehci_activate_qh: unexpected next ptr\n"); 
   | 
||
| 
     			ehci_dump_sqh(sqh); 
   | 
||
| 
     			ehci_dump_sqtds(sqh->sqtd); 
   | 
||
| 
     #endif 
   | 
||
| ... | ... | |
| 
     void 
   | 
||
| 
     ehci_sync_hc(ehci_softc_t *sc) 
   | 
||
| 
     { 
   | 
||
| 
     	int error; 
   | 
||
| 
     	int s, error; 
   | 
||
| 
     	if (sc->sc_dying) { 
   | 
||
| 
     		DPRINTFN(2,("ehci_sync_hc: dying\n")); 
   | 
||
| ... | ... | |
| 
     	} 
   | 
||
| 
     	DPRINTFN(2,("ehci_sync_hc: enter\n")); 
   | 
||
| 
     	/* get doorbell */ 
   | 
||
| 
     	lockmgr(&sc->sc_doorbell_lock, LK_EXCLUSIVE); 
   | 
||
| 
     	crit_enter(); 
   | 
||
| 
     	lockmgr(&sc->sc_doorbell_lock, LK_EXCLUSIVE, NULL); 
   | 
||
| 
     	s = splhardusb(); 
   | 
||
| 
     	/* ask for doorbell */ 
   | 
||
| 
     	EOWRITE4(sc, EHCI_USBCMD, EOREAD4(sc, EHCI_USBCMD) | EHCI_CMD_IAAD); 
   | 
||
| 
     	DPRINTFN(1,("ehci_sync_hc: cmd=0x%08x sts=0x%08x\n", 
   | 
||
| 
     		    EOREAD4(sc, EHCI_USBCMD), EOREAD4(sc, EHCI_USBSTS))); 
   | 
||
| 
     	error = tsleep(&sc->sc_async_head, 0, "ehcidi", hz); /* bell wait */ 
   | 
||
| 
     	error = tsleep(&sc->sc_async_head, PZERO, "ehcidi", hz); /* bell wait */ 
   | 
||
| 
     	DPRINTFN(1,("ehci_sync_hc: cmd=0x%08x sts=0x%08x\n", 
   | 
||
| 
     		    EOREAD4(sc, EHCI_USBCMD), EOREAD4(sc, EHCI_USBSTS))); 
   | 
||
| 
     	crit_exit(); 
   | 
||
| 
     	splx(s); 
   | 
||
| 
     	/* release doorbell */ 
   | 
||
| 
     	lockmgr(&sc->sc_doorbell_lock, LK_RELEASE); 
   | 
||
| 
     	lockmgr(&sc->sc_doorbell_lock, LK_RELEASE, NULL); 
   | 
||
| 
     #ifdef DIAGNOSTIC 
   | 
||
| 
     	if (error) 
   | 
||
| 
     		kprintf("ehci_sync_hc: tsleep() = %d\n", error); 
   | 
||
| 
     		printf("ehci_sync_hc: tsleep() = %d\n", error); 
   | 
||
| 
     #endif 
   | 
||
| 
     	DPRINTFN(2,("ehci_sync_hc: exit\n")); 
   | 
||
| 
     } 
   | 
||
| ... | ... | |
| 
     	usb_device_request_t *req; 
   | 
||
| 
     	void *buf = NULL; 
   | 
||
| 
     	int port, i; 
   | 
||
| 
     	int len, value, index, l, totlen = 0; 
   | 
||
| 
     	int s, len, value, index, l, totlen = 0; 
   | 
||
| 
     	usb_port_status_t ps; 
   | 
||
| 
     	usb_hub_descriptor_t hubd; 
   | 
||
| 
     	usbd_status err; 
   | 
||
| ... | ... | |
| 
     			goto ret; 
   | 
||
| 
     		} 
   | 
||
| 
     		v = EOREAD4(sc, EHCI_PORTSC(index)); 
   | 
||
| 
     		DPRINTFN(8,("ehci_root_ctrl_start: port status=0x%04x\n", v)); 
   | 
||
| 
     		DPRINTFN(8,("ehci_root_ctrl_start: port status=0x%04x\n", 
   | 
||
| 
     			    v)); 
   | 
||
| 
     		i = UPS_HIGH_SPEED; 
   | 
||
| 
     		if (v & EHCI_PS_CS)	i |= UPS_CURRENT_CONNECT_STATUS; 
   | 
||
| 
     		if (v & EHCI_PS_PE)	i |= UPS_PORT_ENABLED; 
   | 
||
| ... | ... | |
| 
     			v = EOREAD4(sc, port); 
   | 
||
| 
     			DPRINTF(("ehci after reset, status=0x%08x\n", v)); 
   | 
||
| 
     			if (v & EHCI_PS_PR) { 
   | 
||
| 
     				kprintf("%s: port reset timeout\n", 
   | 
||
| 
     				printf("%s: port reset timeout\n", 
   | 
||
| 
     				       device_get_nameunit(sc->sc_bus.bdev)); 
   | 
||
| 
     				return (USBD_TIMEOUT); 
   | 
||
| 
     			} 
   | 
||
| ... | ... | |
| 
     	err = USBD_NORMAL_COMPLETION; 
   | 
||
| 
      ret: 
   | 
||
| 
     	xfer->status = err; 
   | 
||
| 
     	crit_enter(); 
   | 
||
| 
     	s = splusb(); 
   | 
||
| 
     	hacksync(xfer);	/* XXX to compensate for usb_transfer_complete */ 
   | 
||
| 
     	usb_transfer_complete(xfer); 
   | 
||
| 
     	crit_exit(); 
   | 
||
| 
     	splx(s); 
   | 
||
| 
     	return (USBD_IN_PROGRESS); 
   | 
||
| 
     } 
   | 
||
| ... | ... | |
| 
     	if (sc->sc_npcomp != 0) { 
   | 
||
| 
     		int i = (index-1) / sc->sc_npcomp; 
   | 
||
| 
     		if (i >= sc->sc_ncomp) 
   | 
||
| 
     			kprintf("%s: strange port\n", 
   | 
||
| 
     			printf("%s: strange port\n", 
   | 
||
| 
     			       device_get_nameunit(sc->sc_bus.bdev)); 
   | 
||
| 
     		else 
   | 
||
| 
     			kprintf("%s: handing over %s speed device on " 
   | 
||
| 
     			printf("%s: handing over %s speed device on " 
   | 
||
| 
     			       "port %d to %s\n", 
   | 
||
| 
     			       device_get_nameunit(sc->sc_bus.bdev), 
   | 
||
| 
     			       lowspeed ? "low" : "full", 
   | 
||
| 
     			       index, device_get_nameunit(sc->sc_comps[i]->bdev)); 
   | 
||
| 
     	} else { 
   | 
||
| 
     		kprintf("%s: npcomp == 0\n", device_get_nameunit(sc->sc_bus.bdev)); 
   | 
||
| 
     		printf("%s: npcomp == 0\n", device_get_nameunit(sc->sc_bus.bdev)); 
   | 
||
| 
     	} 
   | 
||
| 
     #endif 
   | 
||
| 
     	port = EHCI_PORTSC(index); 
   | 
||
| ... | ... | |
| 
     static void 
   | 
||
| 
     ehci_root_intr_abort(usbd_xfer_handle xfer) 
   | 
||
| 
     { 
   | 
||
| 
     	int s; 
   | 
||
| 
     	if (xfer->pipe->intrxfer == xfer) { 
   | 
||
| 
     		DPRINTF(("ehci_root_intr_abort: remove\n")); 
   | 
||
| 
     		xfer->pipe->intrxfer = NULL; 
   | 
||
| 
     	} 
   | 
||
| 
     	xfer->status = USBD_CANCELLED; 
   | 
||
| 
     	crit_enter(); 
   | 
||
| 
     	s = splusb(); 
   | 
||
| 
     	usb_transfer_complete(xfer); 
   | 
||
| 
     	crit_exit(); 
   | 
||
| 
     	splx(s); 
   | 
||
| 
     } 
   | 
||
| 
     /* Close the root pipe. */ 
   | 
||
| ... | ... | |
| 
     			  EHCI_PAGE_SIZE, &dma); 
   | 
||
| 
     #ifdef EHCI_DEBUG 
   | 
||
| 
     		if (err) 
   | 
||
| 
     			kprintf("ehci_alloc_sqh: usb_allocmem()=%d\n", err); 
   | 
||
| 
     			printf("ehci_alloc_sqh: usb_allocmem()=%d\n", err); 
   | 
||
| 
     #endif 
   | 
||
| 
     		if (err) 
   | 
||
| 
     			return (NULL); 
   | 
||
| ... | ... | |
| 
     	usbd_status err; 
   | 
||
| 
     	int i, offs; 
   | 
||
| 
     	usb_dma_t dma; 
   | 
||
| 
     	int s; 
   | 
||
| 
     	if (sc->sc_freeqtds == NULL) { 
   | 
||
| 
     		DPRINTFN(2, ("ehci_alloc_sqtd: allocating chunk\n")); 
   | 
||
| ... | ... | |
| 
     			  EHCI_PAGE_SIZE, &dma); 
   | 
||
| 
     #ifdef EHCI_DEBUG 
   | 
||
| 
     		if (err) 
   | 
||
| 
     			kprintf("ehci_alloc_sqtd: usb_allocmem()=%d\n", err); 
   | 
||
| 
     			printf("ehci_alloc_sqtd: usb_allocmem()=%d\n", err); 
   | 
||
| 
     #endif 
   | 
||
| 
     		if (err) 
   | 
||
| 
     			return (NULL); 
   | 
||
| 
     		crit_enter(); 
   | 
||
| 
     		s = splusb(); 
   | 
||
| 
     		for(i = 0; i < EHCI_SQTD_CHUNK; i++) { 
   | 
||
| 
     			offs = i * EHCI_SQTD_SIZE; 
   | 
||
| 
     			sqtd = KERNADDR(&dma, offs); 
   | 
||
| ... | ... | |
| 
     			sqtd->nextqtd = sc->sc_freeqtds; 
   | 
||
| 
     			sc->sc_freeqtds = sqtd; 
   | 
||
| 
     		} 
   | 
||
| 
     		crit_exit(); 
   | 
||
| 
     		splx(s); 
   | 
||
| 
     	} 
   | 
||
| 
     	crit_enter(); 
   | 
||
| 
     	s = splusb(); 
   | 
||
| 
     	sqtd = sc->sc_freeqtds; 
   | 
||
| 
     	sc->sc_freeqtds = sqtd->nextqtd; 
   | 
||
| 
     	sqtd->qtd.qtd_next = EHCI_NULL; 
   | 
||
| ... | ... | |
| 
     	} 
   | 
||
| 
     	sqtd->nextqtd = NULL; 
   | 
||
| 
     	sqtd->xfer = NULL; 
   | 
||
| 
     	crit_exit(); 
   | 
||
| 
     	splx(s); 
   | 
||
| 
     	return (sqtd); 
   | 
||
| 
     } 
   | 
||
| ... | ... | |
| 
     void 
   | 
||
| 
     ehci_free_sqtd(ehci_softc_t *sc, ehci_soft_qtd_t *sqtd) 
   | 
||
| 
     { 
   | 
||
| 
     	crit_enter(); 
   | 
||
| 
     	int s; 
   | 
||
| 
     	s = splusb(); 
   | 
||
| 
     	sqtd->nextqtd = sc->sc_freeqtds; 
   | 
||
| 
     	sc->sc_freeqtds = sqtd; 
   | 
||
| 
     	crit_exit(); 
   | 
||
| 
     	splx(s); 
   | 
||
| 
     } 
   | 
||
| 
     usbd_status 
   | 
||
| ... | ... | |
| 
     			/* 
   | 
||
| 
     			 * Must stop if there is any gap before or after 
   | 
||
| 
     			 * the page boundary. 
   | 
||
| 
      		 	 */ 
   | 
||
| 
     			 */ 
   | 
||
| 
     			if (EHCI_PAGE_OFFSET(dataphys + pagelen) != 0) 
   | 
||
| 
     				break; 
   | 
||
| 
     			if (seg < dma->nsegs && EHCI_PAGE_OFFSET(segoff + 
   | 
||
| ... | ... | |
| 
     	struct ehci_pipe *epipe = (struct ehci_pipe *)pipe; 
   | 
||
| 
     	ehci_softc_t *sc = (ehci_softc_t *)pipe->device->bus; 
   | 
||
| 
     	ehci_soft_qh_t *sqh = epipe->sqh; 
   | 
||
| 
     	int s; 
   | 
||
| 
     	crit_enter(); 
   | 
||
| 
     	s = splusb(); 
   | 
||
| 
     	ehci_rem_qh(sc, sqh, head); 
   | 
||
| 
     	crit_exit(); 
   | 
||
| 
     	splx(s); 
   | 
||
| 
     	pipe->endpoint->savedtoggle = 
   | 
||
| 
     	    EHCI_QTD_GET_TOGGLE(le32toh(sqh->qh.qh_qtd.qtd_status)); 
   | 
||
| 
     	ehci_free_sqh(sc, epipe->sqh); 
   | 
||
| ... | ... | |
| 
     /* 
   | 
||
| 
      * Abort a device request. 
   | 
||
| 
      * If this routine is called from a critical section it guarantees that the 
   | 
||
| 
      * request will be removed from the hardware scheduling and that the callback 
   | 
||
| 
      * If this routine is called at splusb() it guarantees that the request 
   | 
||
| 
      * will be removed from the hardware scheduling and that the callback 
   | 
||
| 
      * for it will be called with USBD_CANCELLED status. 
   | 
||
| 
      * It's impossible to guarantee that the requested transfer will not 
   | 
||
| 
      * have happened since the hardware runs concurrently. 
   | 
||
| ... | ... | |
| 
     	ehci_soft_qh_t *sqh = epipe->sqh; 
   | 
||
| 
     	ehci_soft_qtd_t *sqtd, *snext; 
   | 
||
| 
     	ehci_physaddr_t cur, us, next; 
   | 
||
| 
     	int s; 
   | 
||
| 
     	int hit, i; 
   | 
||
| 
     	/* int count = 0; */ 
   | 
||
| 
     	ehci_soft_qh_t *psqh; 
   | 
||
| ... | ... | |
| 
     	if (sc->sc_dying) { 
   | 
||
| 
     		/* If we're dying, just do the software part. */ 
   | 
||
| 
     		crit_enter(); 
   | 
||
| 
     		s = splusb(); 
   | 
||
| 
     		xfer->status = status;	/* make software ignore it */ 
   | 
||
| 
     		callout_stop(&xfer->timeout_handle); 
   | 
||
| 
     		usb_rem_task(epipe->pipe.device, &exfer->abort_task); 
   | 
||
| 
     		usb_transfer_complete(xfer); 
   | 
||
| 
     		crit_exit(); 
   | 
||
| 
     		splx(s); 
   | 
||
| 
     		return; 
   | 
||
| 
     	} 
   | 
||
| 
     	if (xfer->device->bus->intr_context /* || !curproc REMOVED DFly */) 
   | 
||
| 
     	if (xfer->device->bus->intr_context || !curproc) 
   | 
||
| 
     		panic("ehci_abort_xfer: not in process context"); 
   | 
||
| 
     	/* 
   | 
||
| ... | ... | |
| 
     		DPRINTFN(2, ("ehci_abort_xfer: waiting for abort to finish\n")); 
   | 
||
| 
     		exfer->ehci_xfer_flags |= EHCI_XFER_ABORTWAIT; 
   | 
||
| 
     		while (exfer->ehci_xfer_flags & EHCI_XFER_ABORTING) 
   | 
||
| 
     			tsleep(&exfer->ehci_xfer_flags, 0, "ehciaw", 0); 
   | 
||
| 
     			tsleep(&exfer->ehci_xfer_flags, PZERO, "ehciaw", 0); 
   | 
||
| 
     		return; 
   | 
||
| 
     	} 
   | 
||
| 
     	/* 
   | 
||
| 
     	 * Step 1: Make interrupt routine and timeouts ignore xfer. 
   | 
||
| 
     	 */ 
   | 
||
| 
     	crit_enter(); 
   | 
||
| 
     	s = splusb(); 
   | 
||
| 
     	exfer->ehci_xfer_flags |= EHCI_XFER_ABORTING; 
   | 
||
| 
     	xfer->status = status;	/* make software ignore it */ 
   | 
||
| 
     	callout_stop(&xfer->timeout_handle); 
   | 
||
| 
     	usb_rem_task(epipe->pipe.device, &exfer->abort_task); 
   | 
||
| 
     	crit_exit(); 
   | 
||
| 
     	splx(s); 
   | 
||
| 
     	/* 
   | 
||
| 
     	 * Step 2: Wait until we know hardware has finished any possible 
   | 
||
| ... | ... | |
| 
     	 * The hardware has no reference to completed items (TDs). 
   | 
||
| 
     	 * It's safe to remove them at any time. 
   | 
||
| 
     	 */ 
   | 
||
| 
     	crit_enter(); 
   | 
||
| 
     	s = splusb(); 
   | 
||
| 
     #ifdef USB_USE_SOFTINTR 
   | 
||
| 
     	sc->sc_softwake = 1; 
   | 
||
| 
     #endif /* USB_USE_SOFTINTR */ 
   | 
||
| 
     	usb_schedsoftintr(&sc->sc_bus); 
   | 
||
| 
     #ifdef USB_USE_SOFTINTR 
   | 
||
| 
     	tsleep(&sc->sc_softwake, 0, "ehciab", 0); 
   | 
||
| 
     	tsleep(&sc->sc_softwake, PZERO, "ehciab", 0); 
   | 
||
| 
     #endif /* USB_USE_SOFTINTR */ 
   | 
||
| 
     	/* 
   | 
||
| ... | ... | |
| 
     	} 
   | 
||
| 
     	usb_transfer_complete(xfer); 
   | 
||
| 
     	/* kprintf("%s: %d TDs aborted\n", __func__, count); */ 
   | 
||
| 
     	crit_exit(); 
   | 
||
| 
     	/* printf("%s: %d TDs aborted\n", __func__, count); */ 
   | 
||
| 
     	splx(s); 
   | 
||
| 
     #undef exfer 
   | 
||
| 
     } 
   | 
||
| ... | ... | |
| 
     	/* Execute the abort in a process context. */ 
   | 
||
| 
     	usb_add_task(exfer->xfer.pipe->device, &exfer->abort_task, 
   | 
||
| 
     		     USB_TASKQ_HC); 
   | 
||
| 
     	    USB_TASKQ_HC); 
   | 
||
| 
     } 
   | 
||
| 
     void 
   | 
||
| 
     ehci_timeout_task(void *addr) 
   | 
||
| 
     { 
   | 
||
| 
     	usbd_xfer_handle xfer = addr; 
   | 
||
| 
     	int s; 
   | 
||
| 
     	DPRINTF(("ehci_timeout_task: xfer=%p\n", xfer)); 
   | 
||
| 
     	crit_enter(); 
   | 
||
| 
     	s = splusb(); 
   | 
||
| 
     	ehci_abort_xfer(xfer, USBD_TIMEOUT); 
   | 
||
| 
     	crit_exit(); 
   | 
||
| 
     	splx(s); 
   | 
||
| 
     } 
   | 
||
| 
     /* 
   | 
||
| ... | ... | |
| 
     ehci_intrlist_timeout(void *arg) 
   | 
||
| 
     { 
   | 
||
| 
     	ehci_softc_t *sc = arg; 
   | 
||
| 
     	int s = splusb(); 
   | 
||
| 
     	DPRINTFN(3, ("ehci_intrlist_timeout\n")); 
   | 
||
| 
     	usb_schedsoftintr(&sc->sc_bus); 
   | 
||
| 
     	splx(s); 
   | 
||
| 
     } 
   | 
||
| 
     /************************/ 
   | 
||
| ... | ... | |
| 
     #ifdef DIAGNOSTIC 
   | 
||
| 
     	if (!(xfer->rqflags & URQ_REQUEST)) { 
   | 
||
| 
     		/* XXX panic */ 
   | 
||
| 
     		kprintf("ehci_device_ctrl_transfer: not a request\n"); 
   | 
||
| 
     		printf("ehci_device_ctrl_transfer: not a request\n"); 
   | 
||
| 
     		return (USBD_INVAL); 
   | 
||
| 
     	} 
   | 
||
| 
     #endif 
   | 
||
| ... | ... | |
| 
     	int isread; 
   | 
||
| 
     	int len; 
   | 
||
| 
     	usbd_status err; 
   | 
||
| 
     	int s; 
   | 
||
| 
     	isread = req->bmRequestType & UT_READ; 
   | 
||
| 
     	len = UGETW(req->wLength); 
   | 
||
| ... | ... | |
| 
     	exfer->sqtdend = stat; 
   | 
||
| 
     #ifdef DIAGNOSTIC 
   | 
||
| 
     	if (!exfer->isdone) { 
   | 
||
| 
     		kprintf("ehci_device_request: not done, exfer=%p\n", exfer); 
   | 
||
| 
     		printf("ehci_device_request: not done, exfer=%p\n", exfer); 
   | 
||
| 
     	} 
   | 
||
| 
     	exfer->isdone = 0; 
   | 
||
| 
     #endif 
   | 
||
| 
     	/* Activate the new qTD in the QH list. */ 
   | 
||
| 
     	crit_enter(); 
   | 
||
| 
     	s = splusb(); 
   | 
||
| 
     	ehci_activate_qh(sqh, setup); 
   | 
||
| 
     	if (xfer->timeout && !sc->sc_bus.use_polling) { 
   | 
||
| 
                     callout_reset(&xfer->timeout_handle, MS_TO_TICKS(xfer->timeout), 
   | 
||
| 
     			    ehci_timeout, xfer); 
   | 
||
| 
     		    ehci_timeout, xfer); 
   | 
||
| 
     	} 
   | 
||
| 
     	ehci_add_intr_list(sc, exfer); 
   | 
||
| 
     	xfer->status = USBD_IN_PROGRESS; 
   | 
||
| 
     	crit_exit(); 
   | 
||
| 
     	splx(s); 
   | 
||
| 
     #ifdef EHCI_DEBUG 
   | 
||
| 
     	if (ehcidebug > 10) { 
   | 
||
| ... | ... | |
| 
     	ehci_soft_qh_t *sqh; 
   | 
||
| 
     	usbd_status err; 
   | 
||
| 
     	int len, isread, endpt; 
   | 
||
| 
     	int s; 
   | 
||
| 
     	DPRINTFN(2, ("ehci_device_bulk_start: xfer=%p len=%d flags=%d\n", 
   | 
||
| 
     		     xfer, xfer->length, xfer->flags)); 
   | 
||
| ... | ... | |
| 
     	exfer->sqtdend = dataend; 
   | 
||
| 
     #ifdef DIAGNOSTIC 
   | 
||
| 
     	if (!exfer->isdone) { 
   | 
||
| 
     		kprintf("ehci_device_bulk_start: not done, ex=%p\n", exfer); 
   | 
||
| 
     		printf("ehci_device_bulk_start: not done, ex=%p\n", exfer); 
   | 
||
| 
     	} 
   | 
||
| 
     	exfer->isdone = 0; 
   | 
||
| 
     #endif 
   | 
||
| 
     	crit_enter(); 
   | 
||
| 
     	s = splusb(); 
   | 
||
| 
     	ehci_activate_qh(sqh, data); 
   | 
||
| 
     	if (xfer->timeout && !sc->sc_bus.use_polling) { 
   | 
||
| 
     		callout_reset(&xfer->timeout_handle, MS_TO_TICKS(xfer->timeout), 
   | 
||
| 
     			    ehci_timeout, xfer); 
   | 
||
| 
     		    ehci_timeout, xfer); 
   | 
||
| 
     	} 
   | 
||
| 
     	ehci_add_intr_list(sc, exfer); 
   | 
||
| 
     	xfer->status = USBD_IN_PROGRESS; 
   | 
||
| 
     	crit_exit(); 
   | 
||
| 
     	splx(s); 
   | 
||
| 
     #ifdef EHCI_DEBUG 
   | 
||
| 
     	if (ehcidebug > 10) { 
   | 
||
| ... | ... | |
| 
     		DPRINTF(("ehci_device_bulk_start: data(3)\n")); 
   | 
||
| 
     		ehci_dump_regs(sc); 
   | 
||
| 
     #if 0 
   | 
||
| 
     		kprintf("async_head:\n"); 
   | 
||
| 
     		printf("async_head:\n"); 
   | 
||
| 
     		ehci_dump_sqh(sc->sc_async_head); 
   | 
||
| 
     #endif 
   | 
||
| 
     		kprintf("sqh:\n"); 
   | 
||
| 
     		printf("sqh:\n"); 
   | 
||
| 
     		ehci_dump_sqh(sqh); 
   | 
||
| 
     		ehci_dump_sqtds(data); 
   | 
||
| 
     	} 
   | 
||
| ... | ... | |
| 
     	/* Pick an interrupt slot at the right level. */ 
   | 
||
| 
     	/* XXX could do better than picking at random. */ 
   | 
||
| 
     	islot = EHCI_IQHIDX(lev, karc4random()); 
   | 
||
| 
     	islot = EHCI_IQHIDX(lev, arc4random()); 
   | 
||
| 
     	sqh->islot = islot; 
   | 
||
| 
     	isp = &sc->sc_islots[islot]; 
   | 
||
| ... | ... | |
| 
     	ehci_soft_qh_t *sqh; 
   | 
||
| 
     	usbd_status err; 
   | 
||
| 
     	int len, isread, endpt; 
   | 
||
| 
     	int s; 
   | 
||
| 
     	DPRINTFN(2, ("ehci_device_intr_start: xfer=%p len=%d flags=%d\n", 
   | 
||
| 
     	    xfer, xfer->length, xfer->flags)); 
   | 
||
| ... | ... | |
| 
     	exfer->sqtdend = dataend; 
   | 
||
| 
     #ifdef DIAGNOSTIC 
   | 
||
| 
     	if (!exfer->isdone) { 
   | 
||
| 
     		kprintf("ehci_device_intr_start: not done, ex=%p\n", exfer); 
   | 
||
| 
     		printf("ehci_device_intr_start: not done, ex=%p\n", exfer); 
   | 
||
| 
     	} 
   | 
||
| 
     	exfer->isdone = 0; 
   | 
||
| 
     #endif 
   | 
||
| 
     	crit_enter(); 
   | 
||
| 
     	s = splusb(); 
   | 
||
| 
     	ehci_activate_qh(sqh, data); 
   | 
||
| 
     	if (xfer->timeout && !sc->sc_bus.use_polling) { 
   | 
||
| 
     		callout_reset(&xfer->timeout_handle, MS_TO_TICKS(xfer->timeout), 
   | 
||
| ... | ... | |
| 
     	} 
   | 
||
| 
     	ehci_add_intr_list(sc, exfer); 
   | 
||
| 
     	xfer->status = USBD_IN_PROGRESS; 
   | 
||
| 
     	crit_exit(); 
   | 
||
| 
     	splx(s); 
   | 
||
| 
     #ifdef EHCI_DEBUG 
   | 
||
| 
     	if (ehcidebug > 10) { 
   | 
||
| ... | ... | |
| 
     		delay(10000); 
   | 
||
| 
     		DPRINTF(("ehci_device_intr_start: data(3)\n")); 
   | 
||
| 
     		ehci_dump_regs(sc); 
   | 
||
| 
     		kprintf("sqh:\n"); 
   | 
||
| 
     		printf("sqh:\n"); 
   | 
||
| 
     		ehci_dump_sqh(sqh); 
   | 
||
| 
     		ehci_dump_sqtds(data); 
   | 
||
| 
     	} 
   | 
||
| ... | ... | |
| 
     	ehci_soft_qtd_t *data, *dataend, *newinactive; 
   | 
||
| 
     	ehci_soft_qh_t *sqh; 
   | 
||
| 
     	usbd_status err; 
   | 
||
| 
     	int len, isread, endpt; 
   | 
||
| 
     	int len, isread, endpt, s; 
   | 
||
| 
     	DPRINTFN(10, ("ehci_device_intr_done: xfer=%p, actlen=%d\n", 
   | 
||
| 
     	    xfer, xfer->actlen)); 
   | 
||
| ... | ... | |
| 
     	if (xfer->pipe->repeat) { 
   | 
||
| 
     		ehci_free_sqtd_chain(sc, sqh, ex->sqtdstart, 
   | 
||
| 
     		    ex->sqtdend->nextqtd); 
   | 
||
| 
     | 
||
| 
     		len = epipe->u.intr.length; 
   | 
||
| 
     		xfer->length = len; 
   | 
||
| 
     		endpt = epipe->pipe.endpoint->edesc->bEndpointAddress; 
   | 
||
| ... | ... | |
| 
     		exfer->sqtdend = dataend; 
   | 
||
| 
     #ifdef DIAGNOSTIC 
   | 
||
| 
     		if (!exfer->isdone) { 
   | 
||
| 
     			kprintf("ehci_device_intr_done: not done, ex=%p\n", 
   | 
||
| 
     			printf("ehci_device_intr_done: not done, ex=%p\n", 
   | 
||
| 
     			    exfer); 
   | 
||
| 
     		} 
   | 
||
| 
     		exfer->isdone = 0; 
   | 
||
| 
     #endif 
   | 
||
| 
     		crit_enter(); 
   | 
||
| 
     		s = splusb(); 
   | 
||
| 
     		ehci_activate_qh(sqh, data); 
   | 
||
| 
     		if (xfer->timeout && !sc->sc_bus.use_polling) { 
   | 
||
| 
     			callout_reset(&xfer->timeout_handle, 
   | 
||
| 
     			    MS_TO_TICKS(xfer->timeout), ehci_timeout, xfer); 
   | 
||
| 
     		} 
   | 
||
| 
     		crit_exit(); 
   | 
||
| 
     		splx(s); 
   | 
||
| 
     		xfer->status = USBD_IN_PROGRESS; 
   | 
||
| 
     	} else if (xfer->status != USBD_NOMEM && ehci_active_intr_list(ex)) { 
   | 
||
| 
     -- ehci_pci.c	2008-05-19 10:32:14 +0000 
   | 
||
| 
     ++ /root/src/sys/dev/usb/ehci_pci.c	2008-04-11 05:50:53 +0000 
   | 
||
| ... | ... | |
| 
     /* 
   | 
||
| ... | ... | |
| 
     /*- 
   | 
||
| 
      * Copyright (c) 1998 The NetBSD Foundation, Inc. 
   | 
||
| 
      * All rights reserved. 
   | 
||
| 
      * 
   | 
||
| ... | ... | |
| 
      * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
   | 
||
| 
      * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
   | 
||
| 
      * POSSIBILITY OF SUCH DAMAGE. 
   | 
||
| 
      * 
   | 
||
| 
      * $FreeBSD: src/sys/dev/usb/ehci_pci.c,v 1.18.2.1 2006/01/26 01:43:13 iedowse Exp $ 
   | 
||
| 
      * $DragonFly: src/sys/bus/usb/ehci_pci.c,v 1.18 2007/08/14 20:06:13 dillon Exp $ 
   | 
||
| 
      */ 
   | 
||
| 
     #include <sys/cdefs.h> 
   | 
||
| 
     __FBSDID("$FreeBSD: src/sys/dev/usb/ehci_pci.c,v 1.32 2008/04/11 05:50:53 benno Exp $"); 
   | 
||
| 
     /* 
   | 
||
| 
      * USB Enhanced Host Controller Driver, a.k.a. USB 2.0 controller. 
   | 
||
| 
      * 
   | 
||
| ... | ... | |
| 
     #include <sys/systm.h> 
   | 
||
| 
     #include <sys/kernel.h> 
   | 
||
| 
     #include <sys/module.h> 
   | 
||
| 
     #include <sys/lock.h> 
   | 
||
| 
     #include <sys/mutex.h> 
   | 
||
| 
     #include <sys/bus.h> 
   | 
||
| 
     #include <sys/queue.h> 
   | 
||
| 
     #include <sys/lock.h> 
   | 
||
| 
     #include <sys/lockmgr.h> 
   | 
||
| 
     #include <machine/bus.h> 
   | 
||
| 
     #include <sys/rman.h> 
   | 
||
| 
     #include <machine/resource.h> 
   | 
||
| 
     #include <bus/pci/pcivar.h> 
   | 
||
| 
     #include <bus/pci/pcireg.h> 
   | 
||
| 
     #include <dev/pci/pcivar.h> 
   | 
||
| 
     #include <dev/pci/pcireg.h> 
   | 
||
| 
     #include <bus/usb/usb.h> 
   | 
||
| 
     #include <bus/usb/usbdi.h> 
   | 
||
| 
     #include <bus/usb/usbdivar.h> 
   | 
||
| 
     #include <bus/usb/usb_mem.h> 
   | 
||
| 
     #include <dev/usb/usb.h> 
   | 
||
| 
     #include <dev/usb/usbdi.h> 
   | 
||
| 
     #include <dev/usb/usbdivar.h> 
   | 
||
| 
     #include <dev/usb/usb_mem.h> 
   | 
||
| 
     #include <bus/usb/ehcireg.h> 
   | 
||
| 
     #include <bus/usb/ehcivar.h> 
   | 
||
| 
     #include <dev/usb/ehcireg.h> 
   | 
||
| 
     #include <dev/usb/ehcivar.h> 
   | 
||
| 
     #define PCI_EHCI_VENDORID_ACERLABS	0x10b9 
   | 
||
| 
     #define PCI_EHCI_VENDORID_AMD		0x1022 
   | 
||
| ... | ... | |
| 
     /* AMD */ 
   | 
||
| 
     #define PCI_EHCI_DEVICEID_8111		0x10227463 
   | 
||
| 
     #define PCI_EHCI_DEVICEID_CS5536	0x20951022 
   | 
||
| 
     static const char *ehci_device_8111 = "AMD 8111 USB 2.0 controller"; 
   | 
||
| 
     static const char *ehci_device_CS5536 = "AMD CS5536 USB 2.0 controller"; 
   | 
||
| 
     /* ATI */ 
   | 
||
| 
     #define PCI_EHCI_DEVICEID_SB200		0x43451002 
   | 
||
| ... | ... | |
| 
     #define PCI_EHCI_DEVICEID_ISP156X	0x15621131 
   | 
||
| 
     static const char *ehci_device_isp156x = "Philips ISP156x USB 2.0 controller"; 
   | 
||
| 
     /* VIA */ 
   | 
||
| 
     #define PCI_EHCI_DEVICEID_VIA		0x31041106 
   | 
||
| 
     static const char *ehci_device_via = "VIA VT6202 USB 2.0 controller"; 
   | 
||
| 
     /* Generic */ 
   | 
||
| 
     static const char *ehci_device_generic = "EHCI (generic) USB 2.0 controller"; 
   | 
||
| 
     #define PCI_EHCI_BASE_REG	0x10 
   | 
||
| 
     #ifdef USB_DEBUG 
   | 
||
| 
     #define EHCI_DEBUG USB_DEBUG 
   | 
||
| 
     #define DPRINTF(x)	do { if (ehcidebug) kprintf x; } while (0) 
   | 
||
| 
     #define DPRINTF(x)	do { if (ehcidebug) printf x; } while (0) 
   | 
||
| 
     extern int ehcidebug; 
   | 
||
| 
     #else 
   | 
||
| 
     #define DPRINTF(x) 
   | 
||
| ... | ... | |
| 
     		return (ehci_device_m5239); 
   | 
||
| 
     	case PCI_EHCI_DEVICEID_8111: 
   | 
||
| 
     		return (ehci_device_8111); 
   | 
||
| 
     	case PCI_EHCI_DEVICEID_CS5536: 
   | 
||
| 
     		return (ehci_device_CS5536); 
   | 
||
| 
     	case PCI_EHCI_DEVICEID_SB200: 
   | 
||
| 
     		return (ehci_device_sb200); 
   | 
||
| 
     	case PCI_EHCI_DEVICEID_SB400: 
   | 
||
| ... | ... | |
| 
     	device_set_desc(sc->sc_bus.bdev, ehci_pci_match(self)); 
   | 
||
| 
     	switch (pci_get_vendor(self)) { 
   | 
||
| 
     	case PCI_EHCI_VENDORID_ACERLABS: 
   | 
||
| 
     		ksprintf(sc->sc_vendor, "AcerLabs"); 
   | 
||
| 
     		sprintf(sc->sc_vendor, "AcerLabs"); 
   | 
||
| 
     		break; 
   | 
||
| 
     	case PCI_EHCI_VENDORID_AMD: 
   | 
||
| 
     		ksprintf(sc->sc_vendor, "AMD"); 
   | 
||
| 
     		sprintf(sc->sc_vendor, "AMD"); 
   | 
||
| 
     		break; 
   | 
||
| 
     	case PCI_EHCI_VENDORID_APPLE: 
   | 
||
| 
     		ksprintf(sc->sc_vendor, "Apple"); 
   | 
||
| 
     		sprintf(sc->sc_vendor, "Apple"); 
   | 
||
| 
     		break; 
   | 
||
| 
     	case PCI_EHCI_VENDORID_ATI: 
   | 
||
| 
     		ksprintf(sc->sc_vendor, "ATI"); 
   | 
||
| 
     		sprintf(sc->sc_vendor, "ATI"); 
   | 
||
| 
     		break; 
   | 
||
| 
     	case PCI_EHCI_VENDORID_CMDTECH: 
   | 
||
| 
     		ksprintf(sc->sc_vendor, "CMDTECH"); 
   | 
||
| 
     		sprintf(sc->sc_vendor, "CMDTECH"); 
   | 
||
| 
     		break; 
   | 
||
| 
     	case PCI_EHCI_VENDORID_INTEL: 
   | 
||
| 
     		ksprintf(sc->sc_vendor, "Intel"); 
   | 
||
| 
     		sprintf(sc->sc_vendor, "Intel"); 
   | 
||
| 
     		break; 
   | 
||
| 
     	case PCI_EHCI_VENDORID_NEC: 
   | 
||
| 
     		ksprintf(sc->sc_vendor, "NEC"); 
   | 
||
| 
     		sprintf(sc->sc_vendor, "NEC"); 
   | 
||
| 
     		break; 
   | 
||
| 
     	case PCI_EHCI_VENDORID_OPTI: 
   | 
||
| 
     		ksprintf(sc->sc_vendor, "OPTi"); 
   | 
||
| 
     		sprintf(sc->sc_vendor, "OPTi"); 
   | 
||
| 
     		break; 
   | 
||
| 
     	case PCI_EHCI_VENDORID_SIS: 
   | 
||
| 
     		ksprintf(sc->sc_vendor, "SiS"); 
   | 
||
| 
     		sprintf(sc->sc_vendor, "SiS"); 
   | 
||
| 
     		break; 
   | 
||
| 
     	case PCI_EHCI_VENDORID_NVIDIA: 
   | 
||
| 
     	case PCI_EHCI_VENDORID_NVIDIA2: 
   | 
||
| 
     		ksprintf(sc->sc_vendor, "nVidia"); 
   | 
||
| 
     		sprintf(sc->sc_vendor, "nVidia"); 
   | 
||
| 
     		break; 
   | 
||
| 
     	case PCI_EHCI_VENDORID_VIA: 
   | 
||
| 
     		ksprintf(sc->sc_vendor, "VIA"); 
   | 
||
| 
     		sprintf(sc->sc_vendor, "VIA"); 
   | 
||
| 
     		break; 
   | 
||
| 
     	default: 
   | 
||
| 
     		if (bootverbose) 
   | 
||
| 
     			device_printf(self, "(New EHCI DeviceId=0x%08x)\n", 
   | 
||
| 
     			    pci_get_devid(self)); 
   | 
||
| 
     		ksprintf(sc->sc_vendor, "(0x%04x)", pci_get_vendor(self)); 
   | 
||
| 
     		sprintf(sc->sc_vendor, "(0x%04x)", pci_get_vendor(self)); 
   | 
||
| 
     	} 
   | 
||
| 
     	err = bus_setup_intr(self, sc->irq_res, 0, 
   | 
||
| 
     	    (driver_intr_t *) ehci_intr, sc, &sc->ih, NULL); 
   | 
||
| 
     	err = bus_setup_intr(self, sc->irq_res, INTR_TYPE_BIO, 
   | 
||
| 
     	    NULL, (driver_intr_t *)ehci_intr, sc, &sc->ih); 
   | 
||
| 
     	if (err) { 
   | 
||
| 
     		device_printf(self, "Could not setup irq, %d\n", err); 
   | 
||
| 
     		sc->ih = NULL; 
   | 
||
| ... | ... | |
| 
     			if (res != 0) 
   | 
||
| 
     				continue; 
   | 
||
| 
     			if (buscount != 1) { 
   | 
||
| 
     				kfree(nbus, M_TEMP); 
   | 
||
| 
     				free(nbus, M_TEMP); 
   | 
||
| 
     				continue; 
   | 
||
| 
     			} 
   | 
||
| 
     			if (device_get_devclass(nbus[0]) != dc) { 
   | 
||
| 
     				kfree(nbus, M_TEMP); 
   | 
||
| 
     				free(nbus, M_TEMP); 
   | 
||
| 
     				continue; 
   | 
||
| 
     			} 
   | 
||
| 
     			bsc = device_get_softc(nbus[0]); 
   | 
||
| 
     			kfree(nbus, M_TEMP); 
   | 
||
| 
     			free(nbus, M_TEMP); 
   | 
||
| 
     			DPRINTF(("ehci_pci_attach: companion %s\n", 
   | 
||
| 
     			    device_get_nameunit(bsc->bdev))); 
   | 
||
| 
     			sc->sc_comps[ncomp++] = bsc; 
   | 
||
| ... | ... | |
| 
     	sc->sc_ncomp = ncomp; 
   | 
||
| 
     	/* Allocate a parent dma tag for DMA maps */ 
   | 
||
| 
     	err = bus_dma_tag_create(/*XXX: bus_get_dma_tag(self)*/NULL, 1, 0, 
   | 
||
| 
     	err = bus_dma_tag_create(bus_get_dma_tag(self), 1, 0, 
   | 
||
| 
     	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 
   | 
||
| 
     	    BUS_SPACE_MAXSIZE_32BIT, USB_DMA_NSEG, BUS_SPACE_MAXSIZE_32BIT, 0, 
   | 
||
| 
     	    &sc->sc_bus.parent_dmatag); 
   | 
||
| 
     	    NULL, NULL, &sc->sc_bus.parent_dmatag); 
   | 
||
| 
     	if (err) { 
   | 
||
| 
     		device_printf(self, "Could not allocate parent DMA tag (%d)\n", 
   | 
||
| 
     		    err); 
   | 
||
| ... | ... | |
| 
     	err = bus_dma_tag_create(sc->sc_bus.parent_dmatag, 1, 0, 
   | 
||
| 
     	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 
   | 
||
| 
     	    BUS_SPACE_MAXSIZE_32BIT, USB_DMA_NSEG, BUS_SPACE_MAXSIZE_32BIT, 0, 
   | 
||
| 
     	    &sc->sc_bus.buffer_dmatag); 
   | 
||
| 
     	    busdma_lock_mutex, &Giant, &sc->sc_bus.buffer_dmatag); 
   | 
||
| 
     	if (err) { 
   | 
||
| 
     		device_printf(self, "Could not allocate buffer DMA tag (%d)\n", 
   | 
||
| 
     		    err); 
   | 
||
| ... | ... | |
| 
     		bus_dma_tag_destroy(sc->sc_bus.parent_dmatag); 
   | 
||
| 
     	if (sc->sc_bus.buffer_dmatag != NULL) 
   | 
||
| 
     		bus_dma_tag_destroy(sc->sc_bus.buffer_dmatag); 
   | 
||
| 
     | 
||
| 
     	if (sc->irq_res && sc->ih) { 
   | 
||
| 
     		int err = bus_teardown_intr(self, sc->irq_res, sc->ih); 
   | 
||
| ... | ... | |
| 
     	/* Synchronise with the BIOS if it owns the controller. */ 
   | 
||
| 
     	for (eecp = EHCI_HCC_EECP(cparams); eecp != 0; 
   | 
||
| 
     	     eecp = EHCI_EECP_NEXT(eec)) { 
   | 
||
| 
     	    eecp = EHCI_EECP_NEXT(eec)) { 
   | 
||
| 
     		eec = pci_read_config(self, eecp, 4); 
   | 
||
| 
     		if (EHCI_EECP_ID(eec) != EHCI_EC_LEGSUP) 
   | 
||
| 
     			continue; 
   | 
||
| ... | ... | |
| 
     		if (legsup & EHCI_LEGSUP_BIOSOWNED) { 
   | 
||
| 
     			pci_write_config(self, eecp, 
   | 
||
| 
     			    legsup | EHCI_LEGSUP_OSOWNED, 4); 
   | 
||
| 
     			kprintf("%s: waiting for BIOS to give up control\n", 
   | 
||
| 
     			printf("%s: waiting for BIOS to give up control\n", 
   | 
||
| 
     			    device_get_nameunit(sc->sc_bus.bdev)); 
   | 
||
| 
     			for (i = 0; i < 5000; i++) { 
   | 
||
| 
     				legsup = pci_read_config(self, eecp, 4); 
   | 
||
| ... | ... | |
| 
     				DELAY(1000); 
   | 
||
| 
     			} 
   | 
||
| 
     			if (legsup & EHCI_LEGSUP_BIOSOWNED) 
   | 
||
| 
     				kprintf("%s: timed out waiting for BIOS\n", 
   | 
||
| 
     				printf("%s: timed out waiting for BIOS\n", 
   | 
||
| 
     				    device_get_nameunit(sc->sc_bus.bdev)); 
   | 
||
| 
     		} 
   | 
||
| 
     	} 
   | 
||
| ... | ... | |
| 
     	cparams = EREAD4(sc, EHCI_HCCPARAMS); 
   | 
||
| 
     	for (eecp = EHCI_HCC_EECP(cparams); eecp != 0; 
   | 
||
| 
     	     eecp = EHCI_EECP_NEXT(eec)) { 
   | 
||
| 
     	    eecp = EHCI_EECP_NEXT(eec)) { 
   | 
||
| 
     		eec = pci_read_config(self, eecp, 4); 
   | 
||
| 
     		if (EHCI_EECP_ID(eec) != EHCI_EC_LEGSUP) 
   | 
||
| 
     			continue; 
   | 
||
| 
     -- ehcireg.h	2007-06-27 12:27:59 +0000 
   | 
||
| 
     ++ /root/src/sys/dev/usb/ehcireg.h	2005-09-18 11:45:39 +0000 
   | 
||
| ... | ... | |
| 
     /*	$NetBSD: ehcireg.h,v 1.18 2004/10/22 10:38:17 augustss Exp $	*/ 
   | 
||
| 
     /*	$FreeBSD: src/sys/dev/usb/ehcireg.h,v 1.7.2.1 2006/01/26 01:43:13 iedowse Exp $	*/ 
   | 
||
| 
     /*	$DragonFly: src/sys/bus/usb/ehcireg.h,v 1.7 2007/06/27 12:27:59 hasso Exp $	*/ 
   | 
||
| 
     /*	$FreeBSD: src/sys/dev/usb/ehcireg.h,v 1.8 2005/09/18 11:45:39 netchild Exp $	*/ 
   | 
||
| 
     /* 
   | 
||
| 
     /*- 
   | 
||
| 
      * Copyright (c) 2001 The NetBSD Foundation, Inc. 
   | 
||
| 
      * All rights reserved. 
   | 
||
| 
      * 
   | 
||
| ... | ... | |
| 
     #define EHCI_PAGE_SIZE 0x1000 
   | 
||
| 
     #define EHCI_PAGE(x) ((x) &~ 0xfff) 
   | 
||
| 
     #define EHCI_PAGE_OFFSET(x) ((x) & 0xfff) 
   | 
||
| 
     #if defined(__FreeBSD__) 
   | 
||
| 
     #define EHCI_PAGE_MASK(x) ((x) & 0xfff) 
   | 
||
| 
     #endif 
   | 
||
| 
     typedef u_int32_t ehci_link_t; 
   | 
||
| 
     #define EHCI_LINK_TERMINATE	0x00000001 
   | 
||
| ... | ... | |
| 
     #define	EHCI_QTD_SET_TOGGLE(x)	((x) << 31) 
   | 
||
| 
     #define EHCI_QTD_TOGGLE_MASK	0x80000000 
   | 
||
| 
     	ehci_physaddr_t	qtd_buffer[EHCI_QTD_NBUFFERS]; 
   | 
||
| 
     	ehci_physaddr_t	qtd_buffer_hi[EHCI_QTD_NBUFFERS]; 
   | 
||
| 
     	ehci_physaddr_t qtd_buffer_hi[EHCI_QTD_NBUFFERS]; 
   | 
||
| 
     } ehci_qtd_t; 
   | 
||
| 
     #define EHCI_QTD_ALIGN 32 
   | 
||
| 
     -- ehcivar.h	2008-05-19 10:17:44 +0000 
   | 
||
| 
     ++ /root/src/sys/dev/usb/ehcivar.h	2007-06-14 16:23:31 +0000 
   | 
||
| ... | ... | |
| 
     /*	$NetBSD: ehcivar.h,v 1.19 2005/04/29 15:04:29 augustss Exp $	*/ 
   | 
||
| 
     /*	$FreeBSD: src/sys/dev/usb/ehcivar.h,v 1.9.2.1 2006/01/26 01:43:13 iedowse Exp $	*/ 
   | 
||
| 
     /*	$DragonFly: src/sys/bus/usb/ehcivar.h,v 1.11 2007/06/30 20:39:22 hasso Exp $	*/ 
   | 
||
| 
     /*	$FreeBSD: src/sys/dev/usb/ehcivar.h,v 1.17 2007/06/14 16:23:31 imp Exp $	*/ 
   | 
||
| 
     /* 
   | 
||
| 
     /*- 
   | 
||
| 
      * Copyright (c) 2001 The NetBSD Foundation, Inc. 
   | 
||
| 
      * All rights reserved. 
   | 
||
| 
      * 
   | 
||
| ... | ... | |
| 
      * Information about an entry in the interrupt list. 
   | 
||
| 
      */ 
   | 
||
| 
     struct ehci_soft_islot { 
   | 
||
| 
     	ehci_soft_qh_t *sqh;	/* Queue Head. */ 
   | 
||
| 
     	ehci_soft_qh_t *sqh;		/* Queue Head. */ 
   | 
||
| 
     }; 
   | 
||
| 
     #define EHCI_FRAMELIST_MAXCOUNT	1024 
   | 
||
| 
     #define EHCI_IPOLLRATES		8	/* Poll rates (1ms, 2, 4, 8 ... 128) */ 
   | 
||
| 
     #define EHCI_INTRQHS		((1 << EHCI_IPOLLRATES) - 1) 
   | 
||
| 
     #define EHCI_MAX_POLLRATE	(1 << (EHCI_IPOLLRATES - 1)) 
   | 
||
| 
     #define EHCI_IQHIDX(lev, pos) \ 
   | 
||
| 
     	((((pos) & ((1 << (lev)) - 1)) | (1 << (lev))) - 1) 
   | 
||
| 
     #define EHCI_IQHIDX(lev, pos)	\ 
   | 
||
| 
         ((((pos) & ((1 << (lev)) - 1)) | (1 << (lev))) - 1) 
   | 
||
| 
     #define EHCI_ILEV_IVAL(lev)	(1 << (lev)) 
   | 
||
| 
     #define EHCI_HASH_SIZE 128 
   | 
||
| 
     #define EHCI_COMPANION_MAX 8 
   | 
||
| ... | ... | |
| 
     typedef struct ehci_softc { 
   | 
||
| 
     	struct usbd_bus sc_bus;		/* base device */ 
   | 
||
| 
     	int sc_flags; 
   | 
||
| 
     	bus_space_tag_t iot; 
   | 
||
| 
     	bus_space_handle_t ioh; 
   | 
||
| 
     	bus_size_t sc_size; 
   | 
||
| 
     #if defined(__FreeBSD__) 
   | 
||
| 
     	void *ih; 
   | 
||
| 
     	struct resource *io_res; 
   | 
||
| 
     	struct resource *irq_res; 
   | 
||
| 
     #endif 
   | 
||
| 
     	u_int sc_offs;			/* offset to operational regs */ 
   | 
||
| 
     	int sc_flags;			/* misc flags */ 
   | 
||
| 
     	char sc_vendor[32];		/* vendor string for root hub */ 
   | 
||
| 
     	int sc_id_vendor;		/* vendor ID for root hub */ 
   | 
||
| 
     	u_int32_t sc_cmd;		/* shadow of cmd reg during suspend */ 
   | 
||
| 
     #if defined(__NetBSD__) || defined(__OpenBSD__) 
   | 
||
| 
     	void *sc_powerhook;		/* cookie from power hook */ 
   | 
||
| 
     	void *sc_shutdownhook;		/* cookie from shutdown hook */ 
   | 
||
| 
     #endif 
   | 
||
| 
     	u_int sc_ncomp; 
   | 
||
| 
     	u_int sc_npcomp; 
   | 
||
| ... | ... | |
| 
     	usb_dma_t sc_fldma; 
   | 
||
| 
     	ehci_link_t *sc_flist; 
   | 
||
| 
     	u_int sc_flsize; 
   | 
||
| 
     #ifndef __FreeBSD__ 
   | 
||
| 
     	u_int sc_rand;			/* XXX need proper intr scheduling */ 
   | 
||
| 
     #endif 
   | 
||
| 
     	struct ehci_soft_islot sc_islots[EHCI_INTRQHS]; 
   | 
||
| ... | ... | |
| 
     	struct callout sc_tmo_intrlist; 
   | 
||
| 
     	char sc_dying; 
   | 
||
| 
     #if defined(__NetBSD__) 
   | 
||
| 
     	struct usb_dma_reserve sc_dma_reserve; 
   | 
||
| 
     #endif 
   | 
||
| 
     } ehci_softc_t; 
   | 
||
| 
     #define EREAD1(sc, a) bus_space_read_1((sc)->iot, (sc)->ioh, (a)) 
   | 
||
| ... | ... | |
| 
     usbd_status	ehci_init(ehci_softc_t *); 
   | 
||
| 
     int		ehci_intr(void *); 
   | 
||
| 
     int		ehci_detach(ehci_softc_t *, int); 
   | 
||
| 
     #if defined(__NetBSD__) || defined(__OpenBSD__) 
   | 
||
| 
     int		ehci_activate(device_t, enum devact); 
   | 
||
| 
     #endif 
   | 
||
| 
     void		ehci_power(int state, void *priv); 
   | 
||
| 
     void		ehci_shutdown(void *v); 
   | 
||
| 
     -- hid.c	2008-05-18 17:51:14 +0000 
   | 
||
| 
     ++ /root/src/sys/dev/usb/hid.c	2008-05-18 21:28:20 +0000 
   | 
||
| ... | ... | |
| 
     /* 
   | 
||
| 
      * $NetBSD: hid.c,v 1.17 2001/11/13 06:24:53 lukem Exp $ 
   | 
||
| 
      * $FreeBSD: src/sys/dev/usb/hid.c,v 1.23 2003/08/24 17:55:54 obrien Exp $ 
   | 
||
| 
      * $DragonFly: src/sys/bus/usb/hid.c,v 1.13 2007/06/28 13:55:12 hasso Exp $ 
   | 
||
| 
      */ 
   | 
||
| 
     /* 
   | 
||
| ... | ... | |
| 
     /*	$NetBSD: hid.c,v 1.17 2001/11/13 06:24:53 lukem Exp $	*/ 
   | 
||
| 
     #include <sys/cdefs.h> 
   | 
||
| 
     __FBSDID("$FreeBSD: src/sys/dev/usb/hid.c,v 1.29 2007/06/20 05:10:52 imp Exp $"); 
   | 
||
| 
     /*- 
   | 
||
| 
      * Copyright (c) 1998 The NetBSD Foundation, Inc. 
   | 
||
| 
      * All rights reserved. 
   | 
||
| 
      * 
   | 
||
| ... | ... | |
| 
     #include <sys/systm.h> 
   | 
||
| 
     #include <sys/malloc.h> 
   | 
||
| 
     #include <bus/usb/usb.h> 
   | 
||
| 
     #include <bus/usb/usbhid.h> 
   | 
||
| 
     #include <dev/usb/usb.h> 
   | 
||
| 
     #include <dev/usb/usbhid.h> 
   | 
||
| 
     #include <bus/usb/hid.h> 
   | 
||
| 
     #include <dev/usb/hid.h> 
   | 
||
| 
     #ifdef USB_DEBUG 
   | 
||
| 
     #define DPRINTF(x)	if (usbdebug) kprintf x 
   | 
||
| 
     #define DPRINTFN(n,x)	if (usbdebug>(n)) kprintf x 
   | 
||
| 
     #define DPRINTF(x)	if (usbdebug) printf x 
   | 
||
| 
     #define DPRINTFN(n,x)	if (usbdebug>(n)) printf x 
   | 
||
| 
     extern int usbdebug; 
   | 
||
| 
     #else 
   | 
||
| 
     #define DPRINTF(x) 
   | 
||
| ... | ... | |
| 
     { 
   | 
||
| 
     	struct hid_data *s; 
   | 
||
- « Previous
 - 1
 - 2
 - Next »