staging: comedi: remove the comed_alloc_subdevices "allocation failed" messages
[deliverable/linux.git] / drivers / staging / comedi / drivers / amplc_pc263.c
CommitLineData
cfd02b71
IA
1/*
2 comedi/drivers/amplc_pc263.c
3 Driver for Amplicon PC263 and PCI263 relay boards.
4
5 Copyright (C) 2002 MEV Ltd. <http://www.mev.co.uk/>
6
7 COMEDI - Linux Control and Measurement Device Interface
8 Copyright (C) 2000 David A. Schleef <ds@schleef.org>
9
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23
24*/
25/*
26Driver: amplc_pc263
27Description: Amplicon PC263, PCI263
28Author: Ian Abbott <abbotti@mev.co.uk>
29Devices: [Amplicon] PC263 (pc263), PCI263 (pci263 or amplc_pc263)
30Updated: Wed, 22 Oct 2008 14:10:53 +0100
31Status: works
32
33Configuration options - PC263:
34 [0] - I/O port base address
35
36Configuration options - PCI263:
37 [0] - PCI bus of device (optional)
38 [1] - PCI slot of device (optional)
39 If bus/slot is not specified, the first available PCI device will be
40 used.
41
42Each board appears as one subdevice, with 16 digital outputs, each
43connected to a reed-relay. Relay contacts are closed when output is 1.
44The state of the outputs can be read.
45*/
46
47#include "../comedidev.h"
48
cfd02b71
IA
49#define PC263_DRIVER_NAME "amplc_pc263"
50
51/* PCI263 PCI configuration register information */
52#define PCI_VENDOR_ID_AMPLICON 0x14dc
53#define PCI_DEVICE_ID_AMPLICON_PCI263 0x000c
54#define PCI_DEVICE_ID_INVALID 0xffff
55
56/* PC263 / PCI263 registers */
57#define PC263_IO_SIZE 2
58
59/*
60 * Board descriptions for Amplicon PC263 / PCI263.
61 */
62
63enum pc263_bustype { isa_bustype, pci_bustype };
64enum pc263_model { pc263_model, pci263_model, anypci_model };
65
4beb86c2 66struct pc263_board {
cfd02b71 67 const char *name;
cfd02b71
IA
68 unsigned short devid;
69 enum pc263_bustype bustype;
70 enum pc263_model model;
4beb86c2
BP
71};
72static const struct pc263_board pc263_boards[] = {
b4843c19 73#if IS_ENABLED(CONFIG_COMEDI_AMPLC_PC263_ISA)
cfd02b71 74 {
b4843c19 75 .name = "pc263",
b4843c19
IA
76 .bustype = isa_bustype,
77 .model = pc263_model,
78 },
3e6be97e 79#endif
b4843c19 80#if IS_ENABLED(CONFIG_COMEDI_AMPLC_PC263_PCI)
cfd02b71 81 {
b4843c19 82 .name = "pci263",
b4843c19
IA
83 .devid = PCI_DEVICE_ID_AMPLICON_PCI263,
84 .bustype = pci_bustype,
85 .model = pci263_model,
86 },
cfd02b71 87 {
b4843c19 88 .name = PC263_DRIVER_NAME,
b4843c19
IA
89 .devid = PCI_DEVICE_ID_INVALID,
90 .bustype = pci_bustype,
91 .model = anypci_model, /* wildcard */
92 },
cfd02b71
IA
93#endif
94};
95
cfd02b71
IA
96/* this structure is for data unique to this hardware driver. If
97 several hardware drivers keep similar information in this structure,
abdedefe
KAP
98 feel free to suggest moving the variable to the struct comedi_device struct.
99*/
cd60d1ec 100struct pc263_private {
cfd02b71
IA
101 /* PCI device. */
102 struct pci_dev *pci_dev;
cd60d1ec 103};
cfd02b71 104
d8967b6e
IA
105/*
106 * This function looks for a board matching the supplied PCI device.
107 */
108static const struct pc263_board *pc263_find_pci_board(struct pci_dev *pci_dev)
109{
110 unsigned int i;
111
112 for (i = 0; i < ARRAY_SIZE(pc263_boards); i++)
113 if (pc263_boards[i].bustype == pci_bustype &&
114 pci_dev->device == pc263_boards[i].devid)
115 return &pc263_boards[i];
116 return NULL;
117}
118
119
cfd02b71
IA
120/*
121 * This function looks for a PCI device matching the requested board name,
122 * bus and slot.
123 */
7ac75ba4
IA
124static struct pci_dev *
125pc263_find_pci(struct comedi_device *dev, int bus, int slot)
cfd02b71 126{
04d66968 127 const struct pc263_board *thisboard = comedi_board(dev);
cfd02b71
IA
128 struct pci_dev *pci_dev = NULL;
129
cfd02b71
IA
130 /* Look for matching PCI device. */
131 for (pci_dev = pci_get_device(PCI_VENDOR_ID_AMPLICON, PCI_ANY_ID, NULL);
0a85b6f0
MT
132 pci_dev != NULL;
133 pci_dev = pci_get_device(PCI_VENDOR_ID_AMPLICON,
134 PCI_ANY_ID, pci_dev)) {
cfd02b71
IA
135 /* If bus/slot specified, check them. */
136 if (bus || slot) {
137 if (bus != pci_dev->bus->number
0a85b6f0 138 || slot != PCI_SLOT(pci_dev->devfn))
cfd02b71
IA
139 continue;
140 }
141 if (thisboard->model == anypci_model) {
d8967b6e
IA
142 /* Wildcard board matches any supported PCI board. */
143 const struct pc263_board *foundboard;
144 foundboard = pc263_find_pci_board(pci_dev);
145 if (foundboard == NULL)
cfd02b71 146 continue;
d8967b6e
IA
147 /* Replace wildcard board_ptr. */
148 dev->board_ptr = thisboard = foundboard;
cfd02b71
IA
149 } else {
150 /* Match specific model name. */
151 if (pci_dev->device != thisboard->devid)
152 continue;
153 }
154
155 /* Found a match. */
7ac75ba4 156 return pci_dev;
cfd02b71
IA
157 }
158 /* No match found. */
159 if (bus || slot) {
03668b10
IA
160 dev_err(dev->class_dev,
161 "error! no %s found at pci %02x:%02x!\n",
162 thisboard->name, bus, slot);
cfd02b71 163 } else {
03668b10
IA
164 dev_err(dev->class_dev, "error! no %s found!\n",
165 thisboard->name);
cfd02b71 166 }
7ac75ba4 167 return NULL;
cfd02b71 168}
ba7914cd
IA
169/*
170 * This function checks and requests an I/O region, reporting an error
171 * if there is a conflict.
172 */
03668b10 173static int pc263_request_region(struct comedi_device *dev, unsigned long from,
ba7914cd
IA
174 unsigned long extent)
175{
176 if (!from || !request_region(from, extent, PC263_DRIVER_NAME)) {
03668b10
IA
177 dev_err(dev->class_dev, "I/O port conflict (%#lx,%lu)!\n",
178 from, extent);
ba7914cd
IA
179 return -EIO;
180 }
181 return 0;
182}
183
184static int pc263_do_insn_bits(struct comedi_device *dev,
185 struct comedi_subdevice *s,
186 struct comedi_insn *insn, unsigned int *data)
187{
188 if (insn->n != 2)
189 return -EINVAL;
190
191 /* The insn data is a mask in data[0] and the new data
192 * in data[1], each channel cooresponding to a bit. */
193 if (data[0]) {
194 s->state &= ~data[0];
195 s->state |= data[0] & data[1];
196 /* Write out the new digital output lines */
197 outb(s->state & 0xFF, dev->iobase);
198 outb(s->state >> 8, dev->iobase + 1);
199 }
200 return 2;
201}
cfd02b71 202
03668b10
IA
203static void pc263_report_attach(struct comedi_device *dev)
204{
04d66968
IA
205 const struct pc263_board *thisboard = comedi_board(dev);
206 struct pc263_private *devpriv = dev->private;
03668b10
IA
207 char tmpbuf[40];
208
209 if (IS_ENABLED(CONFIG_COMEDI_AMPLC_PC263_ISA) &&
210 thisboard->bustype == isa_bustype)
211 snprintf(tmpbuf, sizeof(tmpbuf), "(base %#lx) ", dev->iobase);
212 else if (IS_ENABLED(CONFIG_COMEDI_AMPLC_PC263_PCI) &&
213 thisboard->bustype == pci_bustype)
214 snprintf(tmpbuf, sizeof(tmpbuf), "(pci %s) ",
215 pci_name(devpriv->pci_dev));
216 else
217 tmpbuf[0] = '\0';
218 dev_info(dev->class_dev, "%s %sattached\n", dev->board_name, tmpbuf);
219}
220
d8967b6e
IA
221static int pc263_common_attach(struct comedi_device *dev, unsigned long iobase)
222{
223 const struct pc263_board *thisboard = comedi_board(dev);
224 struct comedi_subdevice *s;
225 int ret;
226
227 dev->board_name = thisboard->name;
228 dev->iobase = iobase;
229
2f0b9d08 230 ret = comedi_alloc_subdevices(dev, 1);
0e4039f3 231 if (ret < 0)
d8967b6e 232 return ret;
d8967b6e
IA
233
234 s = dev->subdevices + 0;
235 /* digital output subdevice */
236 s->type = COMEDI_SUBD_DO;
237 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
238 s->n_chan = 16;
239 s->maxdata = 1;
240 s->range_table = &range_digital;
241 s->insn_bits = pc263_do_insn_bits;
242 /* read initial relay state */
243 s->state = inb(dev->iobase) | (inb(dev->iobase + 1) << 8);
244
245 pc263_report_attach(dev);
246 return 1;
247}
248
249static int pc263_pci_common_attach(struct comedi_device *dev,
250 struct pci_dev *pci_dev)
251{
252 struct pc263_private *devpriv = dev->private;
253 unsigned long iobase;
254 int ret;
255
256 devpriv->pci_dev = pci_dev;
257 ret = comedi_pci_enable(pci_dev, PC263_DRIVER_NAME);
258 if (ret < 0) {
259 dev_err(dev->class_dev,
260 "error! cannot enable PCI device and request regions!\n");
261 return ret;
262 }
263 iobase = pci_resource_start(pci_dev, 2);
264 return pc263_common_attach(dev, iobase);
265}
266
cfd02b71
IA
267/*
268 * Attach is called by the Comedi core to configure the driver
269 * for a particular board. If you specified a board_name array
270 * in the driver structure, dev->board_ptr contains that
271 * address.
272 */
da91b269 273static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it)
cfd02b71 274{
04d66968 275 const struct pc263_board *thisboard = comedi_board(dev);
cfd02b71
IA
276 int ret;
277
03668b10 278 dev_info(dev->class_dev, PC263_DRIVER_NAME ": attach\n");
b4843c19
IA
279
280 /* Process options and reserve resources according to bus type. */
281 if (IS_ENABLED(CONFIG_COMEDI_AMPLC_PC263_ISA) &&
282 thisboard->bustype == isa_bustype) {
d8967b6e 283 unsigned long iobase = it->options[0];
03668b10 284 ret = pc263_request_region(dev, iobase, PC263_IO_SIZE);
b4843c19
IA
285 if (ret < 0)
286 return ret;
d8967b6e 287 return pc263_common_attach(dev, iobase);
b4843c19
IA
288 } else if (IS_ENABLED(CONFIG_COMEDI_AMPLC_PC263_PCI) &&
289 thisboard->bustype == pci_bustype) {
d8967b6e 290 struct pci_dev *pci_dev;
b4843c19
IA
291 int bus, slot;
292
293 ret = alloc_private(dev, sizeof(struct pc263_private));
294 if (ret < 0) {
03668b10 295 dev_err(dev->class_dev, "error! out of memory!\n");
b4843c19
IA
296 return ret;
297 }
cfd02b71
IA
298 bus = it->options[0];
299 slot = it->options[1];
7ac75ba4
IA
300 pci_dev = pc263_find_pci(dev, bus, slot);
301 if (pci_dev == NULL)
302 return -EIO;
d8967b6e 303 return pc263_pci_common_attach(dev, pci_dev);
b4843c19 304 } else {
03668b10
IA
305 dev_err(dev->class_dev, PC263_DRIVER_NAME
306 ": BUG! cannot determine board type!\n");
b4843c19 307 return -EINVAL;
cfd02b71 308 }
d8967b6e
IA
309}
310/*
311 * The attach_pci hook (if non-NULL) is called at PCI probe time in preference
312 * to the "manual" attach hook. dev->board_ptr is NULL on entry. There should
313 * be a board entry matching the supplied PCI device.
314 */
315static int __devinit pc263_attach_pci(struct comedi_device *dev,
316 struct pci_dev *pci_dev)
317{
318 int ret;
b4843c19 319
d8967b6e
IA
320 if (!IS_ENABLED(CONFIG_COMEDI_AMPLC_PC263_PCI))
321 return -EINVAL;
cfd02b71 322
d8967b6e
IA
323 dev_info(dev->class_dev, PC263_DRIVER_NAME ": attach pci %s\n",
324 pci_name(pci_dev));
325 ret = alloc_private(dev, sizeof(struct pc263_private));
c3744138 326 if (ret < 0) {
03668b10 327 dev_err(dev->class_dev, "error! out of memory!\n");
cfd02b71
IA
328 return ret;
329 }
d8967b6e
IA
330 dev->board_ptr = pc263_find_pci_board(pci_dev);
331 if (dev->board_ptr == NULL) {
332 dev_err(dev->class_dev, "BUG! cannot determine board type!\n");
333 return -EINVAL;
334 }
335 return pc263_pci_common_attach(dev, pci_dev);
cfd02b71
IA
336}
337
484ecc95 338static void pc263_detach(struct comedi_device *dev)
cfd02b71 339{
04d66968
IA
340 struct pc263_private *devpriv = dev->private;
341
b4843c19
IA
342 if (IS_ENABLED(CONFIG_COMEDI_AMPLC_PC263_PCI) && devpriv &&
343 devpriv->pci_dev) {
344 if (dev->iobase)
345 comedi_pci_disable(devpriv->pci_dev);
346 pci_dev_put(devpriv->pci_dev);
347 } else if (IS_ENABLED(CONFIG_COMEDI_AMPLC_PC263_ISA)) {
348 if (dev->iobase)
349 release_region(dev->iobase, PC263_IO_SIZE);
cfd02b71 350 }
cfd02b71
IA
351}
352
353/*
ba7914cd
IA
354 * The struct comedi_driver structure tells the Comedi core module
355 * which functions to call to configure/deconfigure (attach/detach)
356 * the board, and also about the kernel module that contains
357 * the device code.
cfd02b71 358 */
ba7914cd
IA
359static struct comedi_driver amplc_pc263_driver = {
360 .driver_name = PC263_DRIVER_NAME,
361 .module = THIS_MODULE,
362 .attach = pc263_attach,
d8967b6e 363 .attach_pci = pc263_attach_pci,
ba7914cd
IA
364 .detach = pc263_detach,
365 .board_name = &pc263_boards[0].name,
366 .offset = sizeof(struct pc263_board),
367 .num_names = ARRAY_SIZE(pc263_boards),
368};
cfd02b71 369
b4843c19 370#if IS_ENABLED(CONFIG_COMEDI_AMPLC_PC263_PCI)
ba7914cd
IA
371static DEFINE_PCI_DEVICE_TABLE(pc263_pci_table) = {
372 { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI263) },
373 {0}
374};
375MODULE_DEVICE_TABLE(pci, pc263_pci_table);
376
40372f5f 377static int __devinit amplc_pc263_pci_probe(struct pci_dev *dev,
727b286b
AT
378 const struct pci_device_id
379 *ent)
380{
40372f5f 381 return comedi_pci_auto_config(dev, &amplc_pc263_driver);
727b286b
AT
382}
383
40372f5f 384static void __devexit amplc_pc263_pci_remove(struct pci_dev *dev)
727b286b
AT
385{
386 comedi_pci_auto_unconfig(dev);
387}
388
40372f5f
IA
389static struct pci_driver amplc_pc263_pci_driver = {
390 .name = PC263_DRIVER_NAME,
727b286b 391 .id_table = pc263_pci_table,
40372f5f
IA
392 .probe = &amplc_pc263_pci_probe,
393 .remove = __devexit_p(&amplc_pc263_pci_remove)
727b286b 394};
40372f5f 395module_comedi_pci_driver(amplc_pc263_driver, amplc_pc263_pci_driver);
cfd02b71 396#else
40372f5f 397module_comedi_driver(amplc_pc263_driver);
cfd02b71 398#endif
90f703d3
AT
399
400MODULE_AUTHOR("Comedi http://www.comedi.org");
401MODULE_DESCRIPTION("Comedi low-level driver");
402MODULE_LICENSE("GPL");
This page took 0.37883 seconds and 5 git commands to generate.