📄 ca91c042.c
字号:
//-----------------------------------------------------------------------------// Function : irq_handler// Inputs : int irq, void *dev_id, struct pt_regs *regs// Outputs : void// Description: // Remarks : // History : //-----------------------------------------------------------------------------static void irq_handler(int irq, void *dev_id, struct pt_regs *regs){ long stat, enable, i, vector; enable = readl(baseaddr+LINT_EN); stat = readl(baseaddr+LINT_STAT); if (stat & 0x0100) DMA_irq_handler(); if (stat & 0x0200) LERR_irq_handler(); if (stat & 0x0400) VERR_irq_handler(); for (i=0;i<7;i++) { vector = readl(baseaddr+vmevec[i]); if (stat & vmeirqbit[i] & enable) { if (vmeirqs[i] != NULL) { vmeirqs[i](i+1, vector, dev_id, regs); } } } writel(stat, baseaddr+LINT_STAT); // Clear all pending ints}//-----------------------------------------------------------------------------// Function : cleanup_module// Inputs : void// Outputs : void// Description: // Remarks : // History : //-----------------------------------------------------------------------------void cleanup_module(void){ int x; int pcivector; writel(0,baseaddr+LINT_EN); // Turn off Ints pcivector = readl(baseaddr+PCI_MISC1) & 0x000000FF; free_irq(pcivector,NULL); // Free Vector for (x=1;x<MAX_MINOR+1;x++) { if (image_ba[x]) iounmap(image_ba[x]); } iounmap(baseaddr); unregister_proc(); unregister_chrdev(UNI_MAJOR, "uni");}//----------------------------------------------------------------------------// init_module()//----------------------------------------------------------------------------int init_module(void){ int x, result; unsigned int temp, ba; char vstr[80]; struct pci_dev *uni_pci_dev = NULL; sprintf(vstr,"Tundra Universe PCI-VME Bridge Driver %s\n",Version); printk(vstr); printk(" Copyright 1997-2001, Michael J. Wyrick\n"); if ((uni_pci_dev = pci_find_device(PCI_VENDOR_ID_TUNDRA, PCI_DEVICE_ID_TUNDRA_CA91C042, uni_pci_dev))) { printk(" Universe device found."); // Lets turn Latency off pci_write_config_dword(uni_pci_dev, PCI_MISC0, 0); // Display PCI Registers pci_read_config_dword(uni_pci_dev, PCI_CSR, &status); printk(" Vendor = %04X Device = %04X Status = %08X\n", uni_pci_dev->vendor,uni_pci_dev->device,status); printk(" Class = %08X\n",uni_pci_dev->class); pci_read_config_dword(uni_pci_dev, PCI_MISC0, &temp); printk(" Misc0 = %08X\n",temp); // Setup Universe Config Space // This is a 4k wide memory area that need to be mapped into the kernel // virtual memory space so we can access it. pci_write_config_dword(uni_pci_dev, PCI_BS, CONFIG_REG_SPACE); pci_read_config_dword(uni_pci_dev, PCI_BS, &ba); baseaddr = (char *)ioremap(ba,4096); if (!baseaddr) { printk(" vremap failed to map Universe to Kernel Space.\r"); return 1; } // Check to see if the Mapping Worked out temp = readl(baseaddr); printk(" Read via mapping, PCI_ID = %08X\n",temp); if (temp != 0x000010E3) { printk(" Universe Chip Failed to Return PCI_ID in Memory Map.\n"); return 1; } // OK, Every this is ok so lets turn off the windows writel(0x00800000,baseaddr+LSI0_CTL); writel(0x00800000,baseaddr+LSI1_CTL); writel(0x00800000,baseaddr+LSI2_CTL); writel(0x00800000,baseaddr+LSI3_CTL); // Write to Misc Register // Set VME Bus Time-out // Arbitration Mode // DTACK Enable writel(0x15060000,baseaddr+MISC_CTL); // Lets turn off interrupts writel(0x00000000,baseaddr+LINT_EN); // Disable interrupts in the Universe first writel(0x0000FFFF,baseaddr+LINT_STAT); // Clear Any Pending Interrupts pci_read_config_dword(uni_pci_dev, PCI_INTERRUPT_LINE, &irq); irq &= 0x000000FF; // Only a byte in size result = request_irq(irq, irq_handler, SA_INTERRUPT, "VMEBus (ca91c042)", NULL); if (result) { printk(" ca91c042: can't get assigned pci irq vector %02X\n", irq); } else { writel(0x0000, baseaddr+LINT_MAP0); // Map all ints to 0 writel(0x0000, baseaddr+LINT_MAP1); // Map all ints to 0 } } else { printk(" Universe device not found on PCI Bus.\n"); return 1; } if (register_chrdev(UNI_MAJOR, "uni", &uni_fops)) { printk(" Error getting Major Number for Drivers\n"); iounmap(baseaddr); return(1); } else { printk(" Tundra Loaded.\n"); } register_proc(); for (x=0;x<MAX_MINOR+1;x++) { image_ba[x] = 0; // Not defined image_ptr[x] = 0; // Not defined opened[x] = 0; // Closed OkToWrite[x] = 0; // Not OK mode[x] = MODE_UNDEFINED; // Undefined } // Setup the DMA Timer init_timer(&DMA_timer); DMA_timer.function = DMA_status; // Enable DMA Interrupts writel(0x0700, baseaddr+LINT_EN); return 0;}//-----------------------------------------------------------------------------//// Public Interface////-----------------------------------------------------------------------------//-----------------------------------------------------------------------------// Function : Universe_BaseAddr// Inputs : void// Outputs : char*// Description: Returns the Base Address of the Universe// Remarks : Used for direct access to the Universe for unsupported functions// History : //-----------------------------------------------------------------------------char* Universe_BaseAddr(void) { return baseaddr;}//-----------------------------------------------------------------------------// Function : Universe_IRQ// Inputs : void// Outputs : int// Description: Returns the PCI IRQ that the Universe is on// Remarks : Used mostly for Status and Debugging// History : //-----------------------------------------------------------------------------int Universe_IRQ(void) { return irq;}//-----------------------------------------------------------------------------// Function : enable_vmeirq// Inputs : int irq// Outputs : int// Description: Enable a VME IRQ// Remarks : // History : //-----------------------------------------------------------------------------void enable_vmeirq(unsigned int irq){ int enable; enable = readl(baseaddr+LINT_EN); enable |= vmeirqbit[irq-1]; writel(enable, baseaddr+LINT_EN);}//-----------------------------------------------------------------------------// Function : disable_vmeirq// Inputs : unsigned int irq// Outputs : void// Description: Disable a VME IRQ// Remarks : // History : //-----------------------------------------------------------------------------void disable_vmeirq(unsigned int irq){ int enable; enable = readl(baseaddr+LINT_EN); enable &= ~vmeirqbit[irq-1]; writel(enable, baseaddr+LINT_EN);}//-----------------------------------------------------------------------------// Function : request_vmeirq// Inputs : unsigned int irq, TirqHandler handler// Outputs : int, 0 if successful// Description: assign a handler to a vme interrupt// Remarks : uses a simple check to see if the interrupt is free, then// assigns a handler for the Interrupt// History : //-----------------------------------------------------------------------------int request_vmeirq(unsigned int irq, TirqHandler handler){ if ((irq >= 1) && (irq <= 7)) { if (vmeirqs[irq-1] == NULL) { vmeirqs[irq-1] = handler; return 0; } } return -1; // IRQ is already assigned or invalid}//-----------------------------------------------------------------------------// Function : free_vmeirq// Inputs : unsigned int irq// Outputs : void// Description: release the vmeirq// Remarks : This does not check that a module is freeing an interrupt it// owns. It is up to the programmer to make sure he knows what// what he is doing// History : //-----------------------------------------------------------------------------void free_vmeirq(unsigned int irq){ if ((irq >= 1) && (irq <= 7)) vmeirqs[irq-1] = NULL;}//-----------------------------------------------------------------------------// Function : mapvme// Inputs : unsigned int pci - PCI Address of Image Map (See howto)// unsigned int vme - VME Address of Image (See howto)// unsigned int size - Size of Image// int image - Image Number to Use (See howto)// int ctl - VME Address Space (See howto)// Outputs : char*// Description: // Remarks : // History : //-----------------------------------------------------------------------------char* mapvme(unsigned int pci,unsigned int vme, unsigned int size, int image, int ctl){ char *ptr; unsigned int to; if ((image >=0) && (image <=3)) { if ((pci >= 0xB0000000) && (pci <= 0xE0000000)) { to = vme-pci; // Setup the Mapping in the Universe writel(pci, baseaddr + aBS[image]); writel(pci + size, baseaddr + aBD[image]); writel(to, baseaddr + aTO[image]); writel(ctl | 0x80000000, baseaddr + aCTL[image]); // Get the Virtual address of the PCI Address map ptr = (char *)ioremap(pci,size); if (ptr == NULL) { printk("<ca91c042> ioremap failed in mapvme\n"); return NULL; } else { return ptr; // Everything went ok, return the address pointer } } } return NULL;}//-----------------------------------------------------------------------------// Function : unmapvme// Inputs : char *ptr, int image// Outputs : void// Description: // Remarks : // History : //-----------------------------------------------------------------------------void unmapvme(char *ptr, int image){ if ((image >= 0) && (image <=3)) { // Clear the Mapping in the Universe writel(0x00000000, baseaddr + aCTL[image]); writel(0x00000000, baseaddr + aBS[image]); writel(0x00000000, baseaddr + aBD[image]); writel(0x00000000, baseaddr + aTO[image]); } // Clear Mapping of PCI Memory iounmap(ptr);}//-----------------------------------------------------------------------------// Function : VME_DMA// Inputs : unsigned int pci - PCI Address of Image Map (See howto)// unsigned int vme - VME Address of Image (See howto)// unsigned int count - Size of Image// int image - Image Number to Use (See howto)// int ctl - VME Address Space (See howto)// Outputs : void// Description: // Remarks : This is Like the CMD Packet Version but will do only one transfer// History : //-----------------------------------------------------------------------------void VME_DMA(void* pci, void* vme, unsigned int count, int ctl, TDMAcallback cback){#ifdef __DEBUG__ char buf[256]; sprintf(buf,"<<ca91c042>> DMA Request of virtpci=0x%08X vme=0x%08X cnt=%i ctl=0x%08X\n", pci,vme,count,ctl); printk(buf);#endif // Setup the DMA Transfer in the Universe writel(ctl, baseaddr + DCTL); writel(count, baseaddr + DTBC); writel(virt_to_bus(pci), baseaddr + DLA); writel((int)vme, baseaddr + DVA); // We need to build a timer to timeout DMA access DMA_timer.expires = jiffies + DMATIMEOUT; add_timer(&DMA_timer); // Setup CallBack Function DMACallBackFunc = cback; // Start the Transfer, // Interrupt on Stop,Halt,Done,LERR,VERR,Prot Error DMAType = DMATYPE_SINGLE; writel(0x80216F6F,baseaddr+DGCS); // We are now all setup, so lets return to the calling function so it can // sleep or what ever until the DMA is done}//-----------------------------------------------------------------------------// Function : VME_DMA_LinkedList// Inputs : void* CmdPacketList,TDMAcallback cback// Outputs : int// Description: // Remarks : CmdPacketList is a Phys Address// History : //-----------------------------------------------------------------------------void VME_DMA_LinkedList(void* CmdPacketList,TDMAcallback cback){ debugptr = CmdPacketList; // Setup a DMA Transfer and once the Transfer is complete call cback writel(0x08316F00,baseaddr+DGCS); writel(0x00000000,baseaddr+DTBC); writel((int)CmdPacketList,baseaddr+DCPP); // Command Packet Pointer // We need to build a timer to timeout DMA access DMA_timer.expires = jiffies + DMATIMEOUT; add_timer(&DMA_timer); // Setup CallBack Function DMACallBackFunc = cback; // Start the Transfer, // Interrupt on Stop,Halt,Done,LERR,VERR,Prot Error DMAType = DMATYPE_LLIST; writel(0x88216F6F,baseaddr+DGCS); // We are now all setup, so lets return to the calling function so it can // sleep or what ever until the DMA is done}//-----------------------------------------------------------------------------// Function : VME_Bus_Error// Inputs : // Outputs : // Description: Returns 1 if a Bus Error is Pending// Remarks : // History : 10/30/2000 mjw Started//-------------------------------------------------------------------------mjw-int VME_Bus_Error(void){ int pci_csr; pci_csr = readl(baseaddr+PCI_CSR); // Check for Bus Error writel(pci_csr,baseaddr+PCI_CSR); // Clear the Error return((pci_csr & 0x08000000) ? 1 : 0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -