3 functions for manipulating drivers
5 COMEDI - Linux Control and Measurement Device Interface
6 Copyright (C) 1997-2000 David A. Schleef <ds@schleef.org>
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.
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.
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.
24 #include <linux/device.h>
25 #include <linux/module.h>
26 #include <linux/errno.h>
27 #include <linux/kconfig.h>
28 #include <linux/kernel.h>
29 #include <linux/sched.h>
30 #include <linux/fcntl.h>
31 #include <linux/delay.h>
32 #include <linux/ioport.h>
34 #include <linux/slab.h>
35 #include <linux/highmem.h> /* for SuSE brokenness */
36 #include <linux/vmalloc.h>
37 #include <linux/cdev.h>
38 #include <linux/dma-mapping.h>
41 #include "comedidev.h"
42 #include "comedi_internal.h"
44 struct comedi_driver
*comedi_drivers
;
46 int comedi_set_hw_dev(struct comedi_device
*dev
, struct device
*hw_dev
)
48 if (hw_dev
== dev
->hw_dev
)
50 if (dev
->hw_dev
!= NULL
)
52 dev
->hw_dev
= get_device(hw_dev
);
55 EXPORT_SYMBOL_GPL(comedi_set_hw_dev
);
57 static void comedi_clear_hw_dev(struct comedi_device
*dev
)
59 put_device(dev
->hw_dev
);
63 int comedi_alloc_subdevices(struct comedi_device
*dev
, int num_subdevices
)
65 struct comedi_subdevice
*s
;
68 if (num_subdevices
< 1)
71 s
= kcalloc(num_subdevices
, sizeof(*s
), GFP_KERNEL
);
75 dev
->n_subdevices
= num_subdevices
;
77 for (i
= 0; i
< num_subdevices
; ++i
) {
78 s
= &dev
->subdevices
[i
];
81 s
->async_dma_dir
= DMA_NONE
;
82 spin_lock_init(&s
->spin_lock
);
87 EXPORT_SYMBOL_GPL(comedi_alloc_subdevices
);
89 static void cleanup_device(struct comedi_device
*dev
)
92 struct comedi_subdevice
*s
;
94 if (dev
->subdevices
) {
95 for (i
= 0; i
< dev
->n_subdevices
; i
++) {
96 s
= &dev
->subdevices
[i
];
97 comedi_free_subdevice_minor(s
);
99 comedi_buf_alloc(dev
, s
, 0);
103 kfree(dev
->subdevices
);
104 dev
->subdevices
= NULL
;
105 dev
->n_subdevices
= 0;
110 dev
->board_name
= NULL
;
111 dev
->board_ptr
= NULL
;
113 dev
->ioenabled
= false;
115 dev
->read_subdev
= NULL
;
116 dev
->write_subdev
= NULL
;
119 comedi_clear_hw_dev(dev
);
122 static void __comedi_device_detach(struct comedi_device
*dev
)
124 dev
->attached
= false;
126 dev
->driver
->detach(dev
);
128 dev_warn(dev
->class_dev
,
129 "BUG: dev->driver=NULL in comedi_device_detach()\n");
133 void comedi_device_detach(struct comedi_device
*dev
)
137 __comedi_device_detach(dev
);
140 static int poll_invalid(struct comedi_device
*dev
, struct comedi_subdevice
*s
)
145 int insn_inval(struct comedi_device
*dev
, struct comedi_subdevice
*s
,
146 struct comedi_insn
*insn
, unsigned int *data
)
151 static int insn_rw_emulate_bits(struct comedi_device
*dev
,
152 struct comedi_subdevice
*s
,
153 struct comedi_insn
*insn
, unsigned int *data
)
155 struct comedi_insn new_insn
;
157 static const unsigned channels_per_bitfield
= 32;
159 unsigned chan
= CR_CHAN(insn
->chanspec
);
160 const unsigned base_bitfield_channel
=
161 (chan
< channels_per_bitfield
) ? 0 : chan
;
162 unsigned int new_data
[2];
163 memset(new_data
, 0, sizeof(new_data
));
164 memset(&new_insn
, 0, sizeof(new_insn
));
165 new_insn
.insn
= INSN_BITS
;
166 new_insn
.chanspec
= base_bitfield_channel
;
168 new_insn
.subdev
= insn
->subdev
;
170 if (insn
->insn
== INSN_WRITE
) {
171 if (!(s
->subdev_flags
& SDF_WRITABLE
))
173 new_data
[0] = 1 << (chan
- base_bitfield_channel
); /* mask */
174 new_data
[1] = data
[0] ? (1 << (chan
- base_bitfield_channel
))
178 ret
= s
->insn_bits(dev
, s
, &new_insn
, new_data
);
182 if (insn
->insn
== INSN_READ
)
183 data
[0] = (new_data
[1] >> (chan
- base_bitfield_channel
)) & 1;
188 static int __comedi_device_postconfig_async(struct comedi_device
*dev
,
189 struct comedi_subdevice
*s
)
191 struct comedi_async
*async
;
192 unsigned int buf_size
;
195 if ((s
->subdev_flags
& (SDF_CMD_READ
| SDF_CMD_WRITE
)) == 0) {
196 dev_warn(dev
->class_dev
,
197 "async subdevices must support SDF_CMD_READ or SDF_CMD_WRITE\n");
200 if (!s
->do_cmdtest
) {
201 dev_warn(dev
->class_dev
,
202 "async subdevices must have a do_cmdtest() function\n");
206 async
= kzalloc(sizeof(*async
), GFP_KERNEL
);
210 init_waitqueue_head(&async
->wait_head
);
211 async
->subdevice
= s
;
214 async
->max_bufsize
= comedi_default_buf_maxsize_kb
* 1024;
215 buf_size
= comedi_default_buf_size_kb
* 1024;
216 if (buf_size
> async
->max_bufsize
)
217 buf_size
= async
->max_bufsize
;
219 if (comedi_buf_alloc(dev
, s
, buf_size
) < 0) {
220 dev_warn(dev
->class_dev
, "Buffer allocation failed\n");
224 ret
= s
->buf_change(dev
, s
, buf_size
);
229 comedi_alloc_subdevice_minor(s
);
234 static int __comedi_device_postconfig(struct comedi_device
*dev
)
236 struct comedi_subdevice
*s
;
240 for (i
= 0; i
< dev
->n_subdevices
; i
++) {
241 s
= &dev
->subdevices
[i
];
243 if (s
->type
== COMEDI_SUBD_UNUSED
)
246 if (s
->len_chanlist
== 0)
250 ret
= __comedi_device_postconfig_async(dev
, s
);
255 if (!s
->range_table
&& !s
->range_table_list
)
256 s
->range_table
= &range_unknown
;
258 if (!s
->insn_read
&& s
->insn_bits
)
259 s
->insn_read
= insn_rw_emulate_bits
;
260 if (!s
->insn_write
&& s
->insn_bits
)
261 s
->insn_write
= insn_rw_emulate_bits
;
264 s
->insn_read
= insn_inval
;
266 s
->insn_write
= insn_inval
;
268 s
->insn_bits
= insn_inval
;
270 s
->insn_config
= insn_inval
;
273 s
->poll
= poll_invalid
;
279 /* do a little post-config cleanup */
280 /* called with module refcount incremented, decrements it */
281 static int comedi_device_postconfig(struct comedi_device
*dev
)
283 int ret
= __comedi_device_postconfig(dev
);
284 module_put(dev
->driver
->module
);
286 __comedi_device_detach(dev
);
289 if (!dev
->board_name
) {
290 dev_warn(dev
->class_dev
, "BUG: dev->board_name=NULL\n");
291 dev
->board_name
= "BUG";
294 dev
->attached
= true;
299 * Generic recognize function for drivers that register their supported
302 * 'driv->board_name' points to a 'const char *' member within the
303 * zeroth element of an array of some private board information
304 * structure, say 'struct foo_board' containing a member 'const char
305 * *board_name' that is initialized to point to a board name string that
306 * is one of the candidates matched against this function's 'name'
309 * 'driv->offset' is the size of the private board information
310 * structure, say 'sizeof(struct foo_board)', and 'driv->num_names' is
311 * the length of the array of private board information structures.
313 * If one of the board names in the array of private board information
314 * structures matches the name supplied to this function, the function
315 * returns a pointer to the pointer to the board name, otherwise it
316 * returns NULL. The return value ends up in the 'board_ptr' member of
317 * a 'struct comedi_device' that the low-level comedi driver's
318 * 'attach()' hook can convert to a point to a particular element of its
319 * array of private board information structures by subtracting the
320 * offset of the member that points to the board name. (No subtraction
321 * is required if the board name pointer is the first member of the
322 * private board information structure, which is generally the case.)
324 static void *comedi_recognize(struct comedi_driver
*driv
, const char *name
)
326 char **name_ptr
= (char **)driv
->board_name
;
329 for (i
= 0; i
< driv
->num_names
; i
++) {
330 if (strcmp(*name_ptr
, name
) == 0)
332 name_ptr
= (void *)name_ptr
+ driv
->offset
;
338 static void comedi_report_boards(struct comedi_driver
*driv
)
341 const char *const *name_ptr
;
343 pr_info("comedi: valid board names for %s driver are:\n",
346 name_ptr
= driv
->board_name
;
347 for (i
= 0; i
< driv
->num_names
; i
++) {
348 pr_info(" %s\n", *name_ptr
);
349 name_ptr
= (const char **)((char *)name_ptr
+ driv
->offset
);
352 if (driv
->num_names
== 0)
353 pr_info(" %s\n", driv
->driver_name
);
356 int comedi_device_attach(struct comedi_device
*dev
, struct comedi_devconfig
*it
)
358 struct comedi_driver
*driv
;
364 for (driv
= comedi_drivers
; driv
; driv
= driv
->next
) {
365 if (!try_module_get(driv
->module
))
367 if (driv
->num_names
) {
368 dev
->board_ptr
= comedi_recognize(driv
, it
->board_name
);
371 } else if (strcmp(driv
->driver_name
, it
->board_name
) == 0)
373 module_put(driv
->module
);
376 /* recognize has failed if we get here */
377 /* report valid board names before returning error */
378 for (driv
= comedi_drivers
; driv
; driv
= driv
->next
) {
379 if (!try_module_get(driv
->module
))
381 comedi_report_boards(driv
);
382 module_put(driv
->module
);
386 if (driv
->attach
== NULL
) {
387 /* driver does not support manual configuration */
388 dev_warn(dev
->class_dev
,
389 "driver '%s' does not support attach using comedi_config\n",
391 module_put(driv
->module
);
394 /* initialize dev->driver here so
395 * comedi_error() can be called from attach */
397 ret
= driv
->attach(dev
, it
);
399 module_put(dev
->driver
->module
);
400 __comedi_device_detach(dev
);
403 return comedi_device_postconfig(dev
);
406 int comedi_auto_config(struct device
*hardware_device
,
407 struct comedi_driver
*driver
, unsigned long context
)
410 struct comedi_device
*comedi_dev
;
413 if (!driver
->auto_attach
) {
414 dev_warn(hardware_device
,
415 "BUG! comedi driver '%s' has no auto_attach handler\n",
416 driver
->driver_name
);
420 minor
= comedi_alloc_board_minor(hardware_device
);
424 comedi_dev
= comedi_dev_from_minor(minor
);
426 mutex_lock(&comedi_dev
->mutex
);
427 if (comedi_dev
->attached
)
429 else if (!try_module_get(driver
->module
))
432 comedi_set_hw_dev(comedi_dev
, hardware_device
);
433 comedi_dev
->driver
= driver
;
434 ret
= driver
->auto_attach(comedi_dev
, context
);
436 module_put(driver
->module
);
437 __comedi_device_detach(comedi_dev
);
439 ret
= comedi_device_postconfig(comedi_dev
);
442 mutex_unlock(&comedi_dev
->mutex
);
445 comedi_free_board_minor(minor
);
448 EXPORT_SYMBOL_GPL(comedi_auto_config
);
450 void comedi_auto_unconfig(struct device
*hardware_device
)
454 if (hardware_device
== NULL
)
456 minor
= comedi_find_board_minor(hardware_device
);
459 comedi_free_board_minor(minor
);
461 EXPORT_SYMBOL_GPL(comedi_auto_unconfig
);
463 int comedi_driver_register(struct comedi_driver
*driver
)
465 driver
->next
= comedi_drivers
;
466 comedi_drivers
= driver
;
470 EXPORT_SYMBOL(comedi_driver_register
);
472 int comedi_driver_unregister(struct comedi_driver
*driver
)
474 struct comedi_driver
*prev
;
477 /* check for devices using this driver */
478 for (i
= 0; i
< COMEDI_NUM_BOARD_MINORS
; i
++) {
479 struct comedi_device
*dev
= comedi_dev_from_minor(i
);
484 mutex_lock(&dev
->mutex
);
485 if (dev
->attached
&& dev
->driver
== driver
) {
487 dev_warn(dev
->class_dev
,
488 "BUG! detaching device with use_count=%d\n",
490 comedi_device_detach(dev
);
492 mutex_unlock(&dev
->mutex
);
495 if (comedi_drivers
== driver
) {
496 comedi_drivers
= driver
->next
;
500 for (prev
= comedi_drivers
; prev
->next
; prev
= prev
->next
) {
501 if (prev
->next
== driver
) {
502 prev
->next
= driver
->next
;
508 EXPORT_SYMBOL(comedi_driver_unregister
);