Staging: comedi: Remove COMEDI_PCI_INITCLEANUP macro
[deliverable/linux.git] / drivers / staging / comedi / drivers / cb_pcidio.c
CommitLineData
028d4864
YM
1/*
2 comedi/drivers/cb_pcidio.c
3 A Comedi driver for PCI-DIO24H & PCI-DIO48H of ComputerBoards (currently MeasurementComputing)
4
5 COMEDI - Linux Control and Measurement Device Interface
6 Copyright (C) 2000 David A. Schleef <ds@schleef.org>
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
22*/
23/*
24Driver: cb_pcidio
25Description: ComputerBoards' DIO boards with PCI interface
26Devices: [Measurement Computing] PCI-DIO24 (cb_pcidio), PCI-DIO24H, PCI-DIO48H
27Author: Yoshiya Matsuzaka
28Updated: Mon, 29 Oct 2007 15:40:47 +0000
29Status: experimental
30
31This driver has been modified from skel.c of comedi-0.7.70.
32
33Configuration Options:
34 [0] - PCI bus of device (optional)
35 [1] - PCI slot of device (optional)
36 If bus/slot is not specified, the first available PCI device will
37 be used.
38
39Passing a zero for an option is the same as leaving it unspecified.
40*/
41
42/*------------------------------ HEADER FILES ---------------------------------*/
43#include "../comedidev.h"
44#include "comedi_pci.h"
45#include "8255.h"
46
47/*-------------------------- MACROS and DATATYPES -----------------------------*/
48#define PCI_VENDOR_ID_CB 0x1307
49
50/*
51 * Board descriptions for two imaginary boards. Describing the
52 * boards in this way is optional, and completely driver-dependent.
53 * Some drivers use arrays such as this, other do not.
54 */
c98d3deb 55struct pcidio_board {
aa65d22a
IA
56 const char *name; /* name of the board */
57 int dev_id;
2696fb57 58 int n_8255; /* number of 8255 chips on board */
028d4864 59
2696fb57 60 /* indices of base address regions */
028d4864
YM
61 int pcicontroler_badrindex;
62 int dioregs_badrindex;
c98d3deb 63};
028d4864 64
c98d3deb 65static const struct pcidio_board pcidio_boards[] = {
028d4864 66 {
0a85b6f0 67 .name = "pci-dio24",
aa65d22a 68 .dev_id = 0x0028,
0a85b6f0
MT
69 .n_8255 = 1,
70 .pcicontroler_badrindex = 1,
71 .dioregs_badrindex = 2,
72 },
028d4864 73 {
0a85b6f0 74 .name = "pci-dio24h",
aa65d22a 75 .dev_id = 0x0014,
0a85b6f0
MT
76 .n_8255 = 1,
77 .pcicontroler_badrindex = 1,
78 .dioregs_badrindex = 2,
79 },
028d4864 80 {
0a85b6f0 81 .name = "pci-dio48h",
aa65d22a 82 .dev_id = 0x000b,
0a85b6f0
MT
83 .n_8255 = 2,
84 .pcicontroler_badrindex = 0,
85 .dioregs_badrindex = 1,
86 },
028d4864
YM
87};
88
89/* This is used by modprobe to translate PCI IDs to drivers. Should
90 * only be used for PCI and ISA-PnP devices */
91/* Please add your PCI vendor ID to comedidev.h, and it will be forwarded
92 * upstream. */
93static DEFINE_PCI_DEVICE_TABLE(pcidio_pci_table) = {
0a85b6f0
MT
94 {
95 PCI_VENDOR_ID_CB, 0x0028, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
96 PCI_VENDOR_ID_CB, 0x0014, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
97 PCI_VENDOR_ID_CB, 0x000b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
98 0}
028d4864
YM
99};
100
101MODULE_DEVICE_TABLE(pci, pcidio_pci_table);
102
103/*
104 * Useful for shorthand access to the particular board structure
105 */
c98d3deb 106#define thisboard ((const struct pcidio_board *)dev->board_ptr)
028d4864
YM
107
108/* this structure is for data unique to this hardware driver. If
109 several hardware drivers keep similar information in this structure,
71b5f4f1 110 feel free to suggest moving the variable to the struct comedi_device struct. */
fe7858af 111struct pcidio_private {
bbc9a991 112 int data; /* currently unused */
028d4864
YM
113
114 /* would be useful for a PCI device */
115 struct pci_dev *pci_dev;
116
bbc9a991 117 /* used for DO readback, currently unused */
790c5541 118 unsigned int do_readback[4]; /* up to 4 unsigned int suffice to hold 96 bits for PCI-DIO96 */
028d4864 119
2696fb57 120 unsigned long dio_reg_base; /* address of port A of the first 8255 chip on board */
fe7858af 121};
028d4864
YM
122
123/*
124 * most drivers define the following macro to make it easy to
125 * access the private structure.
126 */
fe7858af 127#define devpriv ((struct pcidio_private *)dev->private)
028d4864
YM
128
129/*
139dfbdf 130 * The struct comedi_driver structure tells the Comedi core module
028d4864
YM
131 * which functions to call to configure/deconfigure (attach/detach)
132 * the board, and also about the kernel module that contains
133 * the device code.
134 */
0a85b6f0
MT
135static int pcidio_attach(struct comedi_device *dev,
136 struct comedi_devconfig *it);
da91b269 137static int pcidio_detach(struct comedi_device *dev);
139dfbdf 138static struct comedi_driver driver_cb_pcidio = {
68c3dbff
BP
139 .driver_name = "cb_pcidio",
140 .module = THIS_MODULE,
141 .attach = pcidio_attach,
142 .detach = pcidio_detach,
2696fb57 143
028d4864
YM
144/* It is not necessary to implement the following members if you are
145 * writing a driver for a ISA PnP or PCI card */
2696fb57 146
028d4864
YM
147 /* Most drivers will support multiple types of boards by
148 * having an array of board structures. These were defined
149 * in pcidio_boards[] above. Note that the element 'name'
150 * was first in the structure -- Comedi uses this fact to
151 * extract the name of the board without knowing any details
152 * about the structure except for its length.
153 * When a device is attached (by comedi_config), the name
154 * of the device is given to Comedi, and Comedi tries to
155 * match it by going through the list of board names. If
156 * there is a match, the address of the pointer is put
157 * into dev->board_ptr and driver->attach() is called.
158 *
159 * Note that these are not necessary if you can determine
160 * the type of board in software. ISA PnP, PCI, and PCMCIA
161 * devices are such boards.
162 */
2696fb57
BP
163
164/* The following fields should NOT be initialized if you are dealing
165 * with PCI devices
166 *
68c3dbff
BP
167 * .board_name = pcidio_boards,
168 * .offset = sizeof(struct pcidio_board),
169 * .num_names = sizeof(pcidio_boards) / sizeof(structpcidio_board),
2696fb57
BP
170 */
171
028d4864
YM
172};
173
174/*------------------------------- FUNCTIONS -----------------------------------*/
175
176/*
177 * Attach is called by the Comedi core to configure the driver
178 * for a particular board. If you specified a board_name array
179 * in the driver structure, dev->board_ptr contains that
180 * address.
181 */
da91b269 182static int pcidio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
028d4864
YM
183{
184 struct pci_dev *pcidev = NULL;
185 int index;
186 int i;
187
188 printk("comedi%d: cb_pcidio: \n", dev->minor);
189
190/*
191 * Allocate the private structure area. alloc_private() is a
192 * convenient macro defined in comedidev.h.
193 */
fe7858af 194 if (alloc_private(dev, sizeof(struct pcidio_private)) < 0)
028d4864
YM
195 return -ENOMEM;
196/*
197 * If you can probe the device to determine what device in a series
198 * it is, this is the place to do it. Otherwise, dev->board_ptr
199 * should already be initialized.
200 */
201/*
202 * Probe the device to determine what device in the series it is.
203 */
204
205 for (pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL);
0a85b6f0
MT
206 pcidev != NULL;
207 pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pcidev)) {
2696fb57 208 /* is it not a computer boards card? */
028d4864
YM
209 if (pcidev->vendor != PCI_VENDOR_ID_CB)
210 continue;
2696fb57 211 /* loop through cards supported by this driver */
0a85b6f0 212 for (index = 0; index < ARRAY_SIZE(pcidio_boards); index++) {
aa65d22a 213 if (pcidio_boards[index].dev_id != pcidev->device)
028d4864
YM
214 continue;
215
2696fb57 216 /* was a particular bus/slot requested? */
028d4864 217 if (it->options[0] || it->options[1]) {
2696fb57 218 /* are we on the wrong bus/slot? */
028d4864 219 if (pcidev->bus->number != it->options[0] ||
0a85b6f0 220 PCI_SLOT(pcidev->devfn) != it->options[1]) {
028d4864
YM
221 continue;
222 }
223 }
224 dev->board_ptr = pcidio_boards + index;
225 goto found;
226 }
227 }
228
229 printk("No supported ComputerBoards/MeasurementComputing card found on "
0a85b6f0 230 "requested position\n");
028d4864
YM
231 return -EIO;
232
0a85b6f0 233found:
028d4864
YM
234
235/*
236 * Initialize dev->board_name. Note that we can use the "thisboard"
237 * macro now, since we just initialized it in the last line.
238 */
239 dev->board_name = thisboard->name;
240
241 devpriv->pci_dev = pcidev;
242 printk("Found %s on bus %i, slot %i\n", thisboard->name,
0a85b6f0
MT
243 devpriv->pci_dev->bus->number,
244 PCI_SLOT(devpriv->pci_dev->devfn));
028d4864 245 if (comedi_pci_enable(pcidev, thisboard->name)) {
0a85b6f0
MT
246 printk
247 ("cb_pcidio: failed to enable PCI device and request regions\n");
028d4864
YM
248 return -EIO;
249 }
250 devpriv->dio_reg_base
0a85b6f0
MT
251 =
252 pci_resource_start(devpriv->pci_dev,
253 pcidio_boards[index].dioregs_badrindex);
028d4864
YM
254
255/*
256 * Allocate the subdevice structures. alloc_subdevice() is a
257 * convenient macro defined in comedidev.h.
258 */
259 if (alloc_subdevices(dev, thisboard->n_8255) < 0)
260 return -ENOMEM;
261
262 for (i = 0; i < thisboard->n_8255; i++) {
263 subdev_8255_init(dev, dev->subdevices + i,
0a85b6f0 264 NULL, devpriv->dio_reg_base + i * 4);
028d4864 265 printk(" subdev %d: base = 0x%lx\n", i,
0a85b6f0 266 devpriv->dio_reg_base + i * 4);
028d4864
YM
267 }
268
269 printk("attached\n");
270 return 1;
271}
272
273/*
274 * _detach is called to deconfigure a device. It should deallocate
275 * resources.
276 * This function is also called when _attach() fails, so it should be
277 * careful not to release resources that were not necessarily
278 * allocated by _attach(). dev->private and dev->subdevices are
279 * deallocated automatically by the core.
280 */
da91b269 281static int pcidio_detach(struct comedi_device *dev)
028d4864
YM
282{
283 printk("comedi%d: cb_pcidio: remove\n", dev->minor);
284 if (devpriv) {
285 if (devpriv->pci_dev) {
e3a21d0a 286 if (devpriv->dio_reg_base)
028d4864 287 comedi_pci_disable(devpriv->pci_dev);
028d4864
YM
288 pci_dev_put(devpriv->pci_dev);
289 }
290 }
291 if (dev->subdevices) {
292 int i;
e3a21d0a 293 for (i = 0; i < thisboard->n_8255; i++)
028d4864 294 subdev_8255_cleanup(dev, dev->subdevices + i);
028d4864
YM
295 }
296 return 0;
297}
298
299/*
300 * A convenient macro that defines init_module() and cleanup_module(),
301 * as necessary.
302 */
727b286b
AT
303static int __devinit driver_cb_pcidio_pci_probe(struct pci_dev *dev,
304 const struct pci_device_id *ent)
305{
306 return comedi_pci_auto_config(dev, driver_cb_pcidio.driver_name);
307}
308
309static void __devexit driver_cb_pcidio_pci_remove(struct pci_dev *dev)
310{
311 comedi_pci_auto_unconfig(dev);
312}
313
314static struct pci_driver driver_cb_pcidio_pci_driver = {
315 .id_table = pcidio_pci_table,
316 .probe = &driver_cb_pcidio_pci_probe,
317 .remove = __devexit_p(&driver_cb_pcidio_pci_remove)
318};
319
320static int __init driver_cb_pcidio_init_module(void)
321{
322 int retval;
323
324 retval = comedi_driver_register(&driver_cb_pcidio);
325 if (retval < 0)
326 return retval;
327
328 driver_cb_pcidio_pci_driver.name = (char *)driver_cb_pcidio.driver_name;
329 return pci_register_driver(&driver_cb_pcidio_pci_driver);
330}
331
332static void __exit driver_cb_pcidio_cleanup_module(void)
333{
334 pci_unregister_driver(&driver_cb_pcidio_pci_driver);
335 comedi_driver_unregister(&driver_cb_pcidio);
336}
337
338module_init(driver_cb_pcidio_init_module);
339module_exit(driver_cb_pcidio_cleanup_module);
90f703d3
AT
340
341MODULE_AUTHOR("Comedi http://www.comedi.org");
342MODULE_DESCRIPTION("Comedi low-level driver");
343MODULE_LICENSE("GPL");
This page took 0.242173 seconds and 5 git commands to generate.