Bug #1010 » usb.diff
| ehci.c 19 May 2008 11:21:42 -0000 | ||
|---|---|---|
| 
     static void		ehci_free_sqtd(ehci_softc_t *, ehci_soft_qtd_t *); 
   | 
||
| 
     static usbd_status	ehci_alloc_sqtd_chain(struct ehci_pipe *, 
   | 
||
| 
     			    ehci_softc_t *, int, int, usbd_xfer_handle, 
   | 
||
| 
     			    ehci_soft_qtd_t *, ehci_soft_qtd_t *, 
   | 
||
| 
     			    ehci_soft_qtd_t **, ehci_soft_qtd_t **); 
   | 
||
| 
     static void		ehci_free_sqtd_chain(ehci_softc_t *, ehci_soft_qtd_t *, 
   | 
||
| 
     					    ehci_soft_qtd_t *); 
   | 
||
| 
     static void		ehci_free_sqtd_chain(ehci_softc_t *, ehci_soft_qh_t *, 
   | 
||
| 
     			    ehci_soft_qtd_t *, ehci_soft_qtd_t *); 
   | 
||
| 
     static usbd_status	ehci_device_request(usbd_xfer_handle xfer); 
   | 
||
| ... | ... | |
| 
     static void		ehci_add_qh(ehci_soft_qh_t *, ehci_soft_qh_t *); 
   | 
||
| 
     static void		ehci_rem_qh(ehci_softc_t *, ehci_soft_qh_t *, 
   | 
||
| 
     				    ehci_soft_qh_t *); 
   | 
||
| 
     static void		ehci_set_qh_qtd(ehci_soft_qh_t *, ehci_soft_qtd_t *); 
   | 
||
| 
     static void		ehci_activate_qh(ehci_soft_qh_t *, ehci_soft_qtd_t *); 
   | 
||
| 
     static void		ehci_sync_hc(ehci_softc_t *); 
   | 
||
| 
     static void		ehci_close_pipe(usbd_pipe_handle, ehci_soft_qh_t *); 
   | 
||
| ... | ... | |
| 
     	ehci_device_isoc_done, 
   | 
||
| 
     }; 
   | 
||
| 
     static usbd_status 
   | 
||
| 
     ehci_hcreset(ehci_softc_t *sc) 
   | 
||
| 
     { 
   | 
||
| 
     	u_int32_t hcr; 
   | 
||
| 
     	u_int i; 
   | 
||
| 
     	EOWRITE4(sc, EHCI_USBCMD, 0);	/* Halt controller */ 
   | 
||
| 
     	for (i = 0; i < 100; i++) { 
   | 
||
| 
     		usb_delay_ms(&sc->sc_bus, 1); 
   | 
||
| 
     		hcr = EOREAD4(sc, EHCI_USBSTS) & EHCI_STS_HCH; 
   | 
||
| 
     		if (hcr) 
   | 
||
| 
     			break; 
   | 
||
| 
     	} 
   | 
||
| 
     	if (!hcr) 
   | 
||
| 
     		/* 
   | 
||
| 
                      * Fall through and try reset anyway even though 
   | 
||
| 
                      * Table 2-9 in the EHCI spec says this will result 
   | 
||
| 
                      * in undefined behavior. 
   | 
||
| 
                      */ 
   | 
||
| 
     		kprintf("%s: stop timeout\n", 
   | 
||
| 
     		       device_get_nameunit(sc->sc_bus.bdev)); 
   | 
||
| 
     	EOWRITE4(sc, EHCI_USBCMD, EHCI_CMD_HCRESET); 
   | 
||
| 
     	for (i = 0; i < 100; i++) { 
   | 
||
| 
     		usb_delay_ms(&sc->sc_bus, 1); 
   | 
||
| 
     		hcr = EOREAD4(sc, EHCI_USBCMD) & EHCI_CMD_HCRESET; 
   | 
||
| 
     		if (!hcr) 
   | 
||
| 
     			return (USBD_NORMAL_COMPLETION); 
   | 
||
| 
     	} 
   | 
||
| 
     	kprintf("%s: reset timeout\n", device_get_nameunit(sc->sc_bus.bdev)); 
   | 
||
| 
     	return (USBD_IOERROR); 
   | 
||
| 
     } 
   | 
||
| 
     usbd_status 
   | 
||
| 
     ehci_init(ehci_softc_t *sc) 
   | 
||
| 
     { 
   | 
||
| 
     	u_int32_t vers, sparams, cparams, hcr; 
   | 
||
| 
     	u_int32_t version, sparams, cparams, hcr; 
   | 
||
| 
     	u_int i; 
   | 
||
| 
     	usbd_status err; 
   | 
||
| 
     	ehci_soft_qh_t *sqh; 
   | 
||
| ... | ... | |
| 
     	sc->sc_offs = EREAD1(sc, EHCI_CAPLENGTH); 
   | 
||
| 
     	vers = EREAD2(sc, EHCI_HCIVERSION); 
   | 
||
| 
     	version = EREAD2(sc, EHCI_HCIVERSION); 
   | 
||
| 
     	kprintf("%s: EHCI version %x.%x\n", device_get_nameunit(sc->sc_bus.bdev), 
   | 
||
| 
     	       vers >> 8, vers & 0xff); 
   | 
||
| 
     	       version >> 8, version & 0xff); 
   | 
||
| 
     	sparams = EREAD4(sc, EHCI_HCSPARAMS); 
   | 
||
| 
     	DPRINTF(("ehci_init: sparams=0x%x\n", sparams)); 
   | 
||
| ... | ... | |
| 
     	/* Reset the controller */ 
   | 
||
| 
     	DPRINTF(("%s: resetting\n", device_get_nameunit(sc->sc_bus.bdev))); 
   | 
||
| 
     	EOWRITE4(sc, EHCI_USBCMD, 0);	/* Halt controller */ 
   | 
||
| 
     	usb_delay_ms(&sc->sc_bus, 1); 
   | 
||
| 
     	EOWRITE4(sc, EHCI_USBCMD, EHCI_CMD_HCRESET); 
   | 
||
| 
     	for (i = 0; i < 100; i++) { 
   | 
||
| 
     		usb_delay_ms(&sc->sc_bus, 1); 
   | 
||
| 
     		hcr = EOREAD4(sc, EHCI_USBCMD) & EHCI_CMD_HCRESET; 
   | 
||
| 
     		if (!hcr) 
   | 
||
| 
     			break; 
   | 
||
| 
     	} 
   | 
||
| 
     	if (hcr) { 
   | 
||
| 
     		kprintf("%s: reset timeout\n", 
   | 
||
| 
     		    device_get_nameunit(sc->sc_bus.bdev)); 
   | 
||
| 
     		return (USBD_IOERROR); 
   | 
||
| 
     	} 
   | 
||
| 
     	err = ehci_hcreset(sc); 
   | 
||
| 
     	if (err != USBD_NORMAL_COMPLETION) 
   | 
||
| 
     		return (err); 
   | 
||
| 
     	/* frame list size at default, read back what we got and use that */ 
   | 
||
| 
     	switch (EHCI_CMD_FLS(EOREAD4(sc, EHCI_USBCMD))) { 
   | 
||
| ... | ... | |
| 
     		sqh->qh.qh_qtd.qtd_next = EHCI_NULL; 
   | 
||
| 
     		sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL; 
   | 
||
| 
     		sqh->qh.qh_qtd.qtd_status = htole32(EHCI_QTD_HALTED); 
   | 
||
| 
     		sqh->sqtd = NULL; 
   | 
||
| 
     	} 
   | 
||
| 
     	/* Point the frame list at the last level (128ms). */ 
   | 
||
| 
     	for (i = 0; i < sc->sc_flsize; i++) { 
   | 
||
| ... | ... | |
| 
     	/* Fill the overlay qTD */ 
   | 
||
| 
     	sqh->qh.qh_qtd.qtd_next = EHCI_NULL; 
   | 
||
| 
     	sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL; 
   | 
||
| 
     	sqh->qh.qh_qtd.qtd_status = htole32(EHCI_QTD_HALTED); 
   | 
||
| 
     	sqh->sqtd = NULL; 
   | 
||
| 
     	sqh->qh.qh_qtd.qtd_status = htole32(0); 
   | 
||
| 
     #ifdef EHCI_DEBUG 
   | 
||
| 
     	if (ehcidebug) { 
   | 
||
| 
     		ehci_dump_sqh(sqh); 
   | 
||
| ... | ... | |
| 
     { 
   | 
||
| 
     	ehci_softc_t *sc = v; 
   | 
||
| 
     	if (sc->sc_dying || (sc->sc_flags & EHCI_SCFLG_DONEINIT) == 0) 
   | 
||
| 
     	if (sc == NULL || sc->sc_dying) 
   | 
||
| 
     		return (0); 
   | 
||
| 
     	/* If we get an interrupt while polling, then just ignore it. */ 
   | 
||
| ... | ... | |
| 
     	DPRINTFN(20,("ehci_intr1: enter\n")); 
   | 
||
| 
     	/* In case the interrupt occurs before initialization has completed. */ 
   | 
||
| 
     	if (sc == NULL) { 
   | 
||
| 
     #ifdef DIAGNOSTIC 
   | 
||
| 
     		kprintf("ehci_intr1: sc == NULL\n"); 
   | 
||
| 
     #endif 
   | 
||
| 
     		return (0); 
   | 
||
| 
     	} 
   | 
||
| 
     	intrs = EHCI_STS_INTRS(EOREAD4(sc, EHCI_USBSTS)); 
   | 
||
| 
     	if (!intrs) 
   | 
||
| 
     		return (0); 
   | 
||
| ... | ... | |
| 
     	ehci_pcd_able(sc, 1); 
   | 
||
| 
     } 
   | 
||
| 
     /* 
   | 
||
| 
      * XXX write back xfer data for architectures with a write-back 
   | 
||
| 
      *     data cache; this is a hack because usb is mis-architected 
   | 
||
| 
      *     in blindly mixing bus_dma w/ PIO. 
   | 
||
| 
      */ 
   | 
||
| 
     static __inline void 
   | 
||
| 
     hacksync(usbd_xfer_handle xfer) 
   | 
||
| 
     { 
   | 
||
| 
     	bus_dma_tag_t tag; 
   | 
||
| 
     	struct usb_dma_mapping *dmap; 
   | 
||
| 
     	if (xfer->length == 0) 
   | 
||
| 
     		return; 
   | 
||
| 
     	tag = xfer->pipe->device->bus->buffer_dmatag; 
   | 
||
| 
     	dmap = &xfer->dmamap; 
   | 
||
| 
     	bus_dmamap_sync(tag, dmap->map, BUS_DMASYNC_PREWRITE); 
   | 
||
| 
     } 
   | 
||
| 
     void 
   | 
||
| 
     ehci_pcd(ehci_softc_t *sc, usbd_xfer_handle xfer) 
   | 
||
| 
     { 
   | 
||
| ... | ... | |
| 
     	pipe = xfer->pipe; 
   | 
||
| 
     	p = KERNADDR(&xfer->dmabuf, 0); 
   | 
||
| 
     	p = xfer->buffer; 
   | 
||
| 
     	m = min(sc->sc_noport, xfer->length * 8 - 1); 
   | 
||
| 
     	memset(p, 0, xfer->length); 
   | 
||
| 
     	for (i = 1; i <= m; i++) { 
   | 
||
| ... | ... | |
| 
     	xfer->actlen = xfer->length; 
   | 
||
| 
     	xfer->status = USBD_NORMAL_COMPLETION; 
   | 
||
| 
     	hacksync(xfer);	/* XXX to compensate for usb_transfer_complete */ 
   | 
||
| 
     	usb_transfer_complete(xfer); 
   | 
||
| 
     } 
   | 
||
| ... | ... | |
| 
     	/* Schedule a callout to catch any dropped transactions. */ 
   | 
||
| 
     	if ((sc->sc_flags & EHCI_SCFLG_LOSTINTRBUG) && 
   | 
||
| 
     	    !LIST_EMPTY(&sc->sc_intrhead)) 
   | 
||
| 
     		callout_reset(&sc->sc_tmo_intrlist, hz / 5, ehci_intrlist_timeout, 
   | 
||
| 
     		   sc); 
   | 
||
| 
     		callout_reset(&sc->sc_tmo_intrlist, hz / 5, 
   | 
||
| 
     		    ehci_intrlist_timeout, sc); 
   | 
||
| 
     #ifdef USB_USE_SOFTINTR 
   | 
||
| 
     	if (sc->sc_softwake) { 
   | 
||
| ... | ... | |
| 
     ehci_idone(struct ehci_xfer *ex) 
   | 
||
| 
     { 
   | 
||
| 
     	usbd_xfer_handle xfer = &ex->xfer; 
   | 
||
| 
     #ifdef USB_DEBUG 
   | 
||
| 
     	struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe; 
   | 
||
| 
     #endif 
   | 
||
| 
     	ehci_soft_qtd_t *sqtd, *lsqtd; 
   | 
||
| 
     	u_int32_t status = 0, nstatus = 0; 
   | 
||
| 
     	ehci_physaddr_t nextphys, altnextphys; 
   | 
||
| 
     	int actlen, cerr; 
   | 
||
| 
     	DPRINTFN(/*12*/2, ("ehci_idone: ex=%p\n", ex)); 
   | 
||
| ... | ... | |
| 
     		ehci_dump_sqtds(ex->sqtdstart); 
   | 
||
| 
     #endif 
   | 
||
| 
     	/* 
   | 
||
| 
     	 * Make sure that the QH overlay qTD does not reference any 
   | 
||
| 
     	 * of the qTDs we are about to free. This is probably only 
   | 
||
| 
     	 * necessary if the transfer is marked as HALTED. 
   | 
||
| 
     	 */ 
   | 
||
| 
     	nextphys = EHCI_LINK_ADDR(le32toh(epipe->sqh->qh.qh_qtd.qtd_next)); 
   | 
||
| 
     	altnextphys = 
   | 
||
| 
     	    EHCI_LINK_ADDR(le32toh(epipe->sqh->qh.qh_qtd.qtd_altnext)); 
   | 
||
| 
     	for (sqtd = ex->sqtdstart; sqtd != ex->sqtdend->nextqtd; 
   | 
||
| 
     	     sqtd = sqtd->nextqtd) { 
   | 
||
| 
     		if (sqtd->physaddr == nextphys) { 
   | 
||
| 
     			epipe->sqh->qh.qh_qtd.qtd_next = 
   | 
||
| 
     			    htole32(ex->sqtdend->nextqtd->physaddr); 
   | 
||
| 
     			DPRINTFN(4, ("ehci_idone: updated overlay next ptr\n")); 
   | 
||
| 
     		} 
   | 
||
| 
     		if (sqtd->physaddr == altnextphys) { 
   | 
||
| 
     			DPRINTFN(4, 
   | 
||
| 
     			    ("ehci_idone: updated overlay altnext ptr\n")); 
   | 
||
| 
     			epipe->sqh->qh.qh_qtd.qtd_altnext = 
   | 
||
| 
     			    htole32(ex->sqtdend->nextqtd->physaddr); 
   | 
||
| 
     		} 
   | 
||
| 
     	} 
   | 
||
| 
     	/* The transfer is done, compute actual length and status. */ 
   | 
||
| 
     	lsqtd = ex->sqtdend; 
   | 
||
| 
     	actlen = 0; 
   | 
||
| ... | ... | |
| 
     		status = nstatus; 
   | 
||
| 
     		/* halt is ok if descriptor is last, and complete */ 
   | 
||
| 
     		if (sqtd->qtd.qtd_next == EHCI_NULL && 
   | 
||
| 
     		    EHCI_QTD_GET_BYTES(status) == 0) 
   | 
||
| 
     		if (sqtd == lsqtd && EHCI_QTD_GET_BYTES(status) == 0) 
   | 
||
| 
     			status &= ~EHCI_QTD_HALTED; 
   | 
||
| 
     		if (EHCI_QTD_GET_PID(status) !=	EHCI_QTD_PID_SETUP) 
   | 
||
| 
     			actlen += sqtd->len - EHCI_QTD_GET_BYTES(status); 
   | 
||
| ... | ... | |
| 
     	sc->sc_dying = 1; 
   | 
||
| 
     	EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs); 
   | 
||
| 
     	EOWRITE4(sc, EHCI_USBCMD, 0); 
   | 
||
| 
     	EOWRITE4(sc, EHCI_USBCMD, EHCI_CMD_HCRESET); 
   | 
||
| 
     	(void) ehci_hcreset(sc); 
   | 
||
| 
     	callout_stop(&sc->sc_tmo_intrlist); 
   | 
||
| 
     	callout_stop(&sc->sc_tmo_pcd); 
   | 
||
| ... | ... | |
| 
     	switch (why) { 
   | 
||
| 
     	case PWR_SUSPEND: 
   | 
||
| 
     	case PWR_STANDBY: 
   | 
||
| 
     		sc->sc_bus.use_polling++; 
   | 
||
| 
     		for (i = 1; i <= sc->sc_noport; i++) { 
   | 
||
| ... | ... | |
| 
     		sc->sc_bus.use_polling--; 
   | 
||
| 
     		break; 
   | 
||
| 
     	case PWR_SOFTSUSPEND: 
   | 
||
| 
     	case PWR_SOFTSTANDBY: 
   | 
||
| 
     	case PWR_SOFTRESUME: 
   | 
||
| 
     		break; 
   | 
||
| 
     	} 
   | 
||
| 
     	crit_exit(); 
   | 
||
| ... | ... | |
| 
     	ehci_softc_t *sc = v; 
   | 
||
| 
     	DPRINTF(("ehci_shutdown: stopping the HC\n")); 
   | 
||
| 
     	EOWRITE4(sc, EHCI_USBCMD, 0);	/* Halt controller */ 
   | 
||
| 
     	EOWRITE4(sc, EHCI_USBCMD, EHCI_CMD_HCRESET); 
   | 
||
| 
     	(void) ehci_hcreset(sc); 
   | 
||
| 
     } 
   | 
||
| 
     usbd_status 
   | 
||
| ... | ... | |
| 
     		} 
   | 
||
| 
     #endif 
   | 
||
| 
     	} else { 
   | 
||
| 
     		xfer = kmalloc(sizeof(struct ehci_xfer), M_USB, M_INTWAIT); 
   | 
||
| 
     		xfer = kmalloc(sizeof(struct ehci_xfer), M_USB, M_NOWAIT); 
   | 
||
| 
     	} 
   | 
||
| 
     	if (xfer != NULL) { 
   | 
||
| 
     		memset(xfer, 0, sizeof(struct ehci_xfer)); 
   | 
||
| ... | ... | |
| 
      * debugger. 
   | 
||
| 
      */ 
   | 
||
| 
     void 
   | 
||
| 
     ehci_dump(void) 
   | 
||
| 
     ehci_dump() 
   | 
||
| 
     { 
   | 
||
| 
     	ehci_dump_regs(theehci); 
   | 
||
| 
     } 
   | 
||
| ... | ... | |
| 
     	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"); 
   | 
||
| 
     	endp = le32toh(qh->qh_endp); 
   | 
||
| 
     	kprintf("  endp=0x%08x\n", endp); 
   | 
||
| ... | ... | |
| 
     		EHCI_QH_SET_SMASK(xfertype == UE_INTERRUPT ? 0x01 : 0) 
   | 
||
| 
     		); 
   | 
||
| 
     	sqh->qh.qh_curqtd = EHCI_NULL; 
   | 
||
| 
     	/* Fill the overlay qTD */ 
   | 
||
| 
     	sqh->qh.qh_qtd.qtd_next = EHCI_NULL; 
   | 
||
| 
     	sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL; 
   | 
||
| 
     	/* The overlay qTD was already set up by ehci_alloc_sqh(). */ 
   | 
||
| 
     	sqh->qh.qh_qtd.qtd_status = 
   | 
||
| 
     	    htole32(EHCI_QTD_SET_TOGGLE(pipe->endpoint->savedtoggle)); 
   | 
||
| ... | ... | |
| 
     	ehci_sync_hc(sc); 
   | 
||
| 
     } 
   | 
||
| 
     /* Restart a QH following the addition of a qTD. */ 
   | 
||
| 
     void 
   | 
||
| 
     ehci_set_qh_qtd(ehci_soft_qh_t *sqh, ehci_soft_qtd_t *sqtd) 
   | 
||
| 
     ehci_activate_qh(ehci_soft_qh_t *sqh, ehci_soft_qtd_t *sqtd) 
   | 
||
| 
     { 
   | 
||
| 
     	int i; 
   | 
||
| 
     	u_int32_t status; 
   | 
||
| 
     	KASSERT((sqtd->qtd.qtd_status & htole32(EHCI_QTD_ACTIVE)) == 0, 
   | 
||
| 
     	    ("ehci_activate_qh: already active")); 
   | 
||
| 
     	/* Save toggle bit and ping status. */ 
   | 
||
| 
     	status = sqh->qh.qh_qtd.qtd_status & 
   | 
||
| 
     	    htole32(EHCI_QTD_TOGGLE_MASK | 
   | 
||
| 
     		    EHCI_QTD_SET_STATUS(EHCI_QTD_PINGSTATE)); 
   | 
||
| 
     	/* Set HALTED to make hw leave it alone. */ 
   | 
||
| 
     	sqh->qh.qh_qtd.qtd_status = 
   | 
||
| 
     	    htole32(EHCI_QTD_SET_STATUS(EHCI_QTD_HALTED)); 
   | 
||
| 
     	sqh->qh.qh_curqtd = 0; 
   | 
||
| 
     	sqh->qh.qh_qtd.qtd_next = htole32(sqtd->physaddr); 
   | 
||
| 
     	sqh->qh.qh_qtd.qtd_altnext = 0; 
   | 
||
| 
     	for (i = 0; i < EHCI_QTD_NBUFFERS; i++) 
   | 
||
| 
     		sqh->qh.qh_qtd.qtd_buffer[i] = 0; 
   | 
||
| 
     	sqh->sqtd = sqtd; 
   | 
||
| 
     	/* Set !HALTED && !ACTIVE to start execution, preserve some fields */ 
   | 
||
| 
     	sqh->qh.qh_qtd.qtd_status = status; 
   | 
||
| 
     	/* 
   | 
||
| 
     	 * When a QH is idle, the overlay qTD should be marked as not 
   | 
||
| 
     	 * halted and not active. This causes the host controller to 
   | 
||
| 
     	 * retrieve the real qTD on each pass (rather than just examinig 
   | 
||
| 
     	 * the overlay), so it will notice when we activate the qTD. 
   | 
||
| 
     	 */ 
   | 
||
| 
     	if (sqtd == sqh->sqtd) { 
   | 
||
| 
     		/* Check that the hardware is in the state we expect. */ 
   | 
||
| 
     		if (EHCI_LINK_ADDR(le32toh(sqh->qh.qh_qtd.qtd_next)) != 
   | 
||
| 
     		    sqtd->physaddr) { 
   | 
||
| 
     #ifdef EHCI_DEBUG 
   | 
||
| 
     			kprintf("ehci_activate_qh: unexpected next ptr\n"); 
   | 
||
| 
     			ehci_dump_sqh(sqh); 
   | 
||
| 
     			ehci_dump_sqtds(sqh->sqtd); 
   | 
||
| 
     #endif 
   | 
||
| 
     			sqh->qh.qh_qtd.qtd_next = htole32(sqtd->physaddr); 
   | 
||
| 
     			sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL; 
   | 
||
| 
     		} 
   | 
||
| 
     		/* Ensure the flags are correct. */ 
   | 
||
| 
     		sqh->qh.qh_qtd.qtd_status &= htole32(EHCI_QTD_PINGSTATE | 
   | 
||
| 
     		    EHCI_QTD_TOGGLE_MASK); 
   | 
||
| 
     	} 
   | 
||
| 
     	/* Now activate the qTD. */ 
   | 
||
| 
     	sqtd->qtd.qtd_status |= htole32(EHCI_QTD_ACTIVE); 
   | 
||
| 
     } 
   | 
||
| 
     /* 
   | 
||
| ... | ... | |
| 
     	index = UGETW(req->wIndex); 
   | 
||
| 
     	if (len != 0) 
   | 
||
| 
     		buf = KERNADDR(&xfer->dmabuf, 0); 
   | 
||
| 
     		buf = xfer->buffer; 
   | 
||
| 
     #define C(x,y) ((x) | ((y) << 8)) 
   | 
||
| 
     	switch(C(req->bRequest, req->bmRequestType)) { 
   | 
||
| ... | ... | |
| 
      ret: 
   | 
||
| 
     	xfer->status = err; 
   | 
||
| 
     	crit_enter(); 
   | 
||
| 
     	hacksync(xfer);	/* XXX to compensate for usb_transfer_complete */ 
   | 
||
| 
     	usb_transfer_complete(xfer); 
   | 
||
| 
     	crit_exit(); 
   | 
||
| 
     	return (USBD_IN_PROGRESS); 
   | 
||
| ... | ... | |
| 
     ehci_alloc_sqh(ehci_softc_t *sc) 
   | 
||
| 
     { 
   | 
||
| 
     	ehci_soft_qh_t *sqh; 
   | 
||
| 
     	ehci_soft_qtd_t *sqtd; 
   | 
||
| 
     	usbd_status err; 
   | 
||
| 
     	int i, offs; 
   | 
||
| 
     	usb_dma_t dma; 
   | 
||
| ... | ... | |
| 
     			sc->sc_freeqhs = sqh; 
   | 
||
| 
     		} 
   | 
||
| 
     	} 
   | 
||
| 
     	/* Allocate the initial inactive sqtd. */ 
   | 
||
| 
     	sqtd = ehci_alloc_sqtd(sc); 
   | 
||
| 
     	if (sqtd == NULL) 
   | 
||
| 
     		return (NULL); 
   | 
||
| 
     	sqtd->qtd.qtd_status = htole32(0); 
   | 
||
| 
     	sqtd->qtd.qtd_next = EHCI_NULL; 
   | 
||
| 
     	sqtd->qtd.qtd_altnext = EHCI_NULL; 
   | 
||
| 
     	sqh = sc->sc_freeqhs; 
   | 
||
| 
     	sc->sc_freeqhs = sqh->next; 
   | 
||
| 
     	memset(&sqh->qh, 0, sizeof(ehci_qh_t)); 
   | 
||
| 
     	/* The overlay QTD should begin zeroed. */ 
   | 
||
| 
     	sqh->qh.qh_qtd.qtd_next = htole32(sqtd->physaddr); 
   | 
||
| 
     	sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL; 
   | 
||
| 
     	sqh->qh.qh_qtd.qtd_status = 0; 
   | 
||
| 
     	for (i = 0; i < EHCI_QTD_NBUFFERS; i++) { 
   | 
||
| 
     		sqh->qh.qh_qtd.qtd_buffer[i] = 0; 
   | 
||
| 
     		sqh->qh.qh_qtd.qtd_buffer_hi[i] = 0; 
   | 
||
| 
     	} 
   | 
||
| 
     	sqh->next = NULL; 
   | 
||
| 
     	sqh->prev = NULL; 
   | 
||
| 
     	sqh->sqtd = sqtd; 
   | 
||
| 
     	sqh->inactivesqtd = sqtd; 
   | 
||
| 
     	return (sqh); 
   | 
||
| 
     } 
   | 
||
| 
     void 
   | 
||
| 
     ehci_free_sqh(ehci_softc_t *sc, ehci_soft_qh_t *sqh) 
   | 
||
| 
     { 
   | 
||
| 
     	ehci_free_sqtd(sc, sqh->inactivesqtd); 
   | 
||
| 
     	sqh->next = sc->sc_freeqhs; 
   | 
||
| 
     	sc->sc_freeqhs = sqh; 
   | 
||
| 
     } 
   | 
||
| ... | ... | |
| 
     	crit_enter(); 
   | 
||
| 
     	sqtd = sc->sc_freeqtds; 
   | 
||
| 
     	sc->sc_freeqtds = sqtd->nextqtd; 
   | 
||
| 
     	memset(&sqtd->qtd, 0, sizeof(ehci_qtd_t)); 
   | 
||
| 
     	sqtd->qtd.qtd_next = EHCI_NULL; 
   | 
||
| 
     	sqtd->qtd.qtd_altnext = EHCI_NULL; 
   | 
||
| 
     	sqtd->qtd.qtd_status = 0; 
   | 
||
| 
     	for (i = 0; i < EHCI_QTD_NBUFFERS; i++) { 
   | 
||
| 
     		sqtd->qtd.qtd_buffer[i] = 0; 
   | 
||
| 
     		sqtd->qtd.qtd_buffer_hi[i] = 0; 
   | 
||
| 
     	} 
   | 
||
| 
     	sqtd->nextqtd = NULL; 
   | 
||
| 
     	sqtd->xfer = NULL; 
   | 
||
| 
     	crit_exit(); 
   | 
||
| ... | ... | |
| 
     usbd_status 
   | 
||
| 
     ehci_alloc_sqtd_chain(struct ehci_pipe *epipe, ehci_softc_t *sc, 
   | 
||
| 
     		     int alen, int rd, usbd_xfer_handle xfer, 
   | 
||
| 
     		     ehci_soft_qtd_t **sp, ehci_soft_qtd_t **ep) 
   | 
||
| 
          int alen, int rd, usbd_xfer_handle xfer, ehci_soft_qtd_t *start, 
   | 
||
| 
          ehci_soft_qtd_t *newinactive, ehci_soft_qtd_t **sp, ehci_soft_qtd_t **ep) 
   | 
||
| 
     { 
   | 
||
| 
     	ehci_soft_qtd_t *next, *cur; 
   | 
||
| 
     	ehci_physaddr_t dataphys, dataphyspage, dataphyslastpage, nextphys; 
   | 
||
| 
     	ehci_physaddr_t dataphys, nextphys; 
   | 
||
| 
     	u_int32_t qtdstatus; 
   | 
||
| 
     	int len, curlen, mps, offset; 
   | 
||
| 
     	int i, iscontrol; 
   | 
||
| 
     	usb_dma_t *dma = &xfer->dmabuf; 
   | 
||
| 
     	int adj, len, curlen, mps, offset, pagelen, seg, segoff; 
   | 
||
| 
     	int i, iscontrol, forceshort; 
   | 
||
| 
     	struct usb_dma_mapping *dma = &xfer->dmamap; 
   | 
||
| 
     	DPRINTFN(alen<4*4096,("ehci_alloc_sqtd_chain: start len=%d\n", alen)); 
   | 
||
| ... | ... | |
| 
     	len = alen; 
   | 
||
| 
     	iscontrol = (epipe->pipe.endpoint->edesc->bmAttributes & UE_XFERTYPE) == 
   | 
||
| 
     	    UE_CONTROL; 
   | 
||
| 
     	dataphys = DMAADDR(dma, 0); 
   | 
||
| 
     	dataphyslastpage = EHCI_PAGE(DMAADDR(dma, len - 1)); 
   | 
||
| 
     	qtdstatus = EHCI_QTD_ACTIVE | 
   | 
||
| 
     	    EHCI_QTD_SET_PID(rd ? EHCI_QTD_PID_IN : EHCI_QTD_PID_OUT) | 
   | 
||
| 
     	    EHCI_QTD_SET_CERR(3) 
   | 
||
| ... | ... | |
| 
     	    /* BYTES set below */ 
   | 
||
| 
     	    ; 
   | 
||
| 
     	mps = UGETW(epipe->pipe.endpoint->edesc->wMaxPacketSize); 
   | 
||
| 
     	forceshort = ((xfer->flags & USBD_FORCE_SHORT_XFER) || len == 0) && 
   | 
||
| 
     	    len % mps == 0; 
   | 
||
| 
     	/* 
   | 
||
| 
     	 * The control transfer data stage always starts with a toggle of 1. 
   | 
||
| 
     	 * For other transfers we let the hardware track the toggle state. 
   | 
||
| ... | ... | |
| 
     	if (iscontrol) 
   | 
||
| 
     		qtdstatus |= EHCI_QTD_SET_TOGGLE(1); 
   | 
||
| 
     	cur = ehci_alloc_sqtd(sc); 
   | 
||
| 
     	*sp = cur; 
   | 
||
| 
     	if (cur == NULL) 
   | 
||
| 
     		goto nomem; 
   | 
||
| 
     	for (;;) { 
   | 
||
| 
     		dataphyspage = EHCI_PAGE(dataphys); 
   | 
||
| 
     		/* XXX This is pretty broken: Because we do not allocate 
   | 
||
| 
     		 * a contiguous buffer (contiguous in physical pages) we 
   | 
||
| 
     		 * can only transfer one page in one go. 
   | 
||
| 
     		 * So check whether the start and end of the buffer are on 
   | 
||
| 
     		 * the same page. 
   | 
||
| 
     	if (start != NULL) { 
   | 
||
| 
     		/* 
   | 
||
| 
     		 * If we are given a starting qTD, assume it is linked into 
   | 
||
| 
     		 * an active QH so be careful not to mark it active. 
   | 
||
| 
     		 */ 
   | 
||
| 
     		if (dataphyspage == dataphyslastpage) { 
   | 
||
| 
     			curlen = len; 
   | 
||
| 
     		cur = start; 
   | 
||
| 
     		*sp = cur; 
   | 
||
| 
     		qtdstatus &= ~EHCI_QTD_ACTIVE; 
   | 
||
| 
     	} else { 
   | 
||
| 
     		cur = ehci_alloc_sqtd(sc); 
   | 
||
| 
     		*sp = cur; 
   | 
||
| 
     		if (cur == NULL) 
   | 
||
| 
     			goto nomem; 
   | 
||
| 
     	} 
   | 
||
| 
     	seg = 0; 
   | 
||
| 
     	segoff = 0; 
   | 
||
| 
     	for (;;) { 
   | 
||
| 
     		curlen = 0; 
   | 
||
| 
     		/* The EHCI hardware can handle at most 5 pages. */ 
   | 
||
| 
     		for (i = 0; i < EHCI_QTD_NBUFFERS && curlen < len; i++) { 
   | 
||
| 
     			KASSERT(seg < dma->nsegs, 
   | 
||
| 
     			    ("ehci_alloc_sqtd_chain: overrun")); 
   | 
||
| 
     			dataphys = dma->segs[seg].ds_addr + segoff; 
   | 
||
| 
     			pagelen = dma->segs[seg].ds_len - segoff; 
   | 
||
| 
     			if (pagelen > len - curlen) 
   | 
||
| 
     				pagelen = len - curlen; 
   | 
||
| 
     			if (pagelen > EHCI_PAGE_SIZE - 
   | 
||
| 
     			    EHCI_PAGE_OFFSET(dataphys)) 
   | 
||
| 
     				pagelen = EHCI_PAGE_SIZE - 
   | 
||
| 
     				    EHCI_PAGE_OFFSET(dataphys); 
   | 
||
| 
     			segoff += pagelen; 
   | 
||
| 
     			if (segoff >= dma->segs[seg].ds_len) { 
   | 
||
| 
     				KASSERT(segoff == dma->segs[seg].ds_len, 
   | 
||
| 
     				    ("ehci_alloc_sqtd_chain: overlap")); 
   | 
||
| 
     				seg++; 
   | 
||
| 
     				segoff = 0; 
   | 
||
| 
     			} 
   | 
||
| 
     			cur->qtd.qtd_buffer[i] = htole32(dataphys); 
   | 
||
| 
     			cur->qtd.qtd_buffer_hi[i] = 0; 
   | 
||
| 
     			curlen += pagelen; 
   | 
||
| 
     			/* 
   | 
||
| 
     			 * 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 + 
   | 
||
| 
     			    dma->segs[seg].ds_addr) != 0) 
   | 
||
| 
     				break; 
   | 
||
| 
     		} 
   | 
||
| 
     		else { 
   | 
||
| 
     			/* See comment above (XXX) */ 
   | 
||
| 
     			curlen = EHCI_PAGE_SIZE - 
   | 
||
| 
     				 EHCI_PAGE_MASK(dataphys); 
   | 
||
| 
     			/* the length must be a multiple of the max size */ 
   | 
||
| 
     			curlen -= curlen % mps; 
   | 
||
| 
     			DPRINTFN(1,("ehci_alloc_sqtd_chain: multiple QTDs, " 
   | 
||
| 
     				    "curlen=%d\n", curlen)); 
   | 
||
| 
     			KASSERT(curlen != 0, ("ehci_alloc_std: curlen == 0")); 
   | 
||
| 
     		} 
   | 
||
| 
     		DPRINTFN(4,("ehci_alloc_sqtd_chain: dataphys=0x%08x " 
   | 
||
| 
     			    "dataphyslastpage=0x%08x len=%d curlen=%d\n", 
   | 
||
| 
     			    dataphys, dataphyslastpage, 
   | 
||
| 
     			    len, curlen)); 
   | 
||
| 
     		/* Adjust down to a multiple of mps if not at the end. */ 
   | 
||
| 
     		if (curlen < len && curlen % mps != 0) { 
   | 
||
| 
     			adj = curlen % mps; 
   | 
||
| 
     			curlen -= adj; 
   | 
||
| 
     			KASSERT(curlen > 0, 
   | 
||
| 
     			    ("ehci_alloc_sqtd_chain: need to copy")); 
   | 
||
| 
     			segoff -= adj; 
   | 
||
| 
     			if (segoff < 0) { 
   | 
||
| 
     				seg--; 
   | 
||
| 
     				segoff += dma->segs[seg].ds_len; 
   | 
||
| 
     			} 
   | 
||
| 
     			KASSERT(seg >= 0 && segoff >= 0, 
   | 
||
| 
     			    ("ehci_alloc_sqtd_chain: adjust to mps")); 
   | 
||
| 
     		} 
   | 
||
| 
     		len -= curlen; 
   | 
||
| 
     		if (len != 0) { 
   | 
||
| 
     		if (len != 0 || forceshort) { 
   | 
||
| 
     			next = ehci_alloc_sqtd(sc); 
   | 
||
| 
     			if (next == NULL) 
   | 
||
| 
     				goto nomem; 
   | 
||
| ... | ... | |
| 
     			nextphys = EHCI_NULL; 
   | 
||
| 
     		} 
   | 
||
| 
     		for (i = 0; i * EHCI_PAGE_SIZE < curlen; i++) { 
   | 
||
| 
     			ehci_physaddr_t a = dataphys + i * EHCI_PAGE_SIZE; 
   | 
||
| 
     			if (i != 0) /* use offset only in first buffer */ 
   | 
||
| 
     				a = EHCI_PAGE(a); 
   | 
||
| 
     			cur->qtd.qtd_buffer[i] = htole32(a); 
   | 
||
| 
     			cur->qtd.qtd_buffer_hi[i] = 0; 
   | 
||
| 
     #ifdef DIAGNOSTIC 
   | 
||
| 
     			if (i >= EHCI_QTD_NBUFFERS) { 
   | 
||
| 
     				kprintf("ehci_alloc_sqtd_chain: i=%d\n", i); 
   | 
||
| 
     				goto nomem; 
   | 
||
| 
     			} 
   | 
||
| 
     #endif 
   | 
||
| 
     		} 
   | 
||
| 
     		cur->nextqtd = next; 
   | 
||
| 
     		cur->qtd.qtd_next = cur->qtd.qtd_altnext = nextphys; 
   | 
||
| 
     		cur->qtd.qtd_next = nextphys; 
   | 
||
| 
     		/* Make sure to stop after a short transfer. */ 
   | 
||
| 
     		cur->qtd.qtd_altnext = htole32(newinactive->physaddr); 
   | 
||
| 
     		cur->qtd.qtd_status = 
   | 
||
| 
     		    htole32(qtdstatus | EHCI_QTD_SET_BYTES(curlen)); 
   | 
||
| 
     		cur->xfer = xfer; 
   | 
||
| 
     		cur->len = curlen; 
   | 
||
| 
     		DPRINTFN(10,("ehci_alloc_sqtd_chain: cbp=0x%08x end=0x%08x\n", 
   | 
||
| 
     			    dataphys, dataphys + curlen)); 
   | 
||
| 
     		DPRINTFN(10,("ehci_alloc_sqtd_chain: curlen=%d\n", curlen)); 
   | 
||
| 
     		if (iscontrol) { 
   | 
||
| 
     			/* 
   | 
||
| 
     			 * adjust the toggle based on the number of packets 
   | 
||
| 
     			 * in this qtd 
   | 
||
| 
     			 */ 
   | 
||
| 
     			if (((curlen + mps - 1) / mps) & 1) 
   | 
||
| 
     			if ((((curlen + mps - 1) / mps) & 1) || curlen == 0) 
   | 
||
| 
     				qtdstatus ^= EHCI_QTD_TOGGLE_MASK; 
   | 
||
| 
     		} 
   | 
||
| 
     		if (len == 0) 
   | 
||
| 
     			break; 
   | 
||
| 
     		qtdstatus |= EHCI_QTD_ACTIVE; 
   | 
||
| 
     		if (len == 0) { 
   | 
||
| 
     			if (!forceshort) 
   | 
||
| 
     				break; 
   | 
||
| 
     			forceshort = 0; 
   | 
||
| 
     		} 
   | 
||
| 
     		DPRINTFN(10,("ehci_alloc_sqtd_chain: extend chain\n")); 
   | 
||
| 
     		offset += curlen; 
   | 
||
| 
     		dataphys = DMAADDR(dma, offset); 
   | 
||
| 
     		cur = next; 
   | 
||
| 
     	} 
   | 
||
| 
     	cur->qtd.qtd_status |= htole32(EHCI_QTD_IOC); 
   | 
||
| ... | ... | |
| 
     	return (USBD_NOMEM); 
   | 
||
| 
     } 
   | 
||
| 
     /* Free the chain starting at sqtd and end at the qTD before sqtdend */ 
   | 
||
| 
     static void 
   | 
||
| 
     ehci_free_sqtd_chain(ehci_softc_t *sc, ehci_soft_qtd_t *sqtd, 
   | 
||
| 
     		    ehci_soft_qtd_t *sqtdend) 
   | 
||
| 
     ehci_free_sqtd_chain(ehci_softc_t *sc, ehci_soft_qh_t *sqh, 
   | 
||
| 
         ehci_soft_qtd_t *sqtd, ehci_soft_qtd_t *sqtdend) 
   | 
||
| 
     { 
   | 
||
| 
     	ehci_soft_qtd_t *p; 
   | 
||
| 
     	ehci_soft_qtd_t *p, **prevp; 
   | 
||
| 
     	int i; 
   | 
||
| 
     	DPRINTFN(10,("ehci_free_sqtd_chain: sqtd=%p sqtdend=%p\n", 
   | 
||
| 
     		     sqtd, sqtdend)); 
   | 
||
| 
     	/* First unlink the chain from the QH's software qTD list. */ 
   | 
||
| 
     	prevp = &sqh->sqtd; 
   | 
||
| 
     	for (p = sqh->sqtd; p != NULL; p = p->nextqtd) { 
   | 
||
| 
     		if (p == sqtd) { 
   | 
||
| 
     			*prevp = sqtdend; 
   | 
||
| 
     			break; 
   | 
||
| 
     		} 
   | 
||
| 
     		prevp = &p->nextqtd; 
   | 
||
| 
     	} 
   | 
||
| 
     	KASSERT(p != NULL, ("ehci_free_sqtd_chain: chain not found")); 
   | 
||
| 
     	for (i = 0; sqtd != sqtdend; sqtd = p, i++) { 
   | 
||
| 
     		p = sqtd->nextqtd; 
   | 
||
| 
     		ehci_free_sqtd(sc, sqtd); 
   | 
||
| ... | ... | |
| 
      * have happened since the hardware runs concurrently. 
   | 
||
| 
      * If the transaction has already happened we rely on the ordinary 
   | 
||
| 
      * interrupt processing to process it. 
   | 
||
| 
      * XXX This is most probably wrong. 
   | 
||
| 
      */ 
   | 
||
| 
     void 
   | 
||
| 
     ehci_abort_xfer(usbd_xfer_handle xfer, usbd_status status) 
   | 
||
| ... | ... | |
| 
     	struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe; 
   | 
||
| 
     	ehci_softc_t *sc = (ehci_softc_t *)epipe->pipe.device->bus; 
   | 
||
| 
     	ehci_soft_qh_t *sqh = epipe->sqh; 
   | 
||
| 
     	ehci_soft_qtd_t *sqtd, *snext, **psqtd; 
   | 
||
| 
     	ehci_soft_qtd_t *sqtd, *snext; 
   | 
||
| 
     	ehci_physaddr_t cur, us, next; 
   | 
||
| 
     	int hit; 
   | 
||
| 
     	int hit, i; 
   | 
||
| 
     	/* int count = 0; */ 
   | 
||
| 
     	ehci_soft_qh_t *psqh; 
   | 
||
| ... | ... | |
| 
     	/* We will change them to point here */ 
   | 
||
| 
     	snext = exfer->sqtdend->nextqtd; 
   | 
||
| 
     	next = snext ? htole32(snext->physaddr) : EHCI_NULL; 
   | 
||
| 
     	next = htole32(snext->physaddr); 
   | 
||
| 
     	/* 
   | 
||
| 
     	 * Now loop through any qTDs before us and keep track of the pointer 
   | 
||
| 
     	 * that points to us for the end. 
   | 
||
| 
     	 */ 
   | 
||
| 
     	psqtd = &sqh->sqtd; 
   | 
||
| 
     	sqtd = sqh->sqtd; 
   | 
||
| 
     	while (sqtd && sqtd != exfer->sqtdstart) { 
   | 
||
| 
     		hit |= (cur == sqtd->physaddr); 
   | 
||
| ... | ... | |
| 
     			sqtd->qtd.qtd_next = next; 
   | 
||
| 
     		if (EHCI_LINK_ADDR(le32toh(sqtd->qtd.qtd_altnext)) == us) 
   | 
||
| 
     			sqtd->qtd.qtd_altnext = next; 
   | 
||
| 
     		psqtd = &sqtd->nextqtd; 
   | 
||
| 
     		sqtd = sqtd->nextqtd; 
   | 
||
| 
     	} 
   | 
||
| 
     		/* make the software pointer bypass us too */ 
   | 
||
| 
     	*psqtd = exfer->sqtdend->nextqtd; 
   | 
||
| 
     	/* 
   | 
||
| 
     	 * If we already saw the active one then we are pretty much done. 
   | 
||
| ... | ... | |
| 
     		 * (if there is one). We only need to do this if 
   | 
||
| 
     		 * it was previously pointing to us. 
   | 
||
| 
     		 */ 
   | 
||
| 
     		sqtd = exfer->sqtdstart; 
   | 
||
| 
     		for (sqtd = exfer->sqtdstart; ; sqtd = sqtd->nextqtd) { 
   | 
||
| 
     			if (cur == sqtd->physaddr) { 
   | 
||
| 
     				hit++; 
   | 
||
| ... | ... | |
| 
     		 * that we are removing. 
   | 
||
| 
     		 */ 
   | 
||
| 
     		if (hit) { 
   | 
||
| 
     			if (snext) { 
   | 
||
| 
     				ehci_set_qh_qtd(sqh, snext); 
   | 
||
| 
     			} else { 
   | 
||
| 
     				sqh->qh.qh_curqtd = 0; /* unlink qTDs */ 
   | 
||
| 
     				sqh->qh.qh_qtd.qtd_status &= 
   | 
||
| 
     				    htole32(EHCI_QTD_TOGGLE_MASK); 
   | 
||
| 
     				sqh->qh.qh_qtd.qtd_next = 
   | 
||
| 
     				    sqh->qh.qh_qtd.qtd_altnext 
   | 
||
| 
     				        = EHCI_NULL; 
   | 
||
| 
     				DPRINTFN(1,("ehci_abort_xfer: no hit\n")); 
   | 
||
| 
     			sqh->qh.qh_qtd.qtd_next = htole32(snext->physaddr); 
   | 
||
| 
     			sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL; 
   | 
||
| 
     			sqh->qh.qh_qtd.qtd_status &= 
   | 
||
| 
     			    htole32(EHCI_QTD_TOGGLE_MASK); 
   | 
||
| 
     			for (i = 0; i < EHCI_QTD_NBUFFERS; i++) { 
   | 
||
| 
     				sqh->qh.qh_qtd.qtd_buffer[i] = 0; 
   | 
||
| 
     				sqh->qh.qh_qtd.qtd_buffer_hi[i] = 0; 
   | 
||
| 
     			} 
   | 
||
| 
     		} 
   | 
||
| 
     	} 
   | 
||
| ... | ... | |
| 
     { 
   | 
||
| 
     	struct ehci_xfer *ex = EXFER(xfer); 
   | 
||
| 
     	ehci_softc_t *sc = (ehci_softc_t *)xfer->pipe->device->bus; 
   | 
||
| 
     	/*struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe;*/ 
   | 
||
| 
     	struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe; 
   | 
||
| 
     	DPRINTFN(10,("ehci_ctrl_done: xfer=%p\n", xfer)); 
   | 
||
| ... | ... | |
| 
     	if (xfer->status != USBD_NOMEM && ehci_active_intr_list(ex)) { 
   | 
||
| 
     		ehci_del_intr_list(ex);	/* remove from active list */ 
   | 
||
| 
     		ehci_free_sqtd_chain(sc, ex->sqtdstart, NULL); 
   | 
||
| 
     		ehci_free_sqtd_chain(sc, epipe->sqh, ex->sqtdstart, 
   | 
||
| 
     		    ex->sqtdend->nextqtd); 
   | 
||
| 
     	} 
   | 
||
| 
     	DPRINTFN(5, ("ehci_ctrl_done: length=%d\n", xfer->actlen)); 
   | 
||
| ... | ... | |
| 
     	usb_device_request_t *req = &xfer->request; 
   | 
||
| 
     	usbd_device_handle dev = epipe->pipe.device; 
   | 
||
| 
     	ehci_softc_t *sc = (ehci_softc_t *)dev->bus; 
   | 
||
| 
     	int addr = dev->address; 
   | 
||
| 
     	ehci_soft_qtd_t *setup, *stat, *next; 
   | 
||
| 
     	ehci_soft_qtd_t *newinactive, *setup, *stat, *next; 
   | 
||
| 
     	ehci_soft_qh_t *sqh; 
   | 
||
| 
     	int isread; 
   | 
||
| 
     	int len; 
   | 
||
| ... | ... | |
| 
     	DPRINTFN(3,("ehci_device_request: type=0x%02x, request=0x%02x, " 
   | 
||
| 
     		    "wValue=0x%04x, wIndex=0x%04x len=%d, addr=%d, endpt=%d\n", 
   | 
||
| 
     		    req->bmRequestType, req->bRequest, UGETW(req->wValue), 
   | 
||
| 
     		    UGETW(req->wIndex), len, addr, 
   | 
||
| 
     		    UGETW(req->wIndex), len, dev->address, 
   | 
||
| 
     		    epipe->pipe.endpoint->edesc->bEndpointAddress)); 
   | 
||
| 
     	setup = ehci_alloc_sqtd(sc); 
   | 
||
| 
     	if (setup == NULL) { 
   | 
||
| 
     	newinactive = ehci_alloc_sqtd(sc); 
   | 
||
| 
     	if (newinactive == NULL) { 
   | 
||
| 
     		err = USBD_NOMEM; 
   | 
||
| 
     		goto bad1; 
   | 
||
| 
     	} 
   | 
||
| 
     	newinactive->qtd.qtd_status = htole32(0); 
   | 
||
| 
     	newinactive->qtd.qtd_next = EHCI_NULL; 
   | 
||
| 
     	newinactive->qtd.qtd_altnext = EHCI_NULL; 
   | 
||
| 
     	stat = ehci_alloc_sqtd(sc); 
   | 
||
| 
     	if (stat == NULL) { 
   | 
||
| 
     		err = USBD_NOMEM; 
   | 
||
| ... | ... | |
| 
     	} 
   | 
||
| 
     	sqh = epipe->sqh; 
   | 
||
| 
     	setup = sqh->inactivesqtd; 
   | 
||
| 
     	sqh->inactivesqtd = newinactive; 
   | 
||
| 
     	epipe->u.ctl.length = len; 
   | 
||
| 
     	/* Update device address and length since they may have changed 
   | 
||
| 
     	   during the setup of the control pipe in usbd_new_device(). */ 
   | 
||
| 
     	/* XXX This only needs to be done once, but it's too early in open. */ 
   | 
||
| 
     	/* XXXX Should not touch ED here! */ 
   | 
||
| 
     	sqh->qh.qh_endp = 
   | 
||
| 
     	    (sqh->qh.qh_endp & htole32(~(EHCI_QH_ADDRMASK | EHCI_QH_MPLMASK))) | 
   | 
||
| 
     	    htole32( 
   | 
||
| 
     	     EHCI_QH_SET_ADDR(addr) | 
   | 
||
| 
     	     EHCI_QH_SET_MPL(UGETW(epipe->pipe.endpoint->edesc->wMaxPacketSize)) 
   | 
||
| 
     	    ); 
   | 
||
| 
     	/* Set up data transaction */ 
   | 
||
| 
     	if (len != 0) { 
   | 
||
| 
     		ehci_soft_qtd_t *end; 
   | 
||
| 
     		err = ehci_alloc_sqtd_chain(epipe, sc, len, isread, xfer, 
   | 
||
| 
     			  &next, &end); 
   | 
||
| 
     		    NULL, newinactive, &next, &end); 
   | 
||
| 
     		if (err) 
   | 
||
| 
     			goto bad3; 
   | 
||
| 
     		end->qtd.qtd_status &= htole32(~EHCI_QTD_IOC); 
   | 
||
| 
     		end->nextqtd = stat; 
   | 
||
| 
     		end->qtd.qtd_next = 
   | 
||
| 
     		end->qtd.qtd_altnext = htole32(stat->physaddr); 
   | 
||
| 
     		end->qtd.qtd_next = htole32(stat->physaddr); 
   | 
||
| 
     		end->qtd.qtd_altnext = htole32(newinactive->physaddr); 
   | 
||
| 
     	} else { 
   | 
||
| 
     		next = stat; 
   | 
||
| 
     	} 
   | 
||
| 
     	memcpy(KERNADDR(&epipe->u.ctl.reqdma, 0), req, sizeof *req); 
   | 
||
| 
     	/* Clear toggle */ 
   | 
||
| 
     	/* Clear toggle, and do not activate until complete */ 
   | 
||
| 
     	setup->qtd.qtd_status = htole32( 
   | 
||
| 
     	    EHCI_QTD_ACTIVE | 
   | 
||
| 
     	    EHCI_QTD_SET_PID(EHCI_QTD_PID_SETUP) | 
   | 
||
| 
     	    EHCI_QTD_SET_CERR(3) | 
   | 
||
| 
     	    EHCI_QTD_SET_TOGGLE(0) | 
   | 
||
| ... | ... | |
| 
     	setup->qtd.qtd_buffer[0] = htole32(DMAADDR(&epipe->u.ctl.reqdma, 0)); 
   | 
||
| 
     	setup->qtd.qtd_buffer_hi[0] = 0; 
   | 
||
| 
     	setup->nextqtd = next; 
   | 
||
| 
     	setup->qtd.qtd_next = setup->qtd.qtd_altnext = htole32(next->physaddr); 
   | 
||
| 
     	setup->qtd.qtd_next = htole32(next->physaddr); 
   | 
||
| 
     	setup->qtd.qtd_altnext = htole32(newinactive->physaddr); 
   | 
||
| 
     	setup->xfer = xfer; 
   | 
||
| 
     	setup->len = sizeof *req; 
   | 
||
| ... | ... | |
| 
     	    ); 
   | 
||
| 
     	stat->qtd.qtd_buffer[0] = 0; /* XXX not needed? */ 
   | 
||
| 
     	stat->qtd.qtd_buffer_hi[0] = 0; /* XXX not needed? */ 
   | 
||
| 
     	stat->nextqtd = NULL; 
   | 
||
| 
     	stat->qtd.qtd_next = stat->qtd.qtd_altnext = EHCI_NULL; 
   | 
||
| 
     	stat->nextqtd = newinactive; 
   | 
||
| 
     	stat->qtd.qtd_next = htole32(newinactive->physaddr); 
   | 
||
| 
     	stat->qtd.qtd_altnext = htole32(newinactive->physaddr); 
   | 
||
| 
     	stat->xfer = xfer; 
   | 
||
| 
     	stat->len = 0; 
   | 
||
| ... | ... | |
| 
     	exfer->isdone = 0; 
   | 
||
| 
     #endif 
   | 
||
| 
     	/* Insert qTD in QH list. */ 
   | 
||
| 
     	/* Activate the new qTD in the QH list. */ 
   | 
||
| 
     	crit_enter(); 
   | 
||
| 
     	ehci_set_qh_qtd(sqh, setup); 
   | 
||
| 
     	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); 
   | 
||
| ... | ... | |
| 
     	return (USBD_NORMAL_COMPLETION); 
   | 
||
| 
      bad3: 
   | 
||
| 
     	sqh->inactivesqtd = setup; 
   | 
||
| 
     	ehci_free_sqtd(sc, stat); 
   | 
||
| 
      bad2: 
   | 
||
| 
     	ehci_free_sqtd(sc, setup); 
   | 
||
| 
     	ehci_free_sqtd(sc, newinactive); 
   | 
||
| 
      bad1: 
   | 
||
| 
     	DPRINTFN(-1,("ehci_device_request: no memory\n")); 
   | 
||
| 
     	xfer->status = err; 
   | 
||
| ... | ... | |
| 
     	struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe; 
   | 
||
| 
     	usbd_device_handle dev = epipe->pipe.device; 
   | 
||
| 
     	ehci_softc_t *sc = (ehci_softc_t *)dev->bus; 
   | 
||
| 
     	ehci_soft_qtd_t *data, *dataend; 
   | 
||
| 
     	ehci_soft_qtd_t *data, *dataend, *newinactive; 
   | 
||
| 
     	ehci_soft_qh_t *sqh; 
   | 
||
| 
     	usbd_status err; 
   | 
||
| 
     	int len, isread, endpt; 
   | 
||
| ... | ... | |
| 
     	epipe->u.bulk.length = len; 
   | 
||
| 
     	err = ehci_alloc_sqtd_chain(epipe, sc, len, isread, xfer, &data, 
   | 
||
| 
     				   &dataend); 
   | 
||
| 
     	newinactive = ehci_alloc_sqtd(sc); 
   | 
||
| 
     	if (newinactive == NULL) { 
   | 
||
| 
     		DPRINTFN(-1,("ehci_device_bulk_start: no sqtd memory\n")); 
   | 
||
| 
     		err = USBD_NOMEM; 
   | 
||
| 
     		xfer->status = err; 
   | 
||
| 
     		usb_transfer_complete(xfer); 
   | 
||
| 
     		return (err); 
   | 
||
| 
     	} 
   | 
||
| 
     	newinactive->qtd.qtd_status = htole32(0); 
   | 
||
| 
     	newinactive->qtd.qtd_next = EHCI_NULL; 
   | 
||
| 
     	newinactive->qtd.qtd_altnext = EHCI_NULL; 
   | 
||
| 
     	err = ehci_alloc_sqtd_chain(epipe, sc, len, isread, xfer, 
   | 
||
| 
     	    sqh->inactivesqtd, newinactive, &data, &dataend); 
   | 
||
| 
     	if (err) { 
   | 
||
| 
     		DPRINTFN(-1,("ehci_device_bulk_start: no memory\n")); 
   | 
||
| 
     		ehci_free_sqtd(sc, newinactive); 
   | 
||
| 
     		xfer->status = err; 
   | 
||
| 
     		usb_transfer_complete(xfer); 
   | 
||
| 
     		return (err); 
   | 
||
| 
     	} 
   | 
||
| 
     	dataend->nextqtd = newinactive; 
   | 
||
| 
     	dataend->qtd.qtd_next = htole32(newinactive->physaddr); 
   | 
||
| 
     	dataend->qtd.qtd_altnext = htole32(newinactive->physaddr); 
   | 
||
| 
     	sqh->inactivesqtd = newinactive; 
   | 
||
| 
     #ifdef EHCI_DEBUG 
   | 
||
| 
     	if (ehcidebug > 5) { 
   | 
||
| ... | ... | |
| 
     #endif 
   | 
||
| 
     	crit_enter(); 
   | 
||
| 
     	ehci_set_qh_qtd(sqh, data); 
   | 
||
| 
     	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); 
   | 
||
| ... | ... | |
| 
     { 
   | 
||
| 
     	struct ehci_xfer *ex = EXFER(xfer); 
   | 
||
| 
     	ehci_softc_t *sc = (ehci_softc_t *)xfer->pipe->device->bus; 
   | 
||
| 
     	/*struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe;*/ 
   | 
||
| 
     	struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe; 
   | 
||
| 
     	DPRINTFN(10,("ehci_bulk_done: xfer=%p, actlen=%d\n", 
   | 
||
| 
     		     xfer, xfer->actlen)); 
   | 
||
| 
     	if (xfer->status != USBD_NOMEM && ehci_active_intr_list(ex)) { 
   | 
||
| 
     		ehci_del_intr_list(ex);	/* remove from active list */ 
   | 
||
| 
     		ehci_free_sqtd_chain(sc, ex->sqtdstart, NULL); 
   | 
||
| 
     		ehci_free_sqtd_chain(sc, epipe->sqh, ex->sqtdstart, 
   | 
||
| 
     		    ex->sqtdend->nextqtd); 
   | 
||
| 
     	} 
   | 
||
| 
     	DPRINTFN(5, ("ehci_bulk_done: length=%d\n", xfer->actlen)); 
   | 
||
| ... | ... | |
| 
     	struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe; 
   | 
||
| 
     	usbd_device_handle dev = xfer->pipe->device; 
   | 
||
| 
     	ehci_softc_t *sc = (ehci_softc_t *)dev->bus; 
   | 
||
| 
     	ehci_soft_qtd_t *data, *dataend; 
   | 
||
| 
     	ehci_soft_qtd_t *data, *dataend, *newinactive; 
   | 
||
| 
     	ehci_soft_qh_t *sqh; 
   | 
||
| 
     	usbd_status err; 
   | 
||
| 
     	int len, isread, endpt; 
   | 
||
| ... | ... | |
| 
     	epipe->u.intr.length = len; 
   | 
||
| 
     	err = ehci_alloc_sqtd_chain(epipe, sc, len, isread, xfer, &data, 
   | 
||
| 
     	    &dataend); 
   | 
||
| 
     	newinactive = ehci_alloc_sqtd(sc); 
   | 
||
| 
     	if (newinactive == NULL) { 
   | 
||
| 
     		DPRINTFN(-1,("ehci_device_intr_start: no sqtd memory\n")); 
   | 
||
| 
     		err = USBD_NOMEM; 
   | 
||
| 
     		xfer->status = err; 
   | 
||
| 
     		usb_transfer_complete(xfer); 
   | 
||
| 
     		return (err); 
   | 
||
| 
     	} 
   | 
||
| 
     	newinactive->qtd.qtd_status = htole32(0); 
   | 
||
| 
     	newinactive->qtd.qtd_next = EHCI_NULL; 
   | 
||
| 
     	newinactive->qtd.qtd_altnext = EHCI_NULL; 
   | 
||
| 
     	err = ehci_alloc_sqtd_chain(epipe, sc, len, isread, xfer, 
   | 
||
| 
     	    sqh->inactivesqtd, newinactive, &data, &dataend); 
   | 
||
| 
     	if (err) { 
   | 
||
| 
     		DPRINTFN(-1, ("ehci_device_intr_start: no memory\n")); 
   | 
||
| 
     		xfer->status = err; 
   | 
||
| 
     		usb_transfer_complete(xfer); 
   | 
||
| 
     		return (err); 
   | 
||
| 
     	} 
   | 
||
| 
     	dataend->nextqtd = newinactive; 
   | 
||
| 
     	dataend->qtd.qtd_next = htole32(newinactive->physaddr); 
   | 
||
| 
     	dataend->qtd.qtd_altnext = htole32(newinactive->physaddr); 
   | 
||
| 
     	sqh->inactivesqtd = newinactive; 
   | 
||
| 
     #ifdef EHCI_DEBUG 
   | 
||
| 
     	if (ehcidebug > 5) { 
   | 
||
| ... | ... | |
| 
     #endif 
   | 
||
| 
     	crit_enter(); 
   | 
||
| 
     	ehci_set_qh_qtd(sqh, data); 
   | 
||
| 
     	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); 
   | 
||
| ... | ... | |
| 
     	struct ehci_xfer *ex = EXFER(xfer); 
   | 
||
| 
     	ehci_softc_t *sc = (ehci_softc_t *)xfer->pipe->device->bus; 
   | 
||
| 
     	struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe; 
   | 
||
| 
     	ehci_soft_qtd_t *data, *dataend; 
   | 
||
| 
     	ehci_soft_qtd_t *data, *dataend, *newinactive; 
   | 
||
| 
     	ehci_soft_qh_t *sqh; 
   | 
||
| 
     	usbd_status err; 
   | 
||
| 
     	int len, isread, endpt; 
   | 
||
| ... | ... | |
| 
     	DPRINTFN(10, ("ehci_device_intr_done: xfer=%p, actlen=%d\n", 
   | 
||
| 
     	    xfer, xfer->actlen)); 
   | 
||
| 
     	sqh = epipe->sqh; 
   | 
||
| 
     	if (xfer->pipe->repeat) { 
   | 
||
| 
     		ehci_free_sqtd_chain(sc, ex->sqtdstart, NULL); 
   | 
||
| 
     		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; 
   | 
||
| 
     		isread = UE_GET_DIR(endpt) == UE_DIR_IN; 
   | 
||
| 
     		sqh = epipe->sqh; 
   | 
||
| 
     		newinactive = ehci_alloc_sqtd(sc); 
   | 
||
| 
     		if (newinactive == NULL) { 
   | 
||
| 
     			DPRINTFN(-1, 
   | 
||
| 
     			    ("ehci_device_intr_done: no sqtd memory\n")); 
   | 
||
| 
     			err = USBD_NOMEM; 
   | 
||
| 
     			xfer->status = err; 
   | 
||
| 
     			return; 
   | 
||
| 
     		} 
   | 
||
| 
     		newinactive->qtd.qtd_status = htole32(0); 
   | 
||
| 
     		newinactive->qtd.qtd_next = EHCI_NULL; 
   | 
||
| 
     		newinactive->qtd.qtd_altnext = EHCI_NULL; 
   | 
||
| 
     		err = ehci_alloc_sqtd_chain(epipe, sc, len, isread, xfer, 
   | 
||
| 
     		    &data, &dataend); 
   | 
||
| 
     		    sqh->inactivesqtd, newinactive, &data, &dataend); 
   | 
||
| 
     		if (err) { 
   | 
||
| 
     			DPRINTFN(-1, ("ehci_device_intr_done: no memory\n")); 
   | 
||
| 
     			xfer->status = err; 
   | 
||
| 
     			return; 
   | 
||
| 
     		} 
   | 
||
| 
     		dataend->nextqtd = newinactive; 
   | 
||
| 
     		dataend->qtd.qtd_next = htole32(newinactive->physaddr); 
   | 
||
| 
     		dataend->qtd.qtd_altnext = htole32(newinactive->physaddr); 
   | 
||
| 
     		sqh->inactivesqtd = newinactive; 
   | 
||
| 
     		/* Set up interrupt info. */ 
   | 
||
| 
     		exfer->sqtdstart = data; 
   | 
||
| ... | ... | |
| 
     #endif 
   | 
||
| 
     		crit_enter(); 
   | 
||
| 
     		ehci_set_qh_qtd(sqh, data); 
   | 
||
| 
     		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); 
   | 
||
| ... | ... | |
| 
     		xfer->status = USBD_IN_PROGRESS; 
   | 
||
| 
     	} else if (xfer->status != USBD_NOMEM && ehci_active_intr_list(ex)) { 
   | 
||
| 
     		ehci_del_intr_list(ex); /* remove from active list */ 
   | 
||
| 
     		ehci_free_sqtd_chain(sc, ex->sqtdstart, NULL); 
   | 
||
| 
     		ehci_free_sqtd_chain(sc, sqh, ex->sqtdstart, 
   | 
||
| 
     		    ex->sqtdend->nextqtd); 
   | 
||
| 
     	} 
   | 
||
| 
     #undef exfer 
   | 
||
| 
     } 
   | 
||
| 
     /************************/ 
   | 
||
| 
     static usbd_status 
   | 
||
| 
     ehci_device_isoc_transfer(usbd_xfer_handle xfer) 
   | 
||
| 
     { 
   | 
||
| 
     	return USBD_IOERROR; 
   | 
||
| 
     } 
   | 
||
| 
     static usbd_status 
   | 
||
| 
     ehci_device_isoc_start(usbd_xfer_handle xfer) 
   | 
||
| 
     { 
   | 
||
| 
     	return USBD_IOERROR; 
   | 
||
| 
     } 
   | 
||
| 
     static void 
   | 
||
| 
     ehci_device_isoc_abort(usbd_xfer_handle xfer) 
   | 
||
| 
     { 
   | 
||
| 
     } 
   | 
||
| 
     static void 
   | 
||
| 
     ehci_device_isoc_close(usbd_pipe_handle pipe) 
   | 
||
| 
     { 
   | 
||
| 
     } 
   | 
||
| 
     static void 
   | 
||
| 
     ehci_device_isoc_done(usbd_xfer_handle xfer) 
   | 
||
| 
     { 
   | 
||
| 
     } 
   | 
||
| 
     static usbd_status	ehci_device_isoc_transfer(usbd_xfer_handle xfer) { return USBD_IOERROR; } 
   | 
||
| 
     static usbd_status	ehci_device_isoc_start(usbd_xfer_handle xfer) { return USBD_IOERROR; } 
   | 
||
| 
     static void		ehci_device_isoc_abort(usbd_xfer_handle xfer) { } 
   | 
||
| 
     static void		ehci_device_isoc_close(usbd_pipe_handle pipe) { } 
   | 
||
| 
     static void		ehci_device_isoc_done(usbd_xfer_handle xfer) { } 
   | 
||
| ehci_pci.c 19 May 2008 10:32:14 -0000 | ||
|---|---|---|
| 
     static const char *ehci_device_m5239 = "ALi M5239 USB 2.0 controller"; 
   | 
||
| 
     /* AMD */ 
   | 
||
| 
     #define PCI_EHCI_DEVICEID_8111		0x74631022 
   | 
||
| 
     #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"; 
   | 
||
| ... | ... | |
| 
     #define PCI_EHCI_DEVICEID_6300		0x25ad8086 
   | 
||
| 
     static const char *ehci_device_6300 = "Intel 6300ESB USB 2.0 controller"; 
   | 
||
| 
     #define PCI_EHCI_DEVICEID_ICH4		0x24cd8086 
   | 
||
| 
     static const char *ehci_device_ich4 = "Intel 82801DB/L/M USB 2.0 controller"; 
   | 
||
| 
     static const char *ehci_device_ich4 = "Intel 82801DB/L/M (ICH4) USB 2.0 controller"; 
   | 
||
| 
     #define PCI_EHCI_DEVICEID_ICH5		0x24dd8086 
   | 
||
| 
     static const char *ehci_device_ich5 = "Intel 82801EB/R USB 2.0 controller"; 
   | 
||
| 
     static const char *ehci_device_ich5 = "Intel 82801EB/R (ICH5) USB 2.0 controller"; 
   | 
||
| 
     #define PCI_EHCI_DEVICEID_ICH6		0x265c8086 
   | 
||
| 
     static const char *ehci_device_ich6 = "Intel 82801FB USB 2.0 controller"; 
   | 
||
| 
     static const char *ehci_device_ich6 = "Intel 82801FB (ICH6) USB 2.0 controller"; 
   | 
||
| 
     #define PCI_EHCI_DEVICEID_ICH7		0x27cc8086 
   | 
||
| 
     static const char *ehci_device_ich7 = "Intel 82801GB/R USB 2.0 controller"; 
   | 
||
| 
     static const char *ehci_device_ich7 = "Intel 82801GB/R (ICH7) USB 2.0 controller"; 
   | 
||
| 
     #define PCI_EHCI_DEVICEID_ICH8_A	0x28368086 
   | 
||
| 
     static const char *ehci_device_ich8_a = "Intel 82801H (ICH8) USB 2.0 controller USB2-A"; 
   | 
||
| 
     #define PCI_EHCI_DEVICEID_ICH8_B	0x283a8086 
   | 
||
| 
     static const char *ehci_device_ich8_b = "Intel 82801H (ICH8) USB 2.0 controller USB2-B"; 
   | 
||
| 
     #define	PCI_EHCI_DEVICEID_ICH9_A	0x293a8086 
   | 
||
| 
     #define	PCI_EHCI_DEVICEID_ICH9_B	0x293c8086 
   | 
||
| 
     static const char *ehci_device_ich9 = "Intel 82801I (ICH9) USB 2.0 controller"; 
   | 
||
| 
     #define PCI_EHCI_DEVICEID_63XX		0x268c8086 
   | 
||
| 
     static const char *ehci_device_63XX = "Intel 63XXESB USB 2.0 controller"; 
   | 
||
| 
     | 
||
| 
     /* NEC */ 
   | 
||
| 
     #define PCI_EHCI_DEVICEID_NEC		0x00e01033 
   | 
||
| ... | ... | |
| 
     #define DPRINTF(x) 
   | 
||
| 
     #endif 
   | 
||
| 
     static int ehci_pci_attach(device_t self); 
   | 
||
| 
     static int ehci_pci_detach(device_t self); 
   | 
||
| 
     static int ehci_pci_shutdown(device_t self); 
   | 
||
| 
     static int ehci_pci_suspend(device_t self); 
   | 
||
| 
     static int ehci_pci_resume(device_t self); 
   | 
||
| 
     static device_attach_t ehci_pci_attach; 
   | 
||
| 
     static device_detach_t ehci_pci_detach; 
   | 
||
| 
     static device_shutdown_t ehci_pci_shutdown; 
   | 
||
| 
     static device_suspend_t ehci_pci_suspend; 
   | 
||
| 
     static device_resume_t ehci_pci_resume; 
   | 
||
| 
     static void ehci_pci_givecontroller(device_t self); 
   | 
||
| 
     static void ehci_pci_takecontroller(device_t self); 
   | 
||
| ... | ... | |
| 
     		return (ehci_device_sb400); 
   | 
||
| 
     	case PCI_EHCI_DEVICEID_6300: 
   | 
||
| 
     		return (ehci_device_6300); 
   | 
||
| 
     	case PCI_EHCI_DEVICEID_63XX: 
   | 
||
| 
     		return (ehci_device_63XX); 
   | 
||
| 
     	case PCI_EHCI_DEVICEID_ICH4: 
   | 
||
| 
     		return (ehci_device_ich4); 
   | 
||
| 
     	case PCI_EHCI_DEVICEID_ICH5: 
   | 
||
| ... | ... | |
| 
     		return (ehci_device_ich6); 
   | 
||
| 
     	case PCI_EHCI_DEVICEID_ICH7: 
   | 
||
| 
     		return (ehci_device_ich7); 
   | 
||
| 
     	case PCI_EHCI_DEVICEID_ICH8_A: 
   | 
||
| 
     		return (ehci_device_ich8_a); 
   | 
||
| 
     	case PCI_EHCI_DEVICEID_ICH8_B: 
   | 
||
| 
     		return (ehci_device_ich8_b); 
   | 
||
| 
     	case PCI_EHCI_DEVICEID_ICH9_A: 
   | 
||
| 
     	case PCI_EHCI_DEVICEID_ICH9_B: 
   | 
||
| 
     		return (ehci_device_ich9); 
   | 
||
| 
     	case PCI_EHCI_DEVICEID_NEC: 
   | 
||
| 
     		return (ehci_device_nec); 
   | 
||
| 
     	case PCI_EHCI_DEVICEID_NF2: 
   | 
||
| ... | ... | |
| 
     	if (desc) { 
   | 
||
| 
     		device_set_desc(self, desc); 
   | 
||
| 
     		device_set_async_attach(self, TRUE); 
   | 
||
| 
     		return 0; 
   | 
||
| 
     		return BUS_PROBE_DEFAULT; 
   | 
||
| 
     	} else { 
   | 
||
| 
     		return ENXIO; 
   | 
||
| 
     	} 
   | 
||
| ... | ... | |
| 
     ehci_pci_attach(device_t self) 
   | 
||
| 
     { 
   | 
||
| 
     	ehci_softc_t *sc = device_get_softc(self); 
   | 
||
| 
     	devclass_t dc; 
   | 
||
| 
     	device_t parent; 
   | 
||
| 
     	device_t *neighbors; 
   | 
||
| 
     	device_t *nbus; 
   | 
||
| ... | ... | |
| 
     	case PCI_USBREV_1_0: 
   | 
||
| 
     	case PCI_USBREV_1_1: 
   | 
||
| 
     		sc->sc_bus.usbrev = USBREV_UNKNOWN; 
   | 
||
| 
     		kprintf("pre-2.0 USB rev\n"); 
   | 
||
| 
     		device_printf(self, "pre-2.0 USB rev\n"); 
   | 
||
| 
     		return ENXIO; 
   | 
||
| 
     	case PCI_USBREV_2_0: 
   | 
||
| 
     		sc->sc_bus.usbrev = USBREV_2_0; 
   | 
||
| ... | ... | |
| 
     		return ENXIO; 
   | 
||
| 
     	} 
   | 
||
| 
     	ncomp = 0; 
   | 
||
| 
     	dc = devclass_find("usb"); 
   | 
||
| 
     	slot = pci_get_slot(self); 
   | 
||
| 
     	function = pci_get_function(self); 
   | 
||
| 
     	for (i = 0; i < count; i++) { 
   | 
||
| ... | ... | |
| 
     			pci_get_function(neighbors[i]) < function) { 
   | 
||
| 
     			res = device_get_children(neighbors[i], 
   | 
||
| 
     				&nbus, &buscount); 
   | 
||
| 
     			if (res != 0 || buscount != 1) 
   | 
||
| 
     			if (res != 0) 
   | 
||
| 
     				continue; 
   | 
||
| 
     			bsc = device_get_softc(nbus[0]); 
   | 
||
| 
     			if (bsc == NULL || bsc->bdev == NULL) 
   | 
||
| 
     			if (buscount != 1) { 
   | 
||
| 
     				kfree(nbus, M_TEMP); 
   | 
||
| 
     				continue; 
   | 
||
| 
     			} 
   | 
||
| 
     			if (device_get_devclass(nbus[0]) != dc) { 
   | 
||
| 
     				kfree(nbus, M_TEMP); 
   | 
||
| 
     				continue; 
   | 
||
| 
     			} 
   | 
||
| 
     			bsc = device_get_softc(nbus[0]); 
   | 
||
| 
     			kfree(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, 
   | 
||
| 
     	    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); 
   | 
||
| 
     	if (err) { 
   | 
||
| 
     		device_printf(self, "Could not allocate parent DMA tag (%d)\n", 
   | 
||
| 
     		    err); 
   | 
||
| 
     		ehci_pci_detach(self); 
   | 
||
| 
     		return ENXIO; 
   | 
||
| 
     	} 
   | 
||
| 
     	/* Allocate a dma tag for transfer buffers */ 
   | 
||
| 
     	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); 
   | 
||
| 
     	if (err) { 
   | 
||
| 
     		device_printf(self, "Could not allocate buffer DMA tag (%d)\n", 
   | 
||
| 
     		    err); 
   | 
||
| 
     		ehci_pci_detach(self); 
   | 
||
| 
     		return ENXIO; 
   | 
||
| 
     	} 
   | 
||
| 
     	ehci_pci_takecontroller(self); 
   | 
||
| 
     	err = ehci_init(sc); 
   | 
||
| 
     	if (!err) { 
   | 
||
| ... | ... | |
| 
     	 */ 
   | 
||
| 
     	if (sc->iot && sc->ioh) 
   | 
||
| 
     		bus_space_write_4(sc->iot, sc->ioh, EHCI_USBINTR, 0); 
   | 
||
| 
     	if (sc->sc_bus.parent_dmatag != NULL) 
   | 
||
| 
     		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); 
   | 
||
| ... | ... | |
| 
     		if (EHCI_EECP_ID(eec) != EHCI_EC_LEGSUP) 
   | 
||
| 
     			continue; 
   | 
||
| 
     		legsup = eec; 
   | 
||
| 
     		pci_write_config(self, eecp, legsup | EHCI_LEGSUP_OSOWNED, 4); 
   | 
||
| 
     		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", 
   | 
||
| 
     			    device_get_nameunit(sc->sc_bus.bdev)); 
   | 
||
| 
     			for (i = 0; i < 5000; i++) { 
   | 
||
| ... | ... | |
| 
     static void 
   | 
||
| 
     ehci_pci_givecontroller(device_t self) 
   | 
||
| 
     { 
   | 
||
| 
     #if 0 
   | 
||
| 
     	ehci_softc_t *sc = device_get_softc(self); 
   | 
||
| 
     	u_int32_t cparams, eec, legsup; 
   | 
||
| 
     	int eecp; 
   | 
||
| ... | ... | |
| 
     		legsup = eec; 
   | 
||
| 
     		pci_write_config(self, eecp, legsup & ~EHCI_LEGSUP_OSOWNED, 4); 
   | 
||
| 
     	} 
   | 
||
| 
     #endif 
   | 
||
| 
     } 
   | 
||
| 
     static device_method_t ehci_methods[] = { 
   | 
||
| ehcivar.h 19 May 2008 10:17:44 -0000 | ||
|---|---|---|
| 
     	struct ehci_soft_qh *next; 
   | 
||
| 
     	struct ehci_soft_qh *prev; 
   | 
||
| 
     	struct ehci_soft_qtd *sqtd; 
   | 
||
| 
     	struct ehci_soft_qtd *inactivesqtd; 
   | 
||
| 
     	ehci_physaddr_t physaddr; 
   | 
||
| 
     	int islot;		/* Interrupt list slot. */ 
   | 
||
| 
     } ehci_soft_qh_t; 
   | 
||
| ... | ... | |
| 
     #define EXFER(xfer) ((struct ehci_xfer *)(xfer)) 
   | 
||
| 
     /* Information about an entry in the interrupt list. */ 
   | 
||
| 
     /* 
   | 
||
| 
      * Information about an entry in the interrupt list. 
   | 
||
| 
      */ 
   | 
||
| 
     struct ehci_soft_islot { 
   | 
||
| 
     	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_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) \ 
   | 
||
| hid.c 18 May 2008 17:51:14 -0000 | ||
|---|---|---|
| 
     { 
   | 
||
| 
     	struct hid_data *s; 
   | 
||
| 
     	s = kmalloc(sizeof *s, M_TEMP, M_INTWAIT|M_ZERO); 
   | 
||
| 
     	s = kmalloc(sizeof *s, M_TEMP, M_WAITOK|M_ZERO); 
   | 
||
| 
     	s->start = s->p = d; 
   | 
||
| 
     	s->end = (char *)d + len; 
   | 
||
| 
     	s->kindset = kindset; 
   | 
||
| ... | ... | |
| 
     				c->loc.count = dval; 
   | 
||
| 
     				break; 
   | 
||
| 
     			case 10: /* Push */ 
   | 
||
| 
     				hi = kmalloc(sizeof *hi, M_TEMP, M_INTWAIT); 
   | 
||
| 
     				hi = kmalloc(sizeof *hi, M_TEMP, M_WAITOK); 
   | 
||
| 
     				*hi = s->cur; 
   | 
||
| 
     				c->next = hi; 
   | 
||
| 
     				break; 
   | 
||
| ohci.c 19 May 2008 01:15:42 -0000 | ||
|---|---|---|
| 
     static usbd_status	ohci_device_setintr(ohci_softc_t *sc, 
   | 
||
| 
     			    struct ohci_pipe *pipe, int ival); 
   | 
||
| 
     static usbd_status	ohci_device_intr_insert(ohci_softc_t *sc, 
   | 
||
| 
     			    usbd_xfer_handle xfer); 
   | 
||
| 
     static int		ohci_str(usb_string_descriptor_t *, int, const char *); 
   | 
||
| ... | ... | |
| 
     		     int alen, int rd, usbd_xfer_handle xfer, 
   | 
||
| 
     		     ohci_soft_td_t *sp, ohci_soft_td_t **ep) 
   | 
||
| 
     { 
   | 
||
| 
     	ohci_soft_td_t *next, *cur; 
   | 
||
| 
     	ohci_physaddr_t dataphys; 
   | 
||
| 
     	ohci_soft_td_t *next, *cur, *end; 
   | 
||
| 
     	ohci_physaddr_t dataphys, physend; 
   | 
||
| 
     	u_int32_t tdflags; 
   | 
||
| 
     	int offset = 0; 
   | 
||
| 
     	int len, curlen; 
   | 
||
| 
     	usb_dma_t *dma = &xfer->dmabuf; 
   | 
||
| 
     	int len, maxp, curlen, curlen2, seg, segoff; 
   | 
||
| 
     	struct usb_dma_mapping *dma = &xfer->dmamap; 
   | 
||
| 
     	u_int16_t flags = xfer->flags; 
   | 
||
| 
     	DPRINTFN(alen < 4096,("ohci_alloc_std_chain: start len=%d\n", alen)); 
   | 
||
| 
     	len = alen; 
   | 
||
| 
     	cur = sp; 
   | 
||
| 
     	end = NULL; 
   | 
||
| 
     	maxp = UGETW(opipe->pipe.endpoint->edesc->wMaxPacketSize); 
   | 
||
| 
     	tdflags = htole32( 
   | 
||
| 
     	    (rd ? OHCI_TD_IN : OHCI_TD_OUT) | 
   | 
||
| 
     	    (flags & USBD_SHORT_XFER_OK ? OHCI_TD_R : 0) | 
   | 
||
| 
     	    OHCI_TD_NOCC | OHCI_TD_TOGGLE_CARRY | OHCI_TD_SET_DI(6)); 
   | 
||
| 
     	for (;;) { 
   | 
||
| 
     	seg = 0; 
   | 
||
| 
     	segoff = 0; 
   | 
||
| 
     	while (len > 0) { 
   | 
||
| 
     		next = ohci_alloc_std(sc); 
   | 
||
| 
     		if (next == NULL) 
   | 
||
| 
     			goto nomem; 
   | 
||
| 
     		dataphys = DMAADDR(dma, offset); 
   | 
||
| 
     		/* 
   | 
||
| 
     		 * The OHCI hardware can handle at most one 4k crossing. 
   | 
||
| 
     		 * XXX - currently we only allocate contigous buffers, but 
   | 
||
| 
     		 * the OHCI spec says: If during the data transfer the buffer 
   | 
||
| 
     		 * The OHCI spec says: If during the data transfer the buffer 
   | 
||
| 
     		 * address contained in the HC's working copy of 
   | 
||
| 
     		 * CurrentBufferPointer crosses a 4K boundary, the upper 20 
   | 
||
| 
     		 * bits of Buffer End are copied to the working value of 
   | 
||
| ... | ... | |
| 
     		 * each TD except the last one must cover an exact multiple 
   | 
||
| 
     		 * of the maximal packet length. 
   | 
||
| 
     		 */ 
   | 
||
| 
     		if (OHCI_PAGE_OFFSET(dataphys) + len <= (2 * OHCI_PAGE_SIZE)) { 
   | 
||
| 
     			/* We can handle all that remains in this TD */ 
   | 
||
| 
     		KASSERT(seg < dma->nsegs, ("ohci_alloc_std_chain: overrun")); 
   | 
||
| 
     		dataphys = dma->segs[seg].ds_addr + segoff; 
   | 
||
| 
     		curlen = dma->segs[seg].ds_len - segoff; 
   | 
||
| 
     		if (curlen > len) 
   | 
||
| 
     			curlen = len; 
   | 
||
| 
     		} else { 
   | 
||
| 
     			/* must use multiple TDs, fill as much as possible. */ 
   | 
||
| 
     		physend = dataphys + curlen - 1; 
   | 
||
| 
     		if (OHCI_PAGE(dataphys) != OHCI_PAGE(physend)) { 
   | 
||
| 
     			/* Truncate to two OHCI pages if there are more. */ 
   | 
||
| 
     			if (curlen > 2 * OHCI_PAGE_SIZE - 
   | 
||
| 
     			    OHCI_PAGE_OFFSET(dataphys)) 
   | 
||
| 
     			curlen = 2 * OHCI_PAGE_SIZE - 
   | 
||
| 
     				 OHCI_PAGE_OFFSET(dataphys); 
   | 
||
| 
     			/* the length must be a multiple of the max size */ 
   | 
||
| 
     			curlen -= curlen % 
   | 
||
| 
     			    UGETW(opipe->pipe.endpoint->edesc->wMaxPacketSize); 
   | 
||
| 
     			KASSERT((curlen != 0), ("ohci_alloc_std: curlen == 0")); 
   | 
||