1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44#include <linux/module.h>
45#include <linux/interrupt.h>
46
47#include "../comedi_pci.h"
48
49#include "amplc_pc236.h"
50#include "plx9052.h"
51
52
53#define PCI236_INTR_DISABLE (PLX9052_INTCSR_LI1POL | \
54 PLX9052_INTCSR_LI2POL | \
55 PLX9052_INTCSR_LI1SEL | \
56 PLX9052_INTCSR_LI1CLRINT)
57
58
59#define PCI236_INTR_ENABLE (PLX9052_INTCSR_LI1ENAB | \
60 PLX9052_INTCSR_LI1POL | \
61 PLX9052_INTCSR_LI2POL | \
62 PLX9052_INTCSR_PCIENAB | \
63 PLX9052_INTCSR_LI1SEL | \
64 PLX9052_INTCSR_LI1CLRINT)
65
66static void pci236_intr_update_cb(struct comedi_device *dev, bool enable)
67{
68 struct pc236_private *devpriv = dev->private;
69
70
71 outl(enable ? PCI236_INTR_ENABLE : PCI236_INTR_DISABLE,
72 devpriv->lcr_iobase + PLX9052_INTCSR);
73}
74
75static bool pci236_intr_chk_clr_cb(struct comedi_device *dev)
76{
77 struct pc236_private *devpriv = dev->private;
78
79
80 if (!(inl(devpriv->lcr_iobase + PLX9052_INTCSR) &
81 PLX9052_INTCSR_LI1STAT))
82 return false;
83
84 pci236_intr_update_cb(dev, devpriv->enable_irq);
85 return true;
86}
87
88static const struct pc236_board pc236_pci_board = {
89 .name = "pci236",
90 .intr_update_cb = pci236_intr_update_cb,
91 .intr_chk_clr_cb = pci236_intr_chk_clr_cb,
92};
93
94static int pci236_auto_attach(struct comedi_device *dev,
95 unsigned long context_unused)
96{
97 struct pci_dev *pci_dev = comedi_to_pci_dev(dev);
98 struct pc236_private *devpriv;
99 unsigned long iobase;
100 int ret;
101
102 dev_info(dev->class_dev, "amplc_pci236: attach pci %s\n",
103 pci_name(pci_dev));
104
105 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
106 if (!devpriv)
107 return -ENOMEM;
108
109 dev->board_ptr = &pc236_pci_board;
110 dev->board_name = pc236_pci_board.name;
111 ret = comedi_pci_enable(dev);
112 if (ret)
113 return ret;
114
115 devpriv->lcr_iobase = pci_resource_start(pci_dev, 1);
116 iobase = pci_resource_start(pci_dev, 2);
117 return amplc_pc236_common_attach(dev, iobase, pci_dev->irq,
118 IRQF_SHARED);
119}
120
121static struct comedi_driver amplc_pci236_driver = {
122 .driver_name = "amplc_pci236",
123 .module = THIS_MODULE,
124 .auto_attach = pci236_auto_attach,
125 .detach = comedi_pci_detach,
126};
127
128static const struct pci_device_id pci236_pci_table[] = {
129 { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, 0x0009) },
130 { 0 }
131};
132
133MODULE_DEVICE_TABLE(pci, pci236_pci_table);
134
135static int amplc_pci236_pci_probe(struct pci_dev *dev,
136 const struct pci_device_id *id)
137{
138 return comedi_pci_auto_config(dev, &lc_pci236_driver,
139 id->driver_data);
140}
141
142static struct pci_driver amplc_pci236_pci_driver = {
143 .name = "amplc_pci236",
144 .id_table = pci236_pci_table,
145 .probe = &lc_pci236_pci_probe,
146 .remove = comedi_pci_auto_unconfig,
147};
148
149module_comedi_pci_driver(amplc_pci236_driver, amplc_pci236_pci_driver);
150
151MODULE_AUTHOR("Comedi http://www.comedi.org");
152MODULE_DESCRIPTION("Comedi driver for Amplicon PCI236 DIO boards");
153MODULE_LICENSE("GPL");
154