/alps/pcitool

To get this branch, use:
bzr branch http://suren.me/webbzr/alps/pcitool
1 by Suren A. Chilingaryan
Initial import
1
#include <linux/string.h>
2
#include <linux/slab.h>
3
#include <linux/types.h>
4
#include <linux/init.h>
5
#include <linux/module.h>
6
#include <linux/pci.h>
7
#include <linux/kernel.h>
8
#include <linux/errno.h>
9
#include <linux/fs.h>
10
#include <linux/cdev.h>
11
#include <linux/sysfs.h>
12
#include <asm/atomic.h>
13
#include <linux/pagemap.h>
14
#include <linux/spinlock.h>
15
#include <linux/list.h>
395 by Suren A. Chilingaryan
Use linux/scatterlist.h instead of asm/scatterlist.h
16
#include <linux/scatterlist.h>
1 by Suren A. Chilingaryan
Initial import
17
#include <linux/vmalloc.h>
18
#include <linux/stat.h>
19
#include <linux/interrupt.h>
20
#include <linux/wait.h>
21
400 by Suren A. Chilingaryan
Further fixes for out-of-source compilation
22
#include "pcilib/version.h"
365 by Suren A. Chilingaryan
Restructure driver headers
23
#include "build.h"
1 by Suren A. Chilingaryan
Initial import
24
#include "base.h"
365 by Suren A. Chilingaryan
Restructure driver headers
25
26
1 by Suren A. Chilingaryan
Initial import
27
28
/* Module info */
29
MODULE_AUTHOR("Guillermo Marcus");
30
MODULE_DESCRIPTION("Simple PCI Driver");
31
MODULE_LICENSE("GPL v2");
32
365 by Suren A. Chilingaryan
Restructure driver headers
33
/*
34
 * This is the table of PCI devices handled by this driver by default
35
 * If you want to add devices dynamically to this list, do:
36
 *
37
 *   echo "vendor device" > /sys/bus/pci/drivers/pciDriver/new_id
38
 * where vendor and device are in hex, without leading '0x'.
39
 */
40
41
static const __devinitdata struct pci_device_id pcidriver_ids[] = {
42
    { PCI_DEVICE( PCIE_XILINX_VENDOR_ID, PCIE_ML605_DEVICE_ID ) },          // PCI-E Xilinx ML605
43
    { PCI_DEVICE( PCIE_XILINX_VENDOR_ID, PCIE_IPECAMERA_DEVICE_ID ) },      // PCI-E IPE Camera
44
    { PCI_DEVICE( PCIE_XILINX_VENDOR_ID, PCIE_KAPTURE_DEVICE_ID ) },        // PCI-E KAPTURE board for HEB
45
    {0,0,0,0},
46
};
47
48
MODULE_DEVICE_TABLE(pci, pcidriver_ids);
49
1 by Suren A. Chilingaryan
Initial import
50
/* Module class */
365 by Suren A. Chilingaryan
Restructure driver headers
51
static struct class *pcidriver_class;
1 by Suren A. Chilingaryan
Initial import
52
358 by Suren A. Chilingaryan
Support emulation mode without real hardware
53
#ifdef PCIDRIVER_DUMMY_DEVICE
363 by Suren A. Chilingaryan
Resolution of the user-space BAR addresses
54
pcidriver_privdata_t *pcidriver_dummydata = NULL;
358 by Suren A. Chilingaryan
Support emulation mode without real hardware
55
#else /* PCIDRIVER_DUMMY_DEVICE */
365 by Suren A. Chilingaryan
Restructure driver headers
56
static struct pci_driver pcidriver_driver;
57
#endif /* PCIDRIVER_DUMMY_DEVICE */
58
59
/* Hold the allocated major & minor numbers */
60
static dev_t pcidriver_devt;
61
62
/* Number of devices allocated */
63
static atomic_t pcidriver_deviceCount;
64
65
/* Private data for probed devices */
66
static pcidriver_privdata_t* pcidriver_privdata[MAXDEVICES];
67
68
69
pcidriver_privdata_t *pcidriver_get_privdata(int devid) {
70
    if (devid >= MAXDEVICES)
71
        return NULL;
72
73
    return pcidriver_privdata[devid];
74
}
75
76
void pcidriver_put_privdata(pcidriver_privdata_t *privdata) {
77
78
}
79
80
/**
1 by Suren A. Chilingaryan
Initial import
81
 * This function is called when installing the driver for a device
82
 * @param pdev Pointer to the PCI device
83
 */
84
static int __devinit pcidriver_probe(struct pci_dev *pdev, const struct pci_device_id *id)
85
{
364 by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04)
86
    int err = 0;
87
    int devno;
88
    pcidriver_privdata_t *privdata;
89
    int devid;
90
91
    /* At the moment there is no difference between these boards here, other than
92
     * printing a different message in the log.
93
     *
94
     * However, there is some difference in the interrupt handling functions.
95
     */
96
#ifdef PCIDRIVER_DUMMY_DEVICE
97
    mod_info("Emulated device\n");
98
#else /* PCIDRIVER_DUMMY_DEVICE */
99
    if (id->vendor == PCIE_XILINX_VENDOR_ID) {
100
        if (id->device == PCIE_ML605_DEVICE_ID) {
101
            mod_info("Found ML605 board at %s\n", dev_name(&pdev->dev));
102
        } else if (id->device == PCIE_IPECAMERA_DEVICE_ID) {
103
            mod_info("Found IPE Camera at %s\n", dev_name(&pdev->dev));
104
        } else if (id->device == PCIE_KAPTURE_DEVICE_ID) {
105
            mod_info("Found KAPTURE board at %s\n", dev_name(&pdev->dev));
106
        } else {
107
            mod_info("Found unknown Xilinx device (%x) at %s\n", id->device, dev_name(&pdev->dev));
108
        }
109
    } else {
110
        /* It is something else */
111
        mod_info("Found unknown board (%x:%x) at %s\n", id->vendor, id->device, dev_name(&pdev->dev));
112
    }
113
114
    /* Enable the device */
115
    if ((err = pci_enable_device(pdev)) != 0) {
116
        mod_info("Couldn't enable device\n");
117
        goto probe_pcien_fail;
118
    }
119
120
    /* Bus master & dma */
121
    pci_set_master(pdev);
122
123
    err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
124
    if (err < 0) {
125
        printk(KERN_ERR "pci_set_dma_mask failed\n");
126
        goto probe_dma_fail;
127
    }
128
129
    /* Set Memory-Write-Invalidate support */
130
    if ((err = pci_set_mwi(pdev)) != 0)
131
        mod_info("MWI not supported. Continue without enabling MWI.\n");
132
#endif /* PCIDRIVER_DUMMY_DEVICE */
133
134
    /* Get / Increment the device id */
135
    devid = atomic_inc_return(&pcidriver_deviceCount) - 1;
136
    if (devid >= MAXDEVICES) {
137
        mod_info("Maximum number of devices reached! Increase MAXDEVICES.\n");
138
        err = -ENOMSG;
139
        goto probe_maxdevices_fail;
140
    }
141
142
    /* Allocate and initialize the private data for this device */
143
    if ((privdata = kcalloc(1, sizeof(*privdata), GFP_KERNEL)) == NULL) {
144
        err = -ENOMEM;
145
        goto probe_nomem;
146
    }
147
148
    privdata->devid = devid;
149
150
    INIT_LIST_HEAD(&(privdata->kmem_list));
151
    spin_lock_init(&(privdata->kmemlist_lock));
152
    atomic_set(&privdata->kmem_count, 0);
153
154
    INIT_LIST_HEAD(&(privdata->umem_list));
155
    spin_lock_init(&(privdata->umemlist_lock));
156
    atomic_set(&privdata->umem_count, 0);
157
158
#ifdef PCIDRIVER_DUMMY_DEVICE
159
    pcidriver_dummydata = privdata;
160
#else /* PCIDRIVER_DUMMY_DEVICE */
161
    pci_set_drvdata(pdev, privdata);
162
    privdata->pdev = pdev;
163
#endif /* PCIDRIVER_DUMMY_DEVICE */
164
165
    /* Device add to sysfs */
166
    devno = MKDEV(MAJOR(pcidriver_devt), MINOR(pcidriver_devt) + devid);
167
    privdata->devno = devno;
168
169
    /* FIXME: some error checking missing here */
365 by Suren A. Chilingaryan
Restructure driver headers
170
    privdata->class_dev = device_create(pcidriver_class, NULL, devno, privdata, NODENAMEFMT, MINOR(pcidriver_devt) + devid);
171
    dev_set_drvdata(privdata->class_dev, privdata);
364 by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04)
172
    mod_info("Device /dev/%s%d added\n",NODENAME,MINOR(pcidriver_devt) + devid);
358 by Suren A. Chilingaryan
Support emulation mode without real hardware
173
174
#ifndef PCIDRIVER_DUMMY_DEVICE
364 by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04)
175
    /* Setup mmaped BARs into kernel space */
176
    if ((err = pcidriver_probe_irq(privdata)) != 0)
177
        goto probe_irq_probe_fail;
358 by Suren A. Chilingaryan
Support emulation mode without real hardware
178
#endif /* ! PCIDRIVER_DUMMY_DEVICE */
1 by Suren A. Chilingaryan
Initial import
179
364 by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04)
180
    /* TODO: correct errorhandling. ewww. must remove the files in reversed order :-( */
365 by Suren A. Chilingaryan
Restructure driver headers
181
    if (pcidriver_create_sysfs_attributes(privdata) != 0)
182
	goto probe_device_create_fail;
364 by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04)
183
184
    /* Register character device */
365 by Suren A. Chilingaryan
Restructure driver headers
185
    cdev_init(&(privdata->cdev), pcidriver_get_fops());
364 by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04)
186
    privdata->cdev.owner = THIS_MODULE;
365 by Suren A. Chilingaryan
Restructure driver headers
187
    privdata->cdev.ops = pcidriver_get_fops();
364 by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04)
188
    err = cdev_add( &privdata->cdev, devno, 1 );
189
    if (err) {
190
        mod_info( "Couldn't add character device.\n" );
191
        goto probe_cdevadd_fail;
192
    }
193
194
    pcidriver_privdata[devid] = privdata;
195
196
    return 0;
1 by Suren A. Chilingaryan
Initial import
197
198
probe_device_create_fail:
199
probe_cdevadd_fail:
358 by Suren A. Chilingaryan
Support emulation mode without real hardware
200
#ifndef PCIDRIVER_DUMMY_DEVICE
1 by Suren A. Chilingaryan
Initial import
201
probe_irq_probe_fail:
364 by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04)
202
    pcidriver_irq_unmap_bars(privdata);
358 by Suren A. Chilingaryan
Support emulation mode without real hardware
203
#endif /* ! PCIDRIVER_DUMMY_DEVICE */
364 by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04)
204
    kfree(privdata);
1 by Suren A. Chilingaryan
Initial import
205
probe_nomem:
364 by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04)
206
    atomic_dec(&pcidriver_deviceCount);
1 by Suren A. Chilingaryan
Initial import
207
probe_maxdevices_fail:
358 by Suren A. Chilingaryan
Support emulation mode without real hardware
208
#ifndef PCIDRIVER_DUMMY_DEVICE
45 by root
North West Logick DMA implementation
209
probe_dma_fail:
364 by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04)
210
    pci_disable_device(pdev);
1 by Suren A. Chilingaryan
Initial import
211
probe_pcien_fail:
358 by Suren A. Chilingaryan
Support emulation mode without real hardware
212
#endif /* ! PCIDRIVER_DUMMY_DEVICE */
364 by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04)
213
    return err;
1 by Suren A. Chilingaryan
Initial import
214
}
215
216
/**
217
 *
218
 * This function is called when disconnecting a device
219
 *
220
 */
221
static void __devexit pcidriver_remove(struct pci_dev *pdev)
222
{
364 by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04)
223
    pcidriver_privdata_t *privdata;
1 by Suren A. Chilingaryan
Initial import
224
358 by Suren A. Chilingaryan
Support emulation mode without real hardware
225
#ifdef PCIDRIVER_DUMMY_DEVICE
364 by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04)
226
    privdata = pcidriver_dummydata;
227
    pcidriver_dummydata = NULL;
358 by Suren A. Chilingaryan
Support emulation mode without real hardware
228
#else /* PCIDRIVER_DUMMY_DEVICE */
364 by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04)
229
    /* Get private data from the device */
230
    privdata = pci_get_drvdata(pdev);
358 by Suren A. Chilingaryan
Support emulation mode without real hardware
231
#endif /* PCIDRIVER_DUMMY_DEVICE */
1 by Suren A. Chilingaryan
Initial import
232
364 by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04)
233
    // Theoretically we should lock here and when using...
234
    pcidriver_privdata[privdata->devid] = NULL;
363 by Suren A. Chilingaryan
Resolution of the user-space BAR addresses
235
364 by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04)
236
    /* Removing sysfs attributes from class device */
365 by Suren A. Chilingaryan
Restructure driver headers
237
    pcidriver_remove_sysfs_attributes(privdata);
364 by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04)
238
239
    /* Free all allocated kmem buffers before leaving */
240
    pcidriver_kmem_free_all( privdata );
1 by Suren A. Chilingaryan
Initial import
241
358 by Suren A. Chilingaryan
Support emulation mode without real hardware
242
#ifndef PCIDRIVER_DUMMY_DEVICE
243
# ifdef ENABLE_IRQ
364 by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04)
244
    pcidriver_remove_irq(privdata);
358 by Suren A. Chilingaryan
Support emulation mode without real hardware
245
# endif
246
#endif /* ! PCIDRIVER_DUMMY_DEVICE */
1 by Suren A. Chilingaryan
Initial import
247
364 by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04)
248
    /* Removing Character device */
249
    cdev_del(&(privdata->cdev));
250
251
    /* Removing the device from sysfs */
365 by Suren A. Chilingaryan
Restructure driver headers
252
    device_destroy(pcidriver_class, privdata->devno);
364 by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04)
253
254
    /* Releasing privdata */
255
    kfree(privdata);
1 by Suren A. Chilingaryan
Initial import
256
358 by Suren A. Chilingaryan
Support emulation mode without real hardware
257
#ifdef PCIDRIVER_DUMMY_DEVICE
364 by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04)
258
    mod_info("Device at " NODENAMEFMT " removed\n", 0);
358 by Suren A. Chilingaryan
Support emulation mode without real hardware
259
#else /* PCIDRIVER_DUMMY_DEVICE */
364 by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04)
260
    /* Disabling PCI device */
261
    pci_disable_device(pdev);
262
    mod_info("Device at %s removed\n", dev_name(&pdev->dev));
358 by Suren A. Chilingaryan
Support emulation mode without real hardware
263
#endif /* PCIDRIVER_DUMMY_DEVICE */
264
1 by Suren A. Chilingaryan
Initial import
265
}
266
365 by Suren A. Chilingaryan
Restructure driver headers
267
#ifndef PCIDRIVER_DUMMY_DEVICE
268
static struct pci_driver pcidriver_driver = {
269
    .name = MODNAME,
270
    .id_table = pcidriver_ids,
271
    .probe = pcidriver_probe,
272
    .remove = pcidriver_remove,
1 by Suren A. Chilingaryan
Initial import
273
};
365 by Suren A. Chilingaryan
Restructure driver headers
274
#endif /* ! PCIDRIVER_DUMMY_DEVICE */
275
276
static int __init pcidriver_init(void)
277
{
278
    int err = 0;
279
280
    /* Initialize the device count */
281
    atomic_set(&pcidriver_deviceCount, 0);
282
283
    memset(pcidriver_privdata, 0, sizeof(pcidriver_privdata));
284
285
    /* Allocate character device region dynamically */
286
    if ((err = alloc_chrdev_region(&pcidriver_devt, MINORNR, MAXDEVICES, NODENAME)) != 0) {
287
        mod_info("Couldn't allocate chrdev region. Module not loaded.\n");
288
        goto init_alloc_fail;
289
    }
290
    mod_info("Major %d allocated to nodename '%s'\n", MAJOR(pcidriver_devt), NODENAME);
291
292
    /* Register driver class */
293
    pcidriver_class = class_create(THIS_MODULE, NODENAME);
294
295
    if (IS_ERR(pcidriver_class)) {
296
        mod_info("No sysfs support. Module not loaded.\n");
297
        goto init_class_fail;
298
    }
299
300
    /* Register PCI driver. This function returns the number of devices on some
301
     * systems, therefore check for errors as < 0. */
358 by Suren A. Chilingaryan
Support emulation mode without real hardware
302
#ifdef PCIDRIVER_DUMMY_DEVICE
365 by Suren A. Chilingaryan
Restructure driver headers
303
    if ((err = pcidriver_probe(NULL, NULL)) < 0) {
358 by Suren A. Chilingaryan
Support emulation mode without real hardware
304
#else /* PCIDRIVER_DUMMY_DEVICE */
365 by Suren A. Chilingaryan
Restructure driver headers
305
    if ((err = pci_register_driver(&pcidriver_driver)) < 0) {
306
#endif /* PCIDRIVER_DUMMY_DEVICE */
307
        mod_info("Couldn't register PCI driver. Module not loaded.\n");
308
        goto init_pcireg_fail;
309
    }
310
311
    mod_info("pcidriver %u.%u.%u loaded\n", PCILIB_VERSION_GET_MAJOR(PCILIB_VERSION), PCILIB_VERSION_GET_MINOR(PCILIB_VERSION), PCILIB_VERSION_GET_MICRO(PCILIB_VERSION));
312
    mod_info("%s\n", PCIDRIVER_BUILD);
313
    mod_info("%s\n", PCIDRIVER_REVISION);
314
    if (strlen(PCIDRIVER_CHANGES)) {
315
        mod_info("Extra changes - %s\n", PCIDRIVER_CHANGES);
316
    }
317
318
    return 0;
319
320
init_pcireg_fail:
321
    class_destroy(pcidriver_class);
322
init_class_fail:
323
    unregister_chrdev_region(pcidriver_devt, MAXDEVICES);
324
init_alloc_fail:
325
    return err;
326
}
327
328
static void pcidriver_exit(void)
329
{
330
#ifdef PCIDRIVER_DUMMY_DEVICE
331
    pcidriver_remove(NULL);
332
#else
333
    pci_unregister_driver(&pcidriver_driver);
334
#endif /* PCIDRIVER_DUMMY_DEVICE */
335
336
    unregister_chrdev_region(pcidriver_devt, MAXDEVICES);
337
338
    if (pcidriver_class != NULL)
339
        class_destroy(pcidriver_class);
340
341
    mod_info("Module unloaded\n");
342
}
343
344
module_init(pcidriver_init);
345
module_exit(pcidriver_exit);