Subversion Repositories f9daq

Rev

Rev 43 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. //****************************************************************************
  2. // Copyright (C) 2000-2006  ARW Elektronik Germany
  3. //
  4. //
  5. // This program is free software; you can redistribute it and/or modify
  6. // it under the terms of the GNU General Public License as published by
  7. // the Free Software Foundation; either version 2 of the License, or
  8. // (at your option) any later version.
  9. //
  10. // This program is distributed in the hope that it will be useful,
  11. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. // GNU General Public License for more details.
  14. //
  15. // You should have received a copy of the GNU General Public License
  16. // along with this program; if not, write to the Free Software
  17. // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18. //
  19. // This product is not authorized for use as critical component in
  20. // life support systems without the express written approval of
  21. // ARW Elektronik Germany.
  22. //  
  23. // Please announce changes and hints to ARW Elektronik
  24. //
  25. // Maintainer(s): Klaus Hitschler (klaus.hitschler@gmx.de)
  26. //
  27. //****************************************************************************
  28.  
  29. //****************************************************************************
  30. //
  31. // main.c -- the main driver module for the PCIVME PCI to VME Interface
  32. //           Thanks to A.Rubini's Book and Dirk Muelhlenberg and H.J.Mathes
  33. //           for their arwvme driver
  34. //
  35. // $Log: main.c,v $
  36. // Revision 1.10  2006/06/04 12:20:46  klaus
  37. // release_20060604; Version 3.2; pci_{en|dis}able_device() added
  38. //
  39. // Revision 1.9  2004/08/13 19:23:26  klaus
  40. // conversion to kernel-version 2.6, released version 3.0
  41. //
  42. // Revision 1.8  2003/06/27 17:25:52  klaus
  43. // incomplete try to get mmap() with nopage() running for automatic page switch
  44. //
  45. // Revision 1.7  2002/10/18 21:56:28  klaus
  46. // completed functional features, untested
  47. //
  48. // Revision 1.6  2002/10/18 21:56:28  klaus
  49. // completed functional features, untested
  50. //
  51. // Revision 1.5  2002/10/17 19:05:03  klaus
  52. // VME access is working through test to lib to driver
  53. //
  54. //****************************************************************************
  55. #define NOPAGE_SIGBUS   (NULL)
  56.  
  57. #define VERSION_HI 3
  58. #define VERSION_LO 2
  59.  
  60. /*--- INCLUDES ---------------------------------------------------------------------------*/
  61. #include "common.h"  /* must be the first include */
  62. #include <linux/module.h>
  63.  
  64. #include <linux/sched.h>
  65. #include <linux/proc_fs.h>
  66. #include <linux/pci.h>
  67. #include <asm/types.h>
  68. #include <linux/mm.h>
  69. #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
  70. #include <linux/interrupt.h>
  71. #endif
  72.  
  73. #include "askpci.h"
  74. #include "plxbug.h"
  75. #include "plx9050.h"
  76. #include "fops.h"
  77. #include "pcivme.h"
  78. #include "pciif.h"
  79. #include "vic.h"
  80. #include "main.h"
  81.  
  82. /*--- DEFINES -----------------------------------------------------------------------------*/
  83. MODULE_AUTHOR("klaus.hitschler@gmx.de");
  84. MODULE_DESCRIPTION("Driver for ARW Elektronik PCI VME interface.");
  85. MODULE_SUPPORTED_DEVICE("PCIVME");
  86. MODULE_LICENSE("GPL");
  87.  
  88. #define MAJOR_NO               0                         /* use dynamic assignment */
  89.  
  90. #define PCIVME_VENDOR_ID  0x10B5
  91. #define PCIVME_DEVICE_ID  0x9050
  92. #define PCIVME_SUBSYS_ID  0x1167
  93. #define PCIVME_SUBVEN_ID  0x9050
  94.  
  95. /*--- TYPEDEFS ----------------------------------------------------------------------------*/
  96.  
  97. /*--- GLOBALS -----------------------------------------------------------------------------*/
  98. DRIVER_OBJ drv;
  99.  
  100. /*--- LOCALS ------------------------------------------------------------------------------*/
  101.  
  102. /*--- FUNCTIONS ---------------------------------------------------------------------------*/
  103.  
  104. struct proc_dir_entry *proc;
  105.  
  106. static int my_interrupt(u16 intCSR)
  107. {
  108.     int result = NOT_MY_INTERRUPT;
  109.  
  110.     if (intCSR & 0x0040)  // it is global enabled
  111.     {
  112.         if ((intCSR & 0x0028) == 0x0028) // it is a enabled PCIADA interrupt
  113.             result = PCIADA_INTERRUPT;
  114.         else
  115.             if ((intCSR & 0x0005) == 0x0005) // it is a enabled VMEMM interrupt
  116.             result = VMEMM_INTERRUPT;
  117.     }
  118.  
  119.     return result;
  120. }
  121.  
  122. static irqreturn_t pcivme_irqhandler(int irq, void *dev_id )
  123. {
  124.     DEVICE_OBJ *pd = (DEVICE_OBJ *)dev_id;
  125.  
  126.     if (pd)
  127.     {
  128.         // evaluate the reason of the interrupt - if it is mine
  129.         u16 intCSR          = readw((const volatile void *) (pd->pPCIADAIntCSR));
  130.         int which_interrupt = my_interrupt(intCSR);
  131.  
  132.         if (which_interrupt)
  133.         {
  134.             writew(intCSR & ~0x40, (volatile void *) pd->pPCIADAIntCSR); /* disable global interrupts */
  135.             pd->wIrqStatus = (u16)which_interrupt;
  136.             pd->dwInterruptCount++;
  137.             wake_up_interruptible(&pd->event_queue);   /* stop blocking if any */
  138.                        
  139.                         return IRQ_RETVAL(1);
  140.         }
  141.     }
  142.        
  143.         return IRQ_RETVAL(0);
  144. }
  145.  
  146. static int request_io_memory(PCIConfig *pPch)
  147. {
  148.     if (check_mem_region(pci_resource_start(pPch->pciDev, 0),  LCR_SPACE))
  149.     {
  150.         PRINTK(KERN_DEBUG "%s : LCR 0x%08lx\n", DEVICE_NAME, (long unsigned int) pci_resource_start(pPch->pciDev, 0));
  151.         return -EBUSY;
  152.     }
  153.  
  154.     if (check_mem_region(pci_resource_start(pPch->pciDev, 2),  CTL_SPACE))
  155.     {
  156.         PRINTK(KERN_DEBUG "%s : CTL 0x%08lx\n", DEVICE_NAME, (long unsigned int) pci_resource_start(pPch->pciDev, 2));
  157.         return -EBUSY;
  158.     }
  159.  
  160.     if (check_mem_region(pci_resource_start(pPch->pciDev, 2) + CTL_SPACE, VME_SPACE))
  161.     {
  162.         PRINTK(KERN_DEBUG "%s : VME 0x%08lx\n", DEVICE_NAME, (long unsigned int) pci_resource_start(pPch->pciDev, 2) + CTL_SPACE);
  163.         return -EBUSY;
  164.     }
  165.  
  166.     request_mem_region(pci_resource_start(pPch->pciDev, 0),  LCR_SPACE, DEVICE_NAME);
  167.     request_mem_region(pci_resource_start(pPch->pciDev, 2),  CTL_SPACE, DEVICE_NAME);
  168.     request_mem_region(pci_resource_start(pPch->pciDev, 2) + CTL_SPACE, VME_SPACE, DEVICE_NAME);
  169.  
  170.     return 0;
  171. }
  172.  
  173. static void release_io_memory(PCIConfig *pPch)
  174. {
  175.     release_mem_region(pci_resource_start(pPch->pciDev, 0),  LCR_SPACE);
  176.     release_mem_region(pci_resource_start(pPch->pciDev, 2),  CTL_SPACE);
  177.     release_mem_region(pci_resource_start(pPch->pciDev, 2) + CTL_SPACE, VME_SPACE);
  178. }
  179.  
  180. static int translate_addresses(DEVICE_OBJ *pd, PCIConfig *pPch)    /* differs from PCICC32 */
  181. {
  182.     if (pci_resource_start(pPch->pciDev, 0) < LOW_MEMORY)  /* LCR ISA base addresses */
  183.         pd->pLCR = (u32)bus_to_virt(pci_resource_start(pPch->pciDev, 0));
  184.     else
  185.         pd->pLCR = (u32)ioremap(pci_resource_start(pPch->pciDev, 0), LCR_SPACE);
  186.  
  187.     if (pci_resource_start(pPch->pciDev, 2) < LOW_MEMORY)  /* User ISA base addresses */
  188.     {
  189.         pd->pCtl = (u32)bus_to_virt(pci_resource_start(pPch->pciDev, 2)            );
  190.         pd->pVME = (u32)bus_to_virt(pci_resource_start(pPch->pciDev, 2) + CTL_SPACE);
  191.     }
  192.     else
  193.     {
  194.         pd->pPhysVME = pci_resource_start(pPch->pciDev, 2) + CTL_SPACE;
  195.  
  196.         pd->pCtl = (u32)ioremap(pci_resource_start(pPch->pciDev, 2)            , CTL_SPACE);
  197.         pd->pVME = (u32)ioremap(pci_resource_start(pPch->pciDev, 2) + CTL_SPACE, VME_SPACE);
  198.     }
  199.  
  200.     return 0;
  201. }
  202.  
  203. static void un_translate_addresses(DEVICE_OBJ *pd, PCIConfig *pPch)
  204. {
  205.     if (pci_resource_start(pPch->pciDev, 0) >= LOW_MEMORY)  /* no LCR ISA base addresses */
  206.         iounmap((void *)pd->pLCR);
  207.  
  208.     if (pci_resource_start(pPch->pciDev, 2) >= LOW_MEMORY)
  209.     {
  210.         pd->pPhysVME = 0;
  211.  
  212.         iounmap((void *)pd->pCtl);
  213.         iounmap((void *)pd->pVME);
  214.     }
  215. }
  216.  
  217. static void soft_init(DEVICE_OBJ *pd)
  218. {
  219.     if (pd)
  220.     {
  221.         init_waitqueue_head(&pd->event_queue);
  222.  
  223.         pd->pLCR = pd->pCtl = pd->pVME = 0;
  224.         pd->pPch = (PCIConfig *)NULL;
  225.         pd->bConnected = 0;
  226.         pd->wInitStep = 0;    
  227.         pd->wIrq = 0xFFFF;          
  228.         pd->dwInterruptCount = 0;
  229.         pd->wIrqStatus = 0;
  230.         pd->nOpenCounter = 0;
  231.  
  232.         pd->cModuleNumber = 255;
  233.         pd->cFPGAVersion = 255;
  234.         pd->cSystemController = 0;
  235.         pd->cWordMode         = 0;
  236.  
  237.         pd->pAdrMod = 0;
  238.         pd->pAdrReg = 0;
  239.         pd->pCSR    = 0;
  240.  
  241.         pd->pPCIADACntrl  = 0;
  242.         pd->pPCIADAIntCSR = 0;      
  243.  
  244.         pd->bCurrentModifier     = 0;
  245.         pd->dwCurrentPageAddress = -1;
  246.                                 pd->currentMap.pageptr = NOPAGE_SIGBUS;
  247.                                 pd->currentMap.addr = 0;
  248.     }
  249. }
  250.  
  251. int test_connection(DEVICE_OBJ *pd)
  252. {
  253.     u16 intCSR_store;
  254.     u16 cntrl_store;
  255.     int i;      
  256.     int error   = 0;
  257.     u32 dwADRH  = pd->pCtl + ADRH;
  258.     u32 dwADRL  = pd->pCtl + ADRL;
  259.     u32 dwADRHL = pd->pCtl + ADRHL;
  260.     u32 dwStore;
  261.     u16 wRet;
  262.  
  263.     cntrl_store  = readw((const volatile void *) pd->pPCIADACntrl);         /* read CONTROL register */
  264.     intCSR_store = readw((const volatile void *) pd->pPCIADAIntCSR);        /* read interrupt + CSR register */
  265.  
  266.     writew(0, (volatile void *) pd->pPCIADAIntCSR);                   /* disable interrupts */
  267.     writew(cntrl_store | 0x0180, (volatile void *) pd->pPCIADACntrl); /* enable access */
  268.  
  269.     // save adr register
  270.     dwStore = readl((const volatile void *) dwADRHL);
  271.     for (i = 1000; i; i--)
  272.     {
  273.         writew(0x5555, (volatile void *) dwADRH);
  274.         writew(0xAAAA, (volatile void *) dwADRL);
  275.         wRet   = readw((const volatile void *) dwADRH);
  276.         if (wRet != 0x5555)
  277.         {
  278.             error = 1;
  279.             break;
  280.         }
  281.  
  282.         writew(0xAAAA, (volatile void *) dwADRH);
  283.         writew(0x5555, (volatile void *) dwADRL);
  284.         wRet   = readw((const volatile void *) dwADRH);
  285.         if (wRet != 0xAAAA)
  286.         {
  287.             error = 1;
  288.             break;
  289.         }
  290.  
  291.         writew(0x0000, (volatile void *) dwADRH);
  292.         writew(0xFFFF, (volatile void *) dwADRL);
  293.         wRet   = readw((const volatile void *) dwADRH);
  294.         if (wRet != 0x0000)
  295.         {
  296.             error = 1;
  297.             break;
  298.         }
  299.  
  300.         writew(0xFFFF, (volatile void *) dwADRH);
  301.         writew(0x0000, (volatile void *) dwADRL);
  302.         wRet   = readw((const volatile void *) dwADRH);
  303.         if (wRet != 0xFFFF)
  304.         {
  305.             error = 1;
  306.             break;
  307.         }
  308.     }
  309.  
  310.     // restore register
  311.     writel(dwStore, (volatile void *) dwADRHL);
  312.  
  313.     //clear possible interrupts
  314.     writew(cntrl_store & ~0x0100, (volatile void *) pd->pPCIADACntrl); /* clear potential interrupt */
  315.  
  316.     // restore LCR registers
  317.     writew(cntrl_store,  (volatile void *) pd->pPCIADACntrl);
  318.     writew(intCSR_store, (volatile void *) pd->pPCIADAIntCSR);
  319.  
  320.     return error;  
  321. }
  322.  
  323. int get_module_info(DEVICE_OBJ *pd)
  324. {
  325.     u16 intCSR_store;
  326.     u16 cntrl_store;
  327.     int found = 0;
  328.     u16 data;
  329.  
  330.     cntrl_store  = readw((const volatile void *) pd->pPCIADACntrl);  /* read CONTROL register */
  331.     intCSR_store = readw((const volatile void *) pd->pPCIADAIntCSR); /* read interrupt + CSR register */
  332.  
  333.     PRINTK(KERN_DEBUG "%s : cntrl=0x%04x, intCSR=0x%04x\n", DEVICE_NAME, cntrl_store, intCSR_store);
  334.  
  335.     if (cntrl_store & 0x0800) /* a VMEMM is connected */
  336.     {
  337.         u16 bla = cntrl_store | 0x0180;
  338.  
  339.         writew(0,   (volatile void *) pd->pPCIADAIntCSR); /* disable interrupts */
  340.         writew(bla, (volatile void *) pd->pPCIADACntrl);  /* enable access */
  341.  
  342.         // read main status register
  343.         data = readw((const volatile void *) pd->pCSR);
  344.  
  345.         if ((data & 0xF000) != VMEMM_MODULE_TYPE)
  346.         {
  347.             pd->cModuleNumber = pd->cFPGAVersion = 255;
  348.             printk(KERN_ERR "%s : Wrong module type connected @ index %d!\n", DEVICE_NAME, pd->wIndex);
  349.         }
  350.         else
  351.         {
  352.             found = 1;
  353.             pd->cModuleNumber     = (data >> 4) & 0xF;
  354.             pd->cFPGAVersion      = (data >> 8) & 0xF;
  355.             pd->cSystemController = (data & 0x0008);
  356.             pd->cWordMode         = (data & 0x0004);
  357.         }
  358.  
  359.         // clear possible interrupts
  360.         writew(cntrl_store & ~0x0100, (volatile void *) pd->pPCIADACntrl); /* clear potential interrupt */
  361.  
  362.         /* restore all contents */
  363.         writew(cntrl_store,  (volatile void *) pd->pPCIADACntrl);
  364.         writew(intCSR_store, (volatile void *) pd->pPCIADAIntCSR);
  365.     }
  366.  
  367.     return found;  
  368. }
  369.  
  370. #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
  371. static int pcivme_read_proc(char *buf, char **start, off_t offset, int len)
  372. #else
  373. //static int pcivme_read_proc(char *buf, char **start, off_t offset, int len, int *eof, void *data)
  374. static int pcivme_read_proc(struct file *filp,char *buf,size_t count,loff_t *offp )
  375. #endif
  376.     {
  377.     int              pos = 0;
  378.     DEVICE_OBJ       *pd;
  379.     PCIConfig        *ch;
  380.     u16                cntrl;
  381.     char             *cause = "none";
  382.     struct list_head *ptr;
  383.     PRINTK(KERN_DEBUG "%s : pcivme_read_proc()\n",DEVICE_NAME);
  384.    
  385.     if (*offp != 0) return 0;
  386.     pos += sprintf(buf + pos, "\nPCIVME information. Version %d.%d of %s from Klaus Hitschler.\n", VERSION_HI, VERSION_LO, __DATE__);
  387.  
  388.     pos += sprintf(buf + pos, " ---------------------\n");
  389.     pos += sprintf(buf + pos, " Interfaces found : %d\n", drv.count);
  390.     pos += sprintf(buf + pos, " Major Number     : %d\n", drv.nMajor);
  391.  
  392.     for (ptr = drv.devList.next; ptr != &drv.devList; ptr = ptr->next)
  393.     {
  394.         pd = list_entry(ptr, DEVICE_OBJ, list);
  395.         ch = pd->pPch;
  396.         cntrl = readw((const volatile void *)(pd->pLCR + PLX9050_CNTRL));
  397.         pos += sprintf(buf + pos, " --- %d ---------------\n", pd->wIndex + 1);
  398.         pos += sprintf(buf + pos, " LCR     phys/virt/size : 0x%08lx/0x%08x/%d\n",(long unsigned int) pci_resource_start(ch->pciDev, 0),             pd->pLCR, LCR_SPACE);
  399.         pos += sprintf(buf + pos, " Control phys/virt/size : 0x%08lx/0x%08x/%d\n",(long unsigned int)  pci_resource_start(ch->pciDev, 2),             pd->pCtl, CTL_SPACE);
  400.         pos += sprintf(buf + pos, " VME     phys/virt/size : 0x%08lx/0x%08x/%d\n",(long unsigned int)  pci_resource_start(ch->pciDev, 2) + CTL_SPACE, pd->pVME, VME_SPACE);
  401.         pos += sprintf(buf + pos, " Irq                    : %d\n", pd->wIrq);
  402.  
  403.         if (pd->bConnected)
  404.         {
  405.             pos += sprintf(buf + pos, " VMEMM is or was        : (software) connected.\n");
  406.             pos += sprintf(buf + pos, " Module-Number          : %d\n", pd->cModuleNumber);
  407.             pos += sprintf(buf + pos, " FPGA-Version           : %d\n", pd->cFPGAVersion);
  408.             pos += sprintf(buf + pos, " Systemcontroller       : %s\n", (pd->cSystemController) ? "yes" : "no");
  409.             pos += sprintf(buf + pos, " Word Mode              : %s\n", (pd->cWordMode) ? "yes" : "no");
  410.         }
  411.         else
  412.             pos += sprintf(buf + pos, " VMEMM is or was        : not (software) connected.\n");      
  413.  
  414.         if (!((cntrl & 0x0800) && (!(cntrl & 0x0600))))
  415.             pos += sprintf(buf + pos, " VMEMM is               : powered off or cable disconnected.\n");
  416.  
  417.         pos += sprintf(buf + pos, " IrqCount               : %d\n", pd->dwInterruptCount);
  418.         if (pd->wIrqStatus & PCIADA_INTERRUPT)
  419.             cause = "Timeout";
  420.         else
  421.             if (pd->wIrqStatus & VMEMM_INTERRUPT)
  422.                 cause = "VME";
  423.         pos += sprintf(buf + pos, " Pending IrqStatus      : %s\n", cause);
  424.     }
  425.  
  426.     pos += sprintf(buf + pos, "\n");
  427.     if (pos>count) {
  428.       buf[count-1]=0;
  429.       pos=count;
  430.     }    
  431.     PRINTK(KERN_DEBUG "%s : pcivme_read_proc() end count=%d\n",DEVICE_NAME, pos);
  432. #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
  433.     //*eof = 1;
  434. #endif
  435.     *offp = pos;
  436.    
  437.     return pos;
  438. }
  439.  
  440.  
  441.  
  442.  
  443. #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
  444. struct proc_dir_entry pcimod_proc_entry =
  445. {
  446.     namelen:    7,                  /* len of name */
  447.     name:       DEVICE_NAME,        /* entry  name */
  448.     mode:       S_IFREG | S_IRUGO,  /* mode */
  449.     nlink:      1,                  /* nlinks */
  450.     get_info:   pcivme_read_proc,  /* function used to read data */
  451. };
  452. #else
  453. struct file_operations pcivme_read_proc_fops = {
  454. read: pcivme_read_proc
  455. };
  456. #endif
  457.  
  458. static void deleteMyLists(void)
  459. {
  460.     DEVICE_OBJ      *pd;
  461.  
  462.     /* delete my lists */
  463.     while (!list_empty(&drv.devList))                 // cycle through the list of pci devices and remove them
  464.     {
  465.         pd = (DEVICE_OBJ *)drv.devList.prev;            // empty in reverse order
  466.         list_del(&pd->list);
  467.         kfree(pd);
  468.     }
  469.  
  470.     DeletePCIConfig(&drv);
  471. }
  472.  
  473. int pcivme_module_init(void)
  474. {
  475.     PCIConfig        *ch;
  476.     DEVICE_OBJ       *pd;
  477.     int              result = 0;
  478.     struct list_head *ptr;
  479.  
  480.     PRINTK(KERN_DEBUG "%s : init_module\n", DEVICE_NAME);
  481.  
  482.     /* create list of PCIADAs and work devices */
  483.     INIT_LIST_HEAD(&drv.devList);
  484.     INIT_LIST_HEAD(&drv.pciList);
  485.  
  486.     drv.count = 0;
  487.  
  488.     /* search for all PCIADA modules */
  489.     if ((result = GetPCIConfig(&drv, PCIVME_DEVICE_ID, PCIVME_VENDOR_ID, PCIVME_SUBSYS_ID, PCIVME_SUBVEN_ID)))
  490.     {
  491.         deleteMyLists();
  492.         return result;
  493.     }
  494.  
  495.     /* fix the PLX bug in all PCIADAs */
  496.     for (ptr = drv.pciList.next; ptr != &drv.pciList; ptr = ptr->next)
  497.     {
  498.         ch = list_entry(ptr, PCIConfig, list);
  499.         PLX9050BugFix(ch);
  500.     }
  501.  
  502.     /* create work_devices and translate the access addresses */
  503.     for (ptr = drv.pciList.next; ptr != &drv.pciList; ptr = ptr->next)
  504.     {
  505.         ch = list_entry(ptr, PCIConfig, list);
  506.  
  507.         pd = (DEVICE_OBJ *)kmalloc(sizeof(DEVICE_OBJ), GFP_ATOMIC);
  508.         soft_init(pd);
  509.         pd->pPch = ch;
  510.         pd->wIndex = drv.count;
  511.  
  512.         if (!request_io_memory(ch))
  513.         {
  514.             pd->wInitStep = 1;
  515.  
  516.             if (translate_addresses(pd, ch))
  517.             {
  518.                 printk(KERN_ERR "%s : translation of addresses failed!\n", DEVICE_NAME);
  519.                 kfree_s(pd, sizeof(*pd));       // FREE(pd);
  520.             }
  521.             else
  522.             {
  523.                 // successful translate_addresses
  524.                 pd->wInitStep = 2;
  525.  
  526.                 // create some 'fast access' addresses
  527.                 pd->pAdrMod = pd->pCtl + VICBASE + AMSR;
  528.                 pd->pAdrReg = pd->pCtl + ADRHL;
  529.                 pd->pCSR    = pd->pCtl + CSR;
  530.  
  531.                 pd->pPCIADACntrl  = pd->pLCR + PLX9050_CNTRL;
  532.                 pd->pPCIADAIntCSR = pd->pLCR + PLX9050_INTCSR;
  533.  
  534.                 if (request_irq(pd->pPch->pciDev->irq, pcivme_irqhandler, IRQF_DISABLED| IRQF_SHARED, DEVICE_NAME, pd))
  535.                 {
  536.                     printk(KERN_ERR "%s : can't get irq @ %d\n", DEVICE_NAME, pd->pPch->pciDev->irq);
  537.                     kfree_s(pd, sizeof(*pd));       // FREE(pd);
  538.                 }
  539.                 else
  540.                 {
  541.                     // successful request_irq
  542.                     pd->wInitStep = 3;
  543.                     pd->wIrq = pd->pPch->pciDev->irq;
  544.  
  545.                     list_add_tail(&pd->list, &drv.devList);  /* add this device to list of working devices*/
  546.                     drv.count++;
  547.  
  548.                     pd->bConnected =  get_module_info(pd);
  549.                     if (pd->bConnected && test_connection(pd))
  550.                     {
  551.                         printk(KERN_ERR "%s : connection test @ driver install failed!\n", DEVICE_NAME);
  552.                         pd->bConnected = 0;
  553.                     }
  554.                 }
  555.             }
  556.         }
  557.         else
  558.             printk(KERN_ERR "%s : requested io-memory still claimed!\n", DEVICE_NAME);
  559.     }
  560.  
  561.     drv.nMajor = MAJOR_NO;
  562.     result = register_chrdev(drv.nMajor, DEVICE_NAME, &pcivme_fops);
  563.     if (result < 0)
  564.     {
  565.         printk(KERN_ERR "%s: Can't install driver (%d)\n", DEVICE_NAME, result);
  566.  
  567.         /* untranslate translated addresses */
  568.         for (ptr = drv.devList.next; ptr != &drv.devList; ptr = ptr->next)
  569.         {
  570.             pd = list_entry(ptr, DEVICE_OBJ, list);
  571.             ch = pd->pPch;
  572.             un_translate_addresses(pd, ch);
  573.         }
  574.  
  575.         /* delete my lists */
  576.         deleteMyLists();
  577.  
  578.         return result;
  579.     }
  580.     else
  581.     {
  582.         if (drv.nMajor == 0)
  583.             drv.nMajor = result;
  584.  
  585.         printk(KERN_DEBUG "%s : major #%d assigned.\n", DEVICE_NAME, drv.nMajor);
  586.     }
  587.  
  588.     /* register the proc device */
  589.  
  590.     // create_proc_read_entry is depricated since kernel 3.10
  591.     //return create_proc_read_entry(DEVICE_NAME, 0, NULL, pcivme_read_proc, NULL) ? 0 : -ENODEV;
  592.     proc = proc_create_data(DEVICE_NAME, 0, NULL, &pcivme_read_proc_fops, NULL);
  593.     return (proc) ? 0 : -ENODEV;
  594.  
  595. }
  596.  
  597. void pcivme_module_exit(void)
  598. {
  599.     PCIConfig        *ch;
  600.     DEVICE_OBJ       *pd;
  601.     struct list_head *ptr;
  602.  
  603.     PRINTK(KERN_DEBUG "%s : cleanup_module.\n", DEVICE_NAME);
  604.  
  605.     unregister_chrdev(drv.nMajor, DEVICE_NAME);
  606.  
  607.     /* unregister the proc device */
  608. #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
  609.     proc_unregister(&proc_root, pcimod_proc_entry.low_ino);
  610. #else
  611.     remove_proc_entry(DEVICE_NAME, NULL);
  612. #endif
  613.  
  614.     /* redo all */
  615.     for (ptr = drv.devList.next; ptr != &drv.devList; ptr = ptr->next)
  616.     {
  617.         pd = list_entry(ptr, DEVICE_OBJ, list);
  618.         ch = pd->pPch;
  619.         switch (pd->wInitStep)
  620.         {
  621.             case 3:  writew(readw((const volatile void *)(pd->pLCR + PLX9050_INTCSR)) & ~0x40, (volatile void *) (pd->pLCR + PLX9050_INTCSR));  // disable global interrupts
  622.                      free_irq(pd->wIrq, pd);  
  623.             case 2:  un_translate_addresses(pd, ch);
  624.             case 1:  release_io_memory(ch);
  625.             default: pd->wInitStep = 0;
  626.         }
  627.  
  628.         drv.count--;
  629.     }
  630.  
  631.     deleteMyLists();
  632.  
  633.     return;
  634. }
  635.  
  636. module_init(pcivme_module_init);
  637. module_exit(pcivme_module_exit);
  638.  
  639.