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

📄 hc_sl811.c

📁 嵌入式USB HOST sl811hs的驱动程序
💻 C
📖 第 1 页 / 共 3 页
字号:
		len = maxps;	}	speed = hp->RHportStatus->portStatus;	if (speed & PORT_LOW_SPEED_DEV_ATTACH_STAT) {//		ii = (8*7*8 + 6*3) * len + 800; 		ii = 8 * 8 * len + 1024;	} else {		if (slow) {//          		ii = (8*7*8 + 6*3) * len + 800; 			ii = 8 * 8 * len + 2048;		} else//          		ii = (8*7 + 6*3)*len + 110;			ii = 8 * len + 256;	}	ii += 2 * 10 * len;	jj = SL811Read (hci, SL11H_SOFTMRREG);	/* Read back SOF counter HIGH (bit0-bit5 only) 26.11.2002 (hne) */	// kk = (jj & 0xFF) * 64 - ii;	kk = (jj & (64-1)) * 64 - ii;	if (kk < 0) {		DBGVERBOSE		    ("hc_add_trans: no bandwidth for schedule, ii = 0x%x,"		     "jj = 0x%x, len =0x%x, active_trans = 0x%x, kk=%d, omaxps=%d\n", ii, jj, len,		     hci->active_trans, kk, omaxps);		return (-1);	}	if (pid != PID_IN) {		/* Load data into hc */		SL811BufWrite (hci, SL11H_DATA_START, (__u8 *) data, len);	}	/* transmit */	SL11StartXaction (hci, (__u8) address, (__u8) endpoint, (__u8) pid, len,			  toggle, slow, iso, urb_state);	return len;}/************************************************************************ * Function Name : hc_parse_trans *   * This function checks the status of the transmitted or received packet * and copy the data from the SL811HS register into a buffer. * * 1) Check the status of the packet  * 2) If successful, and IN packet then copy the data from the SL811HS register *    into a buffer * * Input:  hci = data structure for the host controller *         actbytes = pointer to actual number of bytes *         data = data buffer *         cc = packet status *         length = the urb transmit length *         pid = packet ID *         urb_state = the current stage of USB transaction *        * Return: 0  ***********************************************************************/static inline int hc_parse_trans (hci_t * hci, int *actbytes, __u8 * data,				  int *cc, int *toggle, int length, int pid,				  int urb_state){	__u8 addr;	__u8 len;	__u8 pkt_stat;	DBGFUNC ("enter hc_parse_trans\n");	/* get packet status; convert ack rcvd to ack-not-rcvd */	*cc = pkt_stat \	    = SL811Read (hci, SL11H_PKTSTATREG);	if (pkt_stat &	    (SL11H_STATMASK_ERROR | SL11H_STATMASK_TMOUT | SL11H_STATMASK_OVF |	     SL11H_STATMASK_NAK | SL11H_STATMASK_STALL)) {		if (*cc & SL11H_STATMASK_OVF)			DBGERR ("parse trans: error recv ack, cc = 0x%x/0x%x, TX_BASE_Len = "				"0x%x, TX_count=0x%x\n", pkt_stat,				SL811Read (hci, SL11H_PKTSTATREG),				SL811Read (hci, SL11H_BUFLNTHREG),				SL811Read (hci, SL11H_XFERCNTREG));		else 			DBGVERBOSE ("parse trans: error recv ack, cc = 0x%x/0x%x\n",				pkt_stat, SL811Read (hci, SL11H_PKTSTATREG));	} else {		DBGVERBOSE ("parse trans: recv ack, cc=0x%x, len=0x%x, pid=0x%x, urb=%d\n",			    pkt_stat, length, pid, urb_state);		/* Successful data */		if ((pid == PID_IN) && (urb_state != US_CTRL_SETUP)) {			/* Find the base address */			addr = SL811Read (hci, SL11H_BUFADDRREG);			/* Find the Transmit Length */			len = SL811Read (hci, SL11H_BUFLNTHREG);			/* The actual data length = xmit length reg - xfer count reg */			*actbytes = len - SL811Read (hci, SL11H_XFERCNTREG);			if ((data != NULL) && (*actbytes > 0)) {				SL811BufRead (hci, addr, data, *actbytes);			} else if ((data == NULL) && (*actbytes <= 0)) {				DBGERR ("hc_parse_trans: data = NULL or actbyte = 0x%x\n",					*actbytes);				return 0;			}		} else if (pid == PID_OUT) {			*actbytes = length;		} else {			// printk ("ERR:parse_trans, pid != IN or OUT, pid = 0x%x\n", pid);		}		*toggle = !*toggle;	}	return 0;}/************************************************************************ * Function Name : hc_start_int *   * This function enables SL811HS interrupts * * Input:  hci = data structure for the host controller *        * Return: none  ***********************************************************************/static void hc_start_int (hci_t * hci){#ifdef HC_SWITCH_INT	int mask =	    SL11H_INTMASK_XFERDONE | SL11H_INTMASK_SOFINTR |	    SL11H_INTMASK_INSRMV | SL11H_INTMASK_USBRESET;	SL811Write (hci, SL11H_INTENBLREG, mask);#endif}/************************************************************************ * Function Name : hc_stop_int *   * This function disables SL811HS interrupts * * Input:  hci = data structure for the host controller *        * Return: none  ***********************************************************************/static void hc_stop_int (hci_t * hci){#ifdef HC_SWITCH_INT	SL811Write (hci, SL11H_INTSTATREG, 0xff);//  SL811Write(hci, SL11H_INTENBLREG, SL11H_INTMASK_INSRMV);#endif}/************************************************************************ * Function Name : handleInsRmvIntr *   * This function handles the insertion or removal of device on  SL811HS.  * It resets the controller and updates the port status * * Input:  hci = data structure for the host controller *        * Return: none  ***********************************************************************/void handleInsRmvIntr (hci_t * hci){	hcipriv_t *hp = &hci->hp;	USBReset (hci);	/* Changes in connection status */	hp->RHportStatus->portChange |= PORT_CONNECT_CHANGE;	/* Port Enable or Disable */	if (hp->RHportStatus->portStatus & PORT_CONNECT_STAT) {		/* device is connected to the port:		 *    1) Enable port 		 *    2) Resume ?? 		 *///               hp->RHportStatus->portChange |= PORT_ENABLE_CHANGE;		/* Over Current is not supported by the SL811 HW ?? */		/* How about the Port Power ?? */	} else {		/* Device has disconnect:		 *    1) Disable port		 */		hp->RHportStatus->portStatus &= ~(PORT_ENABLE_STAT);		hp->RHportStatus->portChange |= PORT_ENABLE_CHANGE;	}}/***************************************************************** * * Function Name: SL11StartXaction *   * This functions load the registers with appropriate value and  * transmit the packet.				   * * Input:  hci = data structure for the host controller *         addr = USB address of the device *         epaddr = endpoint number *         pid = packet ID *         len = data length *         toggle = USB toggle bit, either 0 or 1 *         slow = speed of the device *	   iso = iso transaction *         urb_state = the current stage of USB transaction * * Return: 0 = error; 1 = successful *                 *****************************************************************/int SL11StartXaction (hci_t * hci, __u8 addr, __u8 epaddr, int pid, int len,		      int toggle, int slow, int iso, int urb_state){	hcipriv_t *hp = &hci->hp;	__u8 cmd = 0;	__u8 setup_data[4];	__u16 speed;	speed = hp->RHportStatus->portStatus;	if (!(speed & PORT_LOW_SPEED_DEV_ATTACH_STAT) && slow) {		cmd |= SL11H_HCTLMASK_PREAMBLE;	}	switch (pid) {	case PID_SETUP:		// cmd &= SL11H_HCTLMASK_PREAMBLE;	/* 26.11.2002 (hne) */		cmd |= SL11H_HCTLMASK_ARM		     | SL11H_HCTLMASK_ENBLEP		     | SL11H_HCTLMASK_WRITE;		DBGVERBOSE ("SL811 Xaction: SETUP cmd=%02X\n", cmd);		break;	case PID_OUT:		// cmd &= (SL11H_HCTLMASK_SEQ | SL11H_HCTLMASK_PREAMBLE); /* (hne) 26.11.2002 */		cmd |= SL11H_HCTLMASK_ARM		     | SL11H_HCTLMASK_ENBLEP		     | SL11H_HCTLMASK_WRITE;		if (toggle) {			cmd |= SL11H_HCTLMASK_SEQ;		}		if (iso) {			cmd |= SL11H_HCTLMASK_ISOCH;			DBG("PID_OUT setting SL11H_HCTLMASK_ISOCH\n");		}		DBGVERBOSE ("SL811 Xaction: OUT cmd=%02X\n", cmd);		break;	case PID_IN:		// cmd &= (SL11H_HCTLMASK_SEQ | SL11H_HCTLMASK_PREAMBLE);	/* (hne) 26.11.2002 */		cmd |= SL11H_HCTLMASK_ARM		     | SL11H_HCTLMASK_ENBLEP;		if (iso) {			cmd |= SL11H_HCTLMASK_ISOCH;			DBG("PID_IN setting SL11H_HCTLMASK_ISOCH\n");		}		DBGVERBOSE ("SL811 Xaction: IN cmd=%02x\n", cmd);		break;	default:		DBGERR ("ERR: SL11StartXaction: unknow pid = 0x%x\n", pid);		return 0;	}	setup_data[0] = SL11H_DATA_START;			/* 01:SL11H_BUFADDRREG */	setup_data[1] = len;					/* 02:SL11H_BUFLNTHREG */	setup_data[2] = (((pid & 0x0F) << 4) | (epaddr & 0xF));	/* 03:SL11H_PIDEPREG */	setup_data[3] = addr & 0x7F;				/* 04:SL11H_DEVADDRREG */	SL811BufWrite (hci, SL11H_BUFADDRREG, (__u8 *) & setup_data[0], 4);	SL811Write (hci, SL11H_HOSTCTLREG, cmd);#if 0	/* The SL811 has a hardware flaw when hub devices sends out	 * SE0 between packets. It has been found in a TI chipset and	 * cypress hub chipset. It causes the SL811 to hang	 * The workaround is to re-issue the preample again.	 */	if ((cmd & SL11H_HCTLMASK_PREAMBLE)) {		SL811Write (hci, SL11H_PIDEPREG_B, 0xc0);		SL811Write (hci, SL11H_HOSTCTLREG_B, 0x1);	// send the premable	}#endif	return 1;}/***************************************************************** * * Function Name: hc_interrupt * * Interrupt service routine.  * * 1) determine the causes of interrupt * 2) clears all interrupts * 3) calls appropriate function to service the interrupt * * Input:  irq = interrupt line associated with the controller  *         hci = data structure for the host controller *         r = holds the snapshot of the processor's context before  *             the processor entered interrupt code. (not used here)  * * Return value  : None. *                 *****************************************************************/static void hc_interrupt (int irq, void *__hci, struct pt_regs *r){	__u8 ii;	hci_t *hci = __hci;	int isExcessNak = 0;	int urb_state = 0;	// __u8 tmpIrq = 0;	int irq_loop = 16;	/* total irq handled at one hardware irq */	if (!hci)		return;    do {	/* Get value from interrupt status register */	ii = SL811Read (hci, SL11H_INTSTATREG);	SL811Write (hci, SL11H_INTSTATREG, ii);	/* All interrupts handled? (hne) */	if ( !(ii & (SL11H_INTMASK_INSRMV | SL11H_INTMASK_USBRESET |		     SL11H_INTMASK_XFERDONE | SL11H_INTMASK_SOFINTR)) ) {		break;	}	/* SOF-outputs are to slow. No debug any SOF */	if ( !(ii & SL11H_INTMASK_SOFINTR) )	    DBGVERBOSE ("SL811 ISR: %s%s%s%s\n",		(ii & SL11H_INTMASK_XFERDONE) ?	" DONE": "",		(ii & SL11H_INTMASK_SOFINTR) ?	" SOFINTR": "",		(ii & SL11H_INTMASK_INSRMV) ? 	" INSRMV": "",		(ii & SL11H_INTMASK_USBRESET) ? " USBRESET": "" );	if (ii & (SL11H_INTMASK_INSRMV | SL11H_INTMASK_USBRESET)) {		/* Device insertion or removal detected for the USB port */		/* Disable all interrupts */		SL811Write (hci, SL11H_INTENBLREG, 0);		/* No SOF, Full speed */		SL811Write (hci, SL11H_CTLREG1, 0);		mdelay (100);	// wait for device stable 		handleInsRmvIntr (hci);	}	if (ii & SL11H_INTMASK_XFERDONE) {		/* USB Done interrupt occurred */		// DBGVERBOSE ("xsta=%02X\n", SL811Read (hci, SL11H_PKTSTATREG));		urb_state = sh_done_list (hci, &isExcessNak);#ifdef WARNING		if (hci->td_array->len > 0)			printk ("WARNING: IRQ, td_array->len = 0x%x, s/b:0\n",				hci->td_array->len);#endif		if (hci->td_array->len == 0 && !isExcessNak		    && !(ii & SL11H_INTMASK_SOFINTR) && (urb_state == 0)) {			if (urb_state == 0) {				/* All urb_state has not been finished yet! 				 * continue with the current urb transaction 				 */				if (hci->last_packet_nak == 0) {					if (!usb_pipecontrol					    (hci->td_array->td[0].urb->pipe))						sh_add_packet (hci, hci->td_array-> td[0].urb);				}			} else {				/* The last transaction has completed:				 * schedule the next transaction 				 */				sh_schedule_trans (hci, 0);			}		}	}	if (ii & SL11H_INTMASK_SOFINTR) {		hci->frame_number = (hci->frame_number + 1) % 2048;		if (hci->td_array->len == 0)			sh_schedule_trans (hci, 1);		else {			if (sofWaitCnt++ > 100) {				/* The last transaction has not completed.				 * Need to retire the current td, and let				 * it transmit again later on.				 * (THIS NEEDS TO BE WORK ON MORE, IT SHOULD NEVER 				 *  GET TO THIS POINT)				 */				DBGERR ("SOF interrupt: td_array->len = 0x%x, s/b: 0\n",					hci->td_array->len);				urb_print (hci->td_array->td[hci->td_array->len - 1].urb,					   "INTERRUPT", 0);				/* FIXME: Here sh_done_list was call with urb->dev=NULL 21.11.2002 (hne) */				sh_done_list (hci, &isExcessNak);				/* +++ (hne)				SL811Write (hci, SL11H_INTSTATREG, 0xff);				--- */				hci->td_array->len = 0;				sofWaitCnt = 0;			}		}		#ifdef SL811_DEBUG		 /* Clear SOF interrupt in service SOF, only at debug */		 SL811Write (hci, SL11H_INTSTATREG, SL11H_INTMASK_SOFINTR);		#endif // SL811_DEBUG	}	if (ii & ~(0x80 | SL11H_INTMASK_INSRMV | SL11H_INTMASK_USBRESET |		     SL11H_INTMASK_XFERDONE | SL11H_INTMASK_SOFINTR)) {		DBG ("SL811 ISR: unknown, int = 0x%x \n", ii);	}	/* loop, if any interrupts can read (hne) */    } while (--irq_loop);        return;}/***************************************************************** * * Function Name: hc_reset * * This function does register test and resets the SL811HS  * controller. * * Input:  hci = data structure for the host controller * * Return value  : 0 *                 *****************************************************************/static int hc_reset (hci_t * hci){	int attachFlag = 0;	DBGFUNC ("Enter hc_reset\n");	regTest (hci);	attachFlag = USBReset (hci);	if (attachFlag) {		setPortChange (hci, PORT_CONNECT_CHANGE);	}	return (0);}/***************************************************************** * * Function Name: hc_alloc_trans_buffer * * This function allocates all transfer buffer   *

⌨️ 快捷键说明

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