Subversion Repositories f9daq

Rev

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

Rev Author Line No. Line
9 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
//
31
// main.c -- the main driver module for the PCIVME PCI to VME Interface
32
//           Thanks to A.Rubini's Book and Dirk Muelhlenberg and H.J.Mathes 
33
//           for their arwvme driver
34
//
35
// $Log: main.c,v $
36
// Revision 1.10  2006/06/04 12:20:46  klaus
37
// release_20060604; Version 3.2; pci_{en|dis}able_device() added
38
//
39
// Revision 1.9  2004/08/13 19:23:26  klaus
40
// conversion to kernel-version 2.6, released version 3.0
41
//
42
// Revision 1.8  2003/06/27 17:25:52  klaus
43
// incomplete try to get mmap() with nopage() running for automatic page switch
44
//
45
// Revision 1.7  2002/10/18 21:56:28  klaus
46
// completed functional features, untested
47
//
48
// Revision 1.6  2002/10/18 21:56:28  klaus
49
// completed functional features, untested
50
//
51
// Revision 1.5  2002/10/17 19:05:03  klaus
52
// VME access is working through test to lib to driver
53
//
54
//****************************************************************************
55
#define NOPAGE_SIGBUS   (NULL)
56
 
57
#define VERSION_HI 3
58
#define VERSION_LO 2
59
 
60
/*--- INCLUDES ---------------------------------------------------------------------------*/
61
#include "common.h"  /* must be the first include */
62
#include <linux/module.h>
63
 
64
#include <linux/sched.h>
65
#include <linux/proc_fs.h>
66
#include <linux/pci.h>
67
#include <asm/types.h>
68
#include <linux/mm.h>
69
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
70
#include <linux/interrupt.h>
71
#endif
72
 
73
#include "askpci.h"
74
#include "plxbug.h"
75
#include "plx9050.h"
76
#include "fops.h"
77
#include "pcivme.h"
78
#include "pciif.h"
79
#include "vic.h"
80
#include "main.h"
81
 
82
/*--- DEFINES -----------------------------------------------------------------------------*/
83
MODULE_AUTHOR("klaus.hitschler@gmx.de");
84
MODULE_DESCRIPTION("Driver for ARW Elektronik PCI VME interface.");
85
MODULE_SUPPORTED_DEVICE("PCIVME");
86
MODULE_LICENSE("GPL");
87
 
88
#define MAJOR_NO               0                         /* use dynamic assignment */
89
 
90
#define PCIVME_VENDOR_ID  0x10B5
91
#define PCIVME_DEVICE_ID  0x9050
92
#define PCIVME_SUBSYS_ID  0x1167
93
#define PCIVME_SUBVEN_ID  0x9050
94
 
95
/*--- TYPEDEFS ----------------------------------------------------------------------------*/
96
 
97
/*--- GLOBALS -----------------------------------------------------------------------------*/
98
DRIVER_OBJ drv;
99
 
100
/*--- LOCALS ------------------------------------------------------------------------------*/
101
 
102
/*--- FUNCTIONS ---------------------------------------------------------------------------*/
44 f9daq 103
 
104
struct proc_dir_entry *proc;
105
 
9 f9daq 106
static int my_interrupt(u16 intCSR)
107
{
108
    int result = NOT_MY_INTERRUPT;
109
 
110
    if (intCSR & 0x0040)  // it is global enabled
111
    {
112
        if ((intCSR & 0x0028) == 0x0028) // it is a enabled PCIADA interrupt
113
            result = PCIADA_INTERRUPT;
114
        else
115
            if ((intCSR & 0x0005) == 0x0005) // it is a enabled VMEMM interrupt
116
            result = VMEMM_INTERRUPT;
117
    }
118
 
119
    return result;
120
}
121
 
43 f9daq 122
static irqreturn_t pcivme_irqhandler(int irq, void *dev_id )
9 f9daq 123
{
124
    DEVICE_OBJ *pd = (DEVICE_OBJ *)dev_id;
125
 
126
    if (pd)
127
    {
128
        // evaluate the reason of the interrupt - if it is mine
129
        u16 intCSR          = readw((const volatile void *) (pd->pPCIADAIntCSR));
130
        int which_interrupt = my_interrupt(intCSR);
131
 
132
        if (which_interrupt)
133
        {
134
            writew(intCSR & ~0x40, (volatile void *) pd->pPCIADAIntCSR); /* disable global interrupts */
135
            pd->wIrqStatus = (u16)which_interrupt;
136
            pd->dwInterruptCount++;
137
            wake_up_interruptible(&pd->event_queue);   /* stop blocking if any */
138
 
139
                        return IRQ_RETVAL(1);
140
        }
141
    }
142
 
143
        return IRQ_RETVAL(0);
144
}
145
 
146
static int request_io_memory(PCIConfig *pPch)
147
{
148
    if (check_mem_region(pci_resource_start(pPch->pciDev, 0),  LCR_SPACE))
149
    {
11 f9daq 150
        PRINTK(KERN_DEBUG "%s : LCR 0x%08lx\n", DEVICE_NAME, (long unsigned int) pci_resource_start(pPch->pciDev, 0));
9 f9daq 151
        return -EBUSY;
152
    }
153
 
154
    if (check_mem_region(pci_resource_start(pPch->pciDev, 2),  CTL_SPACE))
155
    {
11 f9daq 156
        PRINTK(KERN_DEBUG "%s : CTL 0x%08lx\n", DEVICE_NAME, (long unsigned int) pci_resource_start(pPch->pciDev, 2));
9 f9daq 157
        return -EBUSY;
158
    }
159
 
160
    if (check_mem_region(pci_resource_start(pPch->pciDev, 2) + CTL_SPACE, VME_SPACE))
161
    {
11 f9daq 162
        PRINTK(KERN_DEBUG "%s : VME 0x%08lx\n", DEVICE_NAME, (long unsigned int) pci_resource_start(pPch->pciDev, 2) + CTL_SPACE);
9 f9daq 163
        return -EBUSY;
164
    }
165
 
166
    request_mem_region(pci_resource_start(pPch->pciDev, 0),  LCR_SPACE, DEVICE_NAME);
167
    request_mem_region(pci_resource_start(pPch->pciDev, 2),  CTL_SPACE, DEVICE_NAME);
168
    request_mem_region(pci_resource_start(pPch->pciDev, 2) + CTL_SPACE, VME_SPACE, DEVICE_NAME);
169
 
170
    return 0;
171
}
172
 
173
static void release_io_memory(PCIConfig *pPch)
174
{
175
    release_mem_region(pci_resource_start(pPch->pciDev, 0),  LCR_SPACE);
176
    release_mem_region(pci_resource_start(pPch->pciDev, 2),  CTL_SPACE);
177
    release_mem_region(pci_resource_start(pPch->pciDev, 2) + CTL_SPACE, VME_SPACE);
178
}
179
 
180
static int translate_addresses(DEVICE_OBJ *pd, PCIConfig *pPch)    /* differs from PCICC32 */
181
{
182
    if (pci_resource_start(pPch->pciDev, 0) < LOW_MEMORY)  /* LCR ISA base addresses */
183
        pd->pLCR = (u32)bus_to_virt(pci_resource_start(pPch->pciDev, 0));
184
    else
185
        pd->pLCR = (u32)ioremap(pci_resource_start(pPch->pciDev, 0), LCR_SPACE);
186
 
187
    if (pci_resource_start(pPch->pciDev, 2) < LOW_MEMORY)  /* User ISA base addresses */
188
    {
189
        pd->pCtl = (u32)bus_to_virt(pci_resource_start(pPch->pciDev, 2)            );
190
        pd->pVME = (u32)bus_to_virt(pci_resource_start(pPch->pciDev, 2) + CTL_SPACE);
191
    }
192
    else
193
    {
194
        pd->pPhysVME = pci_resource_start(pPch->pciDev, 2) + CTL_SPACE;
195
 
196
        pd->pCtl = (u32)ioremap(pci_resource_start(pPch->pciDev, 2)            , CTL_SPACE);
197
        pd->pVME = (u32)ioremap(pci_resource_start(pPch->pciDev, 2) + CTL_SPACE, VME_SPACE);
198
    }
199
 
200
    return 0;
201
}
202
 
203
static void un_translate_addresses(DEVICE_OBJ *pd, PCIConfig *pPch)
204
{
205
    if (pci_resource_start(pPch->pciDev, 0) >= LOW_MEMORY)  /* no LCR ISA base addresses */
206
        iounmap((void *)pd->pLCR);
207
 
208
    if (pci_resource_start(pPch->pciDev, 2) >= LOW_MEMORY)
209
    {
210
        pd->pPhysVME = 0;
211
 
212
        iounmap((void *)pd->pCtl);
213
        iounmap((void *)pd->pVME);
214
    }
215
}
216
 
217
static void soft_init(DEVICE_OBJ *pd)
218
{
219
    if (pd)
220
    {
221
        init_waitqueue_head(&pd->event_queue);
222
 
223
        pd->pLCR = pd->pCtl = pd->pVME = 0;
224
        pd->pPch = (PCIConfig *)NULL;
225
        pd->bConnected = 0;
226
        pd->wInitStep = 0;    
227
        pd->wIrq = 0xFFFF;          
228
        pd->dwInterruptCount = 0;
229
        pd->wIrqStatus = 0;
230
        pd->nOpenCounter = 0;
231
 
232
        pd->cModuleNumber = 255;
233
        pd->cFPGAVersion = 255;
234
        pd->cSystemController = 0;
235
        pd->cWordMode         = 0;
236
 
237
        pd->pAdrMod = 0;
238
        pd->pAdrReg = 0;
239
        pd->pCSR    = 0;
240
 
241
        pd->pPCIADACntrl  = 0;
242
        pd->pPCIADAIntCSR = 0;      
243
 
244
        pd->bCurrentModifier     = 0;
245
        pd->dwCurrentPageAddress = -1;
246
                                pd->currentMap.pageptr = NOPAGE_SIGBUS;
247
                                pd->currentMap.addr = 0;
248
    }
249
}
250
 
251
int test_connection(DEVICE_OBJ *pd)
252
{
253
    u16 intCSR_store;
254
    u16 cntrl_store;
255
    int i;      
256
    int error   = 0;
257
    u32 dwADRH  = pd->pCtl + ADRH;
258
    u32 dwADRL  = pd->pCtl + ADRL;
259
    u32 dwADRHL = pd->pCtl + ADRHL;
260
    u32 dwStore;
261
    u16 wRet;
262
 
263
    cntrl_store  = readw((const volatile void *) pd->pPCIADACntrl);         /* read CONTROL register */
264
    intCSR_store = readw((const volatile void *) pd->pPCIADAIntCSR);        /* read interrupt + CSR register */
265
 
266
    writew(0, (volatile void *) pd->pPCIADAIntCSR);                   /* disable interrupts */
267
    writew(cntrl_store | 0x0180, (volatile void *) pd->pPCIADACntrl); /* enable access */
268
 
269
    // save adr register
270
    dwStore = readl((const volatile void *) dwADRHL);
271
    for (i = 1000; i; i--)
272
    {
273
        writew(0x5555, (volatile void *) dwADRH);
274
        writew(0xAAAA, (volatile void *) dwADRL);
275
        wRet   = readw((const volatile void *) dwADRH);
276
        if (wRet != 0x5555)
277
        {
278
            error = 1;
279
            break;
280
        }
281
 
282
        writew(0xAAAA, (volatile void *) dwADRH);
283
        writew(0x5555, (volatile void *) dwADRL);
284
        wRet   = readw((const volatile void *) dwADRH);
285
        if (wRet != 0xAAAA)
286
        {
287
            error = 1;
288
            break;
289
        }
290
 
291
        writew(0x0000, (volatile void *) dwADRH);
292
        writew(0xFFFF, (volatile void *) dwADRL);
293
        wRet   = readw((const volatile void *) dwADRH);
294
        if (wRet != 0x0000)
295
        {
296
            error = 1;
297
            break;
298
        }
299
 
300
        writew(0xFFFF, (volatile void *) dwADRH);
301
        writew(0x0000, (volatile void *) dwADRL);
302
        wRet   = readw((const volatile void *) dwADRH);
303
        if (wRet != 0xFFFF)
304
        {
305
            error = 1;
306
            break;
307
        }
308
    }
309
 
310
    // restore register
311
    writel(dwStore, (volatile void *) dwADRHL);
312
 
313
    //clear possible interrupts
314
    writew(cntrl_store & ~0x0100, (volatile void *) pd->pPCIADACntrl); /* clear potential interrupt */
315
 
316
    // restore LCR registers
317
    writew(cntrl_store,  (volatile void *) pd->pPCIADACntrl);
318
    writew(intCSR_store, (volatile void *) pd->pPCIADAIntCSR);
319
 
320
    return error;  
321
}
322
 
323
int get_module_info(DEVICE_OBJ *pd)
324
{
325
    u16 intCSR_store;
326
    u16 cntrl_store;
327
    int found = 0;
328
    u16 data;
329
 
330
    cntrl_store  = readw((const volatile void *) pd->pPCIADACntrl);  /* read CONTROL register */
331
    intCSR_store = readw((const volatile void *) pd->pPCIADAIntCSR); /* read interrupt + CSR register */
332
 
333
    PRINTK(KERN_DEBUG "%s : cntrl=0x%04x, intCSR=0x%04x\n", DEVICE_NAME, cntrl_store, intCSR_store);
334
 
335
    if (cntrl_store & 0x0800) /* a VMEMM is connected */
336
    {
337
        u16 bla = cntrl_store | 0x0180;
338
 
339
        writew(0,   (volatile void *) pd->pPCIADAIntCSR); /* disable interrupts */
340
        writew(bla, (volatile void *) pd->pPCIADACntrl);  /* enable access */
341
 
342
        // read main status register
343
        data = readw((const volatile void *) pd->pCSR);
344
 
345
        if ((data & 0xF000) != VMEMM_MODULE_TYPE)
346
        {
347
            pd->cModuleNumber = pd->cFPGAVersion = 255;
348
            printk(KERN_ERR "%s : Wrong module type connected @ index %d!\n", DEVICE_NAME, pd->wIndex);
349
        }
350
        else
351
        {
352
            found = 1;
353
            pd->cModuleNumber     = (data >> 4) & 0xF;
354
            pd->cFPGAVersion      = (data >> 8) & 0xF;
355
            pd->cSystemController = (data & 0x0008);
356
            pd->cWordMode         = (data & 0x0004);
357
        }
358
 
359
        // clear possible interrupts
360
        writew(cntrl_store & ~0x0100, (volatile void *) pd->pPCIADACntrl); /* clear potential interrupt */
361
 
362
        /* restore all contents */
363
        writew(cntrl_store,  (volatile void *) pd->pPCIADACntrl);
364
        writew(intCSR_store, (volatile void *) pd->pPCIADAIntCSR);
365
    }
366
 
367
    return found;  
368
}
369
 
