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

📄 l7205.c

📁 Linux2.4.20针对三星公司的s3c2440内核基础上的一些设备驱动代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * linux/drivers/usbd/l7205_bi/udc.c -- L7205 USB controller driver.  * * Copyright (c) 2000, 2001, 2002 Lineo * * By:  *      Stuart Lynne <sl@lineo.com>,  *      Tom Rushworth <tbr@lineo.com>,  *      Bruce Balden <balden@lineo.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */// Debug enabling defines//#define TRIGGER       1//#define FLAG_F1ERR    1// End of debug enabling defines#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/slab.h>#include <linux/interrupt.h>#include <linux/pci.h>#include <linux/init.h>#include <asm/atomic.h>#include <asm/io.h>#include <linux/proc_fs.h>#include <linux/tqueue.h>#include <linux/netdevice.h>#include <linux/version.h>#include <linux/pci.h>#include <linux/cache.h>#include <asm/dma.h>#include <asm/mach/dma.h>#include <asm/irq.h>#include <asm/system.h>#include <asm/hardware.h>#include <asm/types.h>#include <asm/uaccess.h>#include <asm/io.h>#include <asm/pgtable.h>#include <asm/pgalloc.h>#include <linux/delay.h>#include "../usbd.h"#include "../usbd-func.h"#include "../usbd-bus.h"#include "../usbd-inline.h"#include "usbd-bi.h"#ifdef CONFIG_IRIS#include <asm/arch/hardware.h>#include <asm/arch/gpio.h>#include <asm/arch/fpga.h>#include <asm/arch/iris_serialno.h>#endif#include "hardware.h"#include "l7205.h"#include "udc.h"int sof_saw_tx_active;int sof_saw_rx_f1ne;		// track if we have seen F1NE at SOFint host_sus_interrupt_disabled;	// set if SUS interrupt received and disabled, waiting for SOFint host_reset_interrupt_disabled;	// set if HRST interrupt received and disabled, waiting for SOFint ep2_active;			// set if transmit on ep2 is active, used to track missing interruptsextern unsigned int udc_interrupts;extern unsigned int udc_interrupts_last;static struct usb_device_instance *udc_device;	// for interrupt handlerstruct usb_device_instance *ep1_device;struct usb_endpoint_instance *ep1_endpoint;#ifdef CONFIG_IRIS#define USB_PULLUP_GPIO bitPB6// USB pullup resistor control.// USB cable and AC power connect statusextern int iris_read_usb_sync (void);extern int iris_read_ac_sync (void);extern void iris_AUXPLL_ON_for_usb (void);extern void iris_AUXPLL_OFF_for_usb (void);#endif/* * ep_endpoints - map physical endpoints to logical endpoints */static struct usb_endpoint_instance *ep_endpoints[UDC_MAX_ENDPOINTS];struct usb_device_instance *ep2_device;struct usb_endpoint_instance *ep2_endpoint;#define MIN(a,b) ((a)<(b))?(a):(b)/* ep1 functions ******************************************************************************* *//** * ep1_clear * * Clear ep1 fifo by reading all data and resetting F1BCNT to 32 */static /* __inline__ */ void ep1_clear (void){	int j;	volatile unsigned long junk;	for (j = 0; j < 8; j++) {		junk = IO_USBF_FIFO1;	}	IO_USBF_F1BCNT = 32;}/* * Endpoint 1 interrupts will be directed here. * */static __inline__ void ep1_int_hndlr (void){	if (ep1_endpoint) {		if (!ep1_endpoint->rcv_urb) {			ep1_endpoint->rcv_urb = first_urb_detached (&ep1_endpoint->rdy);			// XXX could we call usbd_fill_rcv() here?		}		if (ep1_endpoint->rcv_urb) {			int len = IO_USBF_F1BCNT;			unsigned long *lp =			    (unsigned long *) (ep1_endpoint->rcv_urb->buffer +					       ep1_endpoint->rcv_urb->actual_length);			// copy 4 bytes at a time, fetching more than available seems ok, use unrolled loop			lp[0] = IO_USBF_FIFO1;			lp[1] = IO_USBF_FIFO1;			lp[2] = IO_USBF_FIFO1;			lp[3] = IO_USBF_FIFO1;			lp[4] = IO_USBF_FIFO1;			lp[5] = IO_USBF_FIFO1;			lp[6] = IO_USBF_FIFO1;			lp[7] = IO_USBF_FIFO1;			usbd_rcv_complete_irq (ep1_endpoint, len, 0);			// reset F1BCNT			IO_USBF_F1BCNT = 32;			return;		}		// fall through if error of any type		usbd_rcv_complete_irq (ep1_endpoint, 0, 0);	}	ep1_clear ();}/* * Endpoint 1 interrupts will be directed here if there was an error. * */void ep1_int_hndlr_error (void){#if 1	int i;	volatile unsigned char *cp = (volatile unsigned char *) IO_USBF_FIFO_RX;	printk (KERN_DEBUG "ep1_int_hndlr: ERROR ");	for (i = 0; i < 32; i++) {		printk ("%02x ", cp[i]);	}	printk ("\n");#endif	if (ep1_endpoint) {		usbd_rcv_complete_irq (ep1_endpoint, 0, 0);	}	ep1_clear ();}/* ep2 functions ******************************************************************************* */static int __inline__ ep2_fill (unsigned char *cp, int len, int delay){	unsigned long *buf = (unsigned long *) cp;	volatile unsigned long *p2 = (volatile unsigned long *) IO_USBF_FIFO_TX;	// unrolled loop to fill fifo	IO_USBF_FIFO2 = buf[0];	IO_USBF_FIFO2 = buf[1];	IO_USBF_FIFO2 = buf[2];	IO_USBF_FIFO2 = buf[3];	IO_USBF_FIFO2 = buf[4];	IO_USBF_FIFO2 = buf[5];	IO_USBF_FIFO2 = buf[6];	IO_USBF_FIFO2 = buf[7];	if ((buf[0] != p2[0]) || (buf[1] != p2[1]) || (buf[2] != p2[2]) || (buf[3] != p2[3]) ||	    (buf[4] != p2[4]) || (buf[5] != p2[5]) || (buf[6] != p2[6]) || (buf[7] != p2[7])) {		udelay (8);	// 		// reset fifo read pointer		l7205_toggle (IO_USBF_CONTROL, USBF_CONTROL_F2CLR);		// unrolled loop to fill fifo		IO_USBF_FIFO2 = buf[0];		IO_USBF_FIFO2 = buf[1];		IO_USBF_FIFO2 = buf[2];		IO_USBF_FIFO2 = buf[3];		IO_USBF_FIFO2 = buf[4];		IO_USBF_FIFO2 = buf[5];		IO_USBF_FIFO2 = buf[6];		IO_USBF_FIFO2 = buf[7];		return (buf[0] != p2[0]) || (buf[1] != p2[1]) || (buf[2] != p2[2])		    || (buf[3] != p2[3]) || (buf[4] != p2[4]) || (buf[5] != p2[5])		    || (buf[6] != p2[6]) || (buf[7] != p2[7]);	}	return 0;}/** * ep2_start * * Fill ep2 fifo with data. */static void ep2_start (void){	int len;	if (ep2_endpoint->tx_urb &&	    (len = MIN ((ep2_endpoint->tx_urb->actual_length - ep2_endpoint->sent),			ep2_endpoint->tx_urb->endpoint->tx_packetSize))) {		ep2_active = 1;		// fill the FIFO, if this fails send a short packet to end of this		// attempt of the BULK transfer and force the restart of this urb at		// th beginning, the host will see a CRC error and drop the		// intermediate results		if (ep2_fill (ep2_endpoint->tx_urb->buffer + ep2_endpoint->sent, len, 0)) {			// ep2_fill failed, reset bulk transfer and decrement len to			// send current usb packet one byte short to guarantee host will			// terminate bulk transfer and it will fail CRC check			IO_USBF_F2BCNT = len - 1;			ep2_endpoint->last = ep2_endpoint->sent = 0;		} else {			ep2_endpoint->last = IO_USBF_F2BCNT = len;		}	} else {		ep2_active = 0;	}}/** * ep2_int_hndlr - transmit interrupt handler, fast version */static __inline__ void ep2_int_hndlr (unsigned int status){	// if we have active buffer, umap the buffer and update position if previous send was successful	if (!(status & (USBF_STATUS_F2ERR | USBF_STATUS_F2BSY))) {		if (ep2_endpoint->tx_urb) {			ep2_endpoint->sent += ep2_endpoint->last;			ep2_endpoint->last = 0;			// if current buffer is finished call urb sent and advance to next urb 			if ((ep2_endpoint->tx_urb->actual_length - ep2_endpoint->sent) <= 0) {				usbd_urb_sent_irq (ep2_endpoint->tx_urb, SEND_FINISHED_OK);				ep2_endpoint->tx_urb = NULL;			}			ep2_start ();		}	}}/** * ep2_int_hndlr_error - transmit interrupt handler, slow version */static void ep2_int_hndlr_error (unsigned int status, int error, int skip){	if (!skip) {		if ((status & (USBF_STATUS_F2ERR | USBF_STATUS_F2BSY | USBF_STATUS_F2NE)) || error) {			if (!(status & USBF_STATUS_F2BSY)) {				dbg_tx (0, "[%d]: F2ERR %08lx", udc_interrupts, IO_USBF_STATUS);				l7205_toggle (IO_USBF_CONTROL, USBF_CONTROL_F2CLR);			}		} else {			ep2_int_hndlr (status);		}	}}/* * l7205 */void l7205_dump_fifos (char *msg, int max){	int i;	dbg_udc (9, " ");	dbg_udc (9, "*********** %s ***********", msg);	if (7 <= dbgflg_usbdbi_udc) {		for (i = 0; i < max; i++) {			if ((i % 32) == 0) {				printk ("\nFF[%02x]: ", i);			}			printk ("%02x ", __IOB (USBF_FIFOS + i));		}		printk ("\n");	}}void l7205_regs (char *msg){	if (1 <= dbgflg_usbdbi_udc) {		int i;		printk (KERN_DEBUG "\n");		printk (KERN_DEBUG "*********** %s ***********\n", msg);		printk (KERN_DEBUG "\n");		printk (KERN_DEBUG "udc: Rev:  %08lx Ctl:  %08lx Sts:  %08lx\n",			IO_USBF_REVISION, IO_USBF_CONTROL, IO_USBF_STATUS);		printk (KERN_DEBUG "udc: IntE: %08lx IntD: %08lx Ep0:  %08lx\n",			IO_USBF_INTENA, IO_USBF_INTDIS, IO_USBF_ENDPTBUF0);		printk (KERN_DEBUG "udc: Ep1:  %08lx Ep2:  %08lx Ep3:  %08lx\n",			IO_USBF_ENDPTBUF1, IO_USBF_ENDPTBUF2, IO_USBF_ENDPTBUF3);		printk (KERN_DEBUG "udc: CFG:  %08lx ST0:  %08lx ST1:  %08lx\n",			IO_USBF_CONFIGBUF1, IO_USBF_STRINGBUF0, IO_USBF_STRINGBUF1);		printk (KERN_DEBUG "udc: ST2:  %08lx ST3:  %08lx ST4:  %08lx\n",			IO_USBF_STRINGBUF2, IO_USBF_STRINGBUF3, IO_USBF_STRINGBUF4);		printk (KERN_DEBUG "\n");		printk (KERN_DEBUG "CLK ENA: %08lx AUX: %08lx SEL: %08lx\n",			IO_SYS_CLOCK_ENABLE, IO_SYS_CLOCK_AUX, IO_SYS_CLOCK_SELECT);		printk (KERN_DEBUG "\n");		printk (KERN_DEBUG			"udc: CFG:  %02lx:%02lx    ST0:  %02lx:%02lx    ST1:  %02lx:%02lx\n",			__IOL (USBF_CONFIGBUF1) >> 9, __IOL (USBF_CONFIGBUF1) & 0x1ff,			__IOL (USBF_STRINGBUF0) >> 9, __IOL (USBF_STRINGBUF0) & 0x1ff,			__IOL (USBF_STRINGBUF1) >> 9, __IOL (USBF_STRINGBUF1) & 0x1ff);		printk (KERN_DEBUG			"udc: ST2:  %02lx:%02lx    ST3:  %02lx:%02lx    ST4:  %02lx:%02lx\n",			__IOL (USBF_STRINGBUF2) >> 9, __IOL (USBF_STRINGBUF2) & 0x1ff,			__IOL (USBF_STRINGBUF3) >> 9, __IOL (USBF_STRINGBUF3) & 0x1ff,			__IOL (USBF_STRINGBUF4) >> 9, __IOL (USBF_STRINGBUF4) & 0x1ff);		for (i = 0; i < 168; i++) {			if ((i % 32) == 0) {				printk ("\nDS[%02x]: ", i);			}			printk ("%02x ", __IOB (USBF_DESCRIPTORS + i));		}		printk ("\n");		printk ("\n");	}}void udc_regs (void){	if (1 <= dbgflg_usbdbi_tick) {		printk (KERN_DEBUG			"%u Ctl: %08lx Sts: %08lx Raw: %08lx Ena: %08lx EP0: %08lx EP1: %08lx EP2: %08lx "			"int: %2d\n",			udc_interrupts,			IO_USBF_CONTROL, IO_USBF_STATUS, IO_USBF_RAWSTATUS, IO_USBF_INTENA,			IO_USBF_F0BCNT, IO_USBF_F1BCNT, IO_USBF_F2BCNT,			udc_interrupts - udc_interrupts_last);		udc_interrupts_last = udc_interrupts;	}}/* * l7205_copy_descriptor * * Copy descriptor to shared SRAM and optionally set descriptor register to point * to where it is located. * * Note that reg CAN be NULL (there is no device descriptor register it is  * always at zero offset) */static int l7205_copy_descriptor (unsigned char *descriptors, volatile unsigned long reg,				  int offset, struct usb_descriptor *descriptor, int size){	// set default 	if (reg) {		__IOL (reg) = 0;	}	if (!descriptors || !descriptor) {		return offset;	}	if (!size) {		if (!(size = descriptor->descriptor.generic.bLength)) {			return offset;		}	}	if (((offset + size) >= (USBF_DESCRIPTORS_MAX - 4))) {		dbg_udc (0, "string too large to copy: offset: %x size: %d", offset, size);		if (reg) {			__IOL (reg) = (4 << 9) | (USBF_DESCRIPTORS_MAX - 4);		}		descriptors[USBF_DESCRIPTORS_MAX - 4] = 4;		descriptors[USBF_DESCRIPTORS_MAX - 3] = 3;		descriptors[USBF_DESCRIPTORS_MAX - 2] = 'A';		descriptors[USBF_DESCRIPTORS_MAX - 1] = 0;		return offset;	}	dbg_udc (3, "reg: %08lx offset: %02x descriptor: %p size: %02x", reg, offset, descriptor,		 size);	// set size and offset if we have a register	if (reg) {		__IOL (reg) = (size << 9) | offset;		dbg_udc (3, "reg: %8lx %8lx size: %2lx off: %2lx", reg, __IOL (reg),			 __IOL (reg) >> 9, __IOL (reg) & 0x1ff);	}	memcpy (descriptors + offset, descriptor, size);	return (offset + size + 3) & 0x1fc;	// 4}static int l7205_copy_request (unsigned char *descriptors, struct usb_device_instance *device,			       volatile unsigned long reg, int offset, int request){	struct urb *udc_urb;	usb_device_state_t device_state;	/*	 * fake a setup request to get descriptors	 */	if (!device || !(udc_urb = usbd_alloc_urb (device, NULL, 0, 512))) {		dbg_udc (0, "cannot alloc urb");		return offset;	}	udc_urb->device_request.bmRequestType = 0x80;	udc_urb->device_request.bRequest = USB_REQ_GET_DESCRIPTOR;	udc_urb->device_request.wValue = cpu_to_le16 ((request << 8));	udc_urb->device_request.wLength = cpu_to_le16 (200);	// max 168?	device_state = device->device_state;	device->device_state = STATE_ADDRESSED;	if (usbd_recv_setup (udc_urb)) {		dbg_udc (0, "cannot process setup request");		usbd_dealloc_urb (udc_urb);		return offset;	}	device->device_state = device_state;	offset =	    l7205_copy_descriptor (descriptors, reg, offset,				   (struct usb_descriptor *) udc_urb->buffer,				   udc_urb->actual_length);	usbd_dealloc_urb (udc_urb);	return offset;}/** * udc_init - initialize L7205 USB Controller * 

⌨️ 快捷键说明

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