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

📄 pxa.c

📁 Linux2.4.20针对三星公司的s3c2440内核基础上的一些设备驱动代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	/* Stop DMA */	DCSR(usb_pxa_dma_out.dmach) &= ~DCSR_RUN;	/* TODO: busy-wait until DMA is really stopped ? */	if (dcsr & DCSR_BUSERR)		/* Is there a way to handle this error somehow ? */                printk (KERN_WARNING "PXA: Bus error in USB RX DMA "                        "- USB data transfer may be incorrect\n");                else if (dcsr & DCSR_ENDINTR) {		DMA_TRACEMSG ("PXA: normal IRQ\n");		if (!usb_pxa_dma_out.endpoint->rcv_urb) {			usb_pxa_dma_out.endpoint->rcv_urb = first_urb_detached (&usb_pxa_dma_out.endpoint->rdy);		}		if (usb_pxa_dma_out.endpoint->rcv_urb) {			int recvsize;			unsigned char *cp = usb_pxa_dma_out.endpoint->rcv_urb->buffer + 				usb_pxa_dma_out.endpoint->rcv_urb->actual_length;						/* Copy all new data to current urb buffer */			memcpy (cp, usb_pxa_dma_out.dma_buf, DMA_OUT_BUFSIZE);						if (usb_pxa_dma_out.dma_buf[DMA_OUT_BUFSIZE - 1] == 0xff) {				/* May be end-of-urb data - must calculate FCS and				   compare with FCS calculated on the host side */				__u32 oldfcs, newfcs;				/* See usbdnet.c for explanation of this */				oldfcs = (usb_pxa_dma_out.dma_buf[DMA_OUT_BUFSIZE - 2] << 24) |					 (usb_pxa_dma_out.dma_buf[DMA_OUT_BUFSIZE - 3] << 16) |					 (usb_pxa_dma_out.dma_buf[DMA_OUT_BUFSIZE - 4] << 8) |					 (usb_pxa_dma_out.dma_buf[DMA_OUT_BUFSIZE - 5]);				newfcs = fcs_compute32					 (usb_pxa_dma_out.endpoint->rcv_urb->buffer,					  usb_pxa_dma_out.endpoint->rcv_urb->actual_length + DMA_OUT_BUFSIZE - 5,					  CRC32_INITFCS);				newfcs = ~newfcs;				/* If FCSs are equal, the last byte of new data				   is 0xff mark and will be ignored */				recvsize = (oldfcs == newfcs) ? (DMA_OUT_BUFSIZE - 1) : DMA_OUT_BUFSIZE;			}			else				recvsize = DMA_OUT_BUFSIZE;			DMA_TRACEMSG ("PXA: urb exists, real size %d\n", recvsize);			usbd_rcv_complete_irq (usb_pxa_dma_out.endpoint, recvsize, 0);		}	}	/* clear RPC and interrupt */        UDCCSN(usb_pxa_dma_out.ep) |= UDCCS_BO_RPC;        pxa_ep_reset_irs(usb_pxa_dma_out.ep);	/* Clear end-of-interrupt */        DCSR(usb_pxa_dma_out.dmach) |= DCSR_ENDINTR;	/* Reinitialize and restart DMA */	pxa_rx_dma_hw_init ();	DCSR(usb_pxa_dma_out.dmach) |= DCSR_RUN;}#endif /* CONFIG_USBD_PXA_DMA_OUT */static __inline__ void pxa_out_n(int ep, struct usb_endpoint_instance *endpoint){        if (UDCCSN(ep) & UDCCS_BO_RPC) {                if (endpoint) {                        if (!endpoint->rcv_urb) {                                endpoint->rcv_urb = first_urb_detached (&endpoint->rdy);                        }                        if (endpoint->rcv_urb) {                                int len = 0;                                unsigned char *cp = endpoint->rcv_urb->buffer + endpoint->rcv_urb->actual_length;                                if (cp) {                                        // read available bytes (max packetsize) into urb buffer                                        int count = MIN(UBCRN(ep) + 1, endpoint->rcv_packetSize);                                        while (count--) {                                                len++;                                                *cp++ = UDDRN(ep);                                        }                                }                                else {                                        printk(KERN_INFO"read[%d:%d] bad arguements\n", udc_interrupts, jifs());                                        pxa_out_flush(ep);                                }                                // fall through if error of any type, len = 0                                usbd_rcv_complete_irq (endpoint, len, 0);                        }                        else {                                pxa_out_flush(ep);                        }                }        }        // clear RPC and interrupt        UDCCSN(ep) = UDCCS_BO_RPC;        pxa_ep_reset_irs(ep);}/* ********************************************************************************************* *//* Bulk IN (tx) */#ifdef CONFIG_USBD_PXA_DMA_INstatic usb_pxa_dma_t usb_pxa_dma_in = {-1, NULL, 0, 0, NULL, 0};static void pxa_tx_dma_irq (int dmach, void *dev_id, struct pt_regs *regs){	int dcsr = DCSR(usb_pxa_dma_in.dmach);	/* Stop DMA */	DCSR(usb_pxa_dma_in.dmach) &= ~DCSR_RUN;	DMA_TRACEMSG ("PXA: in dma IRQ, DCSR 0x%x\n", dcsr);        if (dcsr & DCSR_BUSERR)		/* I don't know better way to handle DMA bus error... */                printk (KERN_WARNING "PXA: Bus error in USB TX DMA "                        "- USB data transfer may be incorrect\n");                else if (dcsr & DCSR_ENDINTR) {                /* All seems ok, checking for we have short packet transmitted */                if ((usb_pxa_dma_in.size < usb_pxa_dma_in.endpoint->tx_packetSize) ||                    ((usb_pxa_dma_in.endpoint->tx_urb->actual_length                       - usb_pxa_dma_in.endpoint->sent ) == usb_pxa_dma_in.size)) {                        UDCCSN(usb_pxa_dma_in.ep) |= UDCCS_BI_TSP;		}                usb_pxa_dma_in.endpoint->last += usb_pxa_dma_in.size;        }        /* Clear end-of-interrupt */        DCSR(usb_pxa_dma_in.dmach) |= DCSR_ENDINTR;        /* Now we can re-enable irq */        pxa_enable_ep_interrupt (usb_pxa_dma_in.ep);}static void __inline__ pxa_start_n_dma_hw (int ep, struct usb_endpoint_instance *endpoint,					   char *mem, int size){	/* Prepare for DMA */	memcpy (usb_pxa_dma_in.dma_buf, mem, size);	usb_pxa_dma_in.ep = ep;	usb_pxa_dma_in.endpoint = endpoint;	usb_pxa_dma_in.size = size;		/* Setup DMA */	DCSR(usb_pxa_dma_in.dmach) |= DCSR_NODESC;	DCMD(usb_pxa_dma_in.dmach) = DCMD_FLOWTRG | DCMD_INCSRCADDR | DCMD_WIDTH1 | 		DCMD_BURST32 | DCMD_ENDIRQEN | size;	DSADR(usb_pxa_dma_in.dmach) = usb_pxa_dma_in.dma_buf_phys;	DTADR(usb_pxa_dma_in.dmach) = _UDDRN[ep];	/* Map DMA (FIXME: assume ep is 1) */	DRCMR25 = usb_pxa_dma_in.dmach | DRCMR_MAPVLD;		/* Start DMA */	DCSR(usb_pxa_dma_in.dmach) |= DCSR_RUN;}static void pxa_start_n_dma (unsigned int ep, struct usb_endpoint_instance *endpoint){	/* We must disable irq for this endpoint */	pxa_disable_ep_interrupt (ep);        if (endpoint->tx_urb) {                struct urb *urb = endpoint->tx_urb;                int last = MIN(urb->actual_length - (endpoint->sent + endpoint->last), 			       endpoint->tx_packetSize);	        if (last) {			pxa_start_n_dma_hw (ep, endpoint, urb->buffer + endpoint->sent + 					    endpoint->last, last);			return;		}	}                /* Do nothing with DMA - re-enable irq */        pxa_enable_ep_interrupt (ep);}#endif /* CONFIG_USBD_PXA_DMA_IN */static void __inline__ pxa_start_n (unsigned int ep, struct usb_endpoint_instance *endpoint){        if (endpoint->tx_urb) {                int last;                struct urb *urb = endpoint->tx_urb;                if (( last = MIN (urb->actual_length - (endpoint->sent + endpoint->last), endpoint->tx_packetSize)))                 {                        int size = last;                        unsigned char *cp = urb->buffer + endpoint->sent + endpoint->last;                        while (size--) {                                UDDRN(ep) = *cp++;                        }                        if (( last < endpoint->tx_packetSize ) ||                                        ( (endpoint->tx_urb->actual_length - endpoint->sent ) == last ))                         {                                UDCCSN(ep) = UDCCS_BI_TSP;                        }                        endpoint->last += last;                }        }}static void __inline__ pxa_in_n (unsigned int ep, struct usb_endpoint_instance *endpoint){        int udccsn;        pxa_ep_reset_irs(ep);        // if TPC update tx urb and clear TPC        if ((udccsn = UDCCSN(ep)) & UDCCS_BI_TPC) {                UDCCSN(ep) = UDCCS_BI_TPC;                usbd_tx_complete_irq(endpoint, 0);        }        if (udccsn & UDCCS_BI_TFS) {                pxa_start_n(ep, endpoint);        }        // clear underrun, not much we can do about it        if (udccsn & UDCCS_BI_TUR) {                UDCCSN(ep) = UDCCS_BI_TUR;        }}/* ********************************************************************************************* *//* Control (endpoint zero) */#ifdef CONFIG_USBD_EP0_SUPPORT/* Changed by Stanley */void pxa_ep0recv(struct usb_endpoint_instance *endpoint, volatile u32 udccs0){	int size=0;	struct urb *urb = endpoint->rcv_urb;	unsigned char* cp = (unsigned char*) (urb->buffer + urb->actual_length);		PXA_REGS(udccs0, "         <-- setup data recv");#ifdef EP0_DEBUG	printk("%d %x %x\n", urb->actual_length, urb->buffer, cp );	printk("udccs0=0x%x\n", udccs0 );#endif	// check for premature status stage	if ( !(udccs0&UDCCS0_OPR) && !(udccs0&UDCCS0_IPR) ) {		if ( urb->device_request.wLength == urb->actual_length ) {#ifdef EP0_DEBUG			printk(KERN_INFO"pxa_ep0recv: UDC ep0 receive all data.\n");#endif			usbd_recv_setup(ep0_urb);		} else {#ifdef EP0_DEBUG			printk(KERN_INFO"pxa_ep0recv: Get a premature status in stage.\n");			printk(KERN_INFO"pxa_ep0recv: request.wLength=0x%x, actual_length=0x%x\n", 			       urb->device_request.wLength, urb->actual_length );#endif			if ( urb->buffer )				kfree( urb->buffer );		}		endpoint->state = WAIT_FOR_SETUP;	}	// receive more data	if (( udccs0 & UDCCS0_OPR ) && !(UDCCS0 & UDCCS0_SA) ) {		while ( UDCCS0&UDCCS0_RNE ) {			*cp++ = UDDRN(0);			urb->actual_length++;		}		/* Do we need this section? */		/* need more tests!  -Stanley */		/* Without the section, the driver still works */#if 1		if ( urb->actual_length == urb->device_request.wLength ) {#ifdef EP0_DEBUG			printk(KERN_INFO"pxa_ep0recv under test: UDC ep0 receive all data.\n");#endif			usbd_recv_setup(ep0_urb);			endpoint->state = WAIT_FOR_SETUP;		}#endif 		UDCCS0 |= UDCCS0_OPR;				// to allow to enter a premature STATUS IN stage		UDCCS0 |= UDCCS0_IPR;	}	return;}#endif void pxa_ep0xmit(struct usb_endpoint_instance *endpoint, volatile u32 udccs0){	int short_packet;	int size;	struct urb *urb = endpoint->tx_urb;        PXA_REGS(udccs0, "          --> xmit");        //printk(KERN_INFO"tx[%d:%d] CS0[%02x]\n", udc_interrupts, jifs(), UDCCS0);        // check for premature status stage - host abandoned previous IN        if ((udccs0 & UDCCS0_OPR) && !(UDCCS0 & UDCCS0_SA) ) {                // clear tx fifo and opr                UDCCS0 = UDCCS0_FTF | UDCCS0_OPR;                endpoint->state = WAIT_FOR_SETUP;                endpoint->tx_urb = NULL;                PXA_REGS(UDCCS0, "          <-- xmit premature status");                return;        }        // check for stall        if (udccs0 & UDCCS0_SST) {                // clear stall and tx fifo                UDCCS0 = UDCCS0_SST | UDCCS0_FTF;                endpoint->state = WAIT_FOR_SETUP;                endpoint->tx_urb = NULL;                PXA_REGS(UDCCS0, "          <-- xmit stall");                return;        }	/* How much are we sending this time? (May be zero!)           (Note that later call of tx_complete() will add last to sent.) */	if (NULL == urb) {		size = 0;	} else {		endpoint->last = size = MIN (urb->actual_length - endpoint->sent, endpoint->tx_packetSize);	}	/* Will this be a short packet?          (It may be the last, but still be full size, in which case we will need a ZLP later.) */        short_packet = (size < endpoint->tx_packetSize);        PXA_XMIT(size);	if (size > 0 && urb->buffer) {		// Stuff the FIFO                unsigned char *cp = urb->buffer + endpoint->sent;		while (size--) {			UDDRN(0) = *cp++;		}        }        // Is this the end of the data state? (We've sent all the data, plus any required ZLP.)        if (!endpoint->tx_urb || (endpoint->last < endpoint->tx_packetSize)) {		// Tell the UDC we are at the end of the packet.		UDCCS0 = UDCCS0_IPR;                endpoint->state = WAIT_FOR_OUT_STATUS;                PXA_REGS(UDCCS0, "          <-- xmit wait for status");	}        else if ((endpoint->last == endpoint->tx_packetSize) &&                         ((endpoint->last + endpoint->sent) == ep0_urb->actual_length)  &&                        ((ep0_urb->actual_length) < le16_to_cpu(ep0_urb->device_request.wLength))                 )         {		// Tell the UDC we are at the end of the packet.                endpoint->state = DATA_STATE_NEED_ZLP;                PXA_REGS(UDCCS0, "          <-- xmit need zlp");	}        else {                PXA_REGS(UDCCS0, "          <-- xmit not finished");        }}void __inline__ pxa_ep0setup(struct usb_endpoint_instance *endpoint, volatile u32 udccs0){        if ((udccs0 & (UDCCS0_SA | UDCCS0_OPR | UDCCS0_RNE)) == (UDCCS0_SA | UDCCS0_OPR | UDCCS0_RNE)) {                int len = 0;                int max = 8;                unsigned char *cp = (unsigned char *)&ep0_urb->device_request;                PXA_REGS(udccs0, "      --> setup");                //memset(cp, 0, max);                while (max-- /*&& (UDCCS0 & UDCCS0_RNE)*/) {                        len++;                        *cp++ = UDDR0;                }                PXA_SETUP(&ep0_urb->device_request);#ifdef CONFIG_USBD_EP0_SUPPORT/* This section is added to give some supports for setup data IN mode. It is necessary  * to call usbd_recv_setup * routine at end of receiving all data *                           - Stanley */#ifdef EP0_DEBUG		printk( KERN_INFO"URB request:\n" );		printk( KERN_INFO"ep0.bmRequestType: 0x%x\n", ep0_urb->device_request.bmRequestType );		printk( KERN_INFO"ep0.bRequest: 0x%x\n", ep0_urb->device_request.bRequest );		printk( KERN_INFO"ep0.wlength: 0x%x\n", ep0_urb->device_request.wLength );#endif		// Controll Write - Maybe we will receive more data from the host		if ((ep0_urb->device_request.bmRequestType & USB_REQ_DIRECTION_MASK) == USB_REQ_HOST2DEVICE			&& le16_to_cpu(ep0_urb->device_request.wLength)!=0 ) 		{#ifdef EP0_DEBUG			printk("HOST2DEVICE\n");#endif			endpoint->state = DATA_STATE_RECV;			// allocate new memory for such a request;			ep0_urb->buffer = kmalloc( ep0_urb->device_request.wLength, GFP_ATOMIC );			if ( !ep0_urb->buffer ) {				panic("pxa_ep0setup: Out of memory!\n");				return;			}						ep0_urb->buffer_length = ep0_urb->device_request.wLength;			ep0_urb->actual_length = 0;			// the bugs			endpoint->rcv_urb = ep0_urb;                        UDCCS0 = UDCCS0_SA | UDCCS0_OPR;                        PXA_REGS(UDCCS0,"      <-- setup recv");			return;		}#endif                // process setup packet                if (usbd_recv_setup(ep0_urb)) {                        // setup processing failed                         UDCCS0 = UDCCS0_FST;                        endpoint->state = WAIT_FOR_SETUP;                        PXA_REGS(udccs0, "      --> bad setup FST");                        return;                }                // check direction                if ((ep0_urb->device_request.bmRequestType & USB_REQ_DIRECTION_MASK) == USB_REQ_HOST2DEVICE)                 {                        // Control Write - we are receiving more data from the host#ifdef EP0_DEBUG			printk("HOST2DEVICE - zero length\n");#endif                        // should we setup to receive data			// Skip this condition; - Stanley                        if (le16_to_cpu (ep0_urb->device_request.wLength)) {                                //printk(KERN_INFO"sl11_ep0: read data %d\n",                                //      le16_to_cpu(ep0_urb->device_request.wLength));                                endpoint->rcv_urb = ep0_urb;                                endpoint->rcv_urb->actual_length = 0;				endpoint->state = DATA_STATE_RECV;                                // XXX this has not been tested                                // pxa_out_0 (0, endpoint);                                PXA_REGS(UDCCS0,"      <-- setup no response");                                return;                        }                        // allow for premature IN (c.f. 12.5.3 #8)                        UDCCS0 = UDCCS0_IPR;                        PXA_REGS(UDCCS0,"      <-- setup nodata");                }                else {                        // Control Read - we are sending data to the host#ifdef EP0_DEBUG			printk("DEVICE2HOST\n");#endif                        // verify that we have non-zero request length                        if (!le16_to_cpu (ep0_urb->device_request.wLength)) {                                udc_stall_ep (0);                                PXA_REGS(UDCCS0,"      <-- setup stalling zero wLength");                                return;                        }                        // verify that we have non-zero length response                        if (!ep0_urb->actual_length) {                                udc_stall_ep (0);                                PXA_REGS(UDCCS0,"      <-- setup stalling zero response");                                return;                        }                        // start sending                        endpoint->tx_urb = ep0_urb;                        endpoint->sent = 0;                        endpoint->last = 0;                        endpoint->state = DATA_STATE_XMIT;

⌨️ 快捷键说明

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