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

📄 omap.c

📁 Linux2.4.20针对三星公司的s3c2440内核基础上的一些设备驱动代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * linux/drivers/usb/device/bi/omap.c * TI OMAP1510/1610 USB bus interface driver * * Author: MontaVista Software, Inc. *	   source@mvista.com * * 2003 (c) MontaVista Software, Inc. This file is licensed under * the terms of the GNU General Public License version 2. This program * is licensed "as is" without any warranty of any kind, whether express * or implied. */#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 <linux/netdevice.h>#include <linux/delay.h>#include <linux/timer.h>#include <asm/atomic.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/system.h>#include <asm/types.h>#include <asm/uaccess.h>#include <asm/io.h>#include "../usbd.h"#include "../usbd-export.h"#include "../usbd-build.h"#include "../usbd-module.h"#include "../usbd-func.h"#include "../usbd-bus.h"#include "../usbd-inline.h"#include "usbd-bi.h"#include "omap.h"#ifdef CONFIG_OMAP_H2#include <linux/i2c.h>#define ISP1301_I2C_ADDR 0x2D#define ISP1301_I2C_MODE_CONTROL_1 0x4#define ISP1301_I2C_MODE_CONTROL_2 0x12#define ISP1301_I2C_OTG_CONTROL_1 0x6#define ISP1301_I2C_OTG_CONTROL_2 0x10#define ISP1301_I2C_INTERRUPT_SOURCE 0x8#define ISP1301_I2C_INTERRUPT_LATCH 0xA#define ISP1301_I2C_INTERRUPT_FALLING 0xC#define ISP1301_I2C_INTERRUPT_RISING 0xE#define ISP1301_I2C_REG_CLEAR_ADDR 1#define OMAP1610_SET_FUNC_MUX_CTRL(mode,reg,bit) outl((inl(reg)&~(0x7<<bit))|(mode<<bit),reg)#define OMAP1610_CONFIRM_MUX_SETUP() outl(0xeaef,COMP_MODE_CTRL_0)#define open_drain(bit,reg) outl(inl(reg)|(1<<bit),reg)#endifMODULE_AUTHOR("source@mvista.com");MODULE_DESCRIPTION("OMAP1510/1610 Innovator USB Device Bus Interface");MODULE_LICENSE("GPL");USBD_MODULE_INFO("omap_bi 0.0.1");/* Some kind of debugging output... */#if 1#define UDCDBG(args,...)#define UDCREG(name)#define UDCREGL(name)#else				/* The bugs still exists... */#define UDCDBG(args,...) printk("%d: " args "\n", __LINE__, ##__VA_ARGS__)#define UDCREG(name)    UDCDBG("%s [16]: %.4x", (#name), inw(name))	/* For 16-bit regs */#define UDCREGL(name)   UDCDBG("%s [32]: %.8x", (#name), inl(name))	/* For 32-bit regs */#endifstatic struct urb *ep0_urb;static unsigned char usb_address;static struct usb_device_instance *udc_device;	/* Used in interrupt handler */extern unsigned int udc_interrupts;	/* Irqs generated by UDC */static u16 udc_devstat = 0;	/* UDC status (DEVSTAT) */#ifdef CONFIG_USBD_SELFPOWERED#define UDC_SYSCON1_INIT (UDC_Self_Pwr)#else#define UDC_SYSCON1_INIT 0#endif#ifdef CONFIG_OMAP_H2static int i2c_write(u8 buf, u8 subaddr);static struct file *i2c_file;static struct i2c_client *omap_i2c_client;static int initstate_i2c;static int initstate_region;static int initstate_thread;static DECLARE_MUTEX_LOCKED(usbd_connect_lock);static DECLARE_MUTEX(usbd_i2c_lock);static DECLARE_COMPLETION(connect_thread_exit);static int connect_thread_terminating = 0;static char usbd_do_connect = 0;static char usbd_connected = 0;static intusbd_connect_thread(void *data){	daemonize();	reparent_to_init();	strcpy(current->comm, "dpm_usbd_connect");	for (;;) {		down(&usbd_connect_lock);		if (connect_thread_terminating == 1)			break;		down(&usbd_i2c_lock);		if ((usbd_do_connect) && (!usbd_connected)) {			/*enable pull-up resistor on D+ */			i2c_write(0x9, ISP1301_I2C_OTG_CONTROL_1);			i2c_write(~0x9,				  ISP1301_I2C_OTG_CONTROL_1 |				  ISP1301_I2C_REG_CLEAR_ADDR);			usbd_connected = 1;		}		usbd_do_connect = 0;		up(&usbd_i2c_lock);	}	complete_and_exit(&connect_thread_exit, 0);	return 0;}static inti2c_configure(void){	char filename[20];	int tmp;	if (initstate_i2c)		return 0;	/*find the I2C driver we need */	for (tmp = 0; tmp < I2C_ADAP_MAX; tmp++) {#ifdef CONFIG_DEVFS_FS		sprintf(filename, "/dev/i2c/%d", tmp);#else		sprintf(filename, "/dev/i2c-%d", tmp);#endif		if (!IS_ERR(i2c_file = filp_open(filename, O_RDWR, 0))) {			/*found some driver */			omap_i2c_client =			    (struct i2c_client *) i2c_file->private_data;			if (strlen(omap_i2c_client->adapter->name) >= 12) {				if (!memcmp				    (omap_i2c_client->adapter->name,				     "OMAP1610 I2C", 12))					break;	/*we found our driver! */			}			filp_close(i2c_file, NULL);		}	}	if (tmp == I2C_ADAP_MAX) {	/*no matching I2C driver found */		printk(KERN_ERR UDC_NAME ": cannot find OMAP1610 I2C driver\n");		return -ENODEV;	}	initstate_i2c = 1;	return 0;}static voidi2c_close(void){	if (initstate_i2c)		filp_close(i2c_file, NULL);	initstate_i2c = 0;}#if 0static inti2c_read(u8 subaddr){	u8 buf = 0;	if (!i2c_configure()) {		omap_i2c_client->addr = ISP1301_I2C_ADDR;		i2c_master_send(omap_i2c_client, &subaddr, 1);		i2c_master_recv(omap_i2c_client, &buf, 1);	}	return buf;}#endifstatic inti2c_write(u8 buf, u8 subaddr){	char tmpbuf[2];	if (!i2c_configure()) {		omap_i2c_client->addr = ISP1301_I2C_ADDR;		tmpbuf[0] = subaddr;	/*register number */		tmpbuf[1] = buf;	/*register data */		i2c_master_send(omap_i2c_client, &tmpbuf[0], 2);	}	return 0;}static voidisp1301_configure(void){	i2c_write(6, ISP1301_I2C_MODE_CONTROL_1);	i2c_write(~6, ISP1301_I2C_MODE_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR);	i2c_write(4, ISP1301_I2C_MODE_CONTROL_2);	i2c_write(~4, ISP1301_I2C_MODE_CONTROL_2 | ISP1301_I2C_REG_CLEAR_ADDR);	i2c_write(0xFF,		  ISP1301_I2C_INTERRUPT_LATCH | ISP1301_I2C_REG_CLEAR_ADDR);	i2c_write(0xFF,		  ISP1301_I2C_INTERRUPT_FALLING | ISP1301_I2C_REG_CLEAR_ADDR);	i2c_write(0xFF,		  ISP1301_I2C_INTERRUPT_RISING | ISP1301_I2C_REG_CLEAR_ADDR);}#endif#if 0static void__dump_ep(struct usb_endpoint_instance *endpoint){	int n;	printk("ep [addr:%x st:%d sent:%d last:%d tx:%p]\n",	       endpoint->endpoint_address, endpoint->state, endpoint->sent,	       endpoint->last, endpoint->tx_urb);	printk("TX urb contents:\n");	for (n = 0; n < endpoint->tx_urb->actual_length; n++) {		printk(" %.2x", endpoint->tx_urb->buffer[n]);		if (n && (n % 16 == 0))			printk("\n");	}	printk("\n");}#endif/* ************************************************************************** *//* IO *//* * omap_prepare_endpoint_for_rx * * This function implements TRM Figure 14-11. * * The endpoint to prepare for transfer is specified as a physical endpoint * number.  For OUT (rx) endpoints 1 through 15, the corresponding endpoint  * configuration register is checked to see if the endpoint is ISO or not. * If the OUT endpoint is valid and is non-ISO then its FIFO is enabled.   * No action is taken for endpoint 0 or for IN (tx) endpoints 16 through 30. */static voidomap_prepare_endpoint_for_rx(int ep){	int ep_addr = PHYS_EP_TO_EP_ADDR(ep);	int ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK;	unsigned long flags;	if (((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT)	    && (ep_num >= 1) && (ep_num <= 15)) {		if ((inw(UDC_EP_RX(ep_num)) &		     (UDC_EPn_RX_Valid | UDC_EPn_RX_Iso))		    == UDC_EPn_RX_Valid) {			/* rx endpoint is valid, non-ISO, so enable its FIFO */			local_irq_save(flags);			outw(ep_num, UDC_EP_NUM);			outw(UDC_Set_FIFO_En, UDC_CTRL);			local_irq_restore(flags);		}	}}/* omap_configure_endpoints * * This function implements TRM Figure 14-10. */static voidomap_configure_endpoints(struct usb_device_instance *device){	int ep;	struct usb_bus_instance *bus;	struct usb_endpoint_instance *endpoint;	struct usb_bus_driver *driver;	unsigned short ep_ptr;	unsigned short ep_size;	unsigned short ep_isoc;	unsigned short ep_doublebuffer;	int ep_addr;	int packet_size;	int buffer_size;	int attributes;	bus = device->bus;	driver = bus->driver;	/* There is a dedicated 2048 byte buffer for USB packets that may be 	 * arbitrarily partitioned among the endpoints on 8-byte boundaries.  	 * The first 8 bytes are reserved for receiving setup packets on	 * endpoint 0.	 */	ep_ptr = 8;		/* reserve the first 8 bytes for the setup fifo */	for (ep = 0; ep < driver->max_endpoints; ep++) {		endpoint = bus->endpoint_array + ep;		ep_addr = PHYS_EP_TO_EP_ADDR(ep);		if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {			/* IN endpoint */			packet_size = endpoint->tx_packetSize;			attributes = endpoint->tx_attributes;		} else {			/* OUT endpoint */			packet_size = endpoint->rcv_packetSize;			attributes = endpoint->rcv_attributes;		}		switch (packet_size) {		case 0:			ep_size = 0;			break;		case 8:			ep_size = 0;			break;		case 16:			ep_size = 1;			break;		case 32:			ep_size = 2;			break;		case 64:			ep_size = 3;			break;		case 128:			ep_size = 4;			break;		case 256:			ep_size = 5;			break;		case 512:			ep_size = 6;			break;		default:			UDCDBG("ep 0x%02x has bad packet size %d",			       ep_addr, packet_size);			packet_size = 0;			ep_size = 0;			break;		}		switch (attributes & USB_ENDPOINT_XFERTYPE_MASK) {		case USB_ENDPOINT_XFER_CONTROL:		case USB_ENDPOINT_XFER_BULK:		case USB_ENDPOINT_XFER_INT:		default:			/* A non-isochronous endpoint may optionally be			 * double-buffered. For now we disable 			 * double-buffering.			 */			ep_doublebuffer = 0;			ep_isoc = 0;			if (packet_size > 64)				packet_size = 0;			if (!ep || !ep_doublebuffer)				buffer_size = packet_size;			else				buffer_size = packet_size * 2;			break;		case USB_ENDPOINT_XFER_ISOC:			/* Isochronous endpoints are always double-			 * buffered, but the double-buffering bit 			 * in the endpoint configuration register 			 * becomes the msb of the endpoint size so we			 * set the double-buffering flag to zero.			 */			ep_doublebuffer = 0;			ep_isoc = 1;			buffer_size = packet_size * 2;			break;		}		/* check to see if our packet buffer RAM is exhausted */		if ((ep_ptr + buffer_size) > 2048) {			UDCDBG("out of packet RAM for ep 0x%02x buf size %d",			       ep_addr, buffer_size);			buffer_size = packet_size = 0;		}		/* force a default configuration for endpoint 0 since it is 		 * always enabled		 */		if (!ep && ((packet_size < 8) || (packet_size > 64))) {			buffer_size = packet_size = 64;			ep_size = 3;		}		if (!ep) {			/* configure endpoint 0 */			outw((ep_size << 12) | (ep_ptr >> 3), UDC_EP0);			UDCDBG("ep 0 buffer offset 0x%03x packet size 0x%03x",			       ep_ptr, packet_size);		} else if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {			/* IN endpoint */			if (packet_size) {				outw((1 << 15) | (ep_doublebuffer << 14) |				     (ep_size << 12) | (ep_isoc << 11) |				     (ep_ptr >> 3),				     UDC_EP_TX(ep_addr &					       USB_ENDPOINT_NUMBER_MASK));				UDCDBG("IN ep %d buffer offset 0x%03x"				       " packet size 0x%03x",				       ep_addr & USB_ENDPOINT_NUMBER_MASK,				       ep_ptr, packet_size);			} else {				outw(0,				     UDC_EP_TX(ep_addr &					       USB_ENDPOINT_NUMBER_MASK));			}		} else {			/* OUT endpoint */			if (packet_size) {				outw((1 << 15) | (ep_doublebuffer << 14) |				     (ep_size << 12) | (ep_isoc << 11) |				     (ep_ptr >> 3),				     UDC_EP_RX(ep_addr &					       USB_ENDPOINT_NUMBER_MASK));				UDCDBG("OUT ep %d buffer offset 0x%03x"				       " packet size 0x%03x",				       ep_addr & USB_ENDPOINT_NUMBER_MASK,				       ep_ptr, packet_size);			} else {				outw(0,				     UDC_EP_RX(ep_addr &					       USB_ENDPOINT_NUMBER_MASK));			}		}		ep_ptr += buffer_size;	}}/* omap_deconfigure_device * * This function balances omap_configure_device. */static voidomap_deconfigure_device(void){	int epnum;	UDCDBG("clear Cfg_Lock");	outw(inw(UDC_SYSCON1) & ~UDC_Cfg_Lock, UDC_SYSCON1);	UDCREG(UDC_SYSCON1);	/* deconfigure all endpoints */	for (epnum = 1; epnum <= 15; epnum++) {		outw(0, UDC_EP_RX(epnum));		outw(0, UDC_EP_TX(epnum));	}}/* omap_configure_device * * This function implements TRM Figure 14-9. */static voidomap_configure_device(struct usb_device_instance *device){	omap_configure_endpoints(device);	/* Figure 14-9 indicates we should enable interrupts here, but we have	 * other routines (udc_all_interrupts, udc_suspended_interrupts) to	 * do that.	 */	UDCDBG("set Cfg_Lock");	outw(inw(UDC_SYSCON1) | UDC_Cfg_Lock, UDC_SYSCON1);	UDCREG(UDC_SYSCON1);}/* omap_write_noniso_tx_fifo * * This function implements TRM Figure 14-30. * * If the endpoint has an active tx_urb, then the next packet of data from the * URB is written to the tx FIFO.  The total amount of data in the urb is given  * by urb->actual_length.  The maximum amount of data that can be sent in any * one packet is given by endpoint->tx_packetSize.  The number of data bytes * from this URB that have already been transmitted is given by endpoint->sent. * endpoint->last is updated by this routine with the number of data bytes  * transmitted in this packet. * * In accordance with Figure 14-30, the EP_NUM register must already have been * written with the value to select the appropriate tx FIFO before this routine  * is called. */static voidomap_write_noniso_tx_fifo(struct usb_endpoint_instance *endpoint){	struct urb *urb = endpoint->tx_urb;	if (urb) {		int last;		if ((last = MIN(urb->actual_length - endpoint->sent,				endpoint->tx_packetSize))) {			unsigned char *cp = urb->buffer + endpoint->sent;			outsw(UDC_DATA, cp, last >> 1);			if (last & 1)				outb(*(cp + last - 1), UDC_DATA);		}		endpoint->last = last;	}

⌨️ 快捷键说明

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