Subversion Repositories f9daq

Rev

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

  1. //****************************************************************************
  2. // Copyright (C) 2000-2004  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. // fops.c -- the file operations module for the PCIVME PCI to VME Interface
  32. //
  33. // $Log: fops.c,v $
  34. // Revision 1.11  2005/03/01 10:56:12  klaus
  35. // removed warnings with gcc 3.3.3
  36. //
  37. // Revision 1.10  2004/08/13 19:23:26  klaus
  38. // conversion to kernel-version 2.6, released version 3.0
  39. //
  40. // Revision 1.9  2003/06/27 17:25:52  klaus
  41. // incomplete try to get mmap() with nopage() running for automatic page switch
  42. //
  43. // Revision 1.8  2002/10/20 18:06:51  klaus
  44. // changed error handling
  45. //
  46. // Revision 1.7  2002/10/18 21:56:28  klaus
  47. // completed functional features, untested
  48. //
  49. // Revision 1.6  2002/10/18 21:56:28  klaus
  50. // completed functional features, untested
  51. //
  52. // Revision 1.5  2002/10/17 19:05:03  klaus
  53. // VME access is working through test to lib to driver
  54. //
  55. //****************************************************************************
  56.  
  57. /*--- INCLUDES -----------------------------------------------------------------------------------*/
  58. #include "common.h"  /* must be the first include */
  59.  
  60. #include <linux/kernel.h> /* printk() */
  61. #include <linux/module.h> /* only here ?cause of MAJOR ... */
  62. #include <linux/pci.h>
  63. #include <linux/list.h>
  64. #include <asm/errno.h>
  65. #include <asm/types.h>
  66. #include <asm/uaccess.h>
  67.  
  68. #include <linux/sched.h>
  69. #include <linux/fs.h>
  70. #if HAVE_UNLOCKED_IOCTL
  71.     #include <linux/mutex.h>
  72. #else
  73.     #include <linux/smp_lock.h>
  74. #endif
  75.  
  76.  
  77. #include "fops.h"
  78. #include "plx9050.h"
  79. #include "pcivme.h"      /* the common ioctl commands and structures between driver and application */
  80. #include "main.h"
  81. #include "askpci.h"
  82. #include "pciif.h"
  83. #include "vic.h"
  84. #include "vme.h"
  85.  
  86. /*--- DEFINES ------------------------------------------------------------------------------------*/
  87.  
  88. #ifndef MINOR
  89. #define MINOR(x) minor(x)            // since 2.5.?
  90. #endif
  91.  
  92. static PCIVME_INIT_ELEMENT init_element[] =
  93. {{LCR,  WORD_ACCESS, PLX9050_INTCSR, DISABLE_PCIADA_IRQS}, // disable interrupts
  94.     {LCR,  WORD_ACCESS, PLX9050_CNTRL,  RELEASE_VMEMM},       // enable interface
  95.  
  96.     {VIC,  BYTE_ACCESS, VIICR, 0xf8+1},      // VIICR
  97.  
  98.     {VIC,  BYTE_ACCESS, VICR1, 0x78+1},      // VICR1
  99.     {VIC,  BYTE_ACCESS, VICR2, 0x78+2},
  100.     {VIC,  BYTE_ACCESS, VICR3, 0x78+3},
  101.     {VIC,  BYTE_ACCESS, VICR4, 0x78+4},
  102.     {VIC,  BYTE_ACCESS, VICR5, 0x78+5},
  103.     {VIC,  BYTE_ACCESS, VICR6, 0x78+6},
  104.     {VIC,  BYTE_ACCESS, VICR7, 0x78+7},      // VICR7
  105.  
  106.     {VIC,  BYTE_ACCESS, DSICR, 0xf8+0},      // DSICR
  107.  
  108.     {VIC,  BYTE_ACCESS, LICR1, 0xf8+1},      // LICR1
  109.     {VIC,  BYTE_ACCESS, LICR2, 0xf8+2},
  110.     {VIC,  BYTE_ACCESS, LICR3, 0xf8+3},
  111.     {VIC,  BYTE_ACCESS, LICR4, 0xf8+4},
  112.     {VIC,  BYTE_ACCESS, LICR5, 0xf8+5},
  113.     {VIC,  BYTE_ACCESS, LICR6, 0x38+6},
  114.     {VIC,  BYTE_ACCESS, LICR7, 0x38+7},      // LICR7
  115.  
  116.     {VIC,  BYTE_ACCESS, ICGSICR, 0xf8+2},    // ICGS
  117.     {VIC,  BYTE_ACCESS, ICMSICR, 0xf8+3},    // ICMS
  118.  
  119.     {VIC,  BYTE_ACCESS, EGICR, 0xf8+6},      // EGICR
  120.  
  121.     {VIC,  BYTE_ACCESS, ICGSVBR, 0x08},      // ICGS-IVBR (!)
  122.     {VIC,  BYTE_ACCESS, ICMSVBR, 0x0c},      // ICMS-IVBR (!)
  123.  
  124.     {VIC,  BYTE_ACCESS, LIVBR, 0x00},        // LIVBR (!)
  125.  
  126.     {VIC,  BYTE_ACCESS, EGIVBR, 0x10},       // EGIVBR (!)
  127.  
  128.     {VIC,  BYTE_ACCESS, ICSR, 0x00},         // ICSR
  129.  
  130.     {VIC,  BYTE_ACCESS, ICR0, 0x00},         // ICR0
  131.     {VIC,  BYTE_ACCESS, ICR1, 0x00},
  132.     {VIC,  BYTE_ACCESS, ICR2, 0x00},
  133.     {VIC,  BYTE_ACCESS, ICR3, 0x00},
  134.     {VIC,  BYTE_ACCESS, ICR4, 0x00},         // ICR4
  135.  
  136.     {VIC,  BYTE_ACCESS, VIRSR, 0xfe},        // VIRSR
  137.  
  138.     {VIC,  BYTE_ACCESS, VIVR1, 0x0f},        // VIVR1
  139.     {VIC,  BYTE_ACCESS, VIVR2, 0x0f},
  140.     {VIC,  BYTE_ACCESS, VIVR3, 0x0f},
  141.     {VIC,  BYTE_ACCESS, VIVR4, 0x0f},
  142.     {VIC,  BYTE_ACCESS, VIVR5, 0x0f},
  143.     {VIC,  BYTE_ACCESS, VIVR6, 0x0f},
  144.     {VIC,  BYTE_ACCESS, VIVR7, 0x0f},        // VIVR7
  145.  
  146.     {VIC,  BYTE_ACCESS, TTR, 0x3c},          // TTR
  147.  
  148.     {VIC,  BYTE_ACCESS, ARCR, 0x40},         // ARCR
  149.     {VIC,  BYTE_ACCESS, AMSR, 0x29},         // AMSR
  150.     {VIC,  BYTE_ACCESS, RCR, 0x00},          // RCR
  151.  
  152.     {IFR,  LONG_ACCESS, (u16)ADRHL, 0xF0F0F0F0},  // ADR-H, ADR-L
  153.     {IFR,  WORD_ACCESS, (u16)CSR  , 0x0000},      // Contr-Reg
  154.  
  155.     {VIC,  BYTE_ACCESS, ICR7, 0x80},         // ICR7
  156.  
  157.     {LCR,  WORD_ACCESS, PLX9050_INTCSR, DISABLE_PCIADA_IRQS},  // disable interrupts
  158.  
  159.     {STOP, WORD_ACCESS, 0,     0}};
  160.  
  161. static PCIVME_INIT_ELEMENT deinit_element_pre[] =
  162. {{VIC,  BYTE_ACCESS, ICR7, 0x00},         // ICR7 - sysfail
  163.     {LCR,  WORD_ACCESS, PLX9050_INTCSR, DISABLE_PCIADA_IRQS},  // disable interrupts
  164.     {STOP, WORD_ACCESS, 0,    0}};
  165.  
  166. static PCIVME_INIT_ELEMENT deinit_element_post[] =
  167. {{LCR,  WORD_ACCESS, PLX9050_CNTRL, INHIBIT_VMEMM},     // disable interface
  168.     {STOP, WORD_ACCESS, 0,    0}};
  169.  
  170.  
  171. /*--- EXTERNALS ----------------------------------------------------------------------------------*/
  172.  
  173. /*--- TYPEDEFS -----------------------------------------------------------------------------------*/
  174.  
  175. /*--- FUNCTIONS ----------------------------------------------------------------------------------*/
  176. static inline void switch_VMEMM_on(DEVICE_OBJ *pd)
  177. {
  178.     writew(RELEASE_VMEMM, (volatile void *) (pd->pLCR + PLX9050_CNTRL)); /* enable access */
  179. }
  180.  
  181. static inline void switch_VMEMM_off(DEVICE_OBJ *pd)
  182. {
  183.     writew(INHIBIT_VMEMM, (volatile void *) (pd->pLCR + PLX9050_CNTRL)); /* enable access */
  184. }
  185.  
  186. static inline void setPageAddress(DEVICE_OBJ *pd, u32 newPageAddress)
  187. {
  188.     PRINTK(KERN_DEBUG "%s : setPageAddress(0x%08x)\n", DEVICE_NAME, newPageAddress);
  189.  
  190.     writel(newPageAddress, (volatile void *) pd->pAdrReg);
  191.     pd->dwCurrentPageAddress = newPageAddress;
  192. }
  193.  
  194. static inline void setModifier(DEVICE_OBJ *pd, u8 newModifier)
  195. {
  196.     PRINTK(KERN_DEBUG "%s : setModifier(0x%02x)\n", DEVICE_NAME, newModifier);
  197.  
  198.     writeb(newModifier, (volatile void *) pd->pAdrMod);
  199.     pd->bCurrentModifier = newModifier;
  200. }
  201.  
  202. /* read and write functions -----------------------------------------------------------------------*/
  203. static inline u8 *increment8(void **pvBuffer)
  204. {
  205.   u8 *tmp = (u8*)*pvBuffer;
  206.  
  207.   *pvBuffer += sizeof(u8);
  208.  
  209.   return tmp;
  210. }
  211.  
  212. static inline u16 *increment16(void **pvBuffer)
  213. {
  214.   u16 *tmp = (u16*)*pvBuffer;
  215.  
  216.   *pvBuffer += sizeof(u16);
  217.  
  218.   return tmp;
  219. }
  220.  
  221. static inline u32 *increment32(void **pvBuffer)
  222. {
  223.   u32 *tmp = (u32*)*pvBuffer;
  224.  
  225.   *pvBuffer += sizeof(u32);
  226.  
  227.   return tmp;
  228. }
  229.  
  230. static void readByte(DEVICE_OBJ *pd, void **pvBuffer, u32 dwLocalAddressInPage)
  231. {
  232.     u8 tmp;
  233.  
  234.     tmp = readb((const volatile void *) (pd->pVME + dwLocalAddressInPage));
  235.     __put_user(tmp, increment8(pvBuffer));
  236. }
  237.  
  238. static void writeByte(DEVICE_OBJ *pd, u32 dwLocalAddressInPage, void **pvBuffer)
  239. {
  240.     u8 tmp;
  241.  
  242.     __get_user(tmp, increment8(pvBuffer));
  243.     writeb(tmp, (volatile void *) (pd->pVME + dwLocalAddressInPage ));
  244. }
  245.  
  246. static void readWord(DEVICE_OBJ *pd, void **pvBuffer, u32 dwLocalAddressInPage)
  247. {
  248.     u16 tmp;
  249.  
  250.     tmp = readw((const volatile void *) (pd->pVME + dwLocalAddressInPage));
  251.     __put_user(tmp, increment16(pvBuffer));
  252. }
  253.  
  254. static void writeWord(DEVICE_OBJ *pd, u32 dwLocalAddressInPage, void **pvBuffer)
  255. {
  256.     u16 tmp;
  257.  
  258.     __get_user(tmp, increment16(pvBuffer));
  259.     writew(tmp, (volatile void *) ( pd->pVME + dwLocalAddressInPage ));
  260. }
  261.  
  262. static void readLong(DEVICE_OBJ *pd, void **pvBuffer, u32 dwLocalAddressInPage)
  263. {
  264.     u32 tmp;
  265.  
  266.     tmp = readl((const volatile void *) (pd->pVME + dwLocalAddressInPage));
  267.     __put_user(tmp, increment32(pvBuffer));
  268. }
  269.  
  270. static void writeLong(DEVICE_OBJ *pd, u32 dwLocalAddressInPage, void **pvBuffer)
  271. {
  272.     u32 tmp;
  273.  
  274.     __get_user(tmp, increment32(pvBuffer));
  275.     writel(tmp, (volatile void *) (pd->pVME + dwLocalAddressInPage));
  276. }
  277.  
  278. /* test alignment functions -----------------------------------------------------------------------*/
  279. static int MisalignmentForByteAccess(loff_t offset)
  280. {
  281.     return 0;
  282. }
  283.  
  284. static int MisalignmentForWordAccess(loff_t offset)
  285. {
  286.     return(offset & 1);
  287. }
  288.  
  289. static int MisalignmentForLongAccess(loff_t offset)
  290. {
  291.     return(offset & 3);
  292. }
  293.  
  294. // helper functions --------------------------------------------------------------------------------
  295. int check_command(const PCIVME_INIT_ELEMENT *psInitElement)
  296. {
  297.     u16 range;
  298.     u16 access_size;
  299.  
  300.     // PRINTK(KERN_DEBUG "%s : check_command()\n", DEVICE_NAME);
  301.  
  302.     switch (psInitElement->bDestination)
  303.     {
  304.         case LCR:
  305.             range = 0x54;    
  306.             break;
  307.         case IFR:
  308.             range = 0x0c;    
  309.             break;
  310.         case VIC:
  311.             range = 0xe4;
  312.             if ((psInitElement->wOffset & 3) != 3)
  313.                 return -EINVAL;
  314.             break;
  315.         default:  
  316.             return -EINVAL;        
  317.             break;
  318.     }
  319.  
  320.     // check alignment and allowed address range
  321.     switch (psInitElement->bAccessType)
  322.     {
  323.         case LONG_ACCESS:
  324.             if (psInitElement->wOffset & 3)
  325.                 return -EINVAL;
  326.             access_size = sizeof(u32);
  327.             break;
  328.         case WORD_ACCESS:
  329.             if (psInitElement->wOffset & 1)
  330.                 return -EINVAL;
  331.             access_size = sizeof(u16);
  332.             break;
  333.         case BYTE_ACCESS:
  334.             access_size = sizeof(u8);
  335.             break;
  336.         default         :
  337.             return -EINVAL;        
  338.             break;
  339.     }
  340.  
  341.     if ((psInitElement->wOffset + access_size) > range)
  342.         return -EINVAL;       // ignore it
  343.  
  344.     return 0;
  345. }
  346.  
  347. static int CmdMachine(DEVICE_OBJ *pd, const PCIVME_INIT_ELEMENT *psInitElement)
  348. {
  349.     u32 adr;
  350.     int err;
  351.  
  352.     PRINTK(KERN_DEBUG "%s : CmdMachine()\n", DEVICE_NAME);
  353.  
  354.     // loop through the init (or deinit) list
  355.     while (psInitElement->bDestination != STOP)
  356.     {
  357.         err = check_command(psInitElement);
  358.         if (!err)
  359.         {
  360.             switch (psInitElement->bDestination)
  361.             {
  362.                 case LCR:
  363.                     adr = pd->pLCR;
  364.                     break;
  365.                 case VIC:
  366.                     adr = pd->pCtl + VICBASE;
  367.                     break;
  368.                 case IFR:
  369.                     adr = pd->pCtl + CSR;
  370.                     break;  
  371.                 default:
  372.                     return -EINVAL;
  373.             }
  374.  
  375.             switch (psInitElement->bAccessType)
  376.             {
  377.                 case LONG_ACCESS:
  378.                     writel(psInitElement->dwValue, (volatile void *) (adr + psInitElement->wOffset));
  379.                     break;
  380.                 case WORD_ACCESS:
  381.                     writew((u16)psInitElement->dwValue, (volatile void *) (adr + psInitElement->wOffset));
  382.                     break;
  383.                 case BYTE_ACCESS:
  384.                     writeb((u8)psInitElement->dwValue, (volatile void *) (adr + psInitElement->wOffset));
  385.                     break;
  386.                 default:
  387.                     return -EINVAL;
  388.             }
  389.         }
  390.         else
  391.             return err;
  392.  
  393.         psInitElement++;
  394.     }
  395.  
  396.     return 0;
  397. }
  398.  
  399. // all ioctls --------------------------------------------------------------------------------------
  400. static int init_hardware(PATH_OBJ *pp, DEVICE_OBJ *pd, PCIVME_INIT_COMMAND *init)
  401. {
  402.     int err;
  403.     PCIVME_INIT_ELEMENT *element = init->sVie;
  404.  
  405.     PRINTK(KERN_DEBUG "%s : init_hardware()\n", DEVICE_NAME);
  406.  
  407.     err = CmdMachine(pd, element);
  408.     if (err)
  409.     {
  410.         PRINTK(KERN_DEBUG "%s : init failed with err = %d!\n", DEVICE_NAME, err);
  411.         return err;
  412.     }
  413.  
  414.     // sync storage with hardware
  415.     pd->bCurrentModifier     = readb((const volatile void *) pd->pAdrMod) & 0x3f;
  416.     pd->dwCurrentPageAddress = readl((const volatile void *) pd->pAdrReg) & HI_ADDRESS_MASK;
  417.  
  418.     return 0;
  419. }
  420.  
  421. static int deinit_hardware(PATH_OBJ *pp, DEVICE_OBJ *pd, PCIVME_INIT_COMMAND *deinit)
  422. {
  423.     int err;
  424.     PCIVME_INIT_ELEMENT *element = deinit->sVie;
  425.  
  426.     PRINTK(KERN_DEBUG "%s : deinit_hardware()\n", DEVICE_NAME);
  427.  
  428.     err = CmdMachine(pd, deinit_element_pre);  
  429.     if (err)
  430.         goto fail;
  431.  
  432.     err = CmdMachine(pd, element);
  433.     if (err)
  434.         goto fail;
  435.  
  436.     err = CmdMachine(pd, deinit_element_post);
  437.     if (err)
  438.         goto fail;
  439.  
  440.     return 0;
  441.  
  442.     fail:
  443.     return err;
  444. }
  445.  
  446. static int access_command(PATH_OBJ *pp, DEVICE_OBJ *pd, PCIVME_ACCESS_COMMAND *cmd)
  447. {
  448.     PRINTK(KERN_DEBUG "%s : access_command()\n", DEVICE_NAME);
  449.  
  450.     pp->bModifier    = cmd->bModifier;
  451.     pp->bAccessType  = cmd->bAccessType;
  452.     pp->bIncrement   = cmd->bIncrement;
  453.  
  454.     switch (pp->bAccessType)
  455.     {
  456.         case BYTE_ACCESS:
  457.             pp->read  = readByte;
  458.             pp->write = writeByte;
  459.             pp->AlignmentCheck = MisalignmentForByteAccess;
  460.             break;
  461.         case WORD_ACCESS:
  462.             pp->read  = readWord;
  463.             pp->write = writeWord;
  464.             pp->AlignmentCheck = MisalignmentForWordAccess;
  465.             break;
  466.         case LONG_ACCESS:
  467.             pp->read  = readLong;
  468.             pp->write = writeLong;
  469.             pp->AlignmentCheck = MisalignmentForLongAccess;
  470.             break;
  471.         default:
  472.             return -EINVAL;
  473.     }
  474.  
  475.     return 0;
  476. }
  477.  
  478. static int get_static_status(PATH_OBJ *pp, DEVICE_OBJ *pd, PCIVME_STATIC_STATUS *static_status)
  479. {
  480.     PRINTK(KERN_DEBUG "%s : get_static_status()\n", DEVICE_NAME);
  481.  
  482.     static_status->bConnected        = pd->bConnected;
  483.     static_status->cModuleNumber     = pd->cModuleNumber;
  484.     static_status->cFPGAVersion      = pd->cFPGAVersion;
  485.     static_status->cSystemController = pd->cSystemController;
  486.     static_status->cWordMode         = pd->cWordMode;
  487.  
  488.     return 0;
  489. }
  490.  
  491. static int get_dynamic_status(PATH_OBJ *pp, DEVICE_OBJ *pd, PCIVME_DYNAMIC_STATUS *dynamic_status)
  492. {
  493.     u16 cntrl  = readw((const volatile void *)  pd->pPCIADACntrl);
  494.     u16 intCSR = readw((const volatile void *)  pd->pPCIADAIntCSR);
  495.  
  496.     PRINTK(KERN_DEBUG "%s : get_dynamic_status()\n", DEVICE_NAME);
  497.  
  498.     dynamic_status->bConnected = (cntrl  & 0x0800) ? 1 : 0;
  499.     dynamic_status->bPCIADAIrq = (intCSR & 0x0020) ? 1 : 0;
  500.     dynamic_status->bVMEMMIrq  = (intCSR & 0x0004) ? 1 : 0;
  501.  
  502.     return 0;
  503. }
  504.  
  505. static int read_vector_polling(PATH_OBJ *pp, DEVICE_OBJ *pd, PCIVME_VECTOR_LEVEL *vector)
  506. {
  507.     u16 cntrl  = readw((const volatile void *) pd->pPCIADACntrl);
  508.     u16 intCSR = readw((const volatile void *) pd->pPCIADAIntCSR);
  509.  
  510.     PRINTK(KERN_DEBUG "%s : read_vector()\n", DEVICE_NAME);
  511.  
  512.     vector->dwStatusID = 0;  
  513.     vector->bLevel     = 0;
  514.     vector->bPCIADAIrq = 0;
  515.  
  516.     if (intCSR & 0x20) // check for PCIADA interrupt
  517.     {
  518.         vector->bPCIADAIrq = 1;
  519.         vector->dwStatusID = 1; // force for PCIADA irqs
  520.  
  521.         writew(cntrl & ~0x0100, (volatile void *) pd->pPCIADACntrl);   // clear pending PCIADA irq
  522.         writew(cntrl,           (volatile void *) pd->pPCIADACntrl);
  523.     }
  524.     else
  525.     {
  526.         if ((cntrl & 0x0980) == 0x0980) // check if VMEMM is connected and ready
  527.         {
  528.             vector->bLevel = (u8)readw((const volatile void *) ( pd->pCtl + VICRES ));
  529.             if (vector->bLevel & 1)
  530.             {
  531.                 if (vector->bLevel != 1)
  532.                     vector->dwStatusID = (u32)readb((const volatile void *) (pd->pCtl + VECBASE + vector->bLevel));
  533.  
  534.                 vector->bLevel >>= 1;
  535.             }
  536.         }
  537.     }
  538.     return 0;
  539. }
  540.  
  541. static int read_vector_blocking(PATH_OBJ *pp, DEVICE_OBJ *pd, PCIVME_VECTOR_LEVEL *vector, struct file *pFile)
  542. {
  543.     int error;
  544.  
  545.     vector->dwStatusID = 0;  
  546.     vector->bLevel     = 0;
  547.     vector->bPCIADAIrq = 0;
  548.  
  549.     // support nonblocking read if requested
  550.     if ((pFile->f_flags & O_NONBLOCK) && (!pd->wIrqStatus))
  551.         return -EAGAIN;
  552.  
  553.     // sleep until data are available
  554.     if ((error = wait_event_interruptible(pd->event_queue, (pd->wIrqStatus))))
  555.         return error;
  556.  
  557.     error = read_vector_polling(pp, pd, vector);
  558.  
  559.     pd->wIrqStatus  = 0;  // clear the status since it is read 
  560.  
  561.     return error;
  562. }
  563.  
  564.  
  565. static int control_interrupts(PATH_OBJ *pp, DEVICE_OBJ *pd, PCIVME_IRQ_CONTROL *irq_control)
  566. {
  567.     u16 intCSR = readw((const volatile void *) pd->pPCIADAIntCSR);
  568.     u8  ret    = (intCSR & 0x40) ? 1 : 0;
  569.  
  570.     PRINTK(KERN_DEBUG "%s : control_interrupts()\n", DEVICE_NAME);
  571.  
  572.     if (irq_control->bEnable)
  573.         writew(intCSR |  0x40, (volatile void *) pd->pPCIADAIntCSR);
  574.     else
  575.         writew(intCSR & ~0x40, (volatile void *) pd->pPCIADAIntCSR);
  576.  
  577.     // return the switch before set
  578.     irq_control->bEnable = ret;
  579.  
  580.     return 0;
  581. }
  582.  
  583. static int VME_TAS(PATH_OBJ *pp, DEVICE_OBJ *pd, PCIVME_TAS_STRUCT *tas_cmd)
  584. {
  585.     u32 access_adr = pd->pVME + (tas_cmd->dwAddress & LO_ADDRESS_MASK); // make low part of address
  586.     u8  data;
  587.  
  588.     // save old contents
  589.     u32 old_address         = readl((const volatile void *) pd->pAdrReg);
  590.     u16 old_CSR             = readw((const volatile void *) pd->pCSR);
  591.     u16 intCSR              = readw((const volatile void *) pd->pPCIADAIntCSR);
  592.     pd->bCurrentModifier    = readb((const volatile void *) pd->pAdrMod) & 0x3f;
  593.  
  594.     PRINTK(KERN_DEBUG "%s : VME_TAS()\n", DEVICE_NAME);
  595.  
  596.     // set new contents
  597.     writew(DISABLE_PCIADA_IRQS,           (volatile void *) pd->pPCIADAIntCSR);
  598.     writeb((u8)tas_cmd->bModifier & 0x3f, (volatile void *) pd->pAdrMod);
  599.     writel(tas_cmd->dwAddress,            (volatile void *) pd->pAdrReg);
  600.     writew(old_CSR | FLAG_RMC,            (volatile void *) pd->pCSR);
  601.  
  602.     // do the read - modify - write
  603.     data = readb((const volatile void *) access_adr);
  604.     writeb(tas_cmd->bContent, (volatile void *) access_adr);
  605.  
  606.     // restore old contents
  607.     writeb(pd->bCurrentModifier, (volatile void *) pd->pAdrMod);
  608.     writew(old_CSR,              (volatile void *) pd->pCSR);
  609.     writel(old_address,          (volatile void *) pd->pAdrReg);
  610.     writew(intCSR,               (volatile void *) pd->pPCIADAIntCSR);
  611.  
  612.     // get back read data
  613.     tas_cmd->bContent = data;
  614.  
  615.     return 0;
  616. }
  617.  
  618. static int VMEMM_RESET(PATH_OBJ *pp, DEVICE_OBJ *pd, PCIVME_RESET_COMMAND *reset_cmd)
  619. {
  620.     u16 cntrl  = readw((const volatile void *) pd->pPCIADACntrl);
  621.     u16 intCSR = readw((const volatile void *) pd->pPCIADAIntCSR);
  622.     int status = 0;
  623.  
  624.     PRINTK(KERN_DEBUG "%s : VMEMM_RESET()\n", DEVICE_NAME);
  625.  
  626.     // am I connected and switched on??
  627.     if ((cntrl & 0x0980) == 0x0980)
  628.     {
  629.         // do command
  630.         switch (reset_cmd->bCommand)
  631.         {
  632.             case POLL_RESET_CMD:
  633.                 break;
  634.             case VME_RESET_CMD:
  635.                 writeb(0, (volatile void *) pd->pAdrMod);
  636.                 writeb(0xf0, (volatile void *) (pd->pCtl + VICBASE + SRR));  // make VME reset
  637.                 break;
  638.             case LOCAL_RESET_CMD:
  639.                 writeb(0, (volatile void *) pd->pAdrMod);
  640.                 writew(LOCAL_RESET,  (volatile void *) (pd->pCtl + VICRES));
  641.                 break;
  642.             case GLOBAL_RESET_CMD:
  643.                 writeb(0, (volatile void *) pd->pAdrMod);
  644.                 writew(GLOBAL_RESET, (volatile void *) (pd->pCtl + VICRES));
  645.                 break;
  646.  
  647.             default: status = -EINVAL;
  648.         }
  649.  
  650.         // inhibit PCIADA generated irqs
  651.         writew(DISABLE_PCIADA_IRQS, (volatile void *) pd->pPCIADAIntCSR);
  652.  
  653.         // always poll reset status - access will sometimes generate PCIADA #2 interrupt
  654.         reset_cmd->bResult = readb((const volatile void *) pd->pAdrMod);
  655.  
  656.         // reset any pending PCIADA interrupt #2
  657.         writew(cntrl & ~0x0100, (volatile void *) pd->pPCIADACntrl);
  658.         writew(cntrl          , (volatile void *) pd->pPCIADACntrl);
  659.  
  660.         // restore IRQStatus
  661.         writew(intCSR          , (volatile void *) pd->pPCIADAIntCSR);
  662.     }
  663.     else
  664.         status = -EBUSY;
  665.  
  666.     // sync storage with hardware
  667.     pd->bCurrentModifier = readb((const volatile void *) pd->pAdrMod) & 0x3f;
  668.  
  669.     return status;
  670. }
  671.  
  672. static int access_VIC68A(PATH_OBJ *pp, DEVICE_OBJ *pd, PCIVME_VIC68A_ACTION *action)
  673. {
  674.     int nStatus = 0;
  675.  
  676.     PRINTK(KERN_DEBUG "%s : access_VIC68A()\n", DEVICE_NAME);
  677.  
  678.     if ((action->wRegisterAddress <= SRR) && ((action->wRegisterAddress & 0x03) == 3))
  679.     {
  680.         u32 dwAddress;
  681.         u8  bByte = 0;
  682.  
  683.         dwAddress = (pd->pCtl + VICBASE + action->wRegisterAddress);
  684.  
  685.         switch (action->bAccessMode)
  686.         {
  687.             case VIC68A_WRITE_ONLY:
  688.                 writeb(action->bContent, (volatile void *) dwAddress);
  689.                 break;
  690.             case VIC68A_WRITE:  
  691.                 writeb(action->bContent, (volatile void *) dwAddress);
  692.                 action->bContent = readb((const volatile void *) dwAddress);
  693.                 break;
  694.             case VIC68A_OR:    
  695.                 bByte      = readb((const volatile void *) dwAddress);
  696.                 bByte     |= action->bContent;
  697.                 writeb(bByte, (volatile void *) dwAddress);
  698.                 action->bContent = readb((const volatile void *) dwAddress);
  699.                 break;
  700.             case VIC68A_AND:    
  701.                 bByte      = readb((const volatile void *) dwAddress);
  702.                 bByte     &= action->bContent;
  703.                 writeb(bByte, (volatile void *) dwAddress);
  704.                 action->bContent = readb((const volatile void *) dwAddress);
  705.                 break;
  706.             case VIC68A_READ:  
  707.                 action->bContent = readb((const volatile void *) dwAddress);
  708.                 break;
  709.             default:            
  710.                 nStatus = -EINVAL;
  711.         }
  712.     }
  713.     else
  714.         nStatus = -EINVAL;
  715.  
  716.     return nStatus;
  717. }
  718.  
  719. // the dispatcher ----------------------------------------------------------------------------------
  720. int pcivme_ioctl(struct inode *pInode, struct file *pFile, unsigned int cmd, unsigned long arg)
  721. {
  722.     PATH_OBJ   *pp = (PATH_OBJ *)pFile->private_data;
  723.     DEVICE_OBJ *pd = pp->pDo;
  724.     int err = 1;
  725.    
  726.     PRINTK(KERN_DEBUG "%s : pcivme_ioctl(0x%08x), size = %d\n", DEVICE_NAME, cmd, _IOC_SIZE(cmd));
  727.  
  728.     if (_IOC_TYPE(cmd) != PCIVME_MAGIC)
  729.         return -EINVAL;
  730.  
  731.     // check for accessible user buffer
  732.     if (_IOC_DIR(cmd) & _IOC_READ)
  733.         err = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd));
  734.     if (_IOC_DIR(cmd) & _IOC_WRITE)
  735.         err = !access_ok(VERIFY_READ,  (void *)arg, _IOC_SIZE(cmd));
  736.     if (err)
  737.         return -EFAULT;
  738.  
  739.     switch (_IOC_NR(cmd))
  740.     {
  741.         case _IOC_NR(PCIVME_READ_VECTOR_BLOCK):
  742.             if (_IOC_SIZE(cmd) < sizeof(PCIVME_VECTOR_LEVEL))
  743.                 return -EINVAL;
  744.             return read_vector_blocking(pp, pd, (PCIVME_VECTOR_LEVEL *)arg, pFile);
  745.  
  746.         case _IOC_NR(PCIVME_READ_VECTOR_POLL):
  747.             if (_IOC_SIZE(cmd) < sizeof(PCIVME_VECTOR_LEVEL))
  748.                 return -EINVAL;
  749.             return read_vector_polling(pp, pd, (PCIVME_VECTOR_LEVEL *)arg);
  750.  
  751.         case _IOC_NR(PCIVME_CONTROL_INTERRUPTS):
  752.             if (_IOC_SIZE(cmd) < sizeof(PCIVME_IRQ_CONTROL))
  753.                 return -EINVAL;
  754.             return control_interrupts(pp, pd, (PCIVME_IRQ_CONTROL *)arg);
  755.  
  756.         case _IOC_NR(PCIVME_TAS):
  757.             if (_IOC_SIZE(cmd) < sizeof(PCIVME_TAS_STRUCT))
  758.                 return -EINVAL;
  759.             return VME_TAS(pp, pd, (PCIVME_TAS_STRUCT *)arg);
  760.  
  761.         case _IOC_NR(PCIVME_ACCESS_VIC68A):
  762.             if (_IOC_SIZE(cmd) < sizeof(PCIVME_VIC68A_ACTION))
  763.                 return -EINVAL;
  764.             return access_VIC68A(pp, pd, (PCIVME_VIC68A_ACTION *)arg);
  765.  
  766.         case _IOC_NR(PCIVME_GET_DYNAMIC_STATUS):
  767.             if (_IOC_SIZE(cmd) < sizeof(PCIVME_DYNAMIC_STATUS))
  768.                 return -EINVAL;
  769.             return get_dynamic_status(pp, pd, (PCIVME_DYNAMIC_STATUS *)arg);
  770.  
  771.         case _IOC_NR(PCIVME_RESET):
  772.             if (_IOC_SIZE(cmd) < sizeof(PCIVME_RESET_COMMAND))
  773.                 return -EINVAL;
  774.             return VMEMM_RESET(pp, pd, (PCIVME_RESET_COMMAND *)arg);
  775.  
  776.         case _IOC_NR(PCIVME_SET_ACCESS_PARA):
  777.             if (_IOC_SIZE(cmd) < sizeof(PCIVME_ACCESS_COMMAND))
  778.                 return -EINVAL;
  779.             return access_command(pp, pd, (PCIVME_ACCESS_COMMAND *)arg);
  780.  
  781.         case _IOC_NR(PCIVME_GET_STATIC_STATUS):
  782.             if (_IOC_SIZE(cmd) < sizeof(PCIVME_STATIC_STATUS))
  783.                 return -EINVAL;
  784.             return get_static_status(pp, pd, (PCIVME_STATIC_STATUS *)arg);
  785.  
  786.         case _IOC_NR(PCIVME_INIT_HARDWARE):
  787.             if (_IOC_SIZE(cmd) < sizeof(PCIVME_INIT_COMMAND))
  788.                 return -EINVAL;
  789.             return init_hardware(pp, pd, (PCIVME_INIT_COMMAND *)arg);
  790.  
  791.         case _IOC_NR(PCIVME_DEINIT_HARDWARE):
  792.             if (_IOC_SIZE(cmd) < sizeof(PCIVME_INIT_COMMAND))
  793.                  return -EINVAL;
  794.             return deinit_hardware(pp, pd, (PCIVME_INIT_COMMAND *)arg);
  795.                                                
  796.         default:
  797.             PRINTK(KERN_DEBUG "%s : pcivme_ioctl(0x%08x) is illegal\n", DEVICE_NAME, cmd);
  798.             return -EINVAL;
  799.     }
  800.  
  801.     return 0;
  802. }
  803.  
  804. static long  pcivme_unlocked_ioctl(struct file *pFile, unsigned int cmd, unsigned long arg){
  805. long retval=0;
  806. #if HAVE_UNLOCKED_IOCTL
  807.     struct mutex  fs_mutex;
  808.    mutex_init(&fs_mutex);
  809.    mutex_lock(&fs_mutex);
  810. #else
  811.    lock_kernel();
  812. #endif
  813.  
  814. retval = pcivme_ioctl(NULL, pFile, cmd,arg);
  815.  
  816. #if HAVE_UNLOCKED_IOCTL
  817.    mutex_unlock(&fs_mutex);
  818. #else
  819.    unlock_kernel();
  820. #endif
  821. return retval;
  822. }
  823.  
  824. int pcivme_open(struct inode *pInode, struct file *pFile)
  825. {
  826.     DEVICE_OBJ *pd   = 0;
  827.     DEVICE_OBJ *desc = 0;
  828.         int nMinor = MINOR(pInode->i_rdev);
  829.     struct list_head *ptr;
  830.  
  831.     PRINTK(KERN_DEBUG "%s : pcivme_open(), %d, %d, scanning %d devices\n", DEVICE_NAME, major(pInode->i_rdev), nMinor, drv.count);
  832.  
  833.     /* search for device */
  834.     for (ptr = drv.devList.next; ptr != &drv.devList; ptr = ptr->next)
  835.     {
  836.         pd = list_entry(ptr, DEVICE_OBJ, list);
  837.         pd->bConnected =  get_module_info(pd);
  838.         if (pd->bConnected)
  839.         {
  840.             if (test_connection(pd))
  841.             {
  842.                 printk(KERN_ERR "%s : connection test for module %d failed!\n", DEVICE_NAME, pd->cModuleNumber);
  843.                 pd->bConnected = 0;
  844.             }
  845.             else
  846.                 if (pd->cModuleNumber == nMinor)
  847.             {
  848.                 desc = pd;
  849.                 break;
  850.             }
  851.         }
  852.         else
  853.             PRINTK(KERN_DEBUG "%s : module %d not connected!\n", DEVICE_NAME, nMinor);
  854.     }
  855.  
  856.     if (desc)
  857.     {
  858.         int       err;
  859.         PATH_OBJ  *pp;
  860.  
  861.         pp = (PATH_OBJ *)kmalloc(sizeof(PATH_OBJ), GFP_ATOMIC);
  862.         if (!pp)
  863.             return -ENOMEM;
  864.  
  865.         // file PATH_OBJ structure with initialisation data            
  866.         pp->pDo            = pd;
  867.         pp->bAccessType    = pp->bIncrement = BYTE_ACCESS;  
  868.         pp->bModifier      = Short_NoPriv;  
  869.         pp->read           = readByte;
  870.         pp->write          = writeByte;
  871.         pp->AlignmentCheck = MisalignmentForByteAccess;
  872.         pFile->private_data = (void *)pp;
  873.  
  874.         PRINTK(KERN_DEBUG "%s : found VMEMM module with number %d.\n", DEVICE_NAME, nMinor);
  875.  
  876.         if (!pd->nOpenCounter)
  877.         {
  878.             err = CmdMachine(pd, init_element);
  879.             if (err)
  880.             {
  881.                 printk(KERN_ERR "%s : default init failed with err = %d!\n", DEVICE_NAME, err);
  882.                 kfree_s(pp, sizeof(*pp));    // FREE(pFile->private_data);
  883.                 return err;
  884.             }
  885.         }
  886.  
  887.         pd->nOpenCounter++;
  888.     }
  889.     else
  890.     {
  891.         printk(KERN_ERR "%s : No VMEMM module found.\n", DEVICE_NAME);
  892.         return -ENODEV;
  893.     }      
  894.  
  895.     __MOD_INC_USE_COUNT__;
  896.     return 0;
  897. }
  898.  
  899. int pcivme_release(struct inode *pInode, struct file *pFile)
  900. {
  901.     PATH_OBJ *pp;
  902.  
  903.     PRINTK(KERN_DEBUG "%s : release()\n", DEVICE_NAME);
  904.  
  905.     if (pFile->private_data)
  906.     {
  907.         pp = (PATH_OBJ *)pFile->private_data;
  908.         if (pp && pp->pDo )
  909.         {
  910.             DEVICE_OBJ *pd = pp->pDo;
  911.  
  912.             pd->nOpenCounter--;
  913.  
  914.             // the last one closes the door
  915.             if (pd->nOpenCounter <= 0)
  916.             {
  917.                 CmdMachine(pd, deinit_element_pre);
  918.                 CmdMachine(pd, deinit_element_post);
  919.  
  920.                 // Vorsicht ist die Mutter der Porzelankiste!
  921.                 pd->nOpenCounter = 0;
  922.             }
  923.  
  924.             pp->pDo = 0;            
  925.         }
  926.  
  927.         kfree_s(pp, sizeof(*pp));    // FREE(pFile->private_data);
  928.     }
  929.  
  930.     __MOD_DEC_USE_COUNT__;
  931.     return 0;
  932. }
  933.  
  934. static ssize_t pcivme_read(struct file *pFile, char *pcBuffer, size_t count, loff_t *offp)
  935. {
  936.     PATH_OBJ *pp     = (PATH_OBJ *)pFile->private_data;
  937.     DEVICE_OBJ *pd   = pp->pDo;
  938.     u32 dwLocalCount = count;
  939.     register u32 dwLocalPageAddress;
  940.     u32 dwLocalAddressInPage;
  941.  
  942.     PRINTK(KERN_DEBUG "%s : pcivme_read(0x%08x, %d)\n", DEVICE_NAME, (u32)*offp, dwLocalCount);
  943.  
  944.     // inhibit misaligned accesses
  945.     if (pp->AlignmentCheck(*offp))
  946.         return -EFAULT;
  947.  
  948.     // check for free access to user buffer
  949.     if (!access_ok(VERIFY_WRITE, pcBuffer, count))
  950.         return -EFAULT;
  951.  
  952.     // do I still have the same modifier?
  953.     if (pp->bModifier != pd->bCurrentModifier)
  954.         setModifier(pd, pp->bModifier);
  955.  
  956.     while (count >= pp->bAccessType)
  957.     {
  958.         dwLocalPageAddress   = *offp & HI_ADDRESS_MASK;
  959.         dwLocalAddressInPage = *offp & LO_ADDRESS_MASK;
  960.  
  961.         // do I still work in the same page?
  962.         if (dwLocalPageAddress != pd->dwCurrentPageAddress)
  963.             setPageAddress(pd, dwLocalPageAddress);
  964.  
  965.         // standard access method
  966.         pp->read(pd, (void **)&pcBuffer, dwLocalAddressInPage);  
  967.  
  968.         // decrement count and update pointer to next access address
  969.         count -= pp->bAccessType;
  970.         *offp += pp->bIncrement;
  971.     }
  972.  
  973.     return dwLocalCount - count;
  974. }
  975.  
  976. static ssize_t pcivme_write(struct file *pFile, const char *pcBuffer, size_t count, loff_t *offp)
  977. {
  978.     PATH_OBJ *pp     = (PATH_OBJ *)pFile->private_data;
  979.     DEVICE_OBJ *pd   = pp->pDo;
  980.     u32 dwLocalCount = count;
  981.     register u32 dwLocalPageAddress;
  982.     u32 dwLocalAddressInPage;
  983.  
  984.     PRINTK(KERN_DEBUG "%s : pcivme_write(0x%08x, %d)\n", DEVICE_NAME, (u32)*offp, dwLocalCount);
  985.  
  986.     // inhibit misaligned accesses
  987.     if (pp->AlignmentCheck(*offp))
  988.         return -EFAULT;
  989.  
  990.     // check for free access to user buffer
  991.     if (!access_ok(VERIFY_READ, pcBuffer, count))
  992.         return -EFAULT;
  993.  
  994.     // do I still have the same modifier?
  995.     if (pp->bModifier != pd->bCurrentModifier)
  996.         setModifier(pd, pp->bModifier);
  997.  
  998.     while (count >= pp->bAccessType)
  999.     {
  1000.         dwLocalPageAddress   = *offp & HI_ADDRESS_MASK;
  1001.         dwLocalAddressInPage = *offp & LO_ADDRESS_MASK;
  1002.  
  1003.         // do I still work in the same page?
  1004.         if (dwLocalPageAddress != pd->dwCurrentPageAddress)
  1005.             setPageAddress(pd, dwLocalPageAddress);
  1006.  
  1007.         // standard access method
  1008.         pp->write(pd, dwLocalAddressInPage, (void **)&pcBuffer);
  1009.  
  1010.         // decrement count and update pointer to next access address
  1011.         count -= pp->bAccessType;
  1012.         *offp += pp->bIncrement;
  1013.     }
  1014.  
  1015.     return dwLocalCount - count;
  1016. }
  1017.  
  1018.  
  1019. #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
  1020. struct file_operations pcivme_fops =
  1021. {
  1022.     NULL,             /* lseek */
  1023.     pcivme_read,      /* read  */
  1024.     pcivme_write,     /* write */
  1025.     NULL,             /* readdir */
  1026.     NULL,             /* select */
  1027.     pcivme_ioctl,     /* ioctl */
  1028.     NULL,             /* mmap */
  1029.     pcivme_open,      /* open */
  1030.     NULL,             /* flush */
  1031.     pcivme_release,   /* release */
  1032. };
  1033. #else
  1034. struct file_operations pcivme_fops =
  1035. {
  1036.     .read    =    pcivme_read,     /* read  */
  1037.     .write   =    pcivme_write,    /* write */
  1038.     .unlocked_ioctl = pcivme_unlocked_ioctl,  /* ioctl */
  1039.     .open    =    pcivme_open,     /* open */
  1040.     .release =    pcivme_release,  /* release */
  1041. };
  1042. #endif
  1043.  
  1044.  
  1045.                                                                                                                              
  1046.                                                                                                                              
  1047.                                                                                                                              
  1048.