/alps/ipecamera

To get this branch, use:
bzr branch http://darksoft.org/webbzr/alps/ipecamera

« back to all changes in this revision

Viewing changes to driver/base.c

  • Committer: Suren A. Chilingaryan
  • Date: 2015-04-27 00:28:57 UTC
  • Revision ID: csa@suren.me-20150427002857-82fk6r3e8rfgy4wr
First stand-alone ipecamera implementation

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/**
2
 
 *
3
 
 * @file base.c
4
 
 * @author Guillermo Marcus
5
 
 * @date 2009-04-05
6
 
 * @brief Contains the main code which connects all the different parts and does
7
 
 * basic driver tasks like initialization.
8
 
 *
9
 
 * This is a full rewrite of the pciDriver.
10
 
 * New default is to support kernel 2.6, using kernel 2.6 APIs.
11
 
 *
12
 
 */
13
 
 
14
 
/*
15
 
 * Change History:
16
 
 *
17
 
 * $Log: not supported by cvs2svn $
18
 
 * Revision 1.13  2008-05-30 11:38:15  marcus
19
 
 * Added patches for kernel 2.6.24
20
 
 *
21
 
 * Revision 1.12  2008-01-24 14:21:36  marcus
22
 
 * Added a CLEAR_INTERRUPT_QUEUE ioctl.
23
 
 * Added a sysfs attribute to show the outstanding IRQ queues.
24
 
 *
25
 
 * Revision 1.11  2008-01-24 12:53:11  marcus
26
 
 * Corrected wait_event condition in waiti_ioctl. Improved the loop too.
27
 
 *
28
 
 * Revision 1.10  2008-01-14 10:39:39  marcus
29
 
 * Set some messages as debug instead of normal.
30
 
 *
31
 
 * Revision 1.9  2008-01-11 10:18:28  marcus
32
 
 * Modified interrupt mechanism. Added atomic functions and queues, to address race conditions. Removed unused interrupt code.
33
 
 *
34
 
 * Revision 1.8  2007-07-17 13:15:55  marcus
35
 
 * Removed Tasklets.
36
 
 * Using newest map for the ABB interrupts.
37
 
 *
38
 
 * Revision 1.7  2007-07-06 15:56:04  marcus
39
 
 * Change default status for OLD_REGISTERS to not defined.
40
 
 *
41
 
 * Revision 1.6  2007-07-05 15:29:59  marcus
42
 
 * Corrected issue with the bar mapping for interrupt handling.
43
 
 * Added support up to kernel 2.6.20
44
 
 *
45
 
 * Revision 1.5  2007-05-29 07:50:18  marcus
46
 
 * Split code into 2 files. May get merged in the future again....
47
 
 *
48
 
 * Revision 1.4  2007/03/01 17:47:34  marcus
49
 
 * Fixed bug when the kernel memory was less than one page, it was not locked properly, recalling an old mapping issue in this case.
50
 
 *
51
 
 * Revision 1.3  2007/03/01 17:01:22  marcus
52
 
 * comment fix (again).
53
 
 *
54
 
 * Revision 1.2  2007/03/01 17:00:25  marcus
55
 
 * Changed some comment in the log.
56
 
 *
57
 
 * Revision 1.1  2007/03/01 16:57:43  marcus
58
 
 * Divided driver file to ease the interrupt hooks for the user of the driver.
59
 
 * Modified Makefile accordingly.
60
 
 *
61
 
 * From pciDriver.c:
62
 
 * Revision 1.11  2006/12/11 16:15:43  marcus
63
 
 * Fixed kernel buffer mmapping, and driver crash when application crashes.
64
 
 * Buffer memory is now marked reserved during allocation, and mmaped with
65
 
 * remap_xx_range.
66
 
 *
67
 
 * Revision 1.10  2006/11/21 09:50:49  marcus
68
 
 * Added PROGRAPE4 vendor/device IDs.
69
 
 *
70
 
 * Revision 1.9  2006/11/17 18:47:36  marcus
71
 
 * Removed MERGE_SGENTRIES flag, now it is selected at runtime with 'type'.
72
 
 * Removed noncached in non-prefetchable areas, to allow the use of MTRRs.
73
 
 *
74
 
 * Revision 1.8  2006/11/17 16:41:21  marcus
75
 
 * Added slot number to the PCI info IOctl.
76
 
 *
77
 
 * Revision 1.7  2006/11/13 12:30:34  marcus
78
 
 * Added a IOctl call, to confiure the interrupt response. (testing pending).
79
 
 * Basic interrupts are now supported, using a Tasklet and Completions.
80
 
 *
81
 
 * Revision 1.6  2006/11/08 21:30:02  marcus
82
 
 * Added changes after compile tests in kernel 2.6.16
83
 
 *
84
 
 * Revision 1.5  2006/10/31 07:57:38  marcus
85
 
 * Improved the pfn calculation in nopage(), to deal with some possible border
86
 
 * conditions. It was really no issue, because they are normally page-aligned
87
 
 * anyway, but to be on the safe side.
88
 
 *
89
 
 * Revision 1.4  2006/10/30 19:37:40  marcus
90
 
 * Solved bug on kernel memory not mapping properly.
91
 
 *
92
 
 * Revision 1.3  2006/10/18 11:19:20  marcus
93
 
 * Added kernel 2.6.8 support based on comments from Joern Adamczewski (GSI).
94
 
 *
95
 
 * Revision 1.2  2006/10/18 11:04:15  marcus
96
 
 * Bus Master is only activated when we detect a specific board.
97
 
 *
98
 
 * Revision 1.1  2006/10/10 14:46:51  marcus
99
 
 * Initial commit of the new pciDriver for kernel 2.6
100
 
 *
101
 
 * Revision 1.9  2006/10/05 11:30:46  marcus
102
 
 * Prerelease. Added bus and devfn to pciInfo for compatibility.
103
 
 *
104
 
 * Revision 1.8  2006/09/25 16:51:07  marcus
105
 
 * Added PCI config IOctls, and implemented basic mmap functions.
106
 
 *
107
 
 * Revision 1.7  2006/09/20 11:12:41  marcus
108
 
 * Added Merge SG entries
109
 
 *
110
 
 * Revision 1.6  2006/09/19 17:22:18  marcus
111
 
 * backup commit.
112
 
 *
113
 
 * Revision 1.5  2006/09/18 17:13:11  marcus
114
 
 * backup commit.
115
 
 *
116
 
 * Revision 1.4  2006/09/15 15:44:41  marcus
117
 
 * backup commit.
118
 
 *
119
 
 * Revision 1.3  2006/08/15 11:40:02  marcus
120
 
 * backup commit.
121
 
 *
122
 
 * Revision 1.2  2006/08/12 18:28:42  marcus
123
 
 * Sync with the laptop
124
 
 *
125
 
 * Revision 1.1  2006/08/11 15:30:46  marcus
126
 
 * Sync with the laptop
127
 
 *
128
 
 */
129
 
 
130
 
#include <linux/version.h>
131
 
 
132
 
/* Check macros and kernel version first */
133
 
#ifndef KERNEL_VERSION
134
 
#error "No KERNEL_VERSION macro! Stopping."
135
 
#endif
136
 
 
137
 
#ifndef LINUX_VERSION_CODE
138
 
#error "No LINUX_VERSION_CODE macro! Stopping."
139
 
#endif
140
 
 
141
 
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,8)
142
 
#error "This driver has been tested only for Kernel 2.6.8 or above."
143
 
#endif
144
 
 
145
 
/* Required includes */
146
 
#include <linux/string.h>
147
 
#include <linux/slab.h>
148
 
#include <linux/types.h>
149
 
#include <linux/init.h>
150
 
#include <linux/module.h>
151
 
#include <linux/pci.h>
152
 
#include <linux/kernel.h>
153
 
#include <linux/errno.h>
154
 
#include <linux/fs.h>
155
 
#include <linux/cdev.h>
156
 
#include <linux/sysfs.h>
157
 
#include <asm/atomic.h>
158
 
#include <linux/pagemap.h>
159
 
#include <linux/spinlock.h>
160
 
#include <linux/list.h>
161
 
#include <asm/scatterlist.h>
162
 
#include <linux/vmalloc.h>
163
 
#include <linux/stat.h>
164
 
#include <linux/interrupt.h>
165
 
#include <linux/wait.h>
166
 
 
167
 
/* Configuration for the driver (what should be compiled in, module name, etc...) */
168
 
#include "config.h"
169
 
 
170
 
/* Compatibility functions/definitions (provides functions which are not available on older kernels) */
171
 
#include "compat.h"
172
 
 
173
 
