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

📄 usbdev.c

📁 microwindows移植到S3C44B0的源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * BRIEF MODULE DESCRIPTION *	Au1000 USB Device-Side Serial TTY Driver * * Copyright 2001 MontaVista Software Inc. * Author: MontaVista Software, Inc. *		stevel@mvista.com or source@mvista.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  SOFTWARE  IS PROVIDED	  ``AS	IS'' AND   ANY	EXPRESS OR IMPLIED *  WARRANTIES,	  INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN *  NO	EVENT  SHALL   THE AUTHOR  BE	 LIABLE FOR ANY	  DIRECT, INDIRECT, *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT *  NOT LIMITED	  TO, PROCUREMENT OF  SUBSTITUTE GOODS	OR SERVICES; LOSS OF *  USE, DATA,	OR PROFITS; OR	BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON *  ANY THEORY OF LIABILITY, WHETHER IN	 CONTRACT, STRICT LIABILITY, OR TORT *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *  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. */#include <linux/config.h>#include <linux/kernel.h>#include <linux/ioport.h>#include <linux/sched.h>#include <linux/signal.h>#include <linux/errno.h>#include <linux/poll.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/fcntl.h>#include <linux/tty.h>#include <linux/tty_driver.h>#include <linux/tty_flip.h>#include <linux/module.h>#include <linux/spinlock.h>#include <linux/list.h>#include <linux/smp_lock.h>#define DEBUG#include <linux/usb.h>#include <asm/io.h>#include <asm/uaccess.h>#include <asm/irq.h>#include <asm/mipsregs.h>#include <asm/au1000.h>#include <asm/au1000_dma.h>/* Module information */MODULE_AUTHOR("Steve Longerbeam, stevel@mvista.com, www.mvista.com");MODULE_DESCRIPTION("Au1000 USB Device-Side Serial TTY Driver");#undef USBDEV_PIO#define SERIAL_TTY_MAJOR 189#define MAX(a,b)	(((a)>(b))?(a):(b))#define ALLOC_FLAGS (in_interrupt () ? GFP_ATOMIC : GFP_KERNEL)#define MAX_NUM_PORTS 2#define NUM_PORTS 1#define NUM_EP 2*NUM_PORTS#define EP0_MAX_PACKET_SIZE 64#define EP2_MAX_PACKET_SIZE 64#define EP3_MAX_PACKET_SIZE 64#define EP4_MAX_PACKET_SIZE 64#define EP5_MAX_PACKET_SIZE 64#ifdef USBDEV_PIO#define EP_FIFO_DEPTH 8#endiftypedef enum {	ATTACHED = 0,	POWERED,	DEFAULT,	ADDRESS,	CONFIGURED} dev_state_t;/* local function prototypes */static int serial_open(struct tty_struct *tty, struct file *filp);static void serial_close(struct tty_struct *tty, struct file *filp);static int serial_write(struct tty_struct *tty, int from_user,			const unsigned char *buf, int count);static int serial_write_room(struct tty_struct *tty);static int serial_chars_in_buffer(struct tty_struct *tty);static void serial_throttle(struct tty_struct *tty);static void serial_unthrottle(struct tty_struct *tty);static int serial_ioctl(struct tty_struct *tty, struct file *file,			unsigned int cmd, unsigned long arg);static void serial_set_termios (struct tty_struct *tty, struct termios * old);typedef struct {	int read_fifo;	int write_fifo;	int ctrl_stat;	int read_fifo_status;	int write_fifo_status;} endpoint_reg_t;typedef struct pkt {	int size;	u8 *bufptr;	struct pkt *next;	u8 buf[0];} pkt_t;typedef struct {	pkt_t *head;	pkt_t *tail;	int count;} pkt_list_t;typedef struct {	struct usb_endpoint_descriptor *desc;	endpoint_reg_t *reg;	// Only one of these are used, unless this is a control ep	pkt_list_t inlist;	pkt_list_t outlist;	unsigned int indma, outdma;	// DMA channel numbers for IN, OUT	int inirq, outirq;	// DMA buffer done irq numbers	int max_pkt_size;	spinlock_t lock;} endpoint_t;struct usb_serial_port {	struct usb_serial *serial;	/* ptr back to the owner of this port */	struct tty_struct *tty;	/* the coresponding tty for this port */	unsigned char number;	char active;		/* someone has this device open */	spinlock_t port_lock;	endpoint_t ep_bulkin;	endpoint_t ep_bulkout;	wait_queue_head_t write_wait;	/* task queue for line discipline waking up on send packet complete */	struct tq_struct send_complete_tq;	/* task queue for line discipline wakeup on receive packet complete */	struct tq_struct receive_complete_tq;	int open_count;		/* number of times this port has been opened */};struct usb_serial {	struct tty_driver *tty_driver;	/* the tty_driver for this device */	unsigned char minor;	/* the minor number for this device */	endpoint_t ep_ctrl;	struct usb_device_descriptor *dev_desc;	struct usb_interface_descriptor *if_desc;	struct usb_config_descriptor *conf_desc;	struct usb_string_descriptor *str_desc[6];	struct usb_serial_port port[NUM_PORTS];	dev_state_t state;	// device state	int suspended;		// suspended flag	int address;		// device address	int interface;	u8 alternate_setting;	u8 configuration;	// configuration value	int remote_wakeup_en;};static struct usb_device_descriptor dev_desc = {	bLength:USB_DT_DEVICE_SIZE,	bDescriptorType:USB_DT_DEVICE,	bcdUSB:0x0110,		//usb rev 1.0	bDeviceClass:USB_CLASS_PER_INTERFACE,	//class    (none)	bDeviceSubClass:0x00,	//subclass (none)	bDeviceProtocol:0x00,	//protocol (none)	bMaxPacketSize0:EP0_MAX_PACKET_SIZE,	//max packet size for ep0	idVendor:0x6d04,	//vendor  id	idProduct:0x0bc0,	//product id	bcdDevice:0x0001,	//BCD rev 0.1	iManufacturer:0x01,	//manufactuer string index	iProduct:0x02,		//product string index	iSerialNumber:0x03,	//serial# string index	bNumConfigurations:0x01	//num configurations};static struct usb_endpoint_descriptor ep_desc[] = {	{	 // EP2, Bulk IN for Port 0	      bLength:USB_DT_ENDPOINT_SIZE,	      bDescriptorType:USB_DT_ENDPOINT,	      bEndpointAddress:USB_DIR_IN | 0x02,	      bmAttributes:USB_ENDPOINT_XFER_BULK,	      wMaxPacketSize:EP2_MAX_PACKET_SIZE,	      bInterval:0x00	// ignored for bulk	 },	{	 // EP4, Bulk OUT for Port 0	      bLength:USB_DT_ENDPOINT_SIZE,	      bDescriptorType:USB_DT_ENDPOINT,	      bEndpointAddress:USB_DIR_OUT | 0x04,	      bmAttributes:USB_ENDPOINT_XFER_BULK,	      wMaxPacketSize:EP4_MAX_PACKET_SIZE,	      bInterval:0x00	// ignored for bulk	 },	{	 // EP3, Bulk IN for Port 1	      bLength:USB_DT_ENDPOINT_SIZE,	      bDescriptorType:USB_DT_ENDPOINT,	      bEndpointAddress:USB_DIR_IN | 0x03,	      bmAttributes:USB_ENDPOINT_XFER_BULK,	      wMaxPacketSize:EP3_MAX_PACKET_SIZE,	      bInterval:0x00	// ignored for bulk	 },	{	 // EP5, Bulk OUT for Port 1	      bLength:USB_DT_ENDPOINT_SIZE,	      bDescriptorType:USB_DT_ENDPOINT,	      bEndpointAddress:USB_DIR_OUT | 0x05,	      bmAttributes:USB_ENDPOINT_XFER_BULK,	      wMaxPacketSize:EP5_MAX_PACKET_SIZE,	      bInterval:0x00	// ignored for bulk	 },};static struct usb_interface_descriptor if_desc = {	bLength:USB_DT_INTERFACE_SIZE,	bDescriptorType:USB_DT_INTERFACE,	bInterfaceNumber:0x00,	bAlternateSetting:0x00,	bNumEndpoints:NUM_EP,	bInterfaceClass:0xff,	bInterfaceSubClass:0xab,	bInterfaceProtocol:0x00,	iInterface:0x05};#define CONFIG_DESC_LEN \ USB_DT_CONFIG_SIZE + USB_DT_INTERFACE_SIZE + NUM_EP*USB_DT_ENDPOINT_SIZEstatic struct usb_config_descriptor config_desc = {	bLength:USB_DT_CONFIG_SIZE,	bDescriptorType:USB_DT_CONFIG,	wTotalLength:CONFIG_DESC_LEN,	bNumInterfaces:0x01,	bConfigurationValue:0x01,	iConfiguration:0x04,	// configuration string	bmAttributes:0xc0,	// self-powered	MaxPower:20		// 40 mA};// These strings will be converted to Unicode before sendingstatic char *strings[5] = {	"Alchemy Semiconductor",	"Alchemy Au1000",	"1.0",	"Au1000 UART Config",	"Au1000 UART Interface"};// String[0] is a list of Language IDs supported by this devicestatic struct usb_string_descriptor string_desc0 = {	bLength:4,	bDescriptorType:USB_DT_STRING,	wData:{0x0409}		// English, US};static endpoint_reg_t ep_reg[] = {	// FIFO's 0 and 1 are EP0 default control	{USBD_EP0RD, USBD_EP0WR, USBD_EP0CS, USBD_EP0RDSTAT, USBD_EP0WRSTAT},	// FIFO 2 is EP2, Port 0, bulk IN	{ -1, USBD_EP2WR, USBD_EP2CS, -1, USBD_EP2WRSTAT },	// FIFO 4 is EP4, Port 0, bulk OUT	    {USBD_EP4RD, -1, USBD_EP4CS, USBD_EP3WR, -1},	// FIFO 3 is EP3, Port 1, bulk IN	{ -1, USBD_EP3WRSTAT, USBD_EP3CS, -1, USBD_EP3WRSTAT },	// FIFO 5 is EP5, Port 1, bulk OUT	    {USBD_EP5RD, -1, USBD_EP5CS, USBD_EP5RDSTAT, -1}};static struct {	unsigned int id;	const char *str;} ep_dma_id[] = {	{ DMA_ID_USBDEV_EP0_TX, "USBDev EP0 IN" },	{ DMA_ID_USBDEV_EP0_RX, "USBDev EP0 OUT" },	{ DMA_ID_USBDEV_EP2_TX, "USBDev EP2 IN" },	{ DMA_ID_USBDEV_EP4_RX, "USBDev EP4 OUT" },	{ DMA_ID_USBDEV_EP3_TX, "USBDev EP3 IN" },	{ DMA_ID_USBDEV_EP5_RX, "USBDev EP5 OUT" }};static int serial_refcount;static struct tty_driver serial_tty_driver;static struct tty_struct *serial_tty[1];static struct termios *serial_termios[1];static struct termios *serial_termios_locked[1];static struct usb_serial usbserial;#define DIR_OUT 0#define DIR_IN  (1<<3)static const u32 au1000_config_table[25] __devinitdata = {	0x00,	    ((EP0_MAX_PACKET_SIZE & 0x380) >> 7) |	    (USB_ENDPOINT_XFER_CONTROL << 4),	(EP0_MAX_PACKET_SIZE & 0x7f) << 1,	0x00,	0x01,	0x10,	    ((EP2_MAX_PACKET_SIZE & 0x380) >> 7) | DIR_IN |	    (USB_ENDPOINT_XFER_BULK << 4),	(EP2_MAX_PACKET_SIZE & 0x7f) << 1,	0x00,	0x02,	0x20,	    ((EP3_MAX_PACKET_SIZE & 0x380) >> 7) | DIR_IN |	    (USB_ENDPOINT_XFER_BULK << 4),	(EP3_MAX_PACKET_SIZE & 0x7f) << 1,	0x00,	0x03,	0x30,	    ((EP4_MAX_PACKET_SIZE & 0x380) >> 7) | DIR_OUT |	    (USB_ENDPOINT_XFER_BULK << 4),	(EP4_MAX_PACKET_SIZE & 0x7f) << 1,	0x00,	0x04,	0x40,	    ((EP5_MAX_PACKET_SIZE & 0x380) >> 7) | DIR_OUT |	    (USB_ENDPOINT_XFER_BULK << 4),	(EP5_MAX_PACKET_SIZE & 0x7f) << 1,	0x00,	0x05};static inline endpoint_t *fifonum_to_ep(struct usb_serial* serial, int fifo_num){	switch (fifo_num) {	case 0:	case 1:		return &serial->ep_ctrl;	case 2:		return &serial->port[0].ep_bulkin;	case 3:		return &serial->port[1].ep_bulkin;	case 4:		return &serial->port[0].ep_bulkout;	case 5:		return &serial->port[1].ep_bulkout;	}	return NULL;}static inline struct usb_serial_port *fifonum_to_port(struct usb_serial* serial, int fifo_num){	switch (fifo_num) {	case 2:	case 4:		return &serial->port[0];	case 3:	case 5:		return &serial->port[1];	}	return NULL;}static inline endpoint_t *epnum_to_ep(struct usb_serial* serial, int ep_num){	switch (ep_num) {	case 0:		return &serial->ep_ctrl;	case 2:		return &serial->port[0].ep_bulkin;	case 3:		return &serial->port[1].ep_bulkin;	case 4:		return &serial->port[0].ep_bulkout;	case 5:		return &serial->port[1].ep_bulkout;	}	return NULL;}static inline intport_paranoia_check(struct usb_serial_port *port, const char *function){	if (!port) {		dbg("%s - port == NULL", function);		return -1;	}	if (!port->serial) {		dbg("%s - port->serial == NULL", function);		return -1;	}	if (!port->tty) {		dbg("%s - port->tty == NULL", function);		return -1;	}	return 0;}static inline struct usb_serial*get_usb_serial (struct usb_serial_port *port, const char *function){	/* if no port was specified, or it fails a paranoia check */	if (!port || port_paranoia_check(port, function)) {		/* then say that we dont have a valid usb_serial thing,		 * which will end up genrating -ENODEV return values */		return NULL;	}	return port->serial;}static inline pkt_t *alloc_packet(int data_size){	pkt_t* pkt = (pkt_t *)kmalloc(sizeof(pkt_t) + data_size, ALLOC_FLAGS);	if (!pkt)		return NULL;	pkt->size = data_size;	pkt->bufptr = pkt->buf;#ifndef USBDEV_PIO	pkt->bufptr = KSEG1ADDR(pkt->bufptr);#endif	pkt->next = NULL;	return pkt;}/* * Link a packet to the tail of the enpoint's packet list. */static voidlink_packet(endpoint_t * ep, pkt_list_t * list, pkt_t * pkt){	unsigned long flags;	spin_lock_irqsave(&ep->lock, flags);	if (!list->tail) {		list->head = list->tail = pkt;		list->count = 1;	} else {		list->tail->next = pkt;		list->tail = pkt;		list->count++;	}	spin_unlock_irqrestore(&ep->lock, flags);}/* * Unlink and return a packet from the head of the enpoint's packet list. */static pkt_t *unlink_packet(endpoint_t * ep, pkt_list_t * list){	unsigned long flags;	pkt_t *pkt;	spin_lock_irqsave(&ep->lock, flags);	pkt = list->head;	if (!pkt || !list->count) {		spin_unlock_irqrestore(&ep->lock, flags);		return NULL;	}	list->head = pkt->next;	if (!list->head) {		list->head = list->tail = NULL;		list->count = 0;	} else		list->count--;	spin_unlock_irqrestore(&ep->lock, flags);	return pkt;}/* * Create and attach a new packet to the tail of the enpoint's * packet list. */static pkt_t *add_packet(endpoint_t * ep, pkt_list_t * list, int size){	pkt_t *pkt = alloc_packet(size);	if (!pkt)		return NULL;	link_packet(ep, list, pkt);	return pkt;}/* * Unlink and free a packet from the head of the enpoint's * packet list. */static inline voidfree_packet(endpoint_t * ep, pkt_list_t * list){	kfree(unlink_packet(ep, list));}static inline voidflush_pkt_list(endpoint_t * ep, pkt_list_t * list){	while (list->count)		free_packet(ep, list);}static inline voidflush_write_fifo(endpoint_t * ep){	if (ep->reg->write_fifo_status >= 0) {		outl_sync(USBDEV_FSTAT_FLUSH, ep->reg->write_fifo_status);		udelay(100);		outl_sync(USBDEV_FSTAT_UF | USBDEV_FSTAT_OF,			  ep->reg->write_fifo_status);	}}static inline voidflush_read_fifo(endpoint_t * ep){	if (ep->reg->read_fifo_status >= 0) {		outl_sync(USBDEV_FSTAT_FLUSH, ep->reg->read_fifo_status);		udelay(100);		outl_sync(USBDEV_FSTAT_UF | USBDEV_FSTAT_OF,			  ep->reg->read_fifo_status);	}}static voidendpoint_flush(endpoint_t * ep){	unsigned long flags;	spin_lock_irqsave(&ep->lock, flags);	// First, flush all packets	flush_pkt_list(ep, &ep->inlist);	flush_pkt_list(ep, &ep->outlist);	// Now flush the endpoint's h/w FIFO(s)	flush_write_fifo(ep);	flush_read_fifo(ep);	spin_unlock_irqrestore(&ep->lock, flags);}static voidendpoint_stall(endpoint_t * ep){	unsigned long flags;	u32 cs;	dbg(__FUNCTION__);	spin_lock_irqsave(&ep->lock, flags);	cs = inl(ep->reg->ctrl_stat) | USBDEV_CS_STALL;	outl_sync(cs, ep->reg->ctrl_stat);	spin_unlock_irqrestore(&ep->lock, flags);}static voidendpoint_unstall(endpoint_t * ep){	unsigned long flags;	u32 cs;	dbg(__FUNCTION__);	spin_lock_irqsave(&ep->lock, flags);	cs = inl(ep->reg->ctrl_stat) & ~USBDEV_CS_STALL;	outl_sync(cs, ep->reg->ctrl_stat);	spin_unlock_irqrestore(&ep->lock, flags);}

⌨️ 快捷键说明

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