staging: comedi: wake up async waiters when become non-busy
[linux-2.6-block.git] / drivers / staging / comedi / drivers.c
CommitLineData
ed9eccbe
DS
1/*
2 module/drivers.c
3 functions for manipulating drivers
4
5 COMEDI - Linux Control and Measurement Device Interface
6 Copyright (C) 1997-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.
ed9eccbe
DS
17*/
18
ed9eccbe
DS
19#include <linux/device.h>
20#include <linux/module.h>
ed9eccbe 21#include <linux/errno.h>
78b10615 22#include <linux/kconfig.h>
ed9eccbe
DS
23#include <linux/kernel.h>
24#include <linux/sched.h>
25#include <linux/fcntl.h>
ed9eccbe
DS
26#include <linux/ioport.h>
27#include <linux/mm.h>
28#include <linux/slab.h>
ed9eccbe
DS
29#include <linux/highmem.h> /* for SuSE brokenness */
30#include <linux/vmalloc.h>
31#include <linux/cdev.h>
32#include <linux/dma-mapping.h>
5617f9da 33#include <linux/io.h>
3d1fe3f7 34#include <linux/interrupt.h>
9ff8b151 35#include <linux/firmware.h>
ed9eccbe 36
242e7ad9 37#include "comedidev.h"
3a5fa275 38#include "comedi_internal.h"
242e7ad9 39
139dfbdf 40struct comedi_driver *comedi_drivers;
c383e2d6 41DEFINE_MUTEX(comedi_drivers_list_lock);
ed9eccbe 42
da717511
IA
43int comedi_set_hw_dev(struct comedi_device *dev, struct device *hw_dev)
44{
de06d7c6
IA
45 if (hw_dev == dev->hw_dev)
46 return 0;
47 if (dev->hw_dev != NULL)
48 return -EEXIST;
da717511 49 dev->hw_dev = get_device(hw_dev);
da717511
IA
50 return 0;
51}
52EXPORT_SYMBOL_GPL(comedi_set_hw_dev);
53
de06d7c6
IA
54static void comedi_clear_hw_dev(struct comedi_device *dev)
55{
56 put_device(dev->hw_dev);
57 dev->hw_dev = NULL;
58}
59
54db996e
HS
60/**
61 * comedi_alloc_devpriv() - Allocate memory for the device private data.
62 * @dev: comedi_device struct
63 * @size: size of the memory to allocate
64 */
65void *comedi_alloc_devpriv(struct comedi_device *dev, size_t size)
66{
67 dev->private = kzalloc(size, GFP_KERNEL);
68 return dev->private;
69}
70EXPORT_SYMBOL_GPL(comedi_alloc_devpriv);
71
8b9ba6e5 72int comedi_alloc_subdevices(struct comedi_device *dev, int num_subdevices)
2f0b9d08 73{
03afcf47 74 struct comedi_subdevice *s;
8b9ba6e5 75 int i;
2f0b9d08 76
7f801c41
HS
77 if (num_subdevices < 1)
78 return -EINVAL;
03afcf47
HS
79
80 s = kcalloc(num_subdevices, sizeof(*s), GFP_KERNEL);
81 if (!s)
2f0b9d08 82 return -ENOMEM;
03afcf47 83 dev->subdevices = s;
fba1d0fa 84 dev->n_subdevices = num_subdevices;
03afcf47 85
2f0b9d08 86 for (i = 0; i < num_subdevices; ++i) {
5e4c58ce 87 s = &dev->subdevices[i];
03afcf47 88 s->device = dev;
90a35c15 89 s->index = i;
03afcf47
HS
90 s->async_dma_dir = DMA_NONE;
91 spin_lock_init(&s->spin_lock);
92 s->minor = -1;
2f0b9d08
HS
93 }
94 return 0;
95}
96EXPORT_SYMBOL_GPL(comedi_alloc_subdevices);
97
3867e20d 98static void comedi_device_detach_cleanup(struct comedi_device *dev)
ed9eccbe
DS
99{
100 int i;
34c43922 101 struct comedi_subdevice *s;
ed9eccbe
DS
102
103 if (dev->subdevices) {
104 for (i = 0; i < dev->n_subdevices; i++) {
5e4c58ce 105 s = &dev->subdevices[i];
588ba6dc
HS
106 if (s->runflags & SRF_FREE_SPRIV)
107 kfree(s->private);
ed9eccbe
DS
108 comedi_free_subdevice_minor(s);
109 if (s->async) {
110 comedi_buf_alloc(dev, s, 0);
111 kfree(s->async);
112 }
113 }
114 kfree(dev->subdevices);
115 dev->subdevices = NULL;
116 dev->n_subdevices = 0;
117 }
dedd1325
BP
118 kfree(dev->private);
119 dev->private = NULL;
7029a874 120 dev->driver = NULL;
ed9eccbe
DS
121 dev->board_name = NULL;
122 dev->board_ptr = NULL;
123 dev->iobase = 0;
316f97f1 124 dev->iolen = 0;
00ca6884 125 dev->ioenabled = false;
ed9eccbe
DS
126 dev->irq = 0;
127 dev->read_subdev = NULL;
128 dev->write_subdev = NULL;
129 dev->open = NULL;
130 dev->close = NULL;
de06d7c6 131 comedi_clear_hw_dev(dev);
ed9eccbe
DS
132}
133
016599f5 134void comedi_device_detach(struct comedi_device *dev)
ed9eccbe 135{
bf11c134 136 down_write(&dev->attach_lock);
a7401cdd 137 dev->attached = false;
5617f9da 138 if (dev->driver)
ed9eccbe 139 dev->driver->detach(dev);
3867e20d 140 comedi_device_detach_cleanup(dev);
bf11c134 141 up_write(&dev->attach_lock);
ed9eccbe
DS
142}
143
01fca378 144static int poll_invalid(struct comedi_device *dev, struct comedi_subdevice *s)
ed9eccbe 145{
01fca378 146 return -EINVAL;
ed9eccbe
DS
147}
148
01fca378
HS
149int insn_inval(struct comedi_device *dev, struct comedi_subdevice *s,
150 struct comedi_insn *insn, unsigned int *data)
ed9eccbe 151{
01fca378 152 return -EINVAL;
ed9eccbe
DS
153}
154
e523c6c8
HS
155/**
156 * comedi_dio_insn_config() - boilerplate (*insn_config) for DIO subdevices.
157 * @dev: comedi_device struct
158 * @s: comedi_subdevice struct
159 * @insn: comedi_insn struct
160 * @data: parameters for the @insn
161 * @mask: io_bits mask for grouped channels
162 */
163int comedi_dio_insn_config(struct comedi_device *dev,
164 struct comedi_subdevice *s,
165 struct comedi_insn *insn,
166 unsigned int *data,
167 unsigned int mask)
168{
169 unsigned int chan_mask = 1 << CR_CHAN(insn->chanspec);
170
171 if (!mask)
172 mask = chan_mask;
173
174 switch (data[0]) {
175 case INSN_CONFIG_DIO_INPUT:
176 s->io_bits &= ~mask;
177 break;
178
179 case INSN_CONFIG_DIO_OUTPUT:
180 s->io_bits |= mask;
181 break;
182
183 case INSN_CONFIG_DIO_QUERY:
184 data[1] = (s->io_bits & mask) ? COMEDI_OUTPUT : COMEDI_INPUT;
185 return insn->n;
186
187 default:
188 return -EINVAL;
189 }
190
191 return 0;
192}
193EXPORT_SYMBOL_GPL(comedi_dio_insn_config);
194
05e60b13
HS
195/**
196 * comedi_dio_update_state() - update the internal state of DIO subdevices.
197 * @s: comedi_subdevice struct
198 * @data: the channel mask and bits to update
199 */
200unsigned int comedi_dio_update_state(struct comedi_subdevice *s,
201 unsigned int *data)
202{
203 unsigned int chanmask = (s->n_chan < 32) ? ((1 << s->n_chan) - 1)
204 : 0xffffffff;
205 unsigned int mask = data[0] & chanmask;
206 unsigned int bits = data[1];
207
208 if (mask) {
209 s->state &= ~mask;
210 s->state |= (bits & mask);
211 }
212
213 return mask;
214}
215EXPORT_SYMBOL_GPL(comedi_dio_update_state);
216
01fca378
HS
217static int insn_rw_emulate_bits(struct comedi_device *dev,
218 struct comedi_subdevice *s,
219 struct comedi_insn *insn, unsigned int *data)
ed9eccbe 220{
01fca378
HS
221 struct comedi_insn new_insn;
222 int ret;
223 static const unsigned channels_per_bitfield = 32;
ed9eccbe 224
01fca378
HS
225 unsigned chan = CR_CHAN(insn->chanspec);
226 const unsigned base_bitfield_channel =
227 (chan < channels_per_bitfield) ? 0 : chan;
228 unsigned int new_data[2];
229 memset(new_data, 0, sizeof(new_data));
230 memset(&new_insn, 0, sizeof(new_insn));
231 new_insn.insn = INSN_BITS;
232 new_insn.chanspec = base_bitfield_channel;
233 new_insn.n = 2;
234 new_insn.subdev = insn->subdev;
ed9eccbe 235
01fca378
HS
236 if (insn->insn == INSN_WRITE) {
237 if (!(s->subdev_flags & SDF_WRITABLE))
238 return -EINVAL;
239 new_data[0] = 1 << (chan - base_bitfield_channel); /* mask */
240 new_data[1] = data[0] ? (1 << (chan - base_bitfield_channel))
241 : 0; /* bits */
ed9eccbe
DS
242 }
243
01fca378
HS
244 ret = s->insn_bits(dev, s, &new_insn, new_data);
245 if (ret < 0)
246 return ret;
ed9eccbe 247
01fca378
HS
248 if (insn->insn == INSN_READ)
249 data[0] = (new_data[1] >> (chan - base_bitfield_channel)) & 1;
250
251 return 1;
ed9eccbe
DS
252}
253
40f58a65
HS
254static int __comedi_device_postconfig_async(struct comedi_device *dev,
255 struct comedi_subdevice *s)
256{
257 struct comedi_async *async;
258 unsigned int buf_size;
259 int ret;
260
57b71c3e
HS
261 if ((s->subdev_flags & (SDF_CMD_READ | SDF_CMD_WRITE)) == 0) {
262 dev_warn(dev->class_dev,
263 "async subdevices must support SDF_CMD_READ or SDF_CMD_WRITE\n");
264 return -EINVAL;
265 }
266 if (!s->do_cmdtest) {
267 dev_warn(dev->class_dev,
268 "async subdevices must have a do_cmdtest() function\n");
269 return -EINVAL;
270 }
40f58a65
HS
271
272 async = kzalloc(sizeof(*async), GFP_KERNEL);
78110bb8 273 if (!async)
40f58a65 274 return -ENOMEM;
78110bb8 275
40f58a65
HS
276 init_waitqueue_head(&async->wait_head);
277 async->subdevice = s;
278 s->async = async;
279
280 async->max_bufsize = comedi_default_buf_maxsize_kb * 1024;
281 buf_size = comedi_default_buf_size_kb * 1024;
282 if (buf_size > async->max_bufsize)
283 buf_size = async->max_bufsize;
284
285 if (comedi_buf_alloc(dev, s, buf_size) < 0) {
286 dev_warn(dev->class_dev, "Buffer allocation failed\n");
287 return -ENOMEM;
288 }
289 if (s->buf_change) {
290 ret = s->buf_change(dev, s, buf_size);
291 if (ret < 0)
292 return ret;
293 }
294
f65cc544 295 comedi_alloc_subdevice_minor(s);
40f58a65
HS
296
297 return 0;
298}
299
300static int __comedi_device_postconfig(struct comedi_device *dev)
ed9eccbe 301{
34c43922 302 struct comedi_subdevice *s;
ed9eccbe 303 int ret;
40f58a65 304 int i;
ed9eccbe
DS
305
306 for (i = 0; i < dev->n_subdevices; i++) {
5e4c58ce 307 s = &dev->subdevices[i];
ed9eccbe
DS
308
309 if (s->type == COMEDI_SUBD_UNUSED)
310 continue;
311
09567cb4
HS
312 if (s->type == COMEDI_SUBD_DO) {
313 if (s->n_chan < 32)
314 s->io_bits = (1 << s->n_chan) - 1;
315 else
316 s->io_bits = 0xffffffff;
317 }
318
ed9eccbe
DS
319 if (s->len_chanlist == 0)
320 s->len_chanlist = 1;
321
322 if (s->do_cmd) {
40f58a65
HS
323 ret = __comedi_device_postconfig_async(dev, s);
324 if (ret)
325 return ret;
ed9eccbe
DS
326 }
327
328 if (!s->range_table && !s->range_table_list)
329 s->range_table = &range_unknown;
330
331 if (!s->insn_read && s->insn_bits)
332 s->insn_read = insn_rw_emulate_bits;
333 if (!s->insn_write && s->insn_bits)
334 s->insn_write = insn_rw_emulate_bits;
335
336 if (!s->insn_read)
337 s->insn_read = insn_inval;
338 if (!s->insn_write)
339 s->insn_write = insn_inval;
340 if (!s->insn_bits)
341 s->insn_bits = insn_inval;
342 if (!s->insn_config)
343 s->insn_config = insn_inval;
344
345 if (!s->poll)
346 s->poll = poll_invalid;
347 }
348
349 return 0;
350}
351
01fca378 352/* do a little post-config cleanup */
01fca378
HS
353static int comedi_device_postconfig(struct comedi_device *dev)
354{
b2a644b4
IA
355 int ret;
356
357 ret = __comedi_device_postconfig(dev);
ae5dd5fc 358 if (ret < 0)
01fca378 359 return ret;
bf11c134 360 down_write(&dev->attach_lock);
a7401cdd 361 dev->attached = true;
bf11c134 362 up_write(&dev->attach_lock);
01fca378
HS
363 return 0;
364}
365
4e2f002f
IA
366/*
367 * Generic recognize function for drivers that register their supported
368 * board names.
369 *
370 * 'driv->board_name' points to a 'const char *' member within the
371 * zeroth element of an array of some private board information
372 * structure, say 'struct foo_board' containing a member 'const char
373 * *board_name' that is initialized to point to a board name string that
374 * is one of the candidates matched against this function's 'name'
375 * parameter.
376 *
377 * 'driv->offset' is the size of the private board information
378 * structure, say 'sizeof(struct foo_board)', and 'driv->num_names' is
379 * the length of the array of private board information structures.
380 *
381 * If one of the board names in the array of private board information
382 * structures matches the name supplied to this function, the function
383 * returns a pointer to the pointer to the board name, otherwise it
384 * returns NULL. The return value ends up in the 'board_ptr' member of
385 * a 'struct comedi_device' that the low-level comedi driver's
386 * 'attach()' hook can convert to a point to a particular element of its
387 * array of private board information structures by subtracting the
388 * offset of the member that points to the board name. (No subtraction
389 * is required if the board name pointer is the first member of the
390 * private board information structure, which is generally the case.)
391 */
7029a874 392static void *comedi_recognize(struct comedi_driver *driv, const char *name)
ed9eccbe 393{
1c9de58a
DC
394 char **name_ptr = (char **)driv->board_name;
395 int i;
396
ed9eccbe
DS
397 for (i = 0; i < driv->num_names; i++) {
398 if (strcmp(*name_ptr, name) == 0)
1c9de58a
DC
399 return name_ptr;
400 name_ptr = (void *)name_ptr + driv->offset;
ed9eccbe
DS
401 }
402
403 return NULL;
404}
405
7029a874 406static void comedi_report_boards(struct comedi_driver *driv)
ed9eccbe
DS
407{
408 unsigned int i;
409 const char *const *name_ptr;
410
4f870fe6
IA
411 pr_info("comedi: valid board names for %s driver are:\n",
412 driv->driver_name);
ed9eccbe
DS
413
414 name_ptr = driv->board_name;
415 for (i = 0; i < driv->num_names; i++) {
4f870fe6 416 pr_info(" %s\n", *name_ptr);
ed9eccbe
DS
417 name_ptr = (const char **)((char *)name_ptr + driv->offset);
418 }
419
420 if (driv->num_names == 0)
4f870fe6 421 pr_info(" %s\n", driv->driver_name);
ed9eccbe
DS
422}
423
9ff8b151
HS
424/**
425 * comedi_load_firmware() - Request and load firmware for a device.
426 * @dev: comedi_device struct
427 * @hw_device: device struct for the comedi_device
428 * @name: the name of the firmware image
429 * @cb: callback to the upload the firmware image
d569541e 430 * @context: private context from the driver
9ff8b151
HS
431 */
432int comedi_load_firmware(struct comedi_device *dev,
433 struct device *device,
434 const char *name,
435 int (*cb)(struct comedi_device *dev,
d569541e
HS
436 const u8 *data, size_t size,
437 unsigned long context),
438 unsigned long context)
9ff8b151
HS
439{
440 const struct firmware *fw;
441 int ret;
442
443 if (!cb)
444 return -EINVAL;
445
446 ret = request_firmware(&fw, name, device);
447 if (ret == 0) {
d569541e 448 ret = cb(dev, fw->data, fw->size, context);
9ff8b151
HS
449 release_firmware(fw);
450 }
451
452 return ret;
453}
454EXPORT_SYMBOL_GPL(comedi_load_firmware);
455
f375ac5f 456/**
ca8b2964 457 * __comedi_request_region() - Request an I/O reqion for a legacy driver.
f375ac5f
HS
458 * @dev: comedi_device struct
459 * @start: base address of the I/O reqion
460 * @len: length of the I/O region
461 */
ca8b2964
HS
462int __comedi_request_region(struct comedi_device *dev,
463 unsigned long start, unsigned long len)
f375ac5f
HS
464{
465 if (!start) {
466 dev_warn(dev->class_dev,
467 "%s: a I/O base address must be specified\n",
468 dev->board_name);
469 return -EINVAL;
470 }
471
472 if (!request_region(start, len, dev->board_name)) {
473 dev_warn(dev->class_dev, "%s: I/O port conflict (%#lx,%lu)\n",
474 dev->board_name, start, len);
475 return -EIO;
476 }
f375ac5f
HS
477
478 return 0;
479}
ca8b2964
HS
480EXPORT_SYMBOL_GPL(__comedi_request_region);
481
482/**
483 * comedi_request_region() - Request an I/O reqion for a legacy driver.
484 * @dev: comedi_device struct
485 * @start: base address of the I/O reqion
486 * @len: length of the I/O region
487 */
488int comedi_request_region(struct comedi_device *dev,
489 unsigned long start, unsigned long len)
490{
491 int ret;
492
493 ret = __comedi_request_region(dev, start, len);
316f97f1 494 if (ret == 0) {
ca8b2964 495 dev->iobase = start;
316f97f1
HS
496 dev->iolen = len;
497 }
ca8b2964
HS
498
499 return ret;
500}
f375ac5f
HS
501EXPORT_SYMBOL_GPL(comedi_request_region);
502
316f97f1
HS
503/**
504 * comedi_legacy_detach() - A generic (*detach) function for legacy drivers.
505 * @dev: comedi_device struct
506 */
507void comedi_legacy_detach(struct comedi_device *dev)
508{
3d1fe3f7
HS
509 if (dev->irq) {
510 free_irq(dev->irq, dev);
511 dev->irq = 0;
512 }
316f97f1
HS
513 if (dev->iobase && dev->iolen) {
514 release_region(dev->iobase, dev->iolen);
515 dev->iobase = 0;
516 dev->iolen = 0;
517 }
518}
519EXPORT_SYMBOL_GPL(comedi_legacy_detach);
520
01fca378 521int comedi_device_attach(struct comedi_device *dev, struct comedi_devconfig *it)
ed9eccbe 522{
01fca378
HS
523 struct comedi_driver *driv;
524 int ret;
525
526 if (dev->attached)
527 return -EBUSY;
528
c383e2d6 529 mutex_lock(&comedi_drivers_list_lock);
01fca378
HS
530 for (driv = comedi_drivers; driv; driv = driv->next) {
531 if (!try_module_get(driv->module))
532 continue;
533 if (driv->num_names) {
534 dev->board_ptr = comedi_recognize(driv, it->board_name);
535 if (dev->board_ptr)
536 break;
537 } else if (strcmp(driv->driver_name, it->board_name) == 0)
538 break;
539 module_put(driv->module);
540 }
541 if (driv == NULL) {
542 /* recognize has failed if we get here */
543 /* report valid board names before returning error */
544 for (driv = comedi_drivers; driv; driv = driv->next) {
545 if (!try_module_get(driv->module))
546 continue;
547 comedi_report_boards(driv);
548 module_put(driv->module);
549 }
c383e2d6
IA
550 ret = -EIO;
551 goto out;
01fca378
HS
552 }
553 if (driv->attach == NULL) {
554 /* driver does not support manual configuration */
555 dev_warn(dev->class_dev,
556 "driver '%s' does not support attach using comedi_config\n",
557 driv->driver_name);
558 module_put(driv->module);
c383e2d6
IA
559 ret = -ENOSYS;
560 goto out;
01fca378
HS
561 }
562 /* initialize dev->driver here so
563 * comedi_error() can be called from attach */
564 dev->driver = driv;
34b68400
HS
565 dev->board_name = dev->board_ptr ? *(const char **)dev->board_ptr
566 : dev->driver->driver_name;
01fca378 567 ret = driv->attach(dev, it);
74ece108
IA
568 if (ret >= 0)
569 ret = comedi_device_postconfig(dev);
01fca378 570 if (ret < 0) {
016599f5 571 comedi_device_detach(dev);
3955dfa8 572 module_put(driv->module);
01fca378 573 }
b2a644b4 574 /* On success, the driver module count has been incremented. */
c383e2d6
IA
575out:
576 mutex_unlock(&comedi_drivers_list_lock);
b2a644b4 577 return ret;
ed9eccbe
DS
578}
579
a588da1d
IA
580int comedi_auto_config(struct device *hardware_device,
581 struct comedi_driver *driver, unsigned long context)
f4011670 582{
6013a9a5 583 struct comedi_device *dev;
f4011670
IA
584 int ret;
585
f08e0ac5
IA
586 if (!hardware_device) {
587 pr_warn("BUG! comedi_auto_config called with NULL hardware_device\n");
588 return -EINVAL;
589 }
590 if (!driver) {
591 dev_warn(hardware_device,
592 "BUG! comedi_auto_config called with NULL comedi driver\n");
593 return -EINVAL;
594 }
595
a588da1d
IA
596 if (!driver->auto_attach) {
597 dev_warn(hardware_device,
598 "BUG! comedi driver '%s' has no auto_attach handler\n",
599 driver->driver_name);
600 return -EINVAL;
601 }
602
6013a9a5
HS
603 dev = comedi_alloc_board_minor(hardware_device);
604 if (IS_ERR(dev))
605 return PTR_ERR(dev);
606 /* Note: comedi_alloc_board_minor() locked dev->mutex. */
f4011670 607
6013a9a5 608 dev->driver = driver;
34b68400 609 dev->board_name = dev->driver->driver_name;
6013a9a5 610 ret = driver->auto_attach(dev, context);
74ece108 611 if (ret >= 0)
6013a9a5 612 ret = comedi_device_postconfig(dev);
b2a644b4 613 if (ret < 0)
6013a9a5
HS
614 comedi_device_detach(dev);
615 mutex_unlock(&dev->mutex);
f4011670
IA
616
617 if (ret < 0)
f5b31e15 618 comedi_release_hardware_device(hardware_device);
f4011670
IA
619 return ret;
620}
8ed705af
IA
621EXPORT_SYMBOL_GPL(comedi_auto_config);
622
623void comedi_auto_unconfig(struct device *hardware_device)
ed9eccbe 624{
c43435d7
IA
625 if (hardware_device == NULL)
626 return;
3346b798 627 comedi_release_hardware_device(hardware_device);
ed9eccbe 628}
8ed705af 629EXPORT_SYMBOL_GPL(comedi_auto_unconfig);
1ae6b20b
HS
630
631int comedi_driver_register(struct comedi_driver *driver)
632{
c383e2d6 633 mutex_lock(&comedi_drivers_list_lock);
1ae6b20b
HS
634 driver->next = comedi_drivers;
635 comedi_drivers = driver;
c383e2d6 636 mutex_unlock(&comedi_drivers_list_lock);
1ae6b20b
HS
637
638 return 0;
639}
5660e742 640EXPORT_SYMBOL_GPL(comedi_driver_register);
1ae6b20b 641
99c0e269 642void comedi_driver_unregister(struct comedi_driver *driver)
1ae6b20b
HS
643{
644 struct comedi_driver *prev;
645 int i;
646
c383e2d6
IA
647 /* unlink the driver */
648 mutex_lock(&comedi_drivers_list_lock);
649 if (comedi_drivers == driver) {
650 comedi_drivers = driver->next;
651 } else {
652 for (prev = comedi_drivers; prev->next; prev = prev->next) {
653 if (prev->next == driver) {
654 prev->next = driver->next;
655 break;
656 }
657 }
658 }
659 mutex_unlock(&comedi_drivers_list_lock);
660
1ae6b20b
HS
661 /* check for devices using this driver */
662 for (i = 0; i < COMEDI_NUM_BOARD_MINORS; i++) {
663 struct comedi_device *dev = comedi_dev_from_minor(i);
664
665 if (!dev)
666 continue;
667
668 mutex_lock(&dev->mutex);
669 if (dev->attached && dev->driver == driver) {
670 if (dev->use_count)
671 dev_warn(dev->class_dev,
672 "BUG! detaching device with use_count=%d\n",
673 dev->use_count);
674 comedi_device_detach(dev);
675 }
676 mutex_unlock(&dev->mutex);
677 }
1ae6b20b 678}
5660e742 679EXPORT_SYMBOL_GPL(comedi_driver_unregister);