Subversion Repositories f9daq

Rev

Blame | 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. // Revision 1.20 support for kernel version=3.13.0-37-generic 2014/10/19  Rok Pestotnik
  31. // fops.c -- the file operations module for the PCICC32 PCI to CAMAC Interface
  32. //
  33. // $Log: fops.c,v $
  34. // Revision 1.19  2006/06/04 12:26:07  klaus
  35. // release_20060604; Version 6.9; pci_{en|dis}able_device() added; remap_page_range reorganized
  36. //
  37. // Revision 1.18  2006/03/28 21:49:49  klaus
  38. // release_20060328; Version 6.8; Support for AMD64 and Kernel 2.6.15
  39. //
  40. // Revision 1.17  2005/03/11 13:23:26  klaus
  41. // simple corrections for to use with kernels 2.4.21
  42. //
  43. // Revision 1.16  2004/08/12 19:59:19  klaus
  44. // conversion to kernel-version 2.6, released version 6.0
  45. //
  46. // Revision 1.15  2004/01/16 18:40:34  klaus
  47. // converted remap_page_range call for kernels >= 2.4.20, contributed by Roberto Bertoni
  48. //
  49. // Revision 1.14  2003/12/04 20:34:49  klaus
  50. // minor change: restore the hardware set intCSR content at release of path, release of version 5.2
  51. //
  52. // Revision 1.13  2003/06/19 08:23:38  klaus
  53. // re-compiled with RH-7.2 (kernel 2.4.10)
  54. //
  55. // Revision 1.12  2003/05/11 11:12:03  klaus
  56. // matched to kernel 2.4 PCI handling, debug messages improved
  57. //
  58. // Revision 1.11  2002/10/08 18:01:46  klaus
  59. // corrections mainly for use with kernel 2.2.19
  60. //
  61. // Revision 1.10  2002/08/06 19:06:50  klaus
  62. // Small changes
  63. //
  64. // Revision 1.9  2002/04/17 19:41:06  klaus
  65. // added support for autoread
  66. //
  67. // Revision 1.8  2002/04/17 18:57:33  klaus
  68. // last changes to release 4.4
  69. //
  70. // Revision 1.7  2002/04/14 18:25:38  klaus
  71. // added interrupt handling, driver 4.4. ...3.5.tar.gz
  72. //
  73. // Revision 1.6  2001/11/20 21:29:24  klaus
  74. // Small changes to correct versioning down to kernel 2.3
  75. //
  76. // Revision 1.5  2001/11/20 20:25:23  klaus
  77. // inserted versioning for kernel 2.4
  78. //
  79. // Revision 1.4  2001/11/20 20:12:50  klaus
  80. // included new header and CVS log
  81. //
  82. // first steps (on my mothers birthday)                        AR   23.02.2000
  83. // MAKE_CC32_ADR serves only F from 0..15                      AR   24.04.2000
  84. // MODVERSIONS included                                        AR   24.04.2000
  85. //  
  86. //****************************************************************************
  87.  
  88. /*--- INCLUDES -----------------------------------------------------------------------------------*/
  89. #include "common.h"  /* must be the first include */
  90.  
  91. #include <linux/kernel.h> /* printk() */
  92. #include <linux/mm.h>
  93. #include <linux/module.h> /* MODULE_AUTHOR and MAJOR ... */
  94. #include <linux/pci.h>
  95. #include <asm/errno.h>
  96. #include <asm/types.h>
  97. #include <asm/uaccess.h>
  98. #include <linux/sched.h>
  99. #include <linux/wait.h>
  100. #include <linux/poll.h>
  101.  
  102. #include "fops.h"
  103. #include "list.h"
  104. #include "plx9050.h"
  105. #include "pcicc32.h"      /* the common ioctl commands and structures between driver and application */
  106.  
  107. /*--- DEFINES ------------------------------------------------------------------------------------*/
  108. MODULE_AUTHOR("klaus.hitschler@gmx.de");
  109. MODULE_DESCRIPTION("Driver for ARW Elektronik PCI CAMAC interface.");
  110. MODULE_SUPPORTED_DEVICE("PCICC32");
  111.  
  112. #if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,10)
  113. MODULE_LICENSE("GPL");               // since 2.4.?
  114. #endif
  115.  
  116. #ifndef MINOR
  117. #define MINOR(x) minor(x)            // since 2.5.?
  118. #endif
  119.  
  120. #define MAKE_CC32_ADR(N, A, F) (u16)((N << 10) + (A << 6) + ((F & 0xf) << 2))
  121.  
  122. #define ENABLE_PCIADA_IRQS  (u16)0x0049 /* enable PCIADA IRQs            */
  123. #define DISABLE_PCIADA_IRQS (u16)0x0009 /* disable PCIADA IRQs           */
  124.  
  125. /*--- EXTERNALS ----------------------------------------------------------------------------------*/
  126. extern int get_module_info(CC32_DESCRIPTOR *wd, u8 *cModuleNumber, u8 *cFPGAVersion);
  127. extern int test_connection(CC32_DESCRIPTOR *wd);
  128. extern List *pcicc32_work_device_header;
  129.  
  130. /*--- TYPEDEFS -----------------------------------------------------------------------------------*/
  131. typedef struct
  132. {
  133.         CC32_DESCRIPTOR *desc;  /* pointer to my PCIADA & CC32 */
  134. } PRIVATE_DATA;
  135.  
  136. /*--- FUNCTIONS ----------------------------------------------------------------------------------*/
  137. static void switch_CC32_on(CC32_DESCRIPTOR *desc)
  138. {
  139.         u16 cntrl;
  140.        
  141.         DPRINTK(KERN_DEBUG "pcicc32 : switch_CC32_on()\n");
  142.        
  143.         cntrl  = readw(desc->pLCR + PLX9050_CNTRL);  /* read CONTROL register */
  144.         cntrl |= 0x0180;
  145.         writew(cntrl, desc->pLCR + PLX9050_CNTRL); /* enable access */
  146. }
  147.  
  148. static void switch_CC32_off(CC32_DESCRIPTOR *desc)
  149. {
  150.         u16 cntrl  = readw(desc->pLCR + PLX9050_CNTRL);  /* read CONTROL register */
  151.        
  152.         DPRINTK(KERN_DEBUG "pcicc32 : switch_CC32_off()\n");
  153.        
  154.   writew(DISABLE_PCIADA_IRQS, desc->pLCR + PLX9050_INTCSR);  /* disable global interrupts */
  155.         cntrl &= ~0x0100;
  156.         writew(cntrl, desc->pLCR + PLX9050_CNTRL);       /* disable access */
  157. }
  158.  
  159. int pcicc32_ioctl(struct inode *pInode, struct file *pFile, unsigned int cmd, unsigned long arg)
  160. {
  161.         u16 cntrl;
  162.         PRIVATE_DATA *pd    = (PRIVATE_DATA *)pFile->private_data;
  163.   CC32_DESCRIPTOR *wd = pd->desc;
  164.        
  165.         DPRINTK(KERN_DEBUG "pcicc32 : pcicc32_ioctl(0x%08x, 0x%08lx)\n", cmd, arg);
  166.        
  167.         if (_IOC_TYPE(cmd) != PCICC32_MAGIC)
  168.           return -EINVAL;
  169.        
  170.         switch(_IOC_NR(cmd))
  171.         {
  172.     case 1: // PCICC32_IOSTATE
  173.                   {
  174.               PCICC32_STATUS *ptr = (PCICC32_STATUS *)arg;  /* makes it simple */
  175.                  
  176.                     if (_IOC_SIZE(cmd) < sizeof(PCICC32_STATUS))
  177.                       return -EINVAL;
  178.                           if (!access_ok(VERIFY_WRITE, ptr, sizeof(*ptr)))
  179.                             return -EFAULT;
  180.                                
  181.                           ptr->bConnected = ((wd->bConnected) && (readw(wd->pLCR + PLX9050_CNTRL) & 0x0800)) ? 1 : 0;
  182.                           ptr->bFail      = (readw(wd->pLCR + PLX9050_INTCSR) & 0x0020) ? 1 : 0;
  183.                           ptr->bIrq       = (readw(wd->pLCR + PLX9050_INTCSR) & 0x0004) ? 1 : 0;
  184.                          
  185.                                 wd->wIrqStatus  = 0;  // clear the status since it is read                             
  186.                         }
  187.                         break;
  188.                 case 2: // PCICC32_IOCNTRL
  189.                   {
  190.                     if (_IOC_SIZE(cmd))
  191.                       return -EINVAL;
  192.                                
  193.                           cntrl  = readw(wd->pLCR + PLX9050_CNTRL);  /* read CONTROL register */
  194.                           writew(cntrl & ~0x0100, wd->pLCR + PLX9050_CNTRL); /* clear USRIO2 */
  195.                           writew(cntrl          , wd->pLCR + PLX9050_CNTRL); /* restore it   */        
  196.                         }
  197.                   break;
  198.           case 3: // PCICC32_CONTROL_INTERRUPTS
  199.             {
  200.               PCICC32_IRQ_CONTROL *ptr = (PCICC32_IRQ_CONTROL *)arg;  /* makes it simple */
  201.               char bEnable = (readw(wd->pLCR + PLX9050_INTCSR) & 0x40) ? 1 : 0;
  202.              
  203.               if (_IOC_SIZE(cmd) < sizeof(PCICC32_IRQ_CONTROL))
  204.                 return -EINVAL;
  205.                           if (!access_ok(VERIFY_WRITE, ptr, sizeof(*ptr)))
  206.                             return -EFAULT;
  207.              
  208.               DPRINTK(KERN_DEBUG "pcicc32 : Interrupt enable = %d\n", ptr->bEnable);
  209.              
  210.               if (ptr->bEnable)
  211.                 writew(ENABLE_PCIADA_IRQS  ,wd->pLCR + PLX9050_INTCSR); // local and global enable
  212.                     else
  213.                       writew(DISABLE_PCIADA_IRQS ,wd->pLCR + PLX9050_INTCSR); // global disable
  214.                      
  215.                     // return last interrupt enable status  
  216.                           ptr->bEnable = bEnable;  
  217.             }
  218.             break;
  219.           case 4: // PCICC32_IOSTATE_BLOCKING
  220.             {
  221.               PCICC32_STATUS *ptr = (PCICC32_STATUS *)arg;  /* makes it simple */
  222.               int err;
  223.                          
  224.                     if (_IOC_SIZE(cmd) < sizeof(PCICC32_STATUS))
  225.                       return -EINVAL;
  226.                    
  227.         // support nonblocking read if requested
  228.         if ((pFile->f_flags & O_NONBLOCK) && (!wd->wIrqStatus))
  229.           return -EAGAIN;
  230.          
  231.         // sleep until data are available
  232.         if ((err = wait_event_interruptible(wd->event_queue, (wd->wIrqStatus))))
  233.                 return err;
  234.                
  235.                           if (!access_ok(VERIFY_WRITE, ptr, sizeof(*ptr)))
  236.                             return -EFAULT;
  237.                                
  238.                           ptr->bConnected = ((wd->bConnected) && (readw(wd->pLCR + PLX9050_CNTRL) & 0x0800)) ? 1 : 0;
  239.                           ptr->bFail      = (readw(wd->pLCR + PLX9050_INTCSR) & 0x0020) ? 1 : 0;
  240.                           ptr->bIrq       = (readw(wd->pLCR + PLX9050_INTCSR) & 0x0004) ? 1 : 0;
  241.                          
  242.                                 wd->wIrqStatus  = 0;  // clear the status since it is read                             
  243.             }
  244.             break;
  245.           case 5: // PCICC32_AUTOREAD_SWITCH
  246.             {
  247.               u16 ctrl, erg;
  248.              
  249.               PCICC32_AUTOREAD *ptr = (PCICC32_AUTOREAD *)arg;  /* makes it simple */
  250.                          
  251.                     if (_IOC_SIZE(cmd) < sizeof(PCICC32_AUTOREAD))
  252.                       return -EINVAL;
  253.                    
  254.                           if (!access_ok(VERIFY_WRITE, ptr, sizeof(*ptr)))
  255.                             return -EFAULT;
  256.                          
  257.                           ctrl = readw(wd->pLCR + PLX9050_CNTRL);  
  258.                           if (ptr->bOn)
  259.                           {
  260.                             erg  = ctrl & ~0x0004;
  261.                             erg |= 0x0002;         // switch output to 1, pin to 0 = on
  262.                             writew(erg, wd->pLCR + PLX9050_CNTRL);
  263.                           }
  264.                           else
  265.                           {
  266.                             erg  = ctrl | 0x0006;  // switch output = 1, pin to 1 = off
  267.                             writew(erg, wd->pLCR + PLX9050_CNTRL);
  268.                           }
  269.                          
  270.                                 // respond the last state
  271.                           ptr->bOn = (ctrl & 0x0004) ? 0 : 1;
  272.             }
  273.             break;
  274.                
  275.                 default:
  276.                   return -EINVAL;
  277.         }
  278.        
  279.         return 0;
  280. }
  281.  
  282.  
  283. static long  pcicc32_unlocked_ioctl(struct file *pFile, unsigned int cmd, unsigned long arg){
  284. long retval=0;
  285.  
  286.  
  287. #if HAVE_UNLOCKED_IOCTL
  288.     struct mutex  fs_mutex;
  289.    mutex_init(&fs_mutex);
  290.    mutex_lock(&fs_mutex);
  291. #else
  292.    lock_kernel();
  293. #endif
  294.  
  295. DPRINTK(KERN_DEBUG "%s : pcicc32_unlocked_ioctl(0x%08x), size = %d\n", DEVICE_NAME, cmd, _IOC_SIZE(cmd));
  296. retval = pcicc32_ioctl(NULL, pFile, cmd,arg);
  297.  
  298. #if HAVE_UNLOCKED_IOCTL
  299.    mutex_unlock(&fs_mutex);
  300. #else
  301.    unlock_kernel();
  302. #endif
  303.  
  304. return retval;
  305. }
  306.  
  307. int pcicc32_mmap(struct file *pFile, struct vm_area_struct *vma)
  308. {
  309.         PRIVATE_DATA *pd = (PRIVATE_DATA *)pFile->private_data;
  310.        
  311.         DPRINTK(KERN_DEBUG "pcicc32 : pcicc32_mmap()\n");
  312.        
  313.         if (pd->desc->pPch->desc[3].type == PCI_BASE_ADDRESS_MEM_TYPE_1M)
  314.         {
  315.                 DPRINTK(KERN_DEBUG "pcicc32 : mmap(address=%p size=%d)\n",
  316.                         virt_to_phys((void *)pd->desc->pUsr), pd->desc->pPch->desc[3].size);
  317.  
  318.                 if (pcicc32_remap_page_range(vma, vma->vm_start,
  319.                         virt_to_phys((void *)pd->desc->pUsr), pd->desc->pPch->desc[3].size, PAGE_SHARED))
  320.                         return -EAGAIN;
  321.         }
  322.         else
  323.         {
  324.                 DPRINTK(KERN_DEBUG "pcicc32 : mmap(address=%p size=%d)\n",
  325.                         virt_to_phys((void *)pd->desc->pUsr), pd->desc->pPch->desc[3].size);
  326.  
  327.                 if (pcicc32_remap_page_range(vma, vma->vm_start,
  328.                         pd->desc->pPch->desc[3].base_address, pd->desc->pPch->desc[3].size, PAGE_SHARED))
  329.                         return -EAGAIN;
  330.         }
  331.        
  332.         return 0;
  333. }
  334.  
  335.  
  336.  
  337. int pcicc32_open(struct inode *pInode, struct file *pFile)
  338. {
  339.         CC32_DESCRIPTOR *wd = 0;
  340.         CC32_DESCRIPTOR *desc = 0;
  341.         int i;
  342.         Node *n;
  343.         int nMinor = MINOR(pInode->i_rdev);
  344.         PRIVATE_DATA *pd;
  345.        
  346.         DPRINTK(KERN_DEBUG "pcicc32 : pcicc32_open(), Major=%d, Minor=%d\n", MAJOR(pInode->i_rdev), nMinor);
  347.        
  348.         /* search for device */
  349.         i = getNumOfNodesInList(pcicc32_work_device_header);
  350.         n = getFirstNode(pcicc32_work_device_header);
  351.        
  352.         DPRINTK(KERN_DEBUG "pcicc32 : scanning %d devices\n", i);
  353.         while (i--)
  354.         {
  355.                 wd  = (CC32_DESCRIPTOR *)getContent(n);
  356.                
  357.                 wd->bConnected =  get_module_info(wd, &wd->cModuleNumber, &wd->cFPGAVersion);
  358.                 if (wd->bConnected)
  359.                 {
  360.                         if  (test_connection(wd))
  361.                         {
  362.                                 printk(KERN_ERR "pcicc32 : connection test for module %d failed!\n", wd->cModuleNumber);
  363.                                 wd->bConnected = 0;
  364.                         }
  365.                         else
  366.                                 if (wd->cModuleNumber == nMinor)
  367.                                 {
  368.                                         desc = wd;
  369.                                         break;
  370.                                 }
  371.                 }
  372.                 else
  373.                 {
  374.                         DPRINTK(KERN_DEBUG "pcicc32 : module %d not connected!\n", nMinor);
  375.                 }
  376.                          
  377.                 n = getNextNode(n);
  378.         }
  379.        
  380.         if (desc)
  381.         {
  382.                 pFile->private_data = (void *)kmalloc(sizeof(PRIVATE_DATA), GFP_ATOMIC);
  383.                 if (!pFile->private_data)
  384.                         return -ENOMEM;
  385.                
  386.                 pd = (PRIVATE_DATA *)pFile->private_data;
  387.                 pd->desc = wd;
  388.                
  389.                 DPRINTK(KERN_DEBUG "pcicc32 : found CC32 module with number %d.\n", nMinor);
  390.         }
  391.         else
  392.         {
  393.                 DPRINTK(KERN_DEBUG "pcicc32 : No CC32 module found.\n");
  394.  
  395.                 return -ENODEV;
  396.         }              
  397.                
  398.         switch_CC32_on(wd);
  399.                        
  400.         __MOD_INC_USE_COUNT__;
  401.         return 0;
  402. }
  403.  
  404. int pcicc32_release(struct inode *pInode, struct file *pFile)
  405. {
  406.         PRIVATE_DATA *pd;
  407.  
  408.         DPRINTK(KERN_DEBUG "pcicc32 : pcicc32_release()\n");
  409.                                
  410.         if (pFile->private_data)
  411.         {
  412.                 pd = (PRIVATE_DATA *)pFile->private_data;
  413.                 if (pd && pd->desc)    
  414.                 {
  415.                         switch_CC32_off(pd->desc);
  416.                         pd->desc = 0;
  417.                 }
  418.                        
  419.                 kfree_s(pd, sizeof(*pd));    // FREE(pFile->private_data);
  420.         }
  421.        
  422.         __MOD_DEC_USE_COUNT__;
  423.         return 0;
  424. }
  425.  
  426. //----------------------------------------------------------------------------
  427. // is called at poll or select
  428. static unsigned int pcicc32_poll(struct file *pFile, poll_table *wait)
  429. {
  430.         PRIVATE_DATA    *pd = (PRIVATE_DATA *)pFile->private_data;
  431.   CC32_DESCRIPTOR *wd = pd->desc;
  432.   unsigned int mask   = 0;
  433.  
  434.         DPRINTK(KERN_DEBUG "pcicc32 : pcicc32_poll()\n");
  435.        
  436.   poll_wait(pFile, &wd->event_queue, wait);
  437.  
  438.   // return on ops that could be performed without blocking
  439.   if (wd->wIrqStatus)      
  440.     mask |= (POLLIN  | POLLRDNORM);
  441.  
  442.   return mask;
  443. }
  444.  
  445. #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
  446. struct file_operations pcicc32_fops =
  447. {
  448.         NULL,                   /* lseek */
  449.         NULL,                   /* read  */
  450.         NULL,                   /* write */
  451.         NULL,                   /* readdir */
  452.         pcicc32_poll,   /* poll, since 2.2., replaces select */
  453.         pcicc32_ioctl,  /* ioctl */
  454.         pcicc32_mmap,   /* mmap */
  455.         pcicc32_open,   /* open */
  456.         NULL,           /* flush */
  457.         pcicc32_release,/* release */
  458. };
  459. #else
  460. struct file_operations pcicc32_fops =
  461. {
  462.         unlocked_ioctl :   pcicc32_unlocked_ioctl,              /* ioctl */
  463. //      ioctl:   pcicc32_ioctl,         /* ioctl */
  464.         mmap:    pcicc32_mmap,          /* mmap */
  465.         open:    pcicc32_open,          /* open */
  466.         release: pcicc32_release,       /* release */
  467.   poll:    pcicc32_poll,    /* poll */
  468. };
  469. #endif
  470.  
  471.  
  472.