/* External interface for the driver */
174
 
#include "pciDriver.h"
175
 
 
176
 
/* Internal definitions for all parts (prototypes, data, macros) */
177
 
#include "common.h"
178
 
 
179
 
/* Internal definitions for the base part */
180
 
#include "base.h"
181
 
 
182
 
/* Internal definitions of the IRQ handling part */
183
 
#include "int.h"
184
 
 
185
 
/* Internal definitions for kernel memory */
186
 
#include "kmem.h"
187
 
 
188
 
/* Internal definitions for user space memory */
189
 
#include "umem.h"
190
 
 
191
 
#include "ioctl.h"
192
 
 
193
 
/*************************************************************************/
194
 
/* Module device table associated with this driver */
195
 
MODULE_DEVICE_TABLE(pci, pcidriver_ids);
196
 
 
197
 
/* Module init and exit points */
198
 
module_init(pcidriver_init);
199
 
module_exit(pcidriver_exit);
200
 
 
201
 
/* Module info */
202
 
MODULE_AUTHOR("Guillermo Marcus");
203
 
MODULE_DESCRIPTION("Simple PCI Driver");
204
 
MODULE_LICENSE("GPL v2");
205
 
 
206
 
/* Module class */
207
 
static struct class_compat *pcidriver_class;
208
 
 
209
 
/**
210
 
 *
211
 
 * Called when loading the driver
212
 
 *
213
 
 */
214
 
static int __init pcidriver_init(void)
215
 
{
216
 
        int err;
217
 
 
218
 
        /* Initialize the device count */
219
 
        atomic_set(&pcidriver_deviceCount, 0);
220
 
 
221
 
        /* Allocate character device region dynamically */
222
 
        if ((err = alloc_chrdev_region(&pcidriver_devt, MINORNR, MAXDEVICES, NODENAME)) != 0) {
223
 
                mod_info("Couldn't allocate chrdev region. Module not loaded.\n");
224
 
                goto init_alloc_fail;
225
 
        }
226
 
        mod_info("Major %d allocated to nodename '%s'\n", MAJOR(pcidriver_devt), NODENAME);
227
 
 
228
 
        /* Register driver class */
229
 
        pcidriver_class = class_create(THIS_MODULE, NODENAME);
230
 
 
231
 
        if (IS_ERR(pcidriver_class)) {
232
 
                mod_info("No sysfs support. Module not loaded.\n");
233
 
                goto init_class_fail;
234
 
        }
235
 
 
236
 
        /* Register PCI driver. This function returns the number of devices on some
237
 
         * systems, therefore check for errors as < 0. */
238
 
        if ((err = pci_register_driver(&pcidriver_driver)) < 0) {
239
 
                mod_info("Couldn't register PCI driver. Module not loaded.\n");
240
 
                goto init_pcireg_fail;
241
 
        }
242
 
 
243
 
        mod_info("Module loaded\n");
244
 
 
245
 
        return 0;
246
 
 
247
 
init_pcireg_fail:
248
 
        class_destroy(pcidriver_class);
249
 
init_class_fail:
250
 
        unregister_chrdev_region(pcidriver_devt, MAXDEVICES);
251
 
init_alloc_fail:
252
 
        return err;
253
 
}
254
 
 
255
 
/**
256
 
 *
257
 
 * Called when unloading the driver
258
 
 *
259
 
 */
260
 
static void pcidriver_exit(void)
261
 
{
262
 
        pci_unregister_driver(&pcidriver_driver);
263
 
        unregister_chrdev_region(pcidriver_devt, MAXDEVICES);
264
 
 
265
 
        if (pcidriver_class != NULL)
266
 
                class_destroy(pcidriver_class);
267
 
 
268
 
        mod_info("Module unloaded\n");
269
 
}
270
 
 
271
 
/*************************************************************************/
272
 
/* Driver functions */
273
 
 
274
 
/**
275
 
 *
276
 
 * This struct defines the PCI entry points.
277
 
 * Will be registered at module init.
278
 
 *
279
 
 */
280
 
static struct pci_driver pcidriver_driver = {
281
 
        .name = MODNAME,
282
 
        .id_table = pcidriver_ids,
283
 
        .probe = pcidriver_probe,
284
 
        .remove = pcidriver_remove,
285
 
};
286
 
 
287
 
/**
288
 
 *
289
 
 * This function is called when installing the driver for a device
290
 
 * @param pdev Pointer to the PCI device
291
 
 *
292
 
 */
293
 
static int __devinit pcidriver_probe(struct pci_dev *pdev, const struct pci_device_id *id)
294
 
{
295
 
        int err;
296
 
        int devno;
297
 
        pcidriver_privdata_t *privdata;
298
 
        int devid;
299
 
 
300
 
        /* At the moment there is no difference between these boards here, other than
301
 
         * printing a different message in the log.
302
 
         *
303
 
         * However, there is some difference in the interrupt handling functions.
304
 
         */
305
 
        if (id->vendor == PCIE_XILINX_VENDOR_ID) {
306
 
            if (id->device == PCIE_ML605_DEVICE_ID) {
307
 
                mod_info("Found ML605 board at %s\n", dev_name(&pdev->dev));
308
 
            } else if (id->device == PCIE_IPECAMERA_DEVICE_ID) {
309
 
                mod_info("Found IPE Camera at %s\n", dev_name(&pdev->dev));
310
 
            } else if (id->device == PCIE_KAPTURE_DEVICE_ID) {
311
 
                mod_info("Found KAPTURE board at %s\n", dev_name(&pdev->dev));
312
 
            } else {
313
 
                mod_info("Found unknown Xilinx device (%x) at %s\n", id->device, dev_name(&pdev->dev));
314
 
            }
315
 
        } else {
316
 
                /* It is something else */
317
 
                mod_info( "Found unknown board (%x:%x) at %s\n", id->vendor, id->device, dev_name(&pdev->dev));
318
 
        }
319
 
 
320
 
        /* Enable the device */
321
 
        if ((err = pci_enable_device(pdev)) != 0) {
322
 
                mod_info("Couldn't enable device\n");
323
 
                goto probe_pcien_fail;
324
 
        }
325
 
        
326
 
        /* Bus master & dma */
327
 
        if ((id->vendor == PCIE_XILINX_VENDOR_ID)&&(id->device == PCIE_IPECAMERA_DEVICE_ID)) {
328
 
            pci_set_master(pdev);
329
 
            
330
 
            err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
331
 
            if (err < 0) {
332
 
                printk(KERN_ERR "pci_set_dma_mask failed\n");
333
 
                goto probe_dma_fail;
334
 
            }
335
 
        }
336
 
 
337
 
        /* Set Memory-Write-Invalidate support */
338
 
        if ((err = pci_set_mwi(pdev)) != 0)
339
 
                mod_info("MWI not supported. Continue without enabling MWI.\n");
340
 
 
341
 
        /* Get / Increment the device id */
342
 
        devid = atomic_inc_return(&pcidriver_deviceCount) - 1;
343
 
        if (devid >= MAXDEVICES) {
344
 
                mod_info("Maximum number of devices reached! Increase MAXDEVICES.\n");
345
 
                err = -ENOMSG;
346
 
                goto probe_maxdevices_fail;
347
 
        }
348
 
 
349
 
        /* Allocate and initialize the private data for this device */
350
 
        if ((privdata = kcalloc(1, sizeof(*privdata), GFP_KERNEL)) == NULL) {
351
 
                err = -ENOMEM;
352
 
                goto probe_nomem;
353
 
        }
354
 
 
355
 
        INIT_LIST_HEAD(&(privdata->kmem_list));
356
 
        spin_lock_init(&(privdata->kmemlist_lock));
357
 
        atomic_set(&privdata->kmem_count, 0);
358
 
        
359
 
        INIT_LIST_HEAD(&(privdata->umem_list));
360
 
        spin_lock_init(&(privdata->umemlist_lock));
361
 
        atomic_set(&privdata->umem_count, 0);
362
 
 
363
 
        pci_set_drvdata( pdev, privdata );
364
 
        privdata->pdev = pdev;
365
 
 
366
 
        /* Device add to sysfs */
367
 
        devno = MKDEV(MAJOR(pcidriver_devt), MINOR(pcidriver_devt) + devid);
368
 
        privdata->devno = devno;
369
 
        if (pcidriver_class != NULL) {
370
 
                /* FIXME: some error checking missing here */
371
 
                privdata->class_dev = class_device_create(pcidriver_class, NULL, devno, &(pdev->dev), NODENAMEFMT, MINOR(pcidriver_devt) + devid, privdata);
372
 
                class_set_devdata( privdata->class_dev, privdata );
373
 
                mod_info("Device /dev/%s%d added\n",NODENAME,MINOR(pcidriver_devt) + devid);
374
 
        }
375
 
 
376
 
        /* Setup mmaped BARs into kernel space */
377
 
        if ((err = pcidriver_probe_irq(privdata)) != 0)
378
 
                goto probe_irq_probe_fail;
379
 
 
380
 
        /* Populate sysfs attributes for the class device */
381
 
        /* TODO: correct errorhandling. ewww. must remove the files in reversed order :-( */
382
 
        #define sysfs_attr(name) do { \
383
 
                        if (class_device_create_file(sysfs_attr_def_pointer, &sysfs_attr_def_name(name)) != 0) \
384
 
                                goto probe_device_create_fail; \
385
 
                        } while (0)
386
 
        #ifdef ENABLE_IRQ
387
 
        sysfs_attr(irq_count);
388
 
        sysfs_attr(irq_queues);
389
 
        #endif
390
 
 
391
 
        sysfs_attr(mmap_mode);
392
 
        sysfs_attr(mmap_area);
393
 
        sysfs_attr(kmem_count);
394
 
        sysfs_attr(kmem_alloc);
395
 
        sysfs_attr(kmem_free);
396
 
        sysfs_attr(kbuffers);
397
 
        sysfs_attr(umappings);
398
 
        sysfs_attr(umem_unmap);
399
 
        #undef sysfs_attr
400
 
 
401
 
        /* Register character device */
402
 
        cdev_init( &(privdata->cdev), &pcidriver_fops );
403
 
        privdata->cdev.owner = THIS_MODULE;
404
 
        privdata->cdev.ops = &pcidriver_fops;
405
 
        err = cdev_add( &privdata->cdev, devno, 1 );
406
 
        if (err) {
407
 
                mod_info( "Couldn't add character device.\n" );
408
 
                goto probe_cdevadd_fail;
409
 
        }
410
 
 
411
 
        return 0;
412
 
 
413
 
probe_device_create_fail:
414
 
probe_cdevadd_fail:
415
 
probe_irq_probe_fail:
416
 
        pcidriver_irq_unmap_bars(privdata);
417
 
        kfree(privdata);
418
 
probe_nomem:
419
 
        atomic_dec(&pcidriver_deviceCount);
420
 
probe_maxdevices_fail:
421
 
probe_dma_fail:
422
 
        pci_disable_device(pdev);
423
 
probe_pcien_fail:
424
 
        return err;
425
 
}
426
 
 
427
 
/**
428
 
 *
429
 
 * This function is called when disconnecting a device
430
 
 *
431
 
 */
432
 
static void __devexit pcidriver_remove(struct pci_dev *pdev)
433
 
{
434
 
        pcidriver_privdata_t *privdata;
435
 
 
436
 
        /* Get private data from the device */
437
 
        privdata = pci_get_drvdata(pdev);
438
 
 
439
 
        /* Removing sysfs attributes from class device */
440
 
        #define sysfs_attr(name) do { \
441
 
                        class_device_remove_file(sysfs_attr_def_pointer, &sysfs_attr_def_name(name)); \
442
 
                        } while (0)
443
 
        #ifdef ENABLE_IRQ
444
 
        sysfs_attr(irq_count);
445
 
        sysfs_attr(irq_queues);
446
 
        #endif
447
 
 
448
 
        sysfs_attr(mmap_mode);
449
 
        sysfs_attr(mmap_area);
450
 
        sysfs_attr(kmem_count);
451
 
        sysfs_attr(kmem_alloc);
452
 
        sysfs_attr(kmem_free);
453
 
        sysfs_attr(kbuffers);
454
 
        sysfs_attr(umappings);
455
 
        sysfs_attr(umem_unmap);
456
 
        #undef sysfs_attr
457
 
 
458
 
        /* Free all allocated kmem buffers before leaving */
459
 
        pcidriver_kmem_free_all( privdata );
460
 
 
461
 
#ifdef ENABLE_IRQ
462
 
        pcidriver_remove_irq(privdata);
463
 
#endif
464
 
 
465
 
        /* Removing Character device */
466
 
        cdev_del(&(privdata->cdev));
467
 
 
468
 
        /* Removing the device from sysfs */
469
 
        class_device_destroy(pcidriver_class, privdata->devno);
470
 
 
471
 
        /* Releasing privdata */
472
 
        kfree(privdata);
473
 
 
474
 
        /* Disabling PCI device */
475
 
        pci_disable_device(pdev);
476
 
 
477
 
        mod_info("Device at %s removed\n", dev_name(&pdev->dev));
478
 
}
479
 
 
480
 
/*************************************************************************/
481
 
/* File operations */
482
 
/*************************************************************************/
483
 
 
484
 
/**
485
 
 * This struct defines the file operation entry points.
486
 
 *
487
 
 * @see pcidriver_ioctl
488
 
 * @see pcidriver_mmap
489
 
 * @see pcidriver_open
490
 
 * @see pcidriver_release
491
 
 *
492
 
 */
493
 
static struct file_operations pcidriver_fops = {
494
 
        .owner = THIS_MODULE,
495
 
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11)
496
 
        .ioctl = pcidriver_ioctl,
497
 
#else
498
 
        .unlocked_ioctl = pcidriver_ioctl,
499
 
#endif 
500
 
        .mmap = pcidriver_mmap,
501
 
        .open = pcidriver_open,
502
 
        .release = pcidriver_release,
503
 
};
504
 
 
505
 
void pcidriver_module_get(pcidriver_privdata_t *privdata) {
506
 
    atomic_inc(&(privdata->refs));
507
 
//    mod_info("Ref: %i\n", atomic_read(&(privdata->refs)));
508
 
}
509
 
 
510
 
void pcidriver_module_put(pcidriver_privdata_t *privdata) {
511
 
    if (atomic_add_negative(-1, &(privdata->refs))) {
512
 
        atomic_inc(&(privdata->refs));
513
 
        mod_info("Reference counting error...");
514
 
    } else {
515
 
//      mod_info("Unref: %i\n", atomic_read(&(privdata->refs)));
516
 
    }
517
 
}
518
 
 
519
 
/**
520
 
 *
521
 
 * Called when an application open()s a /dev/fpga*, attaches the private data
522
 
 * with the file pointer.
523
 
 *
524
 
 */
525
 
int pcidriver_open(struct inode *inode, struct file *filp)
526
 
{
527
 
        pcidriver_privdata_t *privdata;
528
 
 
529
 
        /* Set the private data area for the file */
530
 
        privdata = container_of( inode->i_cdev, pcidriver_privdata_t, cdev);
531
 
        filp->private_data = privdata;
532
 
 
533
 
        pcidriver_module_get(privdata);
534
 
 
535
 
        return 0;
536
 
}
537
 
 
538
 
/**
539
 
 *
540
 
 * Called when the application close()s the file descriptor. Does nothing at
541
 
 * the moment.
542
 
 *
543
 
 */
544
 
int pcidriver_release(struct inode *inode, struct file *filp)
545
 
{
546
 
        pcidriver_privdata_t *privdata;
547
 
 
548
 
        /* Get the private data area */
549
 
        privdata = filp->private_data;
550
 
 
551
 
        pcidriver_module_put(privdata);
552
 
 
553
 
        return 0;
554
 
}
555
 
 
556
 
/**
557
 
 *
558
 
 * This function is the entry point for mmap() and calls either pcidriver_mmap_pci
559
 
 * or pcidriver_mmap_kmem
560
 
 *
561
 
 * @see pcidriver_mmap_pci
562
 
 * @see pcidriver_mmap_kmem
563
 
 *
564
 
 */
565
 
int pcidriver_mmap(struct file *filp, struct vm_area_struct *vma)
566
 
{
567
 
        pcidriver_privdata_t *privdata;
568
 
        int ret = 0, bar;
569
 
 
570
 
        mod_info_dbg("Entering mmap\n");
571
 
 
572
 
        /* Get the private data area */
573
 
        privdata = filp->private_data;
574
 
 
575
 
        /* Check the current mmap mode */
576
 
        switch (privdata->mmap_mode) {
577
 
                case PCIDRIVER_MMAP_PCI:
578
 
                        /* Mmap a PCI region */
579
 
                        switch (privdata->mmap_area) {
580
 
                                case PCIDRIVER_BAR0:    bar = 0; break;
581
 
                                case PCIDRIVER_BAR1:    bar = 1; break;
582
 
                                case PCIDRIVER_BAR2:    bar = 2; break;
583
 
                                case PCIDRIVER_BAR3:    bar = 3; break;
584
 
                                case PCIDRIVER_BAR4:    bar = 4; break;
585
 
                                case PCIDRIVER_BAR5:    bar = 5; break;
586
 
                                default:
587
 
                                        mod_info("Attempted to mmap a PCI area with the wrong mmap_area value: %d\n",privdata->mmap_area);
588
 
                                        return -EINVAL;                 /* invalid parameter */
589
 
                                        break;
590
 
                        }
591
 
                        ret = pcidriver_mmap_pci(privdata, vma, bar);
592
 
                        break;
593
 
                case PCIDRIVER_MMAP_KMEM:
594
 
                        /* mmap a Kernel buffer */
595
 
                        ret = pcidriver_mmap_kmem(privdata, vma);
596
 
                        break;
597
 
                default:
598
 
                        mod_info( "Invalid mmap_mode value (%d)\n",privdata->mmap_mode );
599
 
                        return -EINVAL;                 /* Invalid parameter (mode) */
600
 
        }
601
 
 
602
 
        return ret;
603
 
}
604
 
 
605
 
/*************************************************************************/
606
 
/* Internal driver functions */
607
 
int pcidriver_mmap_pci(pcidriver_privdata_t *privdata, struct vm_area_struct *vmap, int bar)
608
 
{
609
 
        int ret = 0;
610
 
        unsigned long bar_addr;
611
 
        unsigned long bar_length, vma_size;
612
 
        unsigned long bar_flags;
613
 
 
614
 
        mod_info_dbg("Entering mmap_pci\n");
615
 
 
616
 
        /* Get info of the BAR to be mapped */
617
 
        bar_addr = pci_resource_start(privdata->pdev, bar);
618
 
        bar_length = pci_resource_len(privdata->pdev, bar);
619
 
        bar_flags = pci_resource_flags(privdata->pdev, bar);
620
 
 
621
 
        /* Check sizes */
622
 
        vma_size = (vmap->vm_end - vmap->vm_start);
623
 
 
624
 
        if ((vma_size != bar_length) &&
625
 
           ((bar_length < PAGE_SIZE) && (vma_size != PAGE_SIZE))) {
626
 
                mod_info( "mmap size is not correct! bar: %lu - vma: %lu\n", bar_length, vma_size );
627
 
                return -EINVAL;
628
 
        }
629
 
 
630
 
        if (bar_flags & IORESOURCE_IO) {
631
 
                /* Unlikely case, we will mmap a IO region */
632
 
 
633
 
                /* IO regions are never cacheable */
634
 
#ifdef pgprot_noncached
635
 
                vmap->vm_page_prot = pgprot_noncached(vmap->vm_page_prot);
636
 
#endif
637
 
 
638
 
                /* Map the BAR */
639
 
                ret = io_remap_pfn_range_compat(
640
 
                                        vmap,
641
 
                                        vmap->vm_start,
642
 
                                        bar_addr,
643
 
                                        bar_length,
644
 
                                        vmap->vm_page_prot);
645
 
        } else {
646
 
                /* Normal case, mmap a memory region */
647
 
 
648
 
                /* Ensure this VMA is non-cached, if it is not flaged as prefetchable.
649
 
                 * If it is prefetchable, caching is allowed and will give better performance.
650
 
                 * This should be set properly by the BIOS, but we want to be sure. */
651
 
                /* adapted from drivers/char/mem.c, mmap function. */
652
 
#ifdef pgprot_noncached
653
 
/* Setting noncached disables MTRR registers, and we want to use them.
654
 
 * So we take this code out. This can lead to caching problems if and only if
655
 
 * the System BIOS set something wrong. Check LDDv3, page 425.
656
 
 */
657
 
//              if (!(bar_flags & IORESOURCE_PREFETCH))
658
 
//                      vmap->vm_page_prot = pgprot_noncached(vmap->vm_page_prot);
659
 
#endif
660
 
 
661
 
                /* Map the BAR */
662
 
                ret = remap_pfn_range_compat(
663
 
                                        vmap,
664
 
                                        vmap->vm_start,
665
 
                                        bar_addr,
666
 
                                        bar_length,
667
 
                                        vmap->vm_page_prot);
668
 
        }
669
 
 
670
 
        if (ret) {
671
 
                mod_info("remap_pfn_range failed\n");
672
 
                return -EAGAIN;
673
 
        }
674
 
 
675
 
        return 0;       /* success */
676
 
}