Subversion Repositories f9daq

Rev

Rev 11 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
9 f9daq 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>
362 f9daq 70
#include <linux/mutex.h>
9 f9daq 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
 
11 f9daq 348
    //PRINTK(KERN_DEBUG "%s : CmdMachine()\n", DEVICE_NAME);
9 f9daq 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
 
11 f9daq 401
    PRINTK(KERN_INFO "%s : init_hardware()\n", DEVICE_NAME);
9 f9daq 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
 
11 f9daq 620
    PRINTK(KERN_INFO "%s : VMEMM_RESET()\n", DEVICE_NAME);
9 f9daq 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)
362 f9daq 729
        err = !access_ok( (void *)arg, _IOC_SIZE(cmd));
9 f9daq 730
    if (_IOC_DIR(cmd) & _IOC_WRITE)
362 f9daq 731
        err = !access_ok( (void *)arg, _IOC_SIZE(cmd));
9 f9daq 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
 
11 f9daq 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
 
9 f9daq 807
static long  pcivme_unlocked_ioctl(struct file *pFile, unsigned int cmd, unsigned long arg){
808
long retval=0;
11 f9daq 809
 
810
 
9 f9daq 811
    struct mutex  fs_mutex;
812
   mutex_init(&fs_mutex);
813
   mutex_lock(&fs_mutex);
814
 
11 f9daq 815
PRINTK(KERN_DEBUG "%s : pcivme_unlocked_ioctl(0x%08x), size = %d\n", DEVICE_NAME, cmd, _IOC_SIZE(cmd));
9 f9daq 816
retval = pcivme_ioctl(NULL, pFile, cmd,arg);
817
 
818
   mutex_unlock(&fs_mutex);
11 f9daq 819
 
9 f9daq 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;
11 f9daq 827
    int nMinor = MINOR(pInode->i_rdev);
9 f9daq 828
    struct list_head *ptr;
829
 
11 f9daq 830
    PRINTK(KERN_DEBUG "%s : pcivme_open(), %d, scanning %d devices\n", DEVICE_NAME, nMinor, drv.count);
9 f9daq 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
            {
11 f9daq 841
                printk(KERN_ERR "%s :  pcivme_open() connection test for module %d failed!\n", DEVICE_NAME, pd->cModuleNumber);
9 f9daq 842
                pd->bConnected = 0;
843
            }
844
            else
845
                if (pd->cModuleNumber == nMinor)
846
            {
847
                desc = pd;
848
                break;
849
            }
850
        }
851
        else
11 f9daq 852
            PRINTK(KERN_DEBUG "%s  pcivme_open(): module %d not connected!\n", DEVICE_NAME, nMinor);
9 f9daq 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
 
11 f9daq 873
        PRINTK(KERN_DEBUG "%s :  pcivme_open() found VMEMM module with number %d.\n", DEVICE_NAME, nMinor);
9 f9daq 874
 
875
        if (!pd->nOpenCounter)
876
        {
877
            err = CmdMachine(pd, init_element);
878
            if (err)
879
            {
11 f9daq 880
                printk(KERN_ERR "%s :  pcivme_open() default init failed with err = %d!\n", DEVICE_NAME, err);
9 f9daq 881
                kfree_s(pp, sizeof(*pp));    // FREE(pFile->private_data);
882
                return err;
883
            }
884
        }
885
 
886
        pd->nOpenCounter++;
887
    }
888
    else
889
    {
11 f9daq 890
        printk(KERN_ERR "%s  pcivme_open(): No VMEMM module found.\n", DEVICE_NAME);
9 f9daq 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
 
11 f9daq 902
    PRINTK(KERN_DEBUG "%s : pcivme_release()\n", DEVICE_NAME);
9 f9daq 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
362 f9daq 948
    if (!access_ok( pcBuffer, count))
9 f9daq 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
362 f9daq 990
    if (!access_ok( pcBuffer, count))
9 f9daq 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
 
11 f9daq 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)
9 f9daq 1021
{
11 f9daq 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
 
9 f9daq 1042
struct file_operations pcivme_fops =
1043
{
11 f9daq 1044
    .llseek    =    pcivme_lseek,  /* lseek  */
9 f9daq 1045
    .read    =    pcivme_read,     /* read  */
1046
    .write   =    pcivme_write,    /* write */
11 f9daq 1047
//    .compat_ioctl = pcivme_compat_ioctl,  /* ioctl */
9 f9daq 1048
    .unlocked_ioctl = pcivme_unlocked_ioctl,  /* ioctl */
1049
    .open    =    pcivme_open,     /* open */
1050
    .release =    pcivme_release,  /* release */
1051
};
1052
 
1053
 
11 f9daq 1054
 
9 f9daq 1055
 
1056
 
1057