📄 usb_phci.c
字号:
/*************************************************************
* Philips HCD (Host Controller Driver) for USB.
*
* Original Host Controller driver code from Linux OS 2.4.5 Kernel and
* modified for Philips ISP1362 HCD
*
* File Name: usb_phci.c
*
* History:
*
* Version Date Author Comments
* -------------------------------------------------
* 1.0 09/23/02 SYARRA Initial Release
* 1.1 11/22/02 SYARRA Waiting in while loop for IsoTx
* start of frame is changed (ISO_WAIT_FIX)
* 1.20 04/01//03 SYARRA clearing tds for sphci_free_dev when
* devnum == -1 (enumeration failed in usbcore)
* Removed td, dev structure starting address
* 16 byte alignment
* 1.21 08/04/03 SYARRA Adding Break statement in infiniteloop of ProcessIstlInt()
*
*************************************************************/
#include <linux/config.h>
#define MODULE
#include <linux/module.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 <asm/dma.h>
#include "usb_phci.h"
struct isp1362_dev *isp1362_device = NULL;
__u32 g_buff_sts = 0;
static LIST_HEAD (phci_hcd_list);
static spinlock_t usb_ed_lock = SPIN_LOCK_UNLOCKED;
static int cc_to_error[16] = {
/* mapping of the OHCI CC status to error codes */
/* No Error */ USB_ST_NOERROR,
/* CRC Error */ USB_ST_CRC,
/* Bit Stuff */ USB_ST_BITSTUFF,
/* Data Togg */ USB_ST_CRC,
/* Stall */ USB_ST_STALL,
/* DevNotResp */ USB_ST_NORESPONSE,
/* PIDCheck */ USB_ST_BITSTUFF,
/* UnExpPID */ USB_ST_BITSTUFF,
/* DataOver */ USB_ST_DATAOVERRUN,
/* DataUnder */ USB_ST_DATAUNDERRUN,
/* reservd */ USB_ST_NORESPONSE,
/* reservd */ USB_ST_NORESPONSE,
/* BufferOver */ USB_ST_BUFFEROVERRUN,
/* BuffUnder */ USB_ST_BUFFERUNDERRUN,
/* Not Access */ USB_ST_NORESPONSE,
/* Not Access */ USB_ST_NORESPONSE
};
__u8 ptd_test_header[HC_PTD_HEADER_SIZE] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF};
#define phc_name "PHCI-HC"
#define PHCI_UNLINK_TIMEOUT (HZ / 10)
#define DRIVER_AUTHOR "Linux kernel 2.4.5 usb-ohci.c modified for Philips Semiconductors"
#define DRIVER_DESC "USB Philips ISP1362 Host Controller Driver"
/* Trace functions */
#ifdef DEBUG
void print_int_ed_list(phci_t *phci);
#endif
#ifdef __PHCI_DEBUG_DETAIL__
static void phci_print_map_buffers(__u8 index);
static void phci_print_ptd_header(__u8 *header, __u32 pipe);
static void phci_print_hex_data(__u8 *data, __u32 length);
static void phci_print_hc_regs(phci_t *phci, __u8 buff_type);
static void phci_urb_print (struct urb * urb, char * str, int small);
#endif /* __detail_debug__ */
/* HC Register accessing functions decleration */
void fnvPhciHcorWrite (phci_t *phci,__u32 uReg, __u32 uRegData);
void fnvPhciHcorRead (phci_t *phci,__u32 uReg, __u32 *puRegData);
void phci_reg_read16 (__u32 uReg, __u32 *puRegData);
void phci_reg_write16 (__u32 uReg, __u32 uRegData);
/* HC RAM accessing functions decleration */
void fnvPhciRamRead(phci_t *phci, __u32 length, __u32 direction, __u32 addr, __u8 *byte_data);
void fnvPhciRamWrite(phci_t *phci, __u32 length, __u32 direction, __u32 addr, __u8 *byte_data);
/* HC Initialization functions decleration */
static __u32 fnvPhciHostReset (phci_t *phci);
static void fnvHcIntEnable (phci_t *phci);
static void fnvHcControlInit (phci_t *phci);
static void fnvHcInterruptInit (phci_t *phci);
static void fnvHcFmIntervalInit (phci_t *phci);
static void fnvHcRhPower (phci_t *phci);
static int fnuPhciHostInit (phci_t *phci);
static void fnvHcRamBufferInit( phci_t *phci) ;
static phci_t * __devinit hc_alloc_phci (struct isp1362_dev *dev);
int __devinit hc_found_phci (struct isp1362_dev *dev) ;
void hc_release_phci (phci_t * phci);
/* HC Interrupt Functions */
void phci_isr(struct isp1362_dev *dev, void *isr_data);
static void fnvProcessAtlInt(phci_t *phci);
static void fnvProcessIntlInt(phci_t *phci);
static void fnvProcessIstlInt(phci_t *phci);
/* TD-PTD map function declerations */
static void phci_init_map_buffers(phci_t *phci) ;
static void phci_get_td_ptd_index(ed_t *ed);
static void phci_release_td_ptd_index(ed_t *ed);
static void phci_move_pending_td_ptds(td_ptd_map_buff_t *ptd_map_buff);
static void phci_fill_send_ptd(phci_t *phci, __u32 send_ptd_bitmap,td_ptd_map_buff_t *ptd_map_buff);
static void phci_fill_send_isoc_ptd(phci_t *phci, __u32 send_ptd_bitmap,td_ptd_map_buff_t *ptd_map_buff);
static void phci_submit_ed(phci_t *phci, ed_t *ed) ;
/* 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 (phci_t * phci, 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 (phci_t * phci, ed_t * edi);
static int ep_unlink (phci_t * phci, 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 (phci_t * phci, unsigned int frame);
static td_t * dl_reverse_done_list (phci_t * phci, td_t *td_list);
static void dl_done_list (phci_t * phci, td_t * td_list);
/* Root Hub function declerations */
int rh_send_irq (phci_t * phci, 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 phci *hc, urb_priv_t *urb_priv);
static void urb_rm_priv_locked (struct urb *urb);
static void urb_rm_priv (struct urb *urb);
/* USB core (usb.c) interface functions */
static int sphci_alloc_dev (struct usb_device *usb_dev);
static int sphci_free_dev (struct usb_device *usb_dev);
static int sphci_get_current_frame_number (struct usb_device *usb_dev);
static int sphci_return_urb (struct urb * urb);
static int sphci_submit_urb (struct urb *urb);
static int sphci_unlink_urb (struct urb *urb);
#ifdef CONFIG_USB_OTG
/* otg function declerations for OTG driver interface */
int phci_register_otg(phci_otg_data_t *otg_data);
void phci_unregister_otg(phci_otg_data_t *otg_data);
void phci_otg_port_control(void *priv, __u8 cmd, __u32 *data);
#endif /* CONFIG_USB_OTG */
/* Global Variable decleration */
static td_ptd_map_buff_t td_ptd_map_buff[TD_PTD_TOTAL_BUFF_TYPES]; /* td-ptd map buffer for all 1362 buffers */
static __u8 td_ptd_pipe_x_buff_type[PIPE_BULK+1] = { /* Pipe vs buffer type data structure */
TD_PTD_BUFF_TYPE_ISTL0, /* ISOC for ISTL0 */
TD_PTD_BUFF_TYPE_INTL, /* INT for INTL */
TD_PTD_BUFF_TYPE_ATL, /* CONTROL for ATL */
TD_PTD_BUFF_TYPE_ATL /* BULK for ATL */
};
#ifdef CONFIG_USB_OTG
extern int usb_otg_hub_new_device(struct usb_device *otg_dev, int port);
#define phci_hub_new_device(x) otg_hub_new_device(x,0)
#else
#define phci_hub_new_device(x) usb_new_device(x)
#endif
#define phci_spin_lock_irqsave(p,f) if(!(in_interrupt())) spin_lock_irqsave(p, f)
#define phci_spin_unlock_irqrestore(p,f) if(!(in_interrupt())) spin_unlock_irqrestore (p, f)
/*--------------------------------------------------------------*
* Host Controller operational registers write
*--------------------------------------------------------------*/
void fnvPhciHcorWrite(phci_t *phci,__u32 uReg, __u32 uRegData) {
detail_debug(("fnvPhciHcorWrite(phci = 0x%p, uReg = 0x%x, uRegData = 0x%x)\n",phci, uReg, uRegData))
/* Check if the registers are controlled by software */
if ((uReg == uHcHcdControl ) || (uReg == (uHcHcdControl | 0x80))) {
phci->uHcHcdControl_hcd = uRegData;
return;
}
if ((uReg == uHcHcdCommandStatus) || (uReg == (uHcHcdCommandStatus | 0x80))) {
phci->uHcHcdCommandStatus_hcd = uRegData;
return;
}
#ifdef CONFIG_USB_OTG
/* In OTG mode, clear the internal connect status change bit */
if((uReg == (uHcRhPort1Status+OTG_HC_PORT_NO)) || (uReg == ((uHcRhPort1Status+OTG_HC_PORT_NO)|0x80))) {
if(uRegData & RH_PS_CSC) phci->otg_port_status &= ~(RH_PS_CSC);
}
#endif /* CONFIG_USB_OTG */
isp1362_reg_write32(isp1362_device, (uReg|0x80), uRegData);
} /* fnvPhciHcorWrite() */
/*--------------------------------------------------------------*
* Host Controller operational registers read
*--------------------------------------------------------------*/
void fnvPhciHcorRead(phci_t *phci,__u32 uReg, __u32 *puRegData) {
detail_debug(("fnvPhciHcorRead(phci = 0x%p, uReg = 0x%x, puRegData = 0x%p)\n",phci, uReg, puRegData))
/* Service the HCD HC transfer control registers first */
if (uReg == uHcHcdControl ) {
*puRegData = phci->uHcHcdControl_hcd;
return;
}
if (uReg == uHcHcdCommandStatus) {
*puRegData = phci->uHcHcdCommandStatus_hcd;
return;
}
isp1362_reg_read32(isp1362_device, uReg, (*puRegData));
#ifdef CONFIG_USB_OTG
/* In OTG mode mask the Connect status, connect status change bits from HC and give
* internal values which are controlled by OTG module */
if(uReg == (uHcRhPort1Status+OTG_HC_PORT_NO)) {
*puRegData &= ~(RH_PS_CSC|RH_PS_CCS);
*puRegData |= (phci->otg_port_status & (RH_PS_CSC|RH_PS_CCS));
}
#endif /* CONFIG_USB_OTG */
} /* fnvPhciHcorRead() */
/*--------------------------------------------------------------*
* Host Controller registers read
*--------------------------------------------------------------*/
void phci_reg_read16(__u32 uReg, __u32 *puRegData) {
detail_debug(("phci_reg_read16(uReg = 0x%x, puRegData = 0x%p)\n",uReg, puRegData))
isp1362_reg_read16(isp1362_device, uReg, (*puRegData));
} /* phci_reg_read16() */
/*--------------------------------------------------------------*
* Host Controller registers write
*--------------------------------------------------------------*/
void phci_reg_write16(__u32 uReg, __u32 uRegData) {
detail_debug(("phci_reg_write16(uReg = 0x%x, uRegData = 0x%x)\n",uReg, uRegData))
isp1362_reg_write16(isp1362_device, (uReg|0x80), uRegData);
} /* phci_reg_write16() */
/*--------------------------------------------------------------*
* Host Controller registers read 32 bit
*--------------------------------------------------------------*/
void phci_reg_read32(__u32 uReg, __u32 *puRegData) {
detail_debug(("phci_reg_read32(uReg = 0x%x, puRegData = 0x%p)\n",uReg, puRegData))
isp1362_reg_read32(isp1362_device, uReg, (*puRegData));
} /* phci_reg_read32() */
/*--------------------------------------------------------------*
* Host Controller registers write 32 bit
*--------------------------------------------------------------*/
void phci_reg_write32(__u32 uReg, __u32 uRegData) {
detail_debug(("phci_reg_write32(uReg = 0x%x, uRegData = 0x%x)\n",uReg, uRegData))
isp1362_reg_write32(isp1362_device, (uReg|0x80), uRegData);
} /* phci_reg_write32() */
/*--------------------------------------------------------------*
* Host Controller ATL/INTL/ISTL buffer Write
*--------------------------------------------------------------*/
void fnvPhciRamWrite(phci_t *phci, __u32 length, __u32 direction, __u32 addr, __u8 *byte_data) {
__u32 direct_addr_len;
__u32 original_length;
detail_debug(("fnvPhciRamWrite(length = %d, direction = %d, addr = 0x%x, byte_data = 0x%p)\n",length, direction, addr, byte_data))
if(!length || !byte_data) return; /* If there is nothing to write , return back */
original_length = length;
if(length%2) length++;
/* fill the direct address length register with len+dir+addr */
direct_addr_len = addr & 0x7FFF;
direct_addr_len |= direction;
direct_addr_len |= (length << 16);
phci_reg_write32(REG_DIRECT_ADDR_LEN ,direct_addr_len); // writing the direct address length
isp1362_buff_write(isp1362_device, (REG_DIRECT_ADDR_DATA|0x80), byte_data,original_length);
return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -