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

📄 hc_sl811.c

📁 S3C2440ARM9开发板的USB驱动程序
💻 C
📖 第 1 页 / 共 3 页
字号:
	jj = SL811Read (hci, SL11H_SOFTMRREG);	kk = (jj & 0xFF) * 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;	DBGFUNC ("enter hc_parse_trans\n");	/* get packet status; convert ack rcvd to ack-not-rcvd */	*cc = (int) SL811Read (hci, SL11H_PKTSTATREG);	if (*cc &	    (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, TX_BASE_Len = "				"0x%x, TX_count=0x%x\n", *cc,				SL811Read (hci, SL11H_BUFLNTHREG),				SL811Read (hci, SL11H_XFERCNTREG));	} else {		DBGVERBOSE ("parse trans: recv ack, cc = 0x%x, len = 0x%x, \n",			    *cc, length);		/* 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;		cmd |=		    (SL11H_HCTLMASK_ARM | SL11H_HCTLMASK_ENBLEP |		     SL11H_HCTLMASK_WRITE);		break;	case PID_OUT:		cmd &= (SL11H_HCTLMASK_SEQ | SL11H_HCTLMASK_PREAMBLE);		cmd |=		    (SL11H_HCTLMASK_ARM | SL11H_HCTLMASK_ENBLEP |		     SL11H_HCTLMASK_WRITE);		if (toggle) {			cmd |= SL11H_HCTLMASK_SEQ;		}		break;	case PID_IN:		cmd &= (SL11H_HCTLMASK_SEQ | SL11H_HCTLMASK_PREAMBLE);		cmd |= (SL11H_HCTLMASK_ARM | SL11H_HCTLMASK_ENBLEP);		break;	default:		DBGERR ("ERR: SL11StartXaction: unknow pid = 0x%x\n", pid);		return 0;	}	setup_data[0] = SL11H_DATA_START;	setup_data[1] = len;	setup_data[2] = (((pid & 0x0F) << 4) | (epaddr & 0xF));	setup_data[3] = addr & 0x7F;	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){	char ii;	hci_t *hci = __hci;	int isExcessNak = 0;	int urb_state = 0;	char tmpIrq = 0;	/* Get value from interrupt status register */	ii = SL811Read (hci, SL11H_INTSTATREG);	if (ii & SL11H_INTMASK_INSRMV) {		/* Device insertion or removal detected for the USB port */		SL811Write (hci, SL11H_INTENBLREG, 0);		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 */		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);			}		}		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\n",					hci->td_array->len);				urb_print (hci->td_array->td[hci->td_array->len - 1].urb,					   "INTERRUPT", 0);				sh_done_list (hci, &isExcessNak);				SL811Write (hci, SL11H_INTSTATREG, 0xff);				hci->td_array->len = 0;				sofWaitCnt = 0;			}		}		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 ("IRQ occurred while service SOF: irq = 0x%x\n",					tmpIrq);				urb_state = sh_done_list (hci, &isExcessNak);			}			SL811Write (hci, SL11H_INTSTATREG, 0xff);		}	} else {		DBG ("SL811 ISR: unknown, int = 0x%x \n", ii);	}	SL811Write (hci, SL11H_INTSTATREG, 0xff);	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   * * Input:  hci = data structure for the host controller * * Return value  : 0 *                 *****************************************************************/static int hc_alloc_trans_buffer (hci_t * hci){	hcipriv_t *hp = &hci->hp;	int maxlen;	hp->itl0_len = 0;	hp->itl1_len = 0;	hp->atl_len = 0;	hp->itl_buffer_len = 1024;	hp->atl_buffer_len = 4096 - 2 * hp->itl_buffer_len;	/* 2048 */	maxlen = (hp->itl_buffer_len > hp->atl_buffer_len) ? hp->itl_buffer_len : hp->atl_buffer_len;	hp->tl = kmalloc (maxlen, GFP_KERNEL);	if (!hp->tl)		return -ENOMEM;	memset (hp->tl, 0, maxlen);	return 0;}/***************************************************************** * * Function Name: getPortStatusAndChange *

⌨️ 快捷键说明

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