370
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
371
static int pcivme_read_proc(char *buf, char **start, off_t offset, int len)
372
#else
43 f9daq 373
//static int pcivme_read_proc(char *buf, char **start, off_t offset, int len, int *eof, void *data)
374
static int pcivme_read_proc(struct file *filp,char *buf,size_t count,loff_t *offp )
9 f9daq 375
#endif
376
    {
377
    int              pos = 0;
378
    DEVICE_OBJ       *pd;
379
    PCIConfig        *ch;
380
    u16                cntrl;
381
    char             *cause = "none";
382
    struct list_head *ptr;
44 f9daq 383
    PRINTK(KERN_DEBUG "%s : pcivme_read_proc()\n",DEVICE_NAME);
384
 
385
    if (*offp != 0) return 0;
9 f9daq 386
    pos += sprintf(buf + pos, "\nPCIVME information. Version %d.%d of %s from Klaus Hitschler.\n", VERSION_HI, VERSION_LO, __DATE__);
387
 
388
    pos += sprintf(buf + pos, " ---------------------\n");
389
    pos += sprintf(buf + pos, " Interfaces found : %d\n", drv.count);
390
    pos += sprintf(buf + pos, " Major Number     : %d\n", drv.nMajor);
391
 
392
    for (ptr = drv.devList.next; ptr != &drv.devList; ptr = ptr->next)
393
    {
394
        pd = list_entry(ptr, DEVICE_OBJ, list);
395
        ch = pd->pPch;
396
        cntrl = readw((const volatile void *)(pd->pLCR + PLX9050_CNTRL));
397
        pos += sprintf(buf + pos, " --- %d ---------------\n", pd->wIndex + 1);
398
        pos += sprintf(buf + pos, " LCR     phys/virt/size : 0x%08lx/0x%08x/%d\n",(long unsigned int) pci_resource_start(ch->pciDev, 0),             pd->pLCR, LCR_SPACE);
399
        pos += sprintf(buf + pos, " Control phys/virt/size : 0x%08lx/0x%08x/%d\n",(long unsigned int)  pci_resource_start(ch->pciDev, 2),             pd->pCtl, CTL_SPACE);
400
        pos += sprintf(buf + pos, " VME     phys/virt/size : 0x%08lx/0x%08x/%d\n",(long unsigned int)  pci_resource_start(ch->pciDev, 2) + CTL_SPACE, pd->pVME, VME_SPACE);
401
        pos += sprintf(buf + pos, " Irq                    : %d\n", pd->wIrq);
402
 
403
        if (pd->bConnected)
404
        {
405
            pos += sprintf(buf + pos, " VMEMM is or was        : (software) connected.\n");
406
            pos += sprintf(buf + pos, " Module-Number          : %d\n", pd->cModuleNumber);
407
            pos += sprintf(buf + pos, " FPGA-Version           : %d\n", pd->cFPGAVersion);
408
            pos += sprintf(buf + pos, " Systemcontroller       : %s\n", (pd->cSystemController) ? "yes" : "no");
409
            pos += sprintf(buf + pos, " Word Mode              : %s\n", (pd->cWordMode) ? "yes" : "no");
410
        }
411
        else
412
            pos += sprintf(buf + pos, " VMEMM is or was        : not (software) connected.\n");      
413
 
414
        if (!((cntrl & 0x0800) && (!(cntrl & 0x0600))))
415
            pos += sprintf(buf + pos, " VMEMM is               : powered off or cable disconnected.\n");
416
 
417
        pos += sprintf(buf + pos, " IrqCount               : %d\n", pd->dwInterruptCount);
418
        if (pd->wIrqStatus & PCIADA_INTERRUPT)
419
            cause = "Timeout";
420
        else
421
            if (pd->wIrqStatus & VMEMM_INTERRUPT)
422
                cause = "VME";
423
        pos += sprintf(buf + pos, " Pending IrqStatus      : %s\n", cause);
424
    }
425
 
426
    pos += sprintf(buf + pos, "\n");
44 f9daq 427
    if (pos>count) {
428
      buf[count-1]=0;
429
      pos=count;
430
    }    
431
    PRINTK(KERN_DEBUG "%s : pcivme_read_proc() end count=%d\n",DEVICE_NAME, pos);
9 f9daq 432
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
43 f9daq 433
    //*eof = 1;
9 f9daq 434
#endif
44 f9daq 435
    *offp = pos;
436
 
9 f9daq 437
    return pos;
438
}
439
 
43 f9daq 440
 
441
 
442
 
9 f9daq 443
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
444
struct proc_dir_entry pcimod_proc_entry =
445
{
446
    namelen:    7,                  /* len of name */
447
    name:       DEVICE_NAME,        /* entry  name */
448
    mode:       S_IFREG | S_IRUGO,  /* mode */
449
    nlink:      1,                  /* nlinks */
450
    get_info:   pcivme_read_proc,  /* function used to read data */
451
};
43 f9daq 452
#else 
44 f9daq 453
struct file_operations pcivme_read_proc_fops = {
43 f9daq 454
read: pcivme_read_proc
455
};
9 f9daq 456
#endif
457
 
458
static void deleteMyLists(void)
459
{
460
    DEVICE_OBJ      *pd;
461
 
462
    /* delete my lists */
463
    while (!list_empty(&drv.devList))                 // cycle through the list of pci devices and remove them
464
    {
465
        pd = (DEVICE_OBJ *)drv.devList.prev;            // empty in reverse order
466
        list_del(&pd->list);
467
        kfree(pd);
468
    }
469
 
470
    DeletePCIConfig(&drv);
471
}
472
 
44 f9daq 473
int pcivme_module_init(void)
9 f9daq 474
{
475
    PCIConfig        *ch;
476
    DEVICE_OBJ       *pd;
477
    int              result = 0;
478
    struct list_head *ptr;
479
 
480
    PRINTK(KERN_DEBUG "%s : init_module\n", DEVICE_NAME);
481
 
482
    /* create list of PCIADAs and work devices */
483
    INIT_LIST_HEAD(&drv.devList);
484
    INIT_LIST_HEAD(&drv.pciList);
485
 
486
    drv.count = 0;
487
 
488
    /* search for all PCIADA modules */
489
    if ((result = GetPCIConfig(&drv, PCIVME_DEVICE_ID, PCIVME_VENDOR_ID, PCIVME_SUBSYS_ID, PCIVME_SUBVEN_ID)))
490
    {
491
        deleteMyLists();
492
        return result;
493
    }
494
 
495
    /* fix the PLX bug in all PCIADAs */
496
    for (ptr = drv.pciList.next; ptr != &drv.pciList; ptr = ptr->next)
497
    {
498
        ch = list_entry(ptr, PCIConfig, list);
499
        PLX9050BugFix(ch);
500
    }
501
 
502
    /* create work_devices and translate the access addresses */
503
    for (ptr = drv.pciList.next; ptr != &drv.pciList; ptr = ptr->next)
504
    {
505
        ch = list_entry(ptr, PCIConfig, list);
506
 
507
        pd = (DEVICE_OBJ *)kmalloc(sizeof(DEVICE_OBJ), GFP_ATOMIC);
508
        soft_init(pd);
509
        pd->pPch = ch;
510
        pd->wIndex = drv.count;
511
 
512
        if (!request_io_memory(ch))
513
        {
514
            pd->wInitStep = 1;
515
 
516
            if (translate_addresses(pd, ch))
517
            {
518
                printk(KERN_ERR "%s : translation of addresses failed!\n", DEVICE_NAME);
519
                kfree_s(pd, sizeof(*pd));       // FREE(pd);
520
            }
521
            else
522
            {
523
                // successful translate_addresses
524
                pd->wInitStep = 2;
525
 
526
                // create some 'fast access' addresses
527
                pd->pAdrMod = pd->pCtl + VICBASE + AMSR;
528
                pd->pAdrReg = pd->pCtl + ADRHL;
529
                pd->pCSR    = pd->pCtl + CSR;
530
 
531
                pd->pPCIADACntrl  = pd->pLCR + PLX9050_CNTRL;
532
                pd->pPCIADAIntCSR = pd->pLCR + PLX9050_INTCSR;
533
 
534
                if (request_irq(pd->pPch->pciDev->irq, pcivme_irqhandler, IRQF_DISABLED| IRQF_SHARED, DEVICE_NAME, pd))
535
                {
536
                    printk(KERN_ERR "%s : can't get irq @ %d\n", DEVICE_NAME, pd->pPch->pciDev->irq);
537
                    kfree_s(pd, sizeof(*pd));       // FREE(pd);
538
                }
539
                else
540
                {
541
                    // successful request_irq
542
                    pd->wInitStep = 3;
543
                    pd->wIrq = pd->pPch->pciDev->irq;
544
 
545
                    list_add_tail(&pd->list, &drv.devList);  /* add this device to list of working devices*/
546
                    drv.count++;
547
 
548
                    pd->bConnected =  get_module_info(pd);
549
                    if (pd->bConnected && test_connection(pd))
550
                    {
551
                        printk(KERN_ERR "%s : connection test @ driver install failed!\n", DEVICE_NAME);
552
                        pd->bConnected = 0;
553
                    }
554
                }
555
            }
556
        }
557
        else
558
            printk(KERN_ERR "%s : requested io-memory still claimed!\n", DEVICE_NAME);
559
    }
560
 
561
    drv.nMajor = MAJOR_NO;
562
    result = register_chrdev(drv.nMajor, DEVICE_NAME, &pcivme_fops);
563
    if (result < 0)
564
    {
565
        printk(KERN_ERR "%s: Can't install driver (%d)\n", DEVICE_NAME, result);
566
 
567
        /* untranslate translated addresses */
568
        for (ptr = drv.devList.next; ptr != &drv.devList; ptr = ptr->next)
569
        {
570
            pd = list_entry(ptr, DEVICE_OBJ, list);
571
            ch = pd->pPch;
572
            un_translate_addresses(pd, ch);
573
        }
574
 
575
        /* delete my lists */
576
        deleteMyLists();
577
 
578
        return result;
579
    }
580
    else
581
    {
582
        if (drv.nMajor == 0)
583
            drv.nMajor = result;
584
 
585
        printk(KERN_DEBUG "%s : major #%d assigned.\n", DEVICE_NAME, drv.nMajor);
586
    }
587
 
588
    /* register the proc device */
589
 
43 f9daq 590
    // create_proc_read_entry is depricated since kernel 3.10
44 f9daq 591
    //return create_proc_read_entry(DEVICE_NAME, 0, NULL, pcivme_read_proc, NULL) ? 0 : -ENODEV;
592
    proc = proc_create_data(DEVICE_NAME, 0, NULL, &pcivme_read_proc_fops, NULL);
593
    return (proc) ? 0 : -ENODEV;
594
 
9 f9daq 595
}
596
 
44 f9daq 597
void pcivme_module_exit(void)
9 f9daq 598
{
599
    PCIConfig        *ch;
600
    DEVICE_OBJ       *pd;
601
    struct list_head *ptr;
602
 
603
    PRINTK(KERN_DEBUG "%s : cleanup_module.\n", DEVICE_NAME);
604
 
605
    unregister_chrdev(drv.nMajor, DEVICE_NAME);
606
 
607
    /* unregister the proc device */
608
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
609
    proc_unregister(&proc_root, pcimod_proc_entry.low_ino);
610
#else
611
    remove_proc_entry(DEVICE_NAME, NULL);
612
#endif
613
 
614
    /* redo all */
615
    for (ptr = drv.devList.next; ptr != &drv.devList; ptr = ptr->next)
616
    {
617
        pd = list_entry(ptr, DEVICE_OBJ, list);
618
        ch = pd->pPch;
619
        switch (pd->wInitStep)
620
        {
621
            case 3:  writew(readw((const volatile void *)(pd->pLCR + PLX9050_INTCSR)) & ~0x40, (volatile void *) (pd->pLCR + PLX9050_INTCSR));  // disable global interrupts
622
                     free_irq(pd->wIrq, pd);  
623
            case 2:  un_translate_addresses(pd, ch);
624
            case 1:  release_io_memory(ch);
625
            default: pd->wInitStep = 0;
626
        }
627
 
628
        drv.count--;
629
    }
630
 
631
    deleteMyLists();
632
 
633
    return;
634
}
635
 
44 f9daq 636
module_init(pcivme_module_init);
637
module_exit(pcivme_module_exit);
638