Subversion Repositories f9daq

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
86 f9daq 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