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

📄 hc_sl811.c

📁 USB驱动实验 基于清华大学的TEB-44B0实验平台
💻 C
📖 第 1 页 / 共 3 页
字号:
	// 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\n", ii, jj, len,		     hci->active_trans);		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, 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, IntEna, 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 *         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 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;		}		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;		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_PIDEPREG, cmd);			/* 03: grrr (hne) */	SL811Write (hci, SL11H_HOSTCTLREG, cmd);		/* 00: 26.11.2002 (hne) */#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 */#ifdef SL811_DEBUG_IRQ	hcipriv_t *hp = &hci->hp;	unsigned char sta1, sta2;	outb (SL11H_INTSTATREG, 0x220);	// Interrupt-Status register, controller1	sta1 = (__u8) inb (0x220+1);	outb (SL11H_INTSTATREG, 0x222);	// Interrupt-Status register, controller2	sta2 = (__u8) inb (0x222+1);#endif    do {	/* Get value from interrupt status register */	ii = SL811Read (hci, SL11H_INTSTATREG);	/* All interrupts handled? (hne) */	if ( !(ii & (SL11H_INTMASK_INSRMV /* | SL11H_INTMASK_USBRESET */ |		     SL11H_INTMASK_XFERDONE | SL11H_INTMASK_SOFINTR)) )	{#ifdef SL811_DEBUG_IRQ	// printk ("%Xh IRQ ista=%02X not me\n", hp->hcport, ii);	    if ( sta1 != 0x80 && sta1 != 0x90 &&		 sta2 != 0x80 && sta2 != 0x90 )		printk ("%Xh IRQ sta=%02X,%02X\n", hp->hcport, sta1, sta2);#endif		return;	}	/* Interrupt will be handle now (18.09.2003 2.4.22) */	SL811Write (hci, SL11H_INTSTATREG, 0xff);	/* SOF-outputs are to slow. No debug any SOF */	if ( !(ii & SL11H_INTMASK_SOFINTR) )	    DBGVERBOSE ("SL811 ISR: %s%s%s%s io=%03X\n",		(ii & SL11H_INTMASK_XFERDONE) ?	" DONE": "",		(ii & SL11H_INTMASK_SOFINTR) ?	" SOFINTR": "",		(ii & SL11H_INTMASK_INSRMV) ? 	" INSRMV": "",		(ii & SL11H_INTMASK_USBRESET) ? " USBRESET": "",		hci->hp.hcport );	// if (ii & (SL11H_INTMASK_INSRMV | SL11H_INTMASK_USBRESET)) {	// Found in 2.5.75 (19.09.2003)	// "SL11H_INTMASK_USBRESET" is always on, if no device connected!	if (ii & SL11H_INTMASK_INSRMV) {		/* 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);		return;	}	/* Clear all interrupts */	// SL811Write (hci, SL11H_INTSTATREG, 0xff);	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);			}		}		/* +++ (hne)		SL811Write (hci, SL11H_INTSTATREG, 0xff);		--- */		return;	}	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 io=%03X\n",					hci->td_array->len,					hci->hp.hcport	);				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;			}		}#if 0 /* grrr! This READ clears my XFERDONE interrupt! Its better handle this in a loop. (hne) */		tmpIrq = SL811Read (hci, SL11H_INTSTATREG) & SL811Read (hci, SL11H_INTENBLREG);		if (tmpIrq) {			DBG ("IRQ occurred while service SOF: irq = 0x%x\n",			     tmpIrq);			/* If we receive a DONE IRQ after schedule, need to 			 * handle DONE IRQ again 			 */			if (tmpIrq & SL11H_INTMASK_XFERDONE) {				DBGERR ("XFERDONE occurred while service SOF: irq = 0x%x\n",					tmpIrq);				urb_state = sh_done_list (hci, &isExcessNak);			}			SL811Write (hci, SL11H_INTSTATREG, 0xff);		}#endif	} else {		DBG ("SL811 ISR: unknown, int=0x%x io=%03X\n", ii, hci->hp.hcport);		return;	}	/* +++ (hne)	SL811Write (hci, SL11H_INTSTATREG, 0xff);	--- */	/* loop, if any interrupts can read (hne) */    } while (--irq_loop);    //    outl((0x01)<<24, S3C44B0X_I_ISPC);          //add by vencent    	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");	attachFlag = USBReset (hci);	if (attachFlag) {		setPortChange (hci, PORT_CONNECT_CHANGE);	}	return (0);}/***************************************************************** * * Function Name: hc_alloc_trans_buffer * * This function allocates all transfer buffer   * * Input:  hci = data structure for the host controller * * Return value  : 0

⌨️ 快捷键说明

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