📄 usb-host.c
字号:
/* * usb-host.c: ETRAX 100LX USB Host Controller Driver (HCD) * * Copyright (c) 2001 Axis Communications AB. * * $Id: usb-host.c,v 1.13 2001/11/13 12:06:17 pkj Exp $ * */#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 <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>#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.13 $";#undef KERN_DEBUG#define KERN_DEBUG ""#undef USB_DEBUG_RH#undef USB_DEBUG_EP#undef USB_DEBUG_DESC#undef USB_DEBUG_TRACE#undef USB_DEBUG_CTRL#undef USB_DEBUG_BULK#undef USB_DEBUG_INTR#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_EP#define dbg_ep(format, arg...) printk(KERN_DEBUG __FILE__ ": (EP) " format "\n" , ## arg)#else#define dbg_ep(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_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 *** */};#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__);}static unsigned long submit_urb_count = 0;//#define ETRAX_USB_INTR_IRQ//#define ETRAX_USB_INTR_ERROR_FATAL#define RX_BUF_SIZE 32768#define RX_DESC_BUF_SIZE 64#define NBR_OF_RX_DESC (RX_BUF_SIZE / RX_DESC_BUF_SIZE)#define NBR_OF_EP_DESC 32#define MAX_INTR_INTERVAL 128static __u32 ep_usage_bitmask;static __u32 ep_really_active;static __u32 ep_out_traffic;static unsigned char RxBuf[RX_BUF_SIZE];static USB_IN_Desc_t RxDescList[NBR_OF_RX_DESC] __attribute__ ((aligned (4)));static volatile USB_IN_Desc_t *myNextRxDesc;static volatile USB_IN_Desc_t *myLastRxDesc;static volatile USB_IN_Desc_t *myPrevRxDesc;static USB_EP_Desc_t TxCtrlEPList[NBR_OF_EP_DESC] __attribute__ ((aligned (4)));static USB_EP_Desc_t TxBulkEPList[NBR_OF_EP_DESC] __attribute__ ((aligned (4)));static USB_EP_Desc_t TxIntrEPList[MAX_INTR_INTERVAL] __attribute__ ((aligned (4)));static USB_SB_Desc_t TxIntrSB_zout __attribute__ ((aligned (4)));static struct urb *URB_List[NBR_OF_EP_DESC];static kmem_cache_t *usb_desc_cache;static struct usb_bus *etrax_usb_bus;#ifdef USB_DEBUG_DESCstatic void dump_urb (struct urb *urb);#endifstatic void init_rx_buffers(void);static int etrax_rh_unlink_urb (struct urb *urb);static void etrax_rh_send_irq(struct urb *urb);static void etrax_rh_init_int_timer(struct urb *urb);static void etrax_rh_int_timer_do(unsigned long ptr);static void etrax_usb_setup_epid(int epid, char devnum, char endpoint, char packsize, char slow, char out_traffic);static int etrax_usb_lookup_epid(unsigned char devnum, char endpoint, char slow, int maxp, char out_traffic);static int etrax_usb_allocate_epid(void);static void etrax_usb_free_epid(int epid);static void cleanup_sb(USB_SB_Desc_t *sb);static void etrax_usb_do_ctrl_hw_add(struct urb *urb, int epid, char maxlen);static void etrax_usb_do_bulk_hw_add(struct urb *urb, int epid, char maxlen);static int etrax_usb_submit_ctrl_urb(struct urb *urb);static int etrax_usb_submit_urb(struct urb *urb);static int etrax_usb_unlink_urb(struct urb *urb);static int etrax_usb_get_frame_number(struct usb_device *usb_dev);static int etrax_usb_allocate_dev(struct usb_device *usb_dev);static int etrax_usb_deallocate_dev(struct usb_device *usb_dev);static void etrax_usb_tx_interrupt(int irq, void *vhc, struct pt_regs *regs);static void etrax_usb_rx_interrupt(int irq, void *vhc, struct pt_regs *regs);static void etrax_usb_hc_intr_top_half(int irq, void *vhc, struct pt_regs *regs);static int etrax_rh_submit_urb (struct urb *urb);static int etrax_usb_hc_init(void);static void etrax_usb_hc_cleanup(void);static struct usb_operations etrax_usb_device_operations ={ etrax_usb_allocate_dev, etrax_usb_deallocate_dev, etrax_usb_get_frame_number, etrax_usb_submit_urb, etrax_usb_unlink_urb};#ifdef USB_DEBUG_DESCstatic void dump_urb(struct urb *urb){ printk("\nurb :0x%08X\n", urb); printk("next :0x%08X\n", urb->next); printk("dev :0x%08X\n", urb->dev); printk("pipe :0x%08X\n", urb->pipe); printk("status :%d\n", urb->status); printk("transfer_flags :0x%08X\n", urb->transfer_flags); printk("transfer_buffer :0x%08X\n", urb->transfer_buffer); printk("transfer_buffer_length:%d\n", urb->transfer_buffer_length); printk("actual_length :%d\n", urb->actual_length); printk("setup_packet :0x%08X\n", urb->setup_packet); printk("start_frame :%d\n", urb->start_frame); printk("number_of_packets :%d\n", urb->number_of_packets); printk("interval :%d\n", urb->interval); printk("error_count :%d\n", urb->error_count); printk("context :0x%08X\n", urb->context); printk("complete :0x%08X\n\n", urb->complete);}static void dump_in_desc(USB_IN_Desc_t *in){ printk("\nUSB_IN_Desc at 0x%08X\n", in); printk(" sw_len : 0x%04X (%d)\n", in->sw_len, in->sw_len); printk(" command : 0x%04X\n", in->command); printk(" next : 0x%08X\n", in->next); printk(" buf : 0x%08X\n", in->buf); printk(" hw_len : 0x%04X (%d)\n", in->hw_len, in->hw_len); printk(" status : 0x%04X\n\n", in->status);}static void dump_sb_desc(USB_SB_Desc_t *sb){ printk("\nUSB_SB_Desc at 0x%08X\n", sb); printk(" sw_len : 0x%04X (%d)\n", sb->sw_len, sb->sw_len); printk(" command : 0x%04X\n", sb->command); printk(" next : 0x%08X\n", sb->next); printk(" buf : 0x%08X\n\n", sb->buf);}static void dump_ep_desc(USB_EP_Desc_t *ep){ printk("\nUSB_EP_Desc at 0x%08X\n", ep); printk(" hw_len : 0x%04X (%d)\n", ep->hw_len, ep->hw_len); printk(" command : 0x%08X\n", ep->command); printk(" sub : 0x%08X\n", ep->sub); printk(" nep : 0x%08X\n\n", ep->nep);}#else#define dump_urb(...) do {} while (0)#define dump_in_desc(...) do {} while (0)#define dump_sb_desc(...) do {} while (0)#define dump_ep_desc(...) do {} while (0)#endifstatic void init_rx_buffers(void){ int i; DBFENTER; for (i = 0; i < (NBR_OF_RX_DESC - 1); i++) { RxDescList[i].sw_len = RX_DESC_BUF_SIZE; RxDescList[i].command = 0; RxDescList[i].next = virt_to_phys(&RxDescList[i + 1]); RxDescList[i].buf = virt_to_phys(RxBuf + (i * RX_DESC_BUF_SIZE)); RxDescList[i].hw_len = 0; RxDescList[i].status = 0; } RxDescList[i].sw_len = RX_DESC_BUF_SIZE; RxDescList[i].command = IO_STATE(USB_IN_command, eol, yes); RxDescList[i].next = virt_to_phys(&RxDescList[0]); RxDescList[i].buf = virt_to_phys(RxBuf + (i * RX_DESC_BUF_SIZE)); RxDescList[i].hw_len = 0; RxDescList[i].status = 0; myNextRxDesc = &RxDescList[0]; myLastRxDesc = &RxDescList[NBR_OF_RX_DESC - 1]; myPrevRxDesc = &RxDescList[NBR_OF_RX_DESC - 1]; *R_DMA_CH9_FIRST = virt_to_phys(myNextRxDesc); *R_DMA_CH9_CMD = IO_STATE(R_DMA_CH9_CMD, cmd, start); DBFEXIT;}static void init_tx_ctrl_ep(void){ int i; DBFENTER; for (i = 0; i < (NBR_OF_EP_DESC - 1); i++) { TxCtrlEPList[i].hw_len = 0; TxCtrlEPList[i].command = IO_FIELD(USB_EP_command, epid, i); TxCtrlEPList[i].sub = 0; TxCtrlEPList[i].nep = virt_to_phys(&TxCtrlEPList[i + 1]); } TxCtrlEPList[i].hw_len = 0; TxCtrlEPList[i].command = IO_STATE(USB_EP_command, eol, yes) | IO_FIELD(USB_EP_command, epid, i); TxCtrlEPList[i].sub = 0; TxCtrlEPList[i].nep = virt_to_phys(&TxCtrlEPList[0]); *R_DMA_CH8_SUB1_EP = virt_to_phys(&TxCtrlEPList[0]); *R_DMA_CH8_SUB1_CMD = IO_STATE(R_DMA_CH8_SUB1_CMD, cmd, start); DBFEXIT;}static void init_tx_bulk_ep(void){ int i; DBFENTER; for (i = 0; i < (NBR_OF_EP_DESC - 1); i++) { TxBulkEPList[i].hw_len = 0; TxBulkEPList[i].command = IO_FIELD(USB_EP_command, epid, i); TxBulkEPList[i].sub = 0; TxBulkEPList[i].nep = virt_to_phys(&TxBulkEPList[i + 1]); } TxBulkEPList[i].hw_len = 0; TxBulkEPList[i].command = IO_STATE(USB_EP_command, eol, yes) | IO_FIELD(USB_EP_command, epid, i); TxBulkEPList[i].sub = 0; TxBulkEPList[i].nep = virt_to_phys(&TxBulkEPList[0]); *R_DMA_CH8_SUB0_EP = virt_to_phys(&TxBulkEPList[0]); *R_DMA_CH8_SUB0_CMD = IO_STATE(R_DMA_CH8_SUB0_CMD, cmd, start); DBFEXIT;}static void init_tx_intr_ep(void){ int i; DBFENTER; TxIntrSB_zout.sw_len = 0; TxIntrSB_zout.next = 0; TxIntrSB_zout.buf = 0; TxIntrSB_zout.command = IO_FIELD(USB_SB_command, rem, 0) | IO_STATE(USB_SB_command, tt, zout) | IO_STATE(USB_SB_command, full, yes) | IO_STATE(USB_SB_command, eot, yes) | IO_STATE(USB_SB_command, eol, yes); for (i = 0; i < (MAX_INTR_INTERVAL - 1); i++) { TxIntrEPList[i].hw_len = 0; TxIntrEPList[i].command = IO_STATE(USB_EP_command, eof, yes) | IO_STATE(USB_EP_command, enable, yes) | IO_FIELD(USB_EP_command, epid, 0); TxIntrEPList[i].sub = virt_to_phys(&TxIntrSB_zout); TxIntrEPList[i].nep = virt_to_phys(&TxIntrEPList[i + 1]); } TxIntrEPList[i].hw_len = 0; TxIntrEPList[i].command = IO_STATE(USB_EP_command, eof, yes) | IO_STATE(USB_EP_command, enable, yes) | IO_FIELD(USB_EP_command, epid, 0); TxIntrEPList[i].sub = virt_to_phys(&TxIntrSB_zout); TxIntrEPList[i].nep = virt_to_phys(&TxIntrEPList[0]); *R_DMA_CH8_SUB2_EP = virt_to_phys(&TxIntrEPList[0]); *R_DMA_CH8_SUB2_CMD = IO_STATE(R_DMA_CH8_SUB2_CMD, cmd, start); DBFEXIT;}static int etrax_usb_unlink_intr_urb(struct urb *urb){ USB_EP_Desc_t *tmp_ep; USB_EP_Desc_t *first_ep; USB_EP_Desc_t *ep_desc; int epid; char devnum; char endpoint; char slow; int maxlen; char out_traffic; int i; DBFENTER; devnum = usb_pipedevice(urb->pipe); endpoint = usb_pipeendpoint(urb->pipe); slow = usb_pipeslow(urb->pipe); maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)); out_traffic = usb_pipeout(urb->pipe); epid = etrax_usb_lookup_epid(devnum, endpoint, slow, maxlen, out_traffic); if (epid == -1) { err("Trying to unlink urb that is not in traffic queue!!"); return -1; /* fix this */ } *R_DMA_CH8_SUB2_CMD = IO_STATE(R_DMA_CH8_SUB2_CMD, cmd, stop); /* Somehow wait for the DMA to finish current activities */ i = jiffies + 100; while (jiffies < i); first_ep = &TxIntrEPList[0]; tmp_ep = first_ep; do { if (IO_EXTRACT(USB_EP_command, epid, ((USB_EP_Desc_t *)phys_to_virt(tmp_ep->nep))->command) == epid) { /* Unlink it !!! */ dbg_intr("Found urb to unlink for epid %d", epid); ep_desc = phys_to_virt(tmp_ep->nep); tmp_ep->nep = ep_desc->nep; kmem_cache_free(usb_desc_cache, phys_to_virt(ep_desc->sub)); kmem_cache_free(usb_desc_cache, ep_desc); } tmp_ep = phys_to_virt(tmp_ep->nep); } while (tmp_ep != first_ep); /* We should really try to move the EP register to an EP that is not removed instead of restarting, but this will work too */ *R_DMA_CH8_SUB2_EP = virt_to_phys(&TxIntrEPList[0]); *R_DMA_CH8_SUB2_CMD = IO_STATE(R_DMA_CH8_SUB2_CMD, cmd, start);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -