⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 isp116x-hcd.c

📁 U-boot源码 ARM7启动代码
💻 C
📖 第 1 页 / 共 3 页
字号:
		dump_ptd_data(&ptd[i], (__u8 *) data + done, 0);		write_ptddata_to_fifo(isp116x,				      (__u8 *) data + done,				      PTD_GET_LEN(&ptd[i]));		done += PTD_GET_LEN(&ptd[i]);	}}/* Read the processed PTD's and data from fifo ram back to URBs' buffers. * Fifo must be full and done */static int unpack_fifo(struct isp116x *isp116x, struct usb_device *dev,		       unsigned long pipe, struct ptd *ptd, int n, void *data,		       int len){	int buflen = n * sizeof(struct ptd) + len;	int i, done, cc, ret;	isp116x_write_reg16(isp116x, HCuPINT, HCuPINT_AIIEOT);	isp116x_write_reg16(isp116x, HCXFERCTR, buflen);	isp116x_write_addr(isp116x, HCATLPORT);	ret = TD_CC_NOERROR;	done = 0;	for (i = 0; i < n; i++) {		DBG("i=%d - done=%d - len=%d", i, done, PTD_GET_LEN(&ptd[i]));		ptd[i].count = isp116x_read_data16(isp116x);		ptd[i].mps = isp116x_read_data16(isp116x);		ptd[i].len = isp116x_read_data16(isp116x);		ptd[i].faddr = isp116x_read_data16(isp116x);		dump_ptd(&ptd[i]);		read_ptddata_from_fifo(isp116x,				       (__u8 *) data + done,				       PTD_GET_LEN(&ptd[i]));		dump_ptd_data(&ptd[i], (__u8 *) data + done, 1);		done += PTD_GET_LEN(&ptd[i]);		cc = PTD_GET_CC(&ptd[i]);		/* Data underrun means basically that we had more buffer space than		 * the function had data. It is perfectly normal but upper levels have		 * to know how much we actually transferred.		 */		if (cc == TD_NOTACCESSED ||				(cc != TD_CC_NOERROR && (ret == TD_CC_NOERROR || ret == TD_DATAUNDERRUN)))			ret = cc;	}	DBG("--- unpack buffer %p - %d bytes (fifo %d) ---", data, len, buflen);	return ret;}/* Interrupt handling */static int isp116x_interrupt(struct isp116x *isp116x){	u16 irqstat;	u32 intstat;	int ret = 0;	isp116x_write_reg16(isp116x, HCuPINTENB, 0);	irqstat = isp116x_read_reg16(isp116x, HCuPINT);	isp116x_write_reg16(isp116x, HCuPINT, irqstat);	DBG(">>>>>> irqstat %x <<<<<<", irqstat);	if (irqstat & HCuPINT_ATL) {		DBG(">>>>>> HCuPINT_ATL <<<<<<");		udelay(500);		ret = 1;	}	if (irqstat & HCuPINT_OPR) {		intstat = isp116x_read_reg32(isp116x, HCINTSTAT);		isp116x_write_reg32(isp116x, HCINTSTAT, intstat);		DBG(">>>>>> HCuPINT_OPR %x <<<<<<", intstat);		if (intstat & HCINT_UE) {			ERR("unrecoverable error, controller disabled");			/* FIXME: be optimistic, hope that bug won't repeat			 * often. Make some non-interrupt context restart the			 * controller. Count and limit the retries though;			 * either hardware or software errors can go forever...			 */			isp116x_reset(isp116x);			ret = -1;			return -1;		}		if (intstat & HCINT_RHSC) {			got_rhsc = 1;			ret = 1;			/* When root hub or any of its ports is going			   to come out of suspend, it may take more			   than 10ms for status bits to stabilize. */			wait_ms(20);		}		if (intstat & HCINT_SO) {			ERR("schedule overrun");			ret = -1;		}		irqstat &= ~HCuPINT_OPR;	}	return ret;}/* With one PTD we can transfer almost 1K in one go; * HC does the splitting into endpoint digestible transactions */struct ptd ptd[1];static inline int max_transfer_len(struct usb_device *dev, unsigned long pipe){	unsigned mpck = usb_maxpacket(dev, pipe);	/* One PTD can transfer 1023 bytes but try to always	 * transfer multiples of endpoint buffer size	 */	return 1023 / mpck * mpck;}/* Do an USB transfer */static int isp116x_submit_job(struct usb_device *dev, unsigned long pipe,			      int dir, void *buffer, int len){	struct isp116x *isp116x = &isp116x_dev;	int type = usb_pipetype(pipe);	int epnum = usb_pipeendpoint(pipe);	int max = usb_maxpacket(dev, pipe);	int dir_out = usb_pipeout(pipe);	int speed_low = usb_pipeslow(pipe);	int i, done = 0, stat, timeout, cc;	/* 500 frames or 0.5s timeout when function is busy and NAKs transactions for a while */	int retries = 500;	DBG("------------------------------------------------");	dump_msg(dev, pipe, buffer, len, "SUBMIT");	DBG("------------------------------------------------");	if (len >= 1024) {		ERR("Too big job");		dev->status = USB_ST_CRC_ERR;		return -1;	}	if (isp116x->disabled) {		ERR("EPIPE");		dev->status = USB_ST_CRC_ERR;		return -1;	}	/* device pulled? Shortcut the action. */	if (devgone == dev) {		ERR("ENODEV");		dev->status = USB_ST_CRC_ERR;		return USB_ST_CRC_ERR;	}	if (!max) {		ERR("pipesize for pipe %lx is zero", pipe);		dev->status = USB_ST_CRC_ERR;		return -1;	}	if (type == PIPE_ISOCHRONOUS) {		ERR("isochronous transfers not supported");		dev->status = USB_ST_CRC_ERR;		return -1;	}	/* FIFO not empty? */	if (isp116x_read_reg16(isp116x, HCBUFSTAT) & HCBUFSTAT_ATL_FULL) {		ERR("****** FIFO not empty! ******");		dev->status = USB_ST_BUF_ERR;		return -1;	}      retry:	isp116x_write_reg32(isp116x, HCINTSTAT, 0xff);	/* Prepare the PTD data */	ptd->count = PTD_CC_MSK | PTD_ACTIVE_MSK |		PTD_TOGGLE(usb_gettoggle(dev, epnum, dir_out));	ptd->mps = PTD_MPS(max) | PTD_SPD(speed_low) | PTD_EP(epnum) | PTD_LAST_MSK;	ptd->len = PTD_LEN(len) | PTD_DIR(dir);	ptd->faddr = PTD_FA(usb_pipedevice(pipe));retry_same:	/* Pack data into FIFO ram */	pack_fifo(isp116x, dev, pipe, ptd, 1, buffer, len);#ifdef EXTRA_DELAY	wait_ms(EXTRA_DELAY);#endif	/* Start the data transfer */	/* Allow more time for a BULK device to react - some are slow */	if (usb_pipetype(pipe) == PIPE_BULK)		timeout = 5000;	else		timeout = 100;	/* Wait for it to complete */	for (;;) {		/* Check whether the controller is done */		stat = isp116x_interrupt(isp116x);		if (stat < 0) {			dev->status = USB_ST_CRC_ERR;			break;		}		if (stat > 0)			break;		/* Check the timeout */		if (--timeout)			udelay(1);		else {			ERR("CTL:TIMEOUT ");			stat = USB_ST_CRC_ERR;			break;		}	}	/* We got an Root Hub Status Change interrupt */	if (got_rhsc) {		isp116x_show_regs(isp116x);		got_rhsc = 0;		/* Abuse timeout */		timeout = rh_check_port_status(isp116x);		if (timeout >= 0) {			/*			 * FIXME! NOTE! AAAARGH!			 * This is potentially dangerous because it assumes			 * that only one device is ever plugged in!			 */			devgone = dev;		}	}	/* Ok, now we can read transfer status */	/* FIFO not ready? */	if (!(isp116x_read_reg16(isp116x, HCBUFSTAT) & HCBUFSTAT_ATL_DONE)) {		ERR("****** FIFO not ready! ******");		dev->status = USB_ST_BUF_ERR;		return -1;	}	/* Unpack data from FIFO ram */	cc = unpack_fifo(isp116x, dev, pipe, ptd, 1, buffer, len);	i = PTD_GET_COUNT(ptd);	done += i;	buffer += i;	len -= i;	/* There was some kind of real problem; Prepare the PTD again	 * and retry from the failed transaction on	 */	if (cc && cc != TD_NOTACCESSED && cc != TD_DATAUNDERRUN) {		if (retries >= 100) {			retries -= 100;			/* The chip will have toggled the toggle bit for the failed			 * transaction too. We have to toggle it back.			 */			usb_settoggle(dev, epnum, dir_out, !PTD_GET_TOGGLE(ptd));			goto retry;		}	}	/* "Normal" errors; TD_NOTACCESSED would mean in effect that the function have NAKed	 * the transactions from the first on for the whole frame. It may be busy and we retry	 * with the same PTD. PTD_ACTIVE (and not TD_NOTACCESSED) would mean that some of the	 * PTD didn't make it because the function was busy or the frame ended before the PTD	 * finished. We prepare the rest of the data and try again.	 */	else if (cc == TD_NOTACCESSED || PTD_GET_ACTIVE(ptd) || (cc != TD_DATAUNDERRUN && PTD_GET_COUNT(ptd) < PTD_GET_LEN(ptd))) {		if (retries) {			--retries;			if (cc == TD_NOTACCESSED && PTD_GET_ACTIVE(ptd) && !PTD_GET_COUNT(ptd)) goto retry_same;			usb_settoggle(dev, epnum, dir_out, PTD_GET_TOGGLE(ptd));			goto retry;		}	}	if (cc != TD_CC_NOERROR && cc != TD_DATAUNDERRUN) {		DBG("****** completition code error %x ******", cc);		switch (cc) {		case TD_CC_BITSTUFFING:			dev->status = USB_ST_BIT_ERR;			break;		case TD_CC_STALL:			dev->status = USB_ST_STALLED;			break;		case TD_BUFFEROVERRUN:		case TD_BUFFERUNDERRUN:			dev->status = USB_ST_BUF_ERR;			break;		default:			dev->status = USB_ST_CRC_ERR;		}		return -cc;	}	else usb_settoggle(dev, epnum, dir_out, PTD_GET_TOGGLE(ptd));	dump_msg(dev, pipe, buffer, len, "SUBMIT(ret)");	dev->status = 0;	return done;}/* Adapted from au1x00_usb_ohci.c */static int isp116x_submit_rh_msg(struct usb_device *dev, unsigned long pipe,				 void *buffer, int transfer_len,				 struct devrequest *cmd){	struct isp116x *isp116x = &isp116x_dev;	u32 tmp = 0;	int leni = transfer_len;	int len = 0;	int stat = 0;	u32 datab[4];	u8 *data_buf = (u8 *) datab;	u16 bmRType_bReq;	u16 wValue;	u16 wIndex;	u16 wLength;	if ((pipe & PIPE_INTERRUPT) == PIPE_INTERRUPT) {		INFO("Root-Hub submit IRQ: NOT implemented");		return 0;	}	bmRType_bReq = cmd->requesttype | (cmd->request << 8);	wValue = swap_16(cmd->value);	wIndex = swap_16(cmd->index);	wLength = swap_16(cmd->length);	DBG("--- HUB ----------------------------------------");	DBG("submit rh urb, req=%x val=%#x index=%#x len=%d",	    bmRType_bReq, wValue, wIndex, wLength);	dump_msg(dev, pipe, buffer, transfer_len, "RH");	DBG("------------------------------------------------");	switch (bmRType_bReq) {	case RH_GET_STATUS:		DBG("RH_GET_STATUS");		*(__u16 *) data_buf = swap_16(1);		len = 2;		break;	case RH_GET_STATUS | RH_INTERFACE:		DBG("RH_GET_STATUS | RH_INTERFACE");		*(__u16 *) data_buf = swap_16(0);		len = 2;		break;	case RH_GET_STATUS | RH_ENDPOINT:		DBG("RH_GET_STATUS | RH_ENDPOINT");		*(__u16 *) data_buf = swap_16(0);		len = 2;		break;	case RH_GET_STATUS | RH_CLASS:		DBG("RH_GET_STATUS | RH_CLASS");		tmp = isp116x_read_reg32(isp116x, HCRHSTATUS);		*(__u32 *) data_buf = swap_32(tmp & ~(RH_HS_CRWE | RH_HS_DRWE));		len = 4;		break;	case RH_GET_STATUS | RH_OTHER | RH_CLASS:		DBG("RH_GET_STATUS | RH_OTHER | RH_CLASS");		tmp = isp116x_read_reg32(isp116x, HCRHPORT1 + wIndex - 1);		*(__u32 *) data_buf = swap_32(tmp);		isp116x_show_regs(isp116x);		len = 4;		break;	case RH_CLEAR_FEATURE | RH_ENDPOINT:		DBG("RH_CLEAR_FEATURE | RH_ENDPOINT");		switch (wValue) {		case RH_ENDPOINT_STALL:			DBG("C_HUB_ENDPOINT_STALL");			len = 0;			break;		}		break;	case RH_CLEAR_FEATURE | RH_CLASS:		DBG("RH_CLEAR_FEATURE | RH_CLASS");		switch (wValue) {		case RH_C_HUB_LOCAL_POWER:			DBG("C_HUB_LOCAL_POWER");			len = 0;			break;		case RH_C_HUB_OVER_CURRENT:			DBG("C_HUB_OVER_CURRENT");			isp116x_write_reg32(isp116x, HCRHSTATUS, RH_HS_OCIC);			len = 0;			break;		}		break;	case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:		DBG("RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS");		switch (wValue) {		case RH_PORT_ENABLE:			isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,					    RH_PS_CCS);			len = 0;			break;		case RH_PORT_SUSPEND:			isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,					    RH_PS_POCI);			len = 0;			break;		case RH_PORT_POWER:			isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,					    RH_PS_LSDA);			len = 0;			break;		case RH_C_PORT_CONNECTION:			isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,					    RH_PS_CSC);			len = 0;			break;		case RH_C_PORT_ENABLE:			isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,					    RH_PS_PESC);			len = 0;			break;		case RH_C_PORT_SUSPEND:			isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,					    RH_PS_PSSC);			len = 0;			break;		case RH_C_PORT_OVER_CURRENT:			isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,					    RH_PS_POCI);			len = 0;			break;		case RH_C_PORT_RESET:			isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,					    RH_PS_PRSC);			len = 0;			break;		default:			ERR("invalid wValue");			stat = USB_ST_STALLED;		}

⌨️ 快捷键说明

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