Root/
1 | /* uio_pci_generic - generic UIO driver for PCI 2.3 devices |
2 | * |
3 | * Copyright (C) 2009 Red Hat, Inc. |
4 | * Author: Michael S. Tsirkin <mst@redhat.com> |
5 | * |
6 | * This work is licensed under the terms of the GNU GPL, version 2. |
7 | * |
8 | * Since the driver does not declare any device ids, you must allocate |
9 | * id and bind the device to the driver yourself. For example: |
10 | * |
11 | * # echo "8086 10f5" > /sys/bus/pci/drivers/uio_pci_generic/new_id |
12 | * # echo -n 0000:00:19.0 > /sys/bus/pci/drivers/e1000e/unbind |
13 | * # echo -n 0000:00:19.0 > /sys/bus/pci/drivers/uio_pci_generic/bind |
14 | * # ls -l /sys/bus/pci/devices/0000:00:19.0/driver |
15 | * .../0000:00:19.0/driver -> ../../../bus/pci/drivers/uio_pci_generic |
16 | * |
17 | * Driver won't bind to devices which do not support the Interrupt Disable Bit |
18 | * in the command register. All devices compliant to PCI 2.3 (circa 2002) and |
19 | * all compliant PCI Express devices should support this bit. |
20 | */ |
21 | |
22 | #include <linux/device.h> |
23 | #include <linux/module.h> |
24 | #include <linux/pci.h> |
25 | #include <linux/slab.h> |
26 | #include <linux/uio_driver.h> |
27 | |
28 | #define DRIVER_VERSION "0.01.0" |
29 | #define DRIVER_AUTHOR "Michael S. Tsirkin <mst@redhat.com>" |
30 | #define DRIVER_DESC "Generic UIO driver for PCI 2.3 devices" |
31 | |
32 | struct uio_pci_generic_dev { |
33 | struct uio_info info; |
34 | struct pci_dev *pdev; |
35 | }; |
36 | |
37 | static inline struct uio_pci_generic_dev * |
38 | to_uio_pci_generic_dev(struct uio_info *info) |
39 | { |
40 | return container_of(info, struct uio_pci_generic_dev, info); |
41 | } |
42 | |
43 | /* Interrupt handler. Read/modify/write the command register to disable |
44 | * the interrupt. */ |
45 | static irqreturn_t irqhandler(int irq, struct uio_info *info) |
46 | { |
47 | struct uio_pci_generic_dev *gdev = to_uio_pci_generic_dev(info); |
48 | |
49 | if (!pci_check_and_mask_intx(gdev->pdev)) |
50 | return IRQ_NONE; |
51 | |
52 | /* UIO core will signal the user process. */ |
53 | return IRQ_HANDLED; |
54 | } |
55 | |
56 | static int __devinit probe(struct pci_dev *pdev, |
57 | const struct pci_device_id *id) |
58 | { |
59 | struct uio_pci_generic_dev *gdev; |
60 | int err; |
61 | |
62 | err = pci_enable_device(pdev); |
63 | if (err) { |
64 | dev_err(&pdev->dev, "%s: pci_enable_device failed: %d\n", |
65 | __func__, err); |
66 | return err; |
67 | } |
68 | |
69 | if (!pdev->irq) { |
70 | dev_warn(&pdev->dev, "No IRQ assigned to device: " |
71 | "no support for interrupts?\n"); |
72 | pci_disable_device(pdev); |
73 | return -ENODEV; |
74 | } |
75 | |
76 | if (!pci_intx_mask_supported(pdev)) { |
77 | err = -ENODEV; |
78 | goto err_verify; |
79 | } |
80 | |
81 | gdev = kzalloc(sizeof(struct uio_pci_generic_dev), GFP_KERNEL); |
82 | if (!gdev) { |
83 | err = -ENOMEM; |
84 | goto err_alloc; |
85 | } |
86 | |
87 | gdev->info.name = "uio_pci_generic"; |
88 | gdev->info.version = DRIVER_VERSION; |
89 | gdev->info.irq = pdev->irq; |
90 | gdev->info.irq_flags = IRQF_SHARED; |
91 | gdev->info.handler = irqhandler; |
92 | gdev->pdev = pdev; |
93 | |
94 | if (uio_register_device(&pdev->dev, &gdev->info)) |
95 | goto err_register; |
96 | pci_set_drvdata(pdev, gdev); |
97 | |
98 | return 0; |
99 | err_register: |
100 | kfree(gdev); |
101 | err_alloc: |
102 | err_verify: |
103 | pci_disable_device(pdev); |
104 | return err; |
105 | } |
106 | |
107 | static void remove(struct pci_dev *pdev) |
108 | { |
109 | struct uio_pci_generic_dev *gdev = pci_get_drvdata(pdev); |
110 | |
111 | uio_unregister_device(&gdev->info); |
112 | pci_disable_device(pdev); |
113 | kfree(gdev); |
114 | } |
115 | |
116 | static struct pci_driver driver = { |
117 | .name = "uio_pci_generic", |
118 | .id_table = NULL, /* only dynamic id's */ |
119 | .probe = probe, |
120 | .remove = remove, |
121 | }; |
122 | |
123 | static int __init init(void) |
124 | { |
125 | pr_info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); |
126 | return pci_register_driver(&driver); |
127 | } |
128 | |
129 | static void __exit cleanup(void) |
130 | { |
131 | pci_unregister_driver(&driver); |
132 | } |
133 | |
134 | module_init(init); |
135 | module_exit(cleanup); |
136 | |
137 | MODULE_VERSION(DRIVER_VERSION); |
138 | MODULE_LICENSE("GPL v2"); |
139 | MODULE_AUTHOR(DRIVER_AUTHOR); |
140 | MODULE_DESCRIPTION(DRIVER_DESC); |
141 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9