]>
Commit | Line | Data |
---|---|---|
ce157f80 | 1 | #include <linux/module.h> |
33782dd5 HS |
2 | #include <linux/pci.h> |
3 | ||
3d41c443 HS |
4 | #include "../comedidev.h" |
5 | #include "comedi_fc.h" | |
bf36f012 | 6 | #include "amcc_s5933.h" |
3d41c443 HS |
7 | |
8 | #include "addi-data/addi_common.h" | |
3d41c443 | 9 | |
bf6a1578 | 10 | #include "addi-data/hwdrv_apci3120.c" |
bb6986f0 | 11 | |
1df0e5b0 HS |
12 | enum apci3120_boardid { |
13 | BOARD_APCI3120, | |
14 | BOARD_APCI3001, | |
15 | }; | |
16 | ||
20a22b70 | 17 | static const struct addi_board apci3120_boardtypes[] = { |
1df0e5b0 | 18 | [BOARD_APCI3120] = { |
c0a053b8 | 19 | .pc_DriverName = "apci3120", |
c0a053b8 HS |
20 | .i_NbrAiChannel = 16, |
21 | .i_NbrAiChannelDiff = 8, | |
22 | .i_AiChannelList = 16, | |
23 | .i_NbrAoChannel = 8, | |
24 | .i_AiMaxdata = 0xffff, | |
25 | .i_AoMaxdata = 0x3fff, | |
c0a053b8 HS |
26 | .i_NbrDiChannel = 4, |
27 | .i_NbrDoChannel = 4, | |
28 | .i_DoMaxdata = 0x0f, | |
805077b9 | 29 | .interrupt = apci3120_interrupt, |
1df0e5b0 HS |
30 | }, |
31 | [BOARD_APCI3001] = { | |
973781a8 | 32 | .pc_DriverName = "apci3001", |
973781a8 HS |
33 | .i_NbrAiChannel = 16, |
34 | .i_NbrAiChannelDiff = 8, | |
35 | .i_AiChannelList = 16, | |
36 | .i_AiMaxdata = 0xfff, | |
973781a8 HS |
37 | .i_NbrDiChannel = 4, |
38 | .i_NbrDoChannel = 4, | |
39 | .i_DoMaxdata = 0x0f, | |
805077b9 | 40 | .interrupt = apci3120_interrupt, |
c0a053b8 HS |
41 | }, |
42 | }; | |
43 | ||
bb6986f0 HS |
44 | static irqreturn_t v_ADDI_Interrupt(int irq, void *d) |
45 | { | |
46 | struct comedi_device *dev = d; | |
47 | const struct addi_board *this_board = comedi_board(dev); | |
48 | ||
49 | this_board->interrupt(irq, d); | |
50 | return IRQ_RETVAL(1); | |
51 | } | |
52 | ||
a690b7e5 | 53 | static int apci3120_auto_attach(struct comedi_device *dev, |
1df0e5b0 | 54 | unsigned long context) |
bb6986f0 | 55 | { |
891e62c3 | 56 | struct pci_dev *pcidev = comedi_to_pci_dev(dev); |
1df0e5b0 | 57 | const struct addi_board *this_board = NULL; |
bb6986f0 HS |
58 | struct addi_private *devpriv; |
59 | struct comedi_subdevice *s; | |
aea9c4e2 | 60 | int ret, pages, i; |
bb6986f0 | 61 | |
1df0e5b0 HS |
62 | if (context < ARRAY_SIZE(apci3120_boardtypes)) |
63 | this_board = &apci3120_boardtypes[context]; | |
bb6986f0 HS |
64 | if (!this_board) |
65 | return -ENODEV; | |
66 | dev->board_ptr = this_board; | |
67 | dev->board_name = this_board->pc_DriverName; | |
68 | ||
0bdab509 | 69 | devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); |
bb6986f0 HS |
70 | if (!devpriv) |
71 | return -ENOMEM; | |
bb6986f0 | 72 | |
818f569f | 73 | ret = comedi_pci_enable(dev); |
bb6986f0 HS |
74 | if (ret) |
75 | return ret; | |
4fbe36f2 | 76 | pci_set_master(pcidev); |
bb6986f0 | 77 | |
65fe75a6 | 78 | dev->iobase = pci_resource_start(pcidev, 1); |
887f706e HS |
79 | devpriv->iobase = dev->iobase; |
80 | devpriv->i_IobaseAmcc = pci_resource_start(pcidev, 0); | |
81 | devpriv->i_IobaseAddon = pci_resource_start(pcidev, 2); | |
bb6986f0 HS |
82 | devpriv->i_IobaseReserved = pci_resource_start(pcidev, 3); |
83 | ||
bb6986f0 HS |
84 | if (pcidev->irq > 0) { |
85 | ret = request_irq(pcidev->irq, v_ADDI_Interrupt, IRQF_SHARED, | |
86 | dev->board_name, dev); | |
87 | if (ret == 0) | |
88 | dev->irq = pcidev->irq; | |
89 | } | |
90 | ||
223a6402 | 91 | devpriv->us_UseDma = 1; |
bb6986f0 | 92 | |
4fbe36f2 HS |
93 | /* Allocate DMA buffers */ |
94 | devpriv->b_DmaDoubleBuffer = 0; | |
95 | for (i = 0; i < 2; i++) { | |
96 | for (pages = 4; pages >= 0; pages--) { | |
97 | devpriv->ul_DmaBufferVirtual[i] = | |
98 | (void *) __get_free_pages(GFP_KERNEL, pages); | |
99 | ||
100 | if (devpriv->ul_DmaBufferVirtual[i]) | |
101 | break; | |
102 | } | |
103 | if (devpriv->ul_DmaBufferVirtual[i]) { | |
104 | devpriv->ui_DmaBufferPages[i] = pages; | |
105 | devpriv->ui_DmaBufferSize[i] = PAGE_SIZE * pages; | |
4fbe36f2 HS |
106 | devpriv->ul_DmaBufferHw[i] = |
107 | virt_to_bus((void *)devpriv-> | |
108 | ul_DmaBufferVirtual[i]); | |
bb6986f0 HS |
109 | } |
110 | } | |
4fbe36f2 | 111 | if (!devpriv->ul_DmaBufferVirtual[0]) |
223a6402 | 112 | devpriv->us_UseDma = 0; |
4fbe36f2 HS |
113 | |
114 | if (devpriv->ul_DmaBufferVirtual[1]) | |
115 | devpriv->b_DmaDoubleBuffer = 1; | |
bb6986f0 | 116 | |
aea9c4e2 | 117 | ret = comedi_alloc_subdevices(dev, 5); |
bb6986f0 HS |
118 | if (ret) |
119 | return ret; | |
120 | ||
121 | /* Allocate and Initialise AI Subdevice Structures */ | |
122 | s = &dev->subdevices[0]; | |
50231a91 HS |
123 | dev->read_subdev = s; |
124 | s->type = COMEDI_SUBD_AI; | |
125 | s->subdev_flags = | |
126 | SDF_READABLE | SDF_COMMON | SDF_GROUND | |
127 | | SDF_DIFF; | |
301b1ffc | 128 | if (this_board->i_NbrAiChannel) |
50231a91 | 129 | s->n_chan = this_board->i_NbrAiChannel; |
301b1ffc | 130 | else |
50231a91 | 131 | s->n_chan = this_board->i_NbrAiChannelDiff; |
50231a91 HS |
132 | s->maxdata = this_board->i_AiMaxdata; |
133 | s->len_chanlist = this_board->i_AiChannelList; | |
1ba296b9 | 134 | s->range_table = &range_apci3120_ai; |
50231a91 | 135 | |
805077b9 FA |
136 | s->insn_config = apci3120_ai_insn_config; |
137 | s->insn_read = apci3120_ai_insn_read; | |
138 | s->do_cmdtest = apci3120_ai_cmdtest; | |
139 | s->do_cmd = apci3120_ai_cmd; | |
140 | s->cancel = apci3120_cancel; | |
bb6986f0 HS |
141 | |
142 | /* Allocate and Initialise AO Subdevice Structures */ | |
143 | s = &dev->subdevices[1]; | |
48fdf084 | 144 | if (this_board->i_NbrAoChannel) { |
bb6986f0 HS |
145 | s->type = COMEDI_SUBD_AO; |
146 | s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON; | |
48fdf084 HS |
147 | s->n_chan = this_board->i_NbrAoChannel; |
148 | s->maxdata = this_board->i_AoMaxdata; | |
149 | s->len_chanlist = this_board->i_NbrAoChannel; | |
0bb482e2 | 150 | s->range_table = &range_apci3120_ao; |
805077b9 | 151 | s->insn_write = apci3120_ao_insn_write; |
bb6986f0 HS |
152 | } else { |
153 | s->type = COMEDI_SUBD_UNUSED; | |
154 | } | |
f2c872e1 | 155 | |
bb6986f0 HS |
156 | /* Allocate and Initialise DI Subdevice Structures */ |
157 | s = &dev->subdevices[2]; | |
f2c872e1 HS |
158 | s->type = COMEDI_SUBD_DI; |
159 | s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON; | |
160 | s->n_chan = this_board->i_NbrDiChannel; | |
161 | s->maxdata = 1; | |
162 | s->len_chanlist = this_board->i_NbrDiChannel; | |
163 | s->range_table = &range_digital; | |
a7f4b3ca | 164 | s->insn_bits = apci3120_di_insn_bits; |
f2c872e1 | 165 | |
bb6986f0 HS |
166 | /* Allocate and Initialise DO Subdevice Structures */ |
167 | s = &dev->subdevices[3]; | |
43deb75d HS |
168 | s->type = COMEDI_SUBD_DO; |
169 | s->subdev_flags = | |
170 | SDF_READABLE | SDF_WRITEABLE | SDF_GROUND | SDF_COMMON; | |
171 | s->n_chan = this_board->i_NbrDoChannel; | |
172 | s->maxdata = this_board->i_DoMaxdata; | |
173 | s->len_chanlist = this_board->i_NbrDoChannel; | |
174 | s->range_table = &range_digital; | |
66511843 | 175 | s->insn_bits = apci3120_do_insn_bits; |
bb6986f0 HS |
176 | |
177 | /* Allocate and Initialise Timer Subdevice Structures */ | |
178 | s = &dev->subdevices[4]; | |
53b168b9 HS |
179 | s->type = COMEDI_SUBD_TIMER; |
180 | s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON; | |
181 | s->n_chan = 1; | |
182 | s->maxdata = 0; | |
183 | s->len_chanlist = 1; | |
184 | s->range_table = &range_digital; | |
185 | ||
805077b9 FA |
186 | s->insn_write = apci3120_write_insn_timer; |
187 | s->insn_read = apci3120_read_insn_timer; | |
188 | s->insn_config = apci3120_config_insn_timer; | |
bb6986f0 | 189 | |
805077b9 | 190 | apci3120_reset(dev); |
bb6986f0 HS |
191 | return 0; |
192 | } | |
193 | ||
194 | static void apci3120_detach(struct comedi_device *dev) | |
195 | { | |
bb6986f0 HS |
196 | struct addi_private *devpriv = dev->private; |
197 | ||
198 | if (devpriv) { | |
199 | if (dev->iobase) | |
805077b9 | 200 | apci3120_reset(dev); |
bb6986f0 HS |
201 | if (dev->irq) |
202 | free_irq(dev->irq, dev); | |
97641816 HS |
203 | if (devpriv->ul_DmaBufferVirtual[0]) { |
204 | free_pages((unsigned long)devpriv-> | |
205 | ul_DmaBufferVirtual[0], | |
206 | devpriv->ui_DmaBufferPages[0]); | |
207 | } | |
208 | if (devpriv->ul_DmaBufferVirtual[1]) { | |
209 | free_pages((unsigned long)devpriv-> | |
210 | ul_DmaBufferVirtual[1], | |
211 | devpriv->ui_DmaBufferPages[1]); | |
bb6986f0 HS |
212 | } |
213 | } | |
7f072f54 | 214 | comedi_pci_disable(dev); |
bb6986f0 HS |
215 | } |
216 | ||
20a22b70 HS |
217 | static struct comedi_driver apci3120_driver = { |
218 | .driver_name = "addi_apci_3120", | |
219 | .module = THIS_MODULE, | |
891e62c3 | 220 | .auto_attach = apci3120_auto_attach, |
bb6986f0 | 221 | .detach = apci3120_detach, |
20a22b70 HS |
222 | }; |
223 | ||
a690b7e5 | 224 | static int apci3120_pci_probe(struct pci_dev *dev, |
b8f4ac23 | 225 | const struct pci_device_id *id) |
20a22b70 | 226 | { |
b8f4ac23 | 227 | return comedi_pci_auto_config(dev, &apci3120_driver, id->driver_data); |
20a22b70 HS |
228 | } |
229 | ||
41e043fc | 230 | static const struct pci_device_id apci3120_pci_table[] = { |
aee351b2 IA |
231 | { PCI_VDEVICE(AMCC, 0x818d), BOARD_APCI3120 }, |
232 | { PCI_VDEVICE(AMCC, 0x828d), BOARD_APCI3001 }, | |
317285d7 HS |
233 | { 0 } |
234 | }; | |
20a22b70 | 235 | MODULE_DEVICE_TABLE(pci, apci3120_pci_table); |
317285d7 | 236 | |
20a22b70 HS |
237 | static struct pci_driver apci3120_pci_driver = { |
238 | .name = "addi_apci_3120", | |
239 | .id_table = apci3120_pci_table, | |
240 | .probe = apci3120_pci_probe, | |
9901a4d7 | 241 | .remove = comedi_pci_auto_unconfig, |
20a22b70 HS |
242 | }; |
243 | module_comedi_pci_driver(apci3120_driver, apci3120_pci_driver); | |
90f703d3 AT |
244 | |
245 | MODULE_AUTHOR("Comedi http://www.comedi.org"); | |
b5ebcaa8 | 246 | MODULE_DESCRIPTION("ADDI-DATA APCI-3120, Analog input board"); |
90f703d3 | 247 | MODULE_LICENSE("GPL"); |