]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/staging/comedi/drivers/adl_pci7296.c
staging: comedi: update adl_pci7296 driver
[karo-tx-linux.git] / drivers / staging / comedi / drivers / adl_pci7296.c
1 /*
2  * COMEDI driver for the ADLINK PCI-72xx series boards.
3  *
4  * COMEDI - Linux Control and Measurement Device Interface
5  * Copyright (C) 2000 David A. Schleef <ds@schleef.org>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */
21
22 /*
23 Driver: adl_pci7296
24 Description: 24/48/96-Channel Opto-22 Compatible Digital I/O Boards
25 Devices: (ADLink) PCI-7224 [adl_pci7224] - 24 channels
26          (ADLink) PCI-7248 [adl_pci7248] - 48 channels
27          (ADLink) PCI-7296 [adl_pci7296] - 96 channels
28 Author: Jon Grierson <jd@renko.co.uk>
29 Updated: Mon, 14 Apr 2008 15:05:56 +0100
30 Status: testing
31
32 This driver only attaches using the PCI PnP auto config support
33 in the comedi core. The module parameter 'comedi_autoconfig'
34 must be 1 (default) to enable this feature. The COMEDI_DEVCONFIG
35 ioctl, used by the comedi_config utility, is not supported by
36 this driver.
37
38 These boards also have an 8254 programmable timer/counter chip.
39 This chip is not currently supported by this driver.
40
41 Interrupt support for these boards is also not currently supported.
42
43 Configuration Options: not applicable
44 */
45
46 #include "../comedidev.h"
47
48 #include "8255.h"
49
50 /*
51  * PCI Device ID's supported by this driver
52  */
53 #define PCI_DEVICE_ID_PCI7224   0x7224
54 #define PCI_DEVICE_ID_PCI7248   0x7248
55 #define PCI_DEVICE_ID_PCI7296   0x7296
56
57 struct adl_pci7296_boardinfo {
58         const char *name;
59         unsigned short device;
60         int nsubdevs;
61 };
62
63 static const struct adl_pci7296_boardinfo adl_pci7296_boards[] = {
64         {
65                 .name           = "adl_pci7224",
66                 .device         = PCI_DEVICE_ID_PCI7224,
67                 .nsubdevs       = 1,
68         }, {
69                 .name           = "adl_pci7248",
70                 .device         = PCI_DEVICE_ID_PCI7248,
71                 .nsubdevs       = 2,
72         }, {
73                 .name           = "adl_pci7296",
74                 .device         = PCI_DEVICE_ID_PCI7296,
75                 .nsubdevs       = 4,
76         },
77 };
78
79 static const void *adl_pci7296_find_boardinfo(struct comedi_device *dev,
80                                               struct pci_dev *pcidev)
81 {
82         const struct adl_pci7296_boardinfo *board;
83         int i;
84
85         for (i = 0; i < ARRAY_SIZE(adl_pci7296_boards); i++) {
86                 board = &adl_pci7296_boards[i];
87                 if (pcidev->device == board->device)
88                         return board;
89         }
90         return NULL;
91 }
92
93 static int adl_pci7296_attach_pci(struct comedi_device *dev,
94                                   struct pci_dev *pcidev)
95 {
96         const struct adl_pci7296_boardinfo *board;
97         struct comedi_subdevice *s;
98         int ret;
99         int i;
100
101         comedi_set_hw_dev(dev, &pcidev->dev);
102
103         board = adl_pci7296_find_boardinfo(dev, pcidev);
104         if (!board)
105                 return -ENODEV;
106         dev->board_ptr = board;
107         dev->board_name = board->name;
108
109         ret = comedi_pci_enable(pcidev, dev->board_name);
110         if (ret)
111                 return ret;
112         dev->iobase = pci_resource_start(pcidev, 2);
113
114         /*
115          * One, two, or four subdevices are setup by this driver depending
116          * on the number of channels provided by the board. Each subdevice
117          * has 24 channels supported by the 8255 module.
118          */
119         ret = comedi_alloc_subdevices(dev, board->nsubdevs);
120         if (ret)
121                 return ret;
122
123         for (i = 0; i < board->nsubdevs; i++) {
124                 s = dev->subdevices + i;
125                 ret = subdev_8255_init(dev, s, NULL, dev->iobase + (i * 4));
126                 if (ret)
127                         return ret;
128         }
129
130         dev_info(dev->class_dev, "%s attached (%d digital i/o channels)\n",
131                 dev->board_name, board->nsubdevs * 24);
132
133         return 0;
134 }
135
136 static int adl_pci7296_attach(struct comedi_device *dev,
137                               struct comedi_devconfig *it)
138 {
139         dev_warn(dev->class_dev,
140                 "This driver does not support attach using comedi_config\n");
141
142         return -ENOSYS;
143 }
144
145 static void adl_pci7296_detach(struct comedi_device *dev)
146 {
147         struct pci_dev *pcidev = comedi_to_pci_dev(dev);
148         const struct adl_pci7296_boardinfo *board = comedi_board(dev);
149         struct comedi_subdevice *s;
150         int i;
151
152         if (dev->subdevices) {
153                 for (i = 0; i < board->nsubdevs; i++) {
154                         s = dev->subdevices + i;
155                         subdev_8255_cleanup(dev, s);
156                 }
157         }
158         if (pcidev) {
159                 if (dev->iobase)
160                         comedi_pci_disable(pcidev);
161         }
162 }
163
164 static struct comedi_driver adl_pci7296_driver = {
165         .driver_name    = "adl_pci7296",
166         .module         = THIS_MODULE,
167         .attach         = adl_pci7296_attach,
168         .attach_pci     = adl_pci7296_attach_pci,
169         .detach         = adl_pci7296_detach,
170 };
171
172 static int __devinit adl_pci7296_pci_probe(struct pci_dev *dev,
173                                            const struct pci_device_id *ent)
174 {
175         return comedi_pci_auto_config(dev, &adl_pci7296_driver);
176 }
177
178 static void __devexit adl_pci7296_pci_remove(struct pci_dev *dev)
179 {
180         comedi_pci_auto_unconfig(dev);
181 }
182
183 static DEFINE_PCI_DEVICE_TABLE(adl_pci7296_pci_table) = {
184         { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7224) },
185         { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7248) },
186         { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7296) },
187         { 0 }
188 };
189 MODULE_DEVICE_TABLE(pci, adl_pci7296_pci_table);
190
191 static struct pci_driver adl_pci7296_pci_driver = {
192         .name           = "adl_pci7296",
193         .id_table       = adl_pci7296_pci_table,
194         .probe          = adl_pci7296_pci_probe,
195         .remove         = __devexit_p(adl_pci7296_pci_remove),
196 };
197 module_comedi_pci_driver(adl_pci7296_driver, adl_pci7296_pci_driver);
198
199 MODULE_DESCRIPTION("ADLINK PCI-72xx Opto-22 Compatible Digital I/O Boards");
200 MODULE_AUTHOR("Comedi http://www.comedi.org");
201 MODULE_LICENSE("GPL");