?? hcd_1161.c
字號:
/* * Philips 1161 HCD (Host Controller Driver) for USB. * * Original Source from Linux 2.4.5 kernel OHCI HCD * modified for Phlips Semi Conductors * * Copyright 2002 Philips Semiconductors, * * File Name: hcd_1161.c * * History: * * Version Date Author Comments * ------------------------------------------------- * 1.0 03/14/02 SYARRA Initial Release * 1.1 04/24/03 SYARRA NO_PTD_BIT5_5 flag * dependancy of td_t on 16 byte start * address is removed. * * 1.11 05/15/03 SYARRA enabling OHCI_CTRL_CLE/OHCI_CTRL_BLE * in dl_del_list function * Skip RH-timer processing in ISR * proper clearing of ATL & SOF interrupts * * * Note: Use tab space 4 */ #include <linux/config.h>#define MODULE#include <linux/module.h>#include <linux/pci.h>#include <linux/kernel.h>#include <linux/delay.h>#include <linux/ioport.h>#include <linux/sched.h>#include <linux/slab.h>#include <linux/smp_lock.h>#include <linux/errno.h>#include <linux/init.h>#include <linux/timer.h>#include <linux/list.h>#include <linux/interrupt.h> /* for in_interrupt() */#undef DEBUG#include <linux/usb.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/system.h>#include <asm/unaligned.h>#include "hcd_1161.h"typedef __u32 ULONG;typedef __u8 UCHAR;typedef void VOID;static td_tree_addr_t tstAtlBridge[MAX_GTD+1];static td_t *pstDoneHead_hcd ;static isotd_map_buffer_t aIsoTdMapBuffer[2]; /* One for each ITL */static LIST_HEAD (ohci_1161_hcd_list);static spinlock_t usb_ed_lock = SPIN_LOCK_UNLOCKED;#define MAX_BULK_TD_BUFF_SIZE 512#define MAX_CNTL_TD_BUFF_SIZE 1024#define hc_1161_name "ISP116x_HCD" #define OHCI_UNLINK_TIMEOUT (HZ / 10)void print_int_ed_list(ohci_t *ohci);/* 1161 HC accessing functions decleration */void fnvIsp1161HcorWrite (ohci_t *ohci,ULONG uReg, ULONG uRegData);void fnvIsp1161HcorRead (ohci_t *ohci,ULONG uReg, ULONG *puRegData);void fnvIsp1161HcRead (ULONG uReg, ULONG *puRegData);void fnvIsp1161HcWrite (ULONG uReg, ULONG uRegData);void fnvIsp1161AtlRead (__u8* pbyChar, __u32 uTotalByte);void fnvIsp1161AtlWrite (__u8* pbyChar, __u32 uTotalByte);void fnvIsp1161ItlRead (__u8* pbyChar, __u32 uTotalByte);void fnvIsp1161ItlWrite (__u8* pbyChar, __u32 uTotalByte);/* 1161 HC Initialization functions decleration */ULONG fnvIsp1161HostReset (ohci_t *ohci);ULONG fnuIsp1161HostDetect (void);void fnvHcHardwareConfig (ohci_t *ohci, ULONG uIntLevel);void fnvHcIntEnable (ohci_t *ohci);void fnvHcControlInit (ohci_t *ohci);void fnvHcInterruptInit (ohci_t *ohci);void fnvHcFmIntervalInit (ohci_t *ohci);void fnvHcRhPower (ohci_t *ohci);int fnuHci1161HostInit (ohci_t *ohci);/* 1161 HC Interrupt Functions */static void fnvHci1161IrqHandler (int irq, void *__ohci, struct pt_regs *r);void fnvProcessSofItlInt (ohci_t *ohci);/* TD functions decleration */static void td_fill (unsigned int info, void * data, int len, struct urb * urb, int index);static void td_submit_urb (struct urb * urb);/* EP handling functions */static int ep_int_ballance (ohci_t * ohci, int interval, int load);static int ep_2_n_interval (int inter);static int ep_rev (int num_bits, int word);static int ep_link (ohci_t * ohci, ed_t * edi);static int ep_unlink (ohci_t * ohci, ed_t * ed);static void ep_rm_ed (struct usb_device * usb_dev, ed_t * ed);static ed_t * ep_add_ed (struct usb_device * usb_dev, unsigned int pipe, int interval, int load);/* Done List handling functions */static void dl_transfer_length(td_t * td);static void dl_del_urb (struct urb * urb);static void dl_del_list (ohci_t * ohci, unsigned int frame);static td_t * dl_reverse_done_list (ohci_t * ohci, td_t *td_list);static void dl_done_list (ohci_t * ohci, td_t * td_list);/* Root Hub function declerations */static int rh_send_irq (ohci_t * ohci, void * rh_data, int rh_len);static void rh_int_timer_do (unsigned long ptr);static int rh_init_int_timer (struct urb * urb);static int rh_submit_urb (struct urb * urb);static int rh_unlink_urb (struct urb * urb);/* URB support functions */static void urb_free_priv( struct ohci *hc, urb_priv_t *urb_priv);static void urb_rm_priv_locked (struct urb *urb);static void urb_rm_priv (struct urb *urb);/* SOHCI functions */static int s1161_alloc_dev (struct usb_device *usb_dev);static int s1161_free_dev (struct usb_device *usb_dev);static int s1161_get_current_frame_number (struct usb_device *usb_dev);static int s1161_return_urb (struct urb * urb);static int s1161_submit_urb (struct urb *urb);static int s1161_unlink_urb (struct urb *urb);/* OHCI functions */static void hc_release_1161 (ohci_t * ohci);static ohci_t * __devinit hc_alloc_1161 (struct pci_dev *dev);static int __devinit hc_found_1161 ( void) ;#define outb(x,y) outb(y,x)#define inb inb#define outw_hcd(x,y) outw_p(y,x)#define inw_hcd inw_p#define sti_hcd sti#define cli_hcd cli#define iodelay_hcd() udelay(1)#define cmd_delay_hcd() do{udelay(1);}while(0)#define data_delay_hcd() do{}while(0)/*--------------------------------------------------------------* * 1161 Host Controller operational registers write *--------------------------------------------------------------*/void fnvIsp1161HcorWrite(ohci_t *ohci,ULONG uReg, ULONG uRegData){ ULONG uData; /* Check if the registers are controlled by software */ if ((uReg == uHcHcdControl ) || (uReg == (uHcHcdControl | 0x80))) { ohci->uHcHcdControl_hcd = uRegData; return; } if ((uReg == uHcHcdCommandStatus) || (uReg == (uHcHcdCommandStatus | 0x80))) { ohci->uHcHcdCommandStatus_hcd = uRegData; return; } /* Write the register index to the command register */ outw_hcd(HC_COM, uReg | 0x80); /* Write the data to the data register */ uData = uRegData & 0x0000FFFF; /* Write lower 16-bit first */ outw_hcd(HC_DATA, uData); uData = (uRegData & 0xFFFF0000) >> 16; /* Then the higher 16-bit */ outw_hcd(HC_DATA, uData);} /* fnvIsp1161HcorWrite() *//*--------------------------------------------------------------* * 1161 Host Controller operational registers read *--------------------------------------------------------------*/void fnvIsp1161HcorRead(ohci_t *ohci,ULONG uReg, ULONG *puRegData){ ULONG uData; /* Service the HCD HC transfer control registers first */ if (uReg == uHcHcdControl ) { *puRegData = ohci->uHcHcdControl_hcd; return; } if (uReg == uHcHcdCommandStatus) { *puRegData = ohci->uHcHcdCommandStatus_hcd; return; } /* Write the register index to the command register */ outw_hcd(HC_COM, uReg); /* Read the data from the data register */ uData = inw_hcd(HC_DATA); *puRegData = uData & 0x0000FFFF; /* Save the lower 16-bit value */ uData = inw_hcd(HC_DATA); *puRegData |= (uData & 0x0000FFFF) << 16; /* Take the higher 16-bit */} /* fnvIsp1161HcorRead() *//*--------------------------------------------------------------* * 1161 Host Controller registers read *--------------------------------------------------------------*/void fnvIsp1161HcRead(ULONG uReg, ULONG *puRegData){ ULONG uData; /* Write the register index to the command register */ outw_hcd(HC_COM, uReg); /* Read the data from the data register */ uData = inw_hcd(HC_DATA); *puRegData = uData;} /* fnvIsp1161HcRead() *//*--------------------------------------------------------------* * 1161 Host Controller registers write *--------------------------------------------------------------*/void fnvIsp1161HcWrite(ULONG uReg, ULONG uRegData){ /* Write the register index to the command register */ outw_hcd(HC_COM, uReg | 0x80); /* Write the data to the data register */ outw_hcd(HC_DATA, uRegData);} /* fnvIsp1161HcWrite() *//*--------------------------------------------------------------* * 1161 Host Controller Atl Buffer Reading *--------------------------------------------------------------*/void fnvIsp1161AtlRead(__u8* pbyChar, __u32 uTotalByte){ __u32 uTotalDoubleWord; __u32* puLong; __u32 uIndex; __u32 uData1; __u32 uData2;#ifdef __TRACE_MID_LEVEL__ printk("fnvIsp1161AtlRead( buff = 0x%p, bytes = %d)\n",pbyChar,uTotalByte);#endif /* __TRACE_MID_LEVEL__ */ /* Program the transfer counter */ fnvIsp1161HcWrite(REG_XFER_CNTR, uTotalByte); /* 2. Pass HCD ATL to ISP1161 internal ATL through the 32-bit ATLBuffer register */ /* Use PIO for the time being. Will use DMA */ uTotalDoubleWord = uTotalByte >> 2; /* Number of double words to move from ISP1161 ATL */ puLong = (__u32*) pbyChar; /* Convert the HCD byte buffer to double-word buffer */ cli_hcd(); /* Send the command */ outw_hcd(HC_COM,REG_ATL_BUFF_IO); iodelay_hcd(); /* Read data from data port */ for (uIndex = 0; uIndex < uTotalDoubleWord; uIndex ++) { uData1 = inw_hcd(HC_DATA); /* Read lower 16-bit first */ uData2 = inw_hcd(HC_DATA); /* then higher 16-bit */ /* Combine to 32-bit double word */ puLong[uIndex] = (uData1 & 0x0000FFFF) | ((uData2 & 0x0000FFFF) << 16); /* Take the higher 16-bit */ } /* for */ sti_hcd();} /* End of fnvIsp1161AtlRead() *//*--------------------------------------------------------------* * 1161 Host Controller Atl Buffer Reading *--------------------------------------------------------------*/void fnvIsp1161AtlWrite(__u8* pbyChar, __u32 uTotalByte){ __u32 uTotalDoubleWord; __u32* puLong; __u32 uIndex; __u32 uData1; __u32 uData2;#ifdef __TRACE_MID_LEVEL__ printk("fnvIsp1161AtlWrite( buff = 0x%p, bytes = %d)\n",pbyChar,uTotalByte);#endif /* __TRACE_MID_LEVEL__ */ /* Program the transfer counter */ fnvIsp1161HcWrite(REG_XFER_CNTR, uTotalByte); /* 2. Pass HCD ATL to ISP1161 internal ATL through the 32-bit ATLBuffer register */ /* Use PIO for the time being. Will use DMA */ uTotalDoubleWord = uTotalByte >> 2; /* Number of double words to move from ISP1161 ATL */ puLong = (__u32*) pbyChar; /* Convert the HCD byte buffer to double-word buffer */ /* Send the command */ outw_hcd(HC_COM,(REG_ATL_BUFF_IO | 0x80)); /* Don't forget to set bit 7 for write*/ iodelay_hcd(); cli_hcd(); /* Write data to the data port */ for (uIndex = 0; uIndex < uTotalDoubleWord; uIndex ++) { uData1 = puLong[uIndex] & 0x0000FFFF; /* Take the lower 16-bit of the double word */ uData2 = (puLong[uIndex] & 0xFFFF0000) >> 16; /* Take the higher 16-bit of the double word */ /* Write them to ATL */ outw_hcd(HC_DATA,uData1); /* Write lower 16-bit first */ outw_hcd(HC_DATA,uData2); /* Write higher 16-bit */ } /* for */ sti_hcd();} /* End of fnvIsp1161AtlWrite() *//*--------------------------------------------------------------* * 1161 Host Controller Itl Buffer Reading *--------------------------------------------------------------*/void fnvIsp1161ItlRead(__u8* pbyChar, __u32 uTotalByte){ __u32 uTotalDoubleWord; __u32* puLong; __u32 uIndex; __u32 uData1; __u32 uData2;#ifdef __TRACE_MID_LEVEL__ printk("fnvIsp1161ItlRead( buff = 0x%p, bytes = %d)\n",pbyChar,uTotalByte);#endif /* __TRACE_MID_LEVEL__ */ outw_hcd(HC_COM, REG_XFER_CNTR | 0x80); outw_hcd(HC_DATA, uTotalByte); /* 2. Pass HCD ITL to ISP1161 internal ITL through the 32-bit ITLBuffer register */ /* Use PIO for the time being. Will use DMA */ uTotalDoubleWord = uTotalByte >> 2; /* Number of double words to move from ISP1161 ATL */ puLong = (__u32*) pbyChar; /* Convert the HCD byte buffer to double-word buffer */ cli_hcd(); /* Send the command */ outw_hcd(HC_COM,REG_ITL_BUFF_IO); /* Read data from data port */ for (uIndex = 0; uIndex < uTotalDoubleWord; uIndex ++) { uData1 = inw_hcd(HC_DATA); /* Read lower 16-bit first */ uData2 = inw_hcd(HC_DATA); /* then higher 16-bit */ /* Combine to 32-bit double word */ puLong[uIndex] = (uData1 & 0x0000FFFF) | ((uData2 & 0x0000FFFF) << 16); /* Take the higher 16-bit */ } /* for */
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -