📄 hal_pci.c
字号:
* This function is called from PCI Driver as an removal function
* in the absence of PCI device or a de-registration of driver.
* This functions checks the registerd drivers (HCD, DCD, OTG) and calls
* the corresponding removal functions. Also initializes the local variables
* to zero.
*/
static void __devexit
isp1362_pci_remove (struct pci_dev *dev)
{
struct isp1362_dev *loc_dev;
int index;
func_debug(("isp1362_pci_remove(dev=%p)\n",dev))
/* For each controller check whether driver is registerd
* or not. If registerd call the removal function if it is
* present
*/
for(index=ISP1362_1ST_DEV;index<ISP1362_LAST_DEV;index++) {
loc_dev = &isp1362_loc_dev[index];
if(loc_dev->driver) {
loc_dev->driver->remove(loc_dev);
loc_dev->driver = NULL;
return;
}
}
/* Clear the local variables
*/
hal_data.io_usage = 0;
hal_data.irq_usage = 0;
return;
} /* End of isp1362_pci_remove */
/* PCI suspend function of ISP1362
* This function is called from PCI Driver.
* This functions checks the registerd drivers (HCD, DCD, OTG) and calls
* the corresponding suspend functions if present.
*/
static int isp1362_pci_suspend (struct pci_dev *dev, __u32 state)
{
struct isp1362_dev *loc_dev;
int index;
func_debug(("isp1362_pci_suspend(dev=%p, state = %x)\n",dev, state))
loc_dev = (struct isp1362_dev *)pci_get_drvdata(dev);
/* For each controller check whether driver is registerd
* or not. If registerd call the suspend function if it is
* present
*/
for(index=ISP1362_1ST_DEV;index<ISP1362_LAST_DEV;(index++,loc_dev++)) {
if(loc_dev->driver && loc_dev->driver->suspend) {
loc_dev->driver->suspend(loc_dev);
}
}
return 0;
} /* End of isp1362_pci_suspend */
/* PCI resume function of ISP1362
* This function is called from PCI Driver.
* This functions checks the registerd drivers (HCD, DCD, OTG) and calls
* the corresponding resume functions if present.
*/
static int isp1362_pci_resume (struct pci_dev *dev)
{
struct isp1362_dev *loc_dev;
int index;
func_debug(("isp1362_pci_resume(dev=%p)\n",dev))
loc_dev = (struct isp1362_dev *)pci_get_drvdata(dev);
/* For each controller check whether driver is registerd
* or not. If registerd call the resume function if it is
* present
*/
for(index=ISP1362_1ST_DEV;index<ISP1362_LAST_DEV;(index++,loc_dev++)) {
if(loc_dev->driver && loc_dev->driver->resume) {
loc_dev->driver->resume(loc_dev);
}
}
return 0;
} /* End of isp1362_pci_resume */
/*--------------------------------------------------------------*
* Top Drivers (HCD, DCD, OTG) interface functions
*--------------------------------------------------------------*/
/*--------------------------------------------------------------*
* hardware register initialization
*--------------------------------------------------------------*/
/* This fuction initializes the ISP1362 device hardware configuration
* register for PCI interface.
*/
void isp1362_set_hw_config(struct isp1362_dev *dev)
{
__u32 hw_cnfg;
#ifndef CONFIG_USB_OTG
struct isp1362_dev *otg_dev = &isp1362_loc_dev[ISP1362_OTG];
#endif /* CONFIG_USB_OTG */
func_debug(("isp1362_set_hw_config(dev=%p)\n",dev))
switch(dev->index) {
case ISP1362_HC:
isp1362_reg_read16(dev, HC_HW_CNFG_REG,hw_cnfg);
/* Enable HC interrupt Pin
* Use only one interrupt for HC and DC
* Connect the 15K pulldown registers on port1&2
* Level triggering, Active low polarity
*/
hw_cnfg |= (HC_INT_PIN_ENABLE | HC_ONE_INT);
hw_cnfg |= (HC_CONNECT_PLDN_15K_DS2 | HC_CONNECT_PLDN_15K_DS1);
#ifdef CONFIG_USB_PHCD_DMA
hw_cnfg |= (HC_DREQ_OUT_POLARITY | HC_DATA_BUS_16BIT_WIDTH);
#endif /* CONFIG_USB_PHCD_DMA */
isp1362_reg_write16(dev,(HC_HW_CNFG_REG|0x80),hw_cnfg);
#ifndef CONFIG_USB_OTG
/* COnfigure the OTG port as the default Host port
* Always drive the VBUS and detect D+ SRP */
hw_cnfg = (OTG_DRV_VBUS|OTG_A_SEL_SRP|OTG_A_SRP_DET_EN);
isp1362_reg_write16(otg_dev,(OTG_CONTROL_REG|0x80),hw_cnfg);
#endif /* CONFIG_USB_OTG */
break;
case ISP1362_DC:
isp1362_reg_read16(dev, DC_HW_CNFG_REG, hw_cnfg);
/* No Clock Division, Clock is always running
* Level triggering, Active low polarity
*/
hw_cnfg &= ~(DC_CLK_DIV); /* No clock division */
hw_cnfg |= (DC_CLK_RUN); /* Clock is always running */
isp1362_reg_write16(dev,(DC_HW_CNFG_REG&0xFE),hw_cnfg);
#ifndef CONFIG_USB_OTG
/* COnfigure the OTG port as the default device port */
hw_cnfg = (OTG_LOC_CONN|OTG_SEL_HC_DC);
hw_cnfg &= (~OTG_A_RDIS_LCON_EN);
hw_cnfg &= (~OTG_LOC_PULLDN_DP);
isp1362_reg_write16(otg_dev,(OTG_CONTROL_REG|0x80),hw_cnfg);
#endif /* CONFIG_USB_OTG */
break;
default:
break;
}
} /* End of isp1362_set_hw_config() */
/*--------------------------------------------------------------*
* IO PORT Management Functions
*--------------------------------------------------------------*/
/* This fuction checks whether the IO region is free for use or not
* The IO region is specified in the dev structure fields.
* Since OTG uses same IO ports as Host Controller and OTG driver
* depends on HCD, by the time OTG is loaded HCD has already been loaded
* and if HC is using IO resources, we say OTG can access the IO resources
* for HCD and DCD we use system call check_region()
*/
int isp1362_check_io_region(struct isp1362_dev *dev)
{
func_debug(("isp1362_check_io_region(dev=%p)\n",dev))
/* If OTG driver, check the IO resources of HCD
*/
if(dev->index == ISP1362_OTG) {
if(isp1362_loc_dev[ISP1362_HC].io_res) return 0;
else return -EBUSY;
}
return check_region(dev->io_base, dev->io_len);
} /* End of isp1362_check_io_region */
/* This fuction assigns IO region to the driver
* The IO region is specified in the "dev" structure fields.
* Since OTG uses same IO ports as Host Controller and OTG driver
* depends on HCD, for OTG driver the HCD io resources are returned
* for HCD and DCD we use system call request_region()
*/
struct resource* isp1362_request_io_region(struct isp1362_dev *dev)
{
func_debug(("isp1362_request_io_region(dev=%p)\n",dev))
hal_data.io_usage++;
if(dev->index == ISP1362_OTG) {
/* If OTG return the HCD io resources */
dev->io_res = isp1362_loc_dev[ISP1362_HC].io_res;
} else {
/* Store the IO resources */
dev->io_res = request_region(dev->io_base, dev->io_len, isp1362_driver_name);
}
return dev->io_res;
} /* End of isp1362_request_io_region */
/* This fuction releases IO region for the driver
* The IO region is specified in the "dev" structure fields.
* Since OTG uses same IO ports as Host Controller and OTG driver
* depends on HCD, for OTG driver nothing is done
* for HCD and DCD we use system call release_region()
*/
void isp1362_release_io_region(struct isp1362_dev *dev)
{
func_debug(("isp1362_release_io_region(dev=%p)\n",dev))
hal_data.io_usage--;
dev->io_res = NULL;
if(dev->index == ISP1362_OTG) return;
return release_region(dev->io_base, dev->io_len);
} /* End of isp1362_release_io_region */
/*--------------------------------------------------------------*
* Interrupt Management Functions
*--------------------------------------------------------------*/
/* This function registers the ISR of driver with this driver.
* Since there is only one interrupt line, when the first driver
* is registerd, will call the system function request_irq. The PLX
* bridge needs enabling of interrupt in the interrupt control register to
* pass the local interrupts to the PCI (cpu).
* For later registrations will just update the variables. On ISR, this driver
* will look for registered handlers and calls the corresponding driver's
* ISR "handler" function with "isr_data" as parameter.
*/
int isp1362_request_irq(void (*handler)(struct isp1362_dev *, void *),
struct isp1362_dev *dev, void *isr_data)
{
int result = 0;
__u16 intcsr;
func_debug(("isp1362_request_irq(handler=%p,dev=%p,isr_data=%p)\n",handler,dev,isr_data))
if(!(hal_data.irq_usage)) {
/* If this is the first request
*/
result= request_irq(dev->irq,isp1362_pci_isr,
SA_SHIRQ, isp1362_driver_name,
(void*)isp1362_loc_dev);
}
hal_data.irq_usage++;
if(result >= 0) {
if(hal_data.irq_usage == 1) {
/* If this is the first request
*/
intcsr = inb(pci_io_base + PLX_INT_CSR_REG+1);
intcsr |= 0x09;
outb(intcsr,(pci_io_base + PLX_INT_CSR_REG+1));
func_debug(("Enabling PLX bridge local/cpu interrupts\n"))
}
dev->handler = handler;
dev->isr_data = isr_data;
}
return result;
} /* End of isp1362_request_irq */
/* This function de-registers the ISR of driver with this driver.
* Since there is only one interrupt line, when the last driver
* is de-registerd, will call the system function free_irq. The PLX
* bridge needs disabling of interrupt in the interrupt control register to
* block the local interrupts to the PCI (cpu).
*/
void isp1362_free_irq(struct isp1362_dev *dev, void *isr_data)
{
__u16 intcsr;
func_debug(("isp1362_free_irq(dev=%p,isr_data=%p)\n",dev,isr_data))
hal_data.irq_usage--;
if(!hal_data.irq_usage) {
/* If this is the last free request
*/
free_irq(dev->irq,isp1362_loc_dev);
intcsr = inb(pci_io_base + PLX_INT_CSR_REG+1);
intcsr &= 0xF6;
outb(intcsr,(pci_io_base + PLX_INT_CSR_REG+1));
detail_debug(("disabling PLX bridge local/PCI interrupts"))
}
} /* isp1362_free_irq */
/*--------------------------------------------------------------*
* Driver Registration Functions
*--------------------------------------------------------------*/
/* This function is used by top driver (OTG, HCD, DCD) to register
* their communication functions (probe, remove, suspend, resume) using
* the drv data structure.
* This function will call the probe function of the driver if the ISP1362
* corresponding to the driver is enabled
*/
int isp1362_register_driver(struct isp1362_driver *drv)
{
struct isp1362_dev *dev;
int result;
func_debug(("isp1362_register_driver(drv=%p)\n",drv))
if(!drv) return -EINVAL;
dev = &isp1362_loc_dev[drv->index];
if(dev->active) result = drv->probe(dev);
else result = -ENODEV;
if(result >= 0 ) {
isp1362_printk(KERN_INFO __FILE__ ": Registered Driver %s\n",drv->name);
dev->driver = drv;
}
return result;
} /* End of isp1362_register_driver */
/* This function is used by top driver (OTG, HCD, DCD) to de-register
* their communication functions (probe, remove, suspend, resume) using
* the drv data structure.
* This function will check whether the driver is registered or not and
* call the remove function of the driver if registered
*/
void isp1362_unregister_driver(struct isp1362_driver *drv)
{
struct isp1362_dev *dev;
func_debug(("isp1362_unregister_driver(drv=%p)\n",drv))
dev = &isp1362_loc_dev[drv->index];
if(dev->driver == drv) {
/* driver registered is same as the requestig driver */
drv->remove(dev);
#ifndef CONFIG_USB_OTG
if(drv->index == ISP1362_HC || drv->index == ISP1362_DC) {
/* SET OTG Cofiguration to default */
isp1362_reg_write16((&isp1362_loc_dev[ISP1362_OTG]),(OTG_CONTROL_REG|0x80),(OTG_SEL_HC_DC|OTG_LOC_PULLDN_DM|OTG_LOC_PULLDN_DP));
}
#endif /* CONFIG_USB_OTG */
dev->driver = NULL;
isp1362_printk(KERN_INFO __FILE__ ": De-registered Driver %s\n",drv->name);
return;
}
} /* End of isp1362_unregister_driver */
/*--------------------------------------------------------------*
* Module Management Functions
*--------------------------------------------------------------*/
/* This is the module initialization function. It registers to
* PCI driver for a PLX PCI bridge device. And also resets the
* internal data structures before registering to PCI driver.
*/
static int __init isp1362_pci_module_init (void)
{
int result = 0;
func_debug(("isp1362_pci_module_init(void)\n"))
memset(isp1362_loc_dev,0,sizeof(isp1362_loc_dev));
if((result = pci_module_init(&isp1362_pci_driver)) < 0) {
isp1362_printk(KERN_INFO __FILE__ ": %s Iinitialization Failed (error = %d)\n",isp1362_driver_name,result);
return result;
}
isp1362_printk(KERN_INFO __FILE__ ": %s Initialization Success \n",isp1362_driver_name);
return result;
}
/* This is the module eleanup function. It de-registers from
* PCI driver and resets the internal data structures.
*/
static void __exit isp1362_pci_module_cleanup (void)
{
func_debug(("isp1362_pci_module_cleanup(void)\n"))
pci_unregister_driver (&isp1362_pci_driver);
memset(isp1362_loc_dev,0,sizeof(isp1362_loc_dev));
}
module_init (isp1362_pci_module_init);
module_exit (isp1362_pci_module_cleanup);
MODULE_AUTHOR (DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -