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

📄 usb-host.c

📁 linux-2.4.29操作系统的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * usb-host.c: ETRAX 100LX USB Host Controller Driver (HCD) * * Copyright (c) 2002, 2003 Axis Communications AB. */#include <linux/config.h>#include <linux/kernel.h>#include <linux/delay.h>#include <linux/ioport.h>#include <linux/sched.h>#include <linux/slab.h>#include <linux/errno.h>#include <linux/unistd.h>#include <linux/interrupt.h>#include <linux/init.h>#include <linux/version.h>#include <linux/list.h>#include <linux/spinlock.h>#include <asm/uaccess.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/dma.h>#include <asm/system.h>#include <asm/svinto.h>#include <linux/usb.h>/* Ugly include because we don't live with the other host drivers. */#include <../drivers/usb/hcd.h>#if LINUX_VERSION_CODE >= KERNEL_VERSION (2, 4, 20)typedef struct urb urb_t, *purb_t;typedef struct iso_packet_descriptor iso_packet_descriptor_t;typedef struct usb_ctrlrequest devrequest;#endif#include "usb-host.h"#define ETRAX_USB_HC_IRQ USB_HC_IRQ_NBR#define ETRAX_USB_RX_IRQ USB_DMA_RX_IRQ_NBR#define ETRAX_USB_TX_IRQ USB_DMA_TX_IRQ_NBRstatic const char *usb_hcd_version = "$Revision: 1.19 $";#undef KERN_DEBUG#define KERN_DEBUG ""#undef USB_DEBUG_RH#undef USB_DEBUG_EPID#undef USB_DEBUG_SB#undef USB_DEBUG_DESC#undef USB_DEBUG_URB#undef USB_DEBUG_TRACE#undef USB_DEBUG_BULK#undef USB_DEBUG_CTRL#undef USB_DEBUG_INTR#undef USB_DEBUG_ISOC#ifdef USB_DEBUG_RH#define dbg_rh(format, arg...) printk(KERN_DEBUG __FILE__ ": (RH) " format "\n" , ## arg)#else#define dbg_rh(format, arg...) do {} while (0)#endif#ifdef USB_DEBUG_EPID#define dbg_epid(format, arg...) printk(KERN_DEBUG __FILE__ ": (EPID) " format "\n" , ## arg)#else#define dbg_epid(format, arg...) do {} while (0)#endif#ifdef USB_DEBUG_SB#define dbg_sb(format, arg...) printk(KERN_DEBUG __FILE__ ": (SB) " format "\n" , ## arg)#else#define dbg_sb(format, arg...) do {} while (0)#endif#ifdef USB_DEBUG_CTRL#define dbg_ctrl(format, arg...) printk(KERN_DEBUG __FILE__ ": (CTRL) " format "\n" , ## arg)#else#define dbg_ctrl(format, arg...) do {} while (0)#endif#ifdef USB_DEBUG_BULK#define dbg_bulk(format, arg...) printk(KERN_DEBUG __FILE__ ": (BULK) " format "\n" , ## arg)#else#define dbg_bulk(format, arg...) do {} while (0)#endif#ifdef USB_DEBUG_INTR#define dbg_intr(format, arg...) printk(KERN_DEBUG __FILE__ ": (INTR) " format "\n" , ## arg)#else#define dbg_intr(format, arg...) do {} while (0)#endif#ifdef USB_DEBUG_ISOC#define dbg_isoc(format, arg...) printk(KERN_DEBUG __FILE__ ": (ISOC) " format "\n" , ## arg)#else#define dbg_isoc(format, arg...) do {} while (0)#endif#ifdef USB_DEBUG_TRACE#define DBFENTER (printk(KERN_DEBUG __FILE__ ": Entering: " __FUNCTION__ "\n"))#define DBFEXIT  (printk(KERN_DEBUG __FILE__ ": Exiting:  " __FUNCTION__ "\n"))#else#define DBFENTER do {} while (0)#define DBFEXIT  do {} while (0)#endif/*------------------------------------------------------------------- Virtual Root Hub -------------------------------------------------------------------*/static __u8 root_hub_dev_des[] ={	0x12,  /*  __u8  bLength; */	0x01,  /*  __u8  bDescriptorType; Device */	0x00,  /*  __u16 bcdUSB; v1.0 */	0x01,	0x09,  /*  __u8  bDeviceClass; HUB_CLASSCODE */	0x00,  /*  __u8  bDeviceSubClass; */	0x00,  /*  __u8  bDeviceProtocol; */	0x08,  /*  __u8  bMaxPacketSize0; 8 Bytes */	0x00,  /*  __u16 idVendor; */	0x00,	0x00,  /*  __u16 idProduct; */	0x00,	0x00,  /*  __u16 bcdDevice; */	0x00,	0x00,  /*  __u8  iManufacturer; */	0x02,  /*  __u8  iProduct; */	0x01,  /*  __u8  iSerialNumber; */	0x01   /*  __u8  bNumConfigurations; */};/* Configuration descriptor */static __u8 root_hub_config_des[] ={	0x09,  /*  __u8  bLength; */	0x02,  /*  __u8  bDescriptorType; Configuration */	0x19,  /*  __u16 wTotalLength; */	0x00,	0x01,  /*  __u8  bNumInterfaces; */	0x01,  /*  __u8  bConfigurationValue; */	0x00,  /*  __u8  iConfiguration; */	0x40,  /*  __u8  bmAttributes; Bit 7: Bus-powered */	0x00,  /*  __u8  MaxPower; */     /* interface */	0x09,  /*  __u8  if_bLength; */	0x04,  /*  __u8  if_bDescriptorType; Interface */	0x00,  /*  __u8  if_bInterfaceNumber; */	0x00,  /*  __u8  if_bAlternateSetting; */	0x01,  /*  __u8  if_bNumEndpoints; */	0x09,  /*  __u8  if_bInterfaceClass; HUB_CLASSCODE */	0x00,  /*  __u8  if_bInterfaceSubClass; */	0x00,  /*  __u8  if_bInterfaceProtocol; */	0x00,  /*  __u8  if_iInterface; */     /* endpoint */	0x07,  /*  __u8  ep_bLength; */	0x05,  /*  __u8  ep_bDescriptorType; Endpoint */	0x81,  /*  __u8  ep_bEndpointAddress; IN Endpoint 1 */	0x03,  /*  __u8  ep_bmAttributes; Interrupt */	0x08,  /*  __u16 ep_wMaxPacketSize; 8 Bytes */	0x00,	0xff   /*  __u8  ep_bInterval; 255 ms */};static __u8 root_hub_hub_des[] ={	0x09,  /*  __u8  bLength; */	0x29,  /*  __u8  bDescriptorType; Hub-descriptor */	0x02,  /*  __u8  bNbrPorts; */	0x00,  /* __u16  wHubCharacteristics; */	0x00,	0x01,  /*  __u8  bPwrOn2pwrGood; 2ms */	0x00,  /*  __u8  bHubContrCurrent; 0 mA */	0x00,  /*  __u8  DeviceRemovable; *** 7 Ports max *** */	0xff   /*  __u8  PortPwrCtrlMask; *** 7 ports max *** */};static struct timer_list bulk_start_timer;static struct timer_list bulk_eot_timer;/* We want the start timer to expire before the eot timer, because the former might start   traffic, thus making it unnecessary for the latter to time out. */#define BULK_START_TIMER_INTERVAL (HZ/10) /* 100 ms */#define BULK_EOT_TIMER_INTERVAL (HZ/10+2) /* 120 ms */#define OK(x) len = (x); dbg_rh("OK(%d): line: %d", x, __LINE__); break#define CHECK_ALIGN(x) if (((__u32)(x)) & 0x00000003) \{panic("Alignment check (DWORD) failed at %s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__);}#define SLAB_FLAG     (in_interrupt() ? SLAB_ATOMIC : SLAB_KERNEL)#define KMALLOC_FLAG  (in_interrupt() ? GFP_ATOMIC : GFP_KERNEL)/* Most helpful debugging aid */#define assert(expr) ((void) ((expr) ? 0 : (err("assert failed at line %d",__LINE__))))/* Alternative assert define which stops after a failed assert. *//*#define assert(expr)                                      \{                                                         \        if (!(expr)) {                                    \                err("assert failed at line %d",__LINE__); \                while (1);                                \        }                                                 \}*//* FIXME: Should RX_BUF_SIZE be a config option, or maybe we should adjust it dynamically?   To adjust it dynamically we would have to get an interrupt when we reach the end   of the rx descriptor list, or when we get close to the end, and then allocate more   descriptors. */#define NBR_OF_RX_DESC     512#define RX_DESC_BUF_SIZE   1024#define RX_BUF_SIZE        (NBR_OF_RX_DESC * RX_DESC_BUF_SIZE)/* The number of epids is, among other things, used for pre-allocating   ctrl, bulk and isoc EP descriptors (one for each epid).   Assumed to be > 1 when initiating the DMA lists. */#define NBR_OF_EPIDS       32/* Support interrupt traffic intervals up to 128 ms. */#define MAX_INTR_INTERVAL 128/* If periodic traffic (intr or isoc) is to be used, then one entry in the EP table   must be "invalid". By this we mean that we shouldn't care about epid attentions   for this epid, or at least handle them differently from epid attentions for "valid"   epids. This define determines which one to use (don't change it). */   #define INVALID_EPID     31/* A special epid for the bulk dummys. */#define DUMMY_EPID       30/* This is just a software cache for the valid entries in R_USB_EPT_DATA. */static __u32 epid_usage_bitmask;/* A bitfield to keep information on in/out traffic is needed to uniquely identify   an endpoint on a device, since the most significant bit which indicates traffic   direction is lacking in the ep_id field (ETRAX epids can handle both in and   out traffic on endpoints that are otherwise identical). The USB framework, however,   relies on them to be handled separately.  For example, bulk IN and OUT urbs cannot   be queued in the same list, since they would block each other. */static __u32 epid_out_traffic;/* DMA IN cache bug. Align the DMA IN buffers to 32 bytes, i.e. a cache line.   Since RX_DESC_BUF_SIZE is 1024 is a multiple of 32, all rx buffers will be cache aligned. */static volatile unsigned char RxBuf[RX_BUF_SIZE] __attribute__ ((aligned (32)));static volatile USB_IN_Desc_t RxDescList[NBR_OF_RX_DESC] __attribute__ ((aligned (4)));/* Pointers into RxDescList. */static volatile USB_IN_Desc_t *myNextRxDesc;static volatile USB_IN_Desc_t *myLastRxDesc;static volatile USB_IN_Desc_t *myPrevRxDesc;/* EP descriptors must be 32-bit aligned. */static volatile USB_EP_Desc_t TxCtrlEPList[NBR_OF_EPIDS] __attribute__ ((aligned (4)));static volatile USB_EP_Desc_t TxBulkEPList[NBR_OF_EPIDS] __attribute__ ((aligned (4)));/* After each enabled bulk EP (IN or OUT) we put two disabled EP descriptors with the eol flag set,   causing the DMA to stop the DMA channel. The first of these two has the intr flag set, which   gives us a dma8_sub0_descr interrupt. When we receive this, we advance the DMA one step in the   EP list and then restart the bulk channel, thus forcing a switch between bulk EP descriptors   in each frame. */static volatile USB_EP_Desc_t TxBulkDummyEPList[NBR_OF_EPIDS][2] __attribute__ ((aligned (4)));static volatile USB_EP_Desc_t TxIsocEPList[NBR_OF_EPIDS] __attribute__ ((aligned (4)));static volatile USB_SB_Desc_t TxIsocSB_zout __attribute__ ((aligned (4)));static volatile USB_EP_Desc_t TxIntrEPList[MAX_INTR_INTERVAL] __attribute__ ((aligned (4)));static volatile USB_SB_Desc_t TxIntrSB_zout __attribute__ ((aligned (4)));/* A zout transfer makes a memory access at the address of its buf pointer, which means that setting   this buf pointer to 0 will cause an access to the flash. In addition to this, setting sw_len to 0   results in a 16/32 bytes (depending on DMA burst size) transfer. Instead, we set it to 1, and point   it to this buffer. */static int zout_buffer[4] __attribute__ ((aligned (4)));/* Cache for allocating new EP and SB descriptors. */static kmem_cache_t *usb_desc_cache;/* Cache for the registers allocated in the top half. */static kmem_cache_t *top_half_reg_cache;static struct usb_bus *etrax_usb_bus;/* This is a circular (double-linked) list of the active urbs for each epid.   The head is never removed, and new urbs are linked onto the list as    urb_entry_t elements. Don't reference urb_list directly; use the wrapper   functions instead. Note that working with these lists might require spinlock   protection. */static struct list_head urb_list[NBR_OF_EPIDS];/* Read about the need and usage of this lock in submit_ctrl_urb. */static spinlock_t urb_list_lock;/* Used when unlinking asynchronously. */static struct list_head urb_unlink_list;/* Wrappers around the list functions (include/linux/list.h). */static inline int urb_list_empty(int epid){        return list_empty(&urb_list[epid]);}/* Returns first urb for this epid, or NULL if list is empty. */static inline urb_t *urb_list_first(int epid){        urb_t *first_urb = 0;        if (!urb_list_empty(epid)) {                /* Get the first urb (i.e. head->next). */                urb_entry_t *urb_entry = list_entry((&urb_list[epid])->next, urb_entry_t, list);                first_urb = urb_entry->urb;        }        return first_urb;}/* Adds an urb_entry last in the list for this epid. */static inline void urb_list_add(urb_t *urb, int epid){        urb_entry_t *urb_entry = (urb_entry_t *)kmalloc(sizeof(urb_entry_t), KMALLOC_FLAG);        assert(urb_entry);        urb_entry->urb = urb;        list_add_tail(&urb_entry->list, &urb_list[epid]);}/* Search through the list for an element that contains this urb. (The list   is expected to be short and the one we are about to delete will often be   the first in the list.) */static inline urb_entry_t *__urb_list_entry(urb_t *urb, int epid){        struct list_head *entry;        struct list_head *tmp;        urb_entry_t *urb_entry;        list_for_each_safe(entry, tmp, &urb_list[epid]) {                urb_entry = list_entry(entry, urb_entry_t, list);                assert(urb_entry);                assert(urb_entry->urb);                                if (urb_entry->urb == urb) {                        return urb_entry;                }        }        return 0;}/* Delete an urb from the list. */static inline void urb_list_del(urb_t *urb, int epid){        urb_entry_t *urb_entry = __urb_list_entry(urb, epid);        assert(urb_entry);                /* Delete entry and free. */        list_del(&urb_entry->list);        kfree(urb_entry);}/* Move an urb to the end of the list. */static inline void urb_list_move_last(urb_t *urb, int epid){        urb_entry_t *urb_entry = __urb_list_entry(urb, epid);        assert(urb_entry);        list_del(&urb_entry->list);        list_add_tail(&urb_entry->list, &urb_list[epid]);}/* For debug purposes only. */static inline void urb_list_dump(int epid){        struct list_head *entry;        struct list_head *tmp;        urb_entry_t *urb_entry;        int i = 0;

⌨️ 快捷键说明

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