Subversion Repositories f9daq

Rev

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