ohci.c

来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 2,245 行 · 第 1/4 页

C
2,245
字号
	printf("               port1=0x%08x port2=0x%08x\n",	       OREAD4(sc, OHCI_RH_PORT_STATUS(1)),	       OREAD4(sc, OHCI_RH_PORT_STATUS(2)));	printf("         HCCA: frame_number=0x%04x done_head=0x%08x\n",	       LE(sc->sc_hcca->hcca_frame_number),	       LE(sc->sc_hcca->hcca_done_head));}#endifintohci_intr(p)	void *p;{	ohci_softc_t *sc = p;	u_int32_t intrs, eintrs;	ohci_physaddr_t done;	/* In case the interrupt occurs before initialization has completed. */	if (sc == NULL || sc->sc_hcca == NULL) {	/* NWH added sc==0 */#ifdef DIAGNOSTIC		printf("ohci_intr: sc->sc_hcca == NULL\n");#endif		return (0);	}	intrs = 0;	done = LE(sc->sc_hcca->hcca_done_head);	if (done != 0) {		sc->sc_hcca->hcca_done_head = 0;		if (done & ~OHCI_DONE_INTRS)			intrs = OHCI_WDH;		if (done & OHCI_DONE_INTRS)			intrs |= OREAD4(sc, OHCI_INTERRUPT_STATUS);	} else		intrs = OREAD4(sc, OHCI_INTERRUPT_STATUS);	if (!intrs)		return (0);	intrs &= ~OHCI_MIE;	OWRITE4(sc, OHCI_INTERRUPT_STATUS, intrs); /* Acknowledge */	eintrs = intrs & sc->sc_eintrs;	if (!eintrs)		return (0);	sc->sc_intrs++;	DPRINTFN(7, ("ohci_intr: sc=%p intrs=%x(%x) eintr=%x\n", 		     sc, (u_int)intrs, OREAD4(sc, OHCI_INTERRUPT_STATUS),		     (u_int)eintrs));	if (eintrs & OHCI_SO) {		printf("%s: scheduling overrun\n",USBDEVNAME(sc->sc_bus.bdev));		/* XXX do what */		intrs &= ~OHCI_SO;	}	if (eintrs & OHCI_WDH) {		ohci_process_done(sc, done &~ OHCI_DONE_INTRS);		intrs &= ~OHCI_WDH;	}	if (eintrs & OHCI_RD) {		/* XXX process resume detect */	}	if (eintrs & OHCI_UE) {		printf("%s: unrecoverable error, controller halted\n",		       USBDEVNAME(sc->sc_bus.bdev));		OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET);		/* XXX what else */	}	if (eintrs & OHCI_RHSC) {		ohci_rhsc(sc, sc->sc_intrreqh);		intrs &= ~OHCI_RHSC;		/* 		 * Disable RHSC interrupt for now, because it will be		 * on until the port has been reset.		 */		ohci_rhsc_able(sc, 0);	}	/* Block unprocessed interrupts. XXX */	OWRITE4(sc, OHCI_INTERRUPT_DISABLE, intrs);	sc->sc_eintrs &= ~intrs;	return (1);}voidohci_rhsc_able(sc, on)	ohci_softc_t *sc;	int on;{	DPRINTFN(4, ("ohci_rhsc_able: on=%d\n", on));	if (on) {		sc->sc_eintrs |= OHCI_RHSC;		OWRITE4(sc, OHCI_INTERRUPT_ENABLE, OHCI_RHSC);	} else {		sc->sc_eintrs &= ~OHCI_RHSC;		OWRITE4(sc, OHCI_INTERRUPT_DISABLE, OHCI_RHSC);	}}#ifdef OHCI_DEBUGchar *ohci_cc_strs[] = {	"NO_ERROR",	"CRC",	"BIT_STUFFING",	"DATA_TOGGLE_MISMATCH",	"STALL",	"DEVICE_NOT_RESPONDING",	"PID_CHECK_FAILURE",	"UNEXPECTED_PID",	"DATA_OVERRUN",	"DATA_UNDERRUN",	"BUFFER_OVERRUN",	"BUFFER_UNDERRUN",	"NOT_ACCESSED",};#endifvoidohci_process_done(sc, done)	ohci_softc_t *sc;	ohci_physaddr_t done;{	ohci_soft_td_t *std, *sdone;	usbd_request_handle reqh;	int len, cc;	DPRINTFN(10,("ohci_process_done: done=0x%08lx\n", (u_long)done));	/* Reverse the done list. */	for (sdone = 0; done; done = LE(std->td->td_nexttd)) {		std = ohci_hash_find_td(sc, done);		std->dnext = sdone;		sdone = std;	}#ifdef OHCI_DEBUG	if (ohcidebug > 11) {		printf("ohci_process_done: TD done:\n");		ohci_dump_tds(sdone);	}#endif	for (std = sdone; std; std = std->dnext) {		reqh = std->reqh;		DPRINTFN(10, ("ohci_process_done: std=%p reqh=%p hcpriv=%p\n",				std, reqh, reqh->hcpriv));		cc = OHCI_TD_GET_CC(LE(std->td->td_flags));		if (cc == OHCI_CC_NO_ERROR) {			if (std->td->td_cbp == 0)				len = std->len;			else				len = LE(std->td->td_be) - 				      LE(std->td->td_cbp) + 1;			/* 			 * Only do a callback on the last stage of a transfer.			 * Others have hcpriv = 0.			 */			if ((reqh->pipe->endpoint->edesc->bmAttributes & 			     UE_XFERTYPE) == UE_CONTROL) {				/* For a control transfer the length is in				 * the xfer stage */				if (reqh->hcpriv == std) {					reqh->status = USBD_NORMAL_COMPLETION;					ohci_ii_done(sc, reqh);				} else					reqh->actlen = len;			} else {				if (reqh->hcpriv == std) {					reqh->actlen = len;					reqh->status = USBD_NORMAL_COMPLETION;					ohci_ii_done(sc, reqh);				}			}		} else {			ohci_soft_td_t *p, *n;			struct ohci_pipe *opipe = 				(struct ohci_pipe *)reqh->pipe;			DPRINTFN(-1,("ohci_process_done: error cc=%d (%s)\n",			 OHCI_TD_GET_CC(LE(std->td->td_flags)),			 ohci_cc_strs[OHCI_TD_GET_CC(LE(std->td->td_flags))]));			/*			 * Endpoint is halted.  First unlink all the TDs			 * belonging to the failed transfer, and then restart			 * the endpoint.			 */			for (p = std->nexttd; p->reqh == reqh; p = n) {				n = p->nexttd;				ohci_hash_rem_td(sc, p);				ohci_free_std(sc, p);			}			/* clear halt */			opipe->sed->ed->ed_headp = LE(p->physaddr);			OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_CLF);						if (cc == OHCI_CC_STALL)				reqh->status = USBD_STALLED;			else				reqh->status = USBD_IOERROR;			ohci_ii_done(sc, reqh);		}		ohci_hash_rem_td(sc, std);		ohci_free_std(sc, std);	}}voidohci_ii_done(sc, reqh)	ohci_softc_t *sc;	usbd_request_handle reqh;{	switch (reqh->pipe->endpoint->edesc->bmAttributes & UE_XFERTYPE) {	case UE_CONTROL:		ohci_ctrl_done(sc, reqh);		usb_start_next(reqh->pipe);		break;	case UE_INTERRUPT:		ohci_intr_done(sc, reqh);		break;	case UE_BULK:		ohci_bulk_done(sc, reqh);		usb_start_next(reqh->pipe);		break;	case UE_ISOCHRONOUS:		printf("ohci_process_done: ISO done?\n");		usb_start_next(reqh->pipe);		break;	}	/* And finally execute callback. */	reqh->xfercb(reqh);}voidohci_ctrl_done(sc, reqh)	ohci_softc_t *sc;	usbd_request_handle reqh;{	struct ohci_pipe *opipe = (struct ohci_pipe *)reqh->pipe;	u_int len = opipe->u.ctl.length;	usb_dma_t *dma;	DPRINTFN(10,("ohci_ctrl_done: reqh=%p\n", reqh));	if (!reqh->isreq) {		panic("ohci_ctrl_done: not a request\n");		return;	}	if (len != 0) {		dma = &opipe->u.ctl.datadma;		if (reqh->request.bmRequestType & UT_READ)			memcpy(reqh->buffer, KERNADDR(dma), len);		usb_freemem(sc->sc_dmatag, dma);	}	usb_untimeout(ohci_timeout, reqh, reqh->timo_handle);}voidohci_intr_done(sc, reqh)	ohci_softc_t *sc;	usbd_request_handle reqh;{	struct ohci_pipe *opipe = (struct ohci_pipe *)reqh->pipe;	usb_dma_t *dma;	ohci_soft_ed_t *sed = opipe->sed;	ohci_soft_td_t *xfer, *tail;	DPRINTFN(10,("ohci_intr_done: reqh=%p, actlen=%d\n", 		     reqh, reqh->actlen));	dma = &opipe->u.intr.datadma;	memcpy(reqh->buffer, KERNADDR(dma), reqh->actlen);	if (reqh->pipe->intrreqh == reqh) {		xfer = opipe->tail;		tail = ohci_alloc_std(sc); /* XXX should reuse TD */		if (!tail) {			reqh->status = USBD_NOMEM;			return;		}		tail->reqh = 0;				xfer->td->td_flags = LE(			OHCI_TD_IN | OHCI_TD_NOCC | 			OHCI_TD_SET_DI(1) | OHCI_TD_TOGGLE_CARRY);		if (reqh->flags & USBD_SHORT_XFER_OK)			xfer->td->td_flags |= LE(OHCI_TD_R);		xfer->td->td_cbp = LE(DMAADDR(dma));		xfer->nexttd = tail;		xfer->td->td_nexttd = LE(tail->physaddr);		xfer->td->td_be = LE(LE(xfer->td->td_cbp) + reqh->length - 1);		xfer->len = reqh->length;		xfer->reqh = reqh;		reqh->hcpriv = xfer;		ohci_hash_add_td(sc, xfer);		sed->ed->ed_tailp = LE(tail->physaddr);		opipe->tail = tail;	} else {		usb_freemem(sc->sc_dmatag, dma);		usb_start_next(reqh->pipe);	}}voidohci_bulk_done(sc, reqh)	ohci_softc_t *sc;	usbd_request_handle reqh;{	struct ohci_pipe *opipe = (struct ohci_pipe *)reqh->pipe;	usb_dma_t *dma;	DPRINTFN(10,("ohci_bulk_done: reqh=%p, actlen=%d\n", 		     reqh, reqh->actlen));	dma = &opipe->u.bulk.datadma;	if (reqh->request.bmRequestType & UT_READ)		memcpy(reqh->buffer, KERNADDR(dma), reqh->actlen);	usb_freemem(sc->sc_dmatag, dma);	usb_untimeout(ohci_timeout, reqh, reqh->timo_handle);}voidohci_rhsc(sc, reqh)	ohci_softc_t *sc;	usbd_request_handle reqh;{	usbd_pipe_handle pipe;	struct ohci_pipe *opipe;	u_char *p;	int i, m;	int hstatus;	hstatus = OREAD4(sc, OHCI_RH_STATUS);	DPRINTF(("ohci_rhsc: sc=%p reqh=%p hstatus=0x%08x\n", 		 sc, reqh, hstatus));	if (reqh == 0) {		/* Just ignore the change. */		return;	}	pipe = reqh->pipe;	opipe = (struct ohci_pipe *)pipe;	p = KERNADDR(&opipe->u.intr.datadma);	m = min(sc->sc_noport, reqh->length * 8 - 1);	memset(p, 0, reqh->length);	for (i = 1; i <= m; i++) {		if (OREAD4(sc, OHCI_RH_PORT_STATUS(i)) >> 16)			p[i/8] |= 1 << (i%8);	}	DPRINTF(("ohci_rhsc: change=0x%02x\n", *p));	reqh->actlen = reqh->length;	reqh->status = USBD_NORMAL_COMPLETION;	reqh->xfercb(reqh);	if (reqh->pipe->intrreqh != reqh) {		sc->sc_intrreqh = 0;		usb_freemem(sc->sc_dmatag, &opipe->u.intr.datadma);		usb_start_next(reqh->pipe);	}}/* * Wait here until controller claims to have an interrupt. * Then call ohci_intr and return.  Use timeout to avoid waiting * too long. */voidohci_waitintr(sc, reqh)	ohci_softc_t *sc;	usbd_request_handle reqh;{	int timo = reqh->timeout;	int usecs;	u_int32_t intrs;	reqh->status = USBD_IN_PROGRESS;	for (usecs = timo * 1000000 / hz; usecs > 0; usecs -= 1000) {		usb_delay_ms(&sc->sc_bus, 1);		intrs = OREAD4(sc, OHCI_INTERRUPT_STATUS) & sc->sc_eintrs;		DPRINTFN(15,("ohci_waitintr: 0x%04x\n", intrs));#ifdef OHCI_DEBUG		if (ohcidebug > 15)			ohci_dumpregs(sc);#endif		if (intrs) {			ohci_intr(sc);			if (reqh->status != USBD_IN_PROGRESS)				return;		}	}	/* Timeout */	DPRINTF(("ohci_waitintr: timeout\n"));	reqh->status = USBD_TIMEOUT;	ohci_ii_done(sc, reqh);	/* XXX should free TD */}voidohci_poll(bus)	struct usbd_bus *bus;{	ohci_softc_t *sc = (ohci_softc_t *)bus;	if (OREAD4(sc, OHCI_INTERRUPT_STATUS) & sc->sc_eintrs)		ohci_intr(sc);}usbd_statusohci_device_request(reqh)	usbd_request_handle reqh;{	struct ohci_pipe *opipe = (struct ohci_pipe *)reqh->pipe;	usb_device_request_t *req = &reqh->request;	usbd_device_handle dev = opipe->pipe.device;	ohci_softc_t *sc = (ohci_softc_t *)dev->bus;	int addr = dev->address;	ohci_soft_td_t *setup, *xfer = 0, *stat, *next, *tail;	ohci_soft_ed_t *sed;	usb_dma_t *dmap;	int isread;	int len;	usbd_status r;	int s;	isread = req->bmRequestType & UT_READ;	len = UGETW(req->wLength);	DPRINTFN(3,("ohci_device_control 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, 		    opipe->pipe.endpoint->edesc->bEndpointAddress));	setup = opipe->tail;	stat = ohci_alloc_std(sc);	if (!stat) {		r = USBD_NOMEM;		goto bad1;	}	tail = ohci_alloc_std(sc);	if (!tail) {		r = USBD_NOMEM;		goto bad2;	}	tail->reqh = 0;	sed = opipe->sed;	dmap = &opipe->u.ctl.datadma;	opipe->u.ctl.length = len;	/* Update device address and length since they may have changed. */	/* XXX This only needs to be done once, but it's too early in open. */	sed->ed->ed_flags = LE(	 (LE(sed->ed->ed_flags) & ~(OHCI_ED_ADDRMASK | OHCI_ED_MAXPMASK)) |	 OHCI_ED_SET_FA(addr) |	 OHCI_ED_SET_MAXP(UGETW(opipe->pipe.endpoint->edesc->wMaxPacketSize)));	/* Set up data transaction */	if (len != 0) {		xfer = ohci_alloc_std(sc);		if (!xfer) {			r = USBD_NOMEM;			goto bad3;		}		r = usb_allocmem(sc->sc_dmatag, len, 0, dmap);		if (r != USBD_NORMAL_COMPLETION)			goto bad4;		xfer->td->td_flags = LE(			(isread ? OHCI_TD_IN : OHCI_TD_OUT) | OHCI_TD_NOCC |			OHCI_TD_TOGGLE_1 | OHCI_TD_NOINTR |			(reqh->flags & USBD_SHORT_XFER_OK ? OHCI_TD_R : 0));		xfer->td->td_cbp = LE(DMAADDR(dmap));		xfer->nexttd = stat;		xfer->td->td_nexttd = LE(stat->physaddr);		xfer->td->td_be = LE(LE(xfer->td->td_cbp) + len - 1);		xfer->len = len;		xfer->reqh = reqh;		next = xfer;	} else		next = stat;	memcpy(KERNADDR(&opipe->u.ctl.reqdma), req, sizeof *req);	if (!isread && len != 0)		memcpy(KERNADDR(dmap), reqh->buffer, len);	setup->td->td_flags = LE(OHCI_TD_SETUP | OHCI_TD_NOCC |				 OHCI_TD_TOGGLE_0 | OHCI_TD_NOINTR);	setup->td->td_cbp = LE(DMAADDR(&opipe->u.ctl.reqdma));	setup->nexttd = next;	setup->td->td_nexttd = LE(next->physaddr);	setup->td->td_be = LE(LE(setup->td->td_cbp) + sizeof *req - 1);	setup->len = 0;		/* XXX The number of byte we count */	setup->reqh = reqh;	stat->td->td_flags = LE(		(isread ? OHCI_TD_OUT : OHCI_TD_IN) | OHCI_TD_NOCC |		OHCI_TD_TOGGLE_1 | OHCI_TD_SET_DI(1));	stat->td->td_cbp = 0;	stat->nexttd = tail;	stat->td->td_nexttd = LE(tail->physaddr);	stat->td->td_be = 0;	stat->len = 0;	stat->reqh = reqh;	reqh->hcpriv = stat;#ifdef OHCI_DEBUG	if (ohcidebug > 5) {		printf("ohci_device_request:\n");		ohci_dump_ed(sed);		ohci_dump_tds(setup);	}#endif	/* Insert ED in schedule */	s = splusb();	ohci_hash_add_td(sc, setup);	if (len != 0)		ohci_hash_add_td(sc, xfer);	ohci_hash_add_td(sc, stat);	sed->ed->ed_tailp = LE(tail->physaddr);	opipe->tail = tail;	OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_CLF);	if (reqh->timeout && !sc->sc_bus.use_polling) {                usb_timeout(ohci_timeout, reqh,			    MS_TO_TICKS(reqh->timeout), reqh->timo_handle);	}	splx(s);#if 0#ifdef OHCI_DEBUG	if (ohcidebug > 15) {		delay(5000);		printf("ohci_device_request: status=%x\n",		       OREAD4(sc, OHCI_COMMAND_STATUS));		ohci_dump_ed(sed);		ohci_dump_tds(setup);	}#endif#endif	return (USBD_NORMAL_COMPLETION); bad4:	ohci_free_std(sc, xfer); bad3:	ohci_free_std(sc, tail); bad2:	ohci_free_std(sc, stat); bad1:	return (r);}/*

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?