0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/device.h>
0012 #include <linux/module.h>
0013 #include <linux/errno.h>
0014 #include <linux/kernel.h>
0015 #include <linux/ioport.h>
0016 #include <linux/slab.h>
0017 #include <linux/dma-direction.h>
0018 #include <linux/interrupt.h>
0019 #include <linux/firmware.h>
0020 #include <linux/comedi/comedidev.h>
0021 #include "comedi_internal.h"
0022
0023 struct comedi_driver *comedi_drivers;
0024
0025 DEFINE_MUTEX(comedi_drivers_list_lock);
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049 int comedi_set_hw_dev(struct comedi_device *dev, struct device *hw_dev)
0050 {
0051 if (hw_dev == dev->hw_dev)
0052 return 0;
0053 if (dev->hw_dev)
0054 return -EEXIST;
0055 dev->hw_dev = get_device(hw_dev);
0056 return 0;
0057 }
0058 EXPORT_SYMBOL_GPL(comedi_set_hw_dev);
0059
0060 static void comedi_clear_hw_dev(struct comedi_device *dev)
0061 {
0062 put_device(dev->hw_dev);
0063 dev->hw_dev = NULL;
0064 }
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077 void *comedi_alloc_devpriv(struct comedi_device *dev, size_t size)
0078 {
0079 dev->private = kzalloc(size, GFP_KERNEL);
0080 return dev->private;
0081 }
0082 EXPORT_SYMBOL_GPL(comedi_alloc_devpriv);
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096 int comedi_alloc_subdevices(struct comedi_device *dev, int num_subdevices)
0097 {
0098 struct comedi_subdevice *s;
0099 int i;
0100
0101 if (num_subdevices < 1)
0102 return -EINVAL;
0103
0104 s = kcalloc(num_subdevices, sizeof(*s), GFP_KERNEL);
0105 if (!s)
0106 return -ENOMEM;
0107 dev->subdevices = s;
0108 dev->n_subdevices = num_subdevices;
0109
0110 for (i = 0; i < num_subdevices; ++i) {
0111 s = &dev->subdevices[i];
0112 s->device = dev;
0113 s->index = i;
0114 s->async_dma_dir = DMA_NONE;
0115 spin_lock_init(&s->spin_lock);
0116 s->minor = -1;
0117 }
0118 return 0;
0119 }
0120 EXPORT_SYMBOL_GPL(comedi_alloc_subdevices);
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140 int comedi_alloc_subdev_readback(struct comedi_subdevice *s)
0141 {
0142 if (!s->n_chan)
0143 return -EINVAL;
0144
0145 s->readback = kcalloc(s->n_chan, sizeof(*s->readback), GFP_KERNEL);
0146 if (!s->readback)
0147 return -ENOMEM;
0148
0149 if (!s->insn_read)
0150 s->insn_read = comedi_readback_insn_read;
0151
0152 return 0;
0153 }
0154 EXPORT_SYMBOL_GPL(comedi_alloc_subdev_readback);
0155
0156 static void comedi_device_detach_cleanup(struct comedi_device *dev)
0157 {
0158 int i;
0159 struct comedi_subdevice *s;
0160
0161 lockdep_assert_held(&dev->attach_lock);
0162 lockdep_assert_held(&dev->mutex);
0163 if (dev->subdevices) {
0164 for (i = 0; i < dev->n_subdevices; i++) {
0165 s = &dev->subdevices[i];
0166 if (comedi_can_auto_free_spriv(s))
0167 kfree(s->private);
0168 comedi_free_subdevice_minor(s);
0169 if (s->async) {
0170 comedi_buf_alloc(dev, s, 0);
0171 kfree(s->async);
0172 }
0173 kfree(s->readback);
0174 }
0175 kfree(dev->subdevices);
0176 dev->subdevices = NULL;
0177 dev->n_subdevices = 0;
0178 }
0179 kfree(dev->private);
0180 kfree(dev->pacer);
0181 dev->private = NULL;
0182 dev->pacer = NULL;
0183 dev->driver = NULL;
0184 dev->board_name = NULL;
0185 dev->board_ptr = NULL;
0186 dev->mmio = NULL;
0187 dev->iobase = 0;
0188 dev->iolen = 0;
0189 dev->ioenabled = false;
0190 dev->irq = 0;
0191 dev->read_subdev = NULL;
0192 dev->write_subdev = NULL;
0193 dev->open = NULL;
0194 dev->close = NULL;
0195 comedi_clear_hw_dev(dev);
0196 }
0197
0198 void comedi_device_detach(struct comedi_device *dev)
0199 {
0200 lockdep_assert_held(&dev->mutex);
0201 comedi_device_cancel_all(dev);
0202 down_write(&dev->attach_lock);
0203 dev->attached = false;
0204 dev->detach_count++;
0205 if (dev->driver)
0206 dev->driver->detach(dev);
0207 comedi_device_detach_cleanup(dev);
0208 up_write(&dev->attach_lock);
0209 }
0210
0211 static int poll_invalid(struct comedi_device *dev, struct comedi_subdevice *s)
0212 {
0213 return -EINVAL;
0214 }
0215
0216 static int insn_device_inval(struct comedi_device *dev,
0217 struct comedi_insn *insn, unsigned int *data)
0218 {
0219 return -EINVAL;
0220 }
0221
0222 static unsigned int get_zero_valid_routes(struct comedi_device *dev,
0223 unsigned int n_pairs,
0224 unsigned int *pair_data)
0225 {
0226 return 0;
0227 }
0228
0229 int insn_inval(struct comedi_device *dev, struct comedi_subdevice *s,
0230 struct comedi_insn *insn, unsigned int *data)
0231 {
0232 return -EINVAL;
0233 }
0234
0235
0236
0237
0238
0239
0240
0241
0242
0243
0244
0245
0246
0247
0248
0249
0250
0251
0252 int comedi_readback_insn_read(struct comedi_device *dev,
0253 struct comedi_subdevice *s,
0254 struct comedi_insn *insn,
0255 unsigned int *data)
0256 {
0257 unsigned int chan = CR_CHAN(insn->chanspec);
0258 int i;
0259
0260 if (!s->readback)
0261 return -EINVAL;
0262
0263 for (i = 0; i < insn->n; i++)
0264 data[i] = s->readback[chan];
0265
0266 return insn->n;
0267 }
0268 EXPORT_SYMBOL_GPL(comedi_readback_insn_read);
0269
0270
0271
0272
0273
0274
0275
0276
0277
0278
0279
0280
0281
0282
0283
0284
0285
0286
0287 int comedi_timeout(struct comedi_device *dev,
0288 struct comedi_subdevice *s,
0289 struct comedi_insn *insn,
0290 int (*cb)(struct comedi_device *dev,
0291 struct comedi_subdevice *s,
0292 struct comedi_insn *insn,
0293 unsigned long context),
0294 unsigned long context)
0295 {
0296 unsigned long timeout = jiffies + msecs_to_jiffies(COMEDI_TIMEOUT_MS);
0297 int ret;
0298
0299 while (time_before(jiffies, timeout)) {
0300 ret = cb(dev, s, insn, context);
0301 if (ret != -EBUSY)
0302 return ret;
0303 cpu_relax();
0304 }
0305 return -ETIMEDOUT;
0306 }
0307 EXPORT_SYMBOL_GPL(comedi_timeout);
0308
0309
0310
0311
0312
0313
0314
0315
0316
0317
0318
0319
0320
0321
0322
0323
0324
0325
0326
0327
0328
0329
0330
0331
0332
0333
0334
0335 int comedi_dio_insn_config(struct comedi_device *dev,
0336 struct comedi_subdevice *s,
0337 struct comedi_insn *insn,
0338 unsigned int *data,
0339 unsigned int mask)
0340 {
0341 unsigned int chan_mask = 1 << CR_CHAN(insn->chanspec);
0342
0343 if (!mask)
0344 mask = chan_mask;
0345
0346 switch (data[0]) {
0347 case INSN_CONFIG_DIO_INPUT:
0348 s->io_bits &= ~mask;
0349 break;
0350
0351 case INSN_CONFIG_DIO_OUTPUT:
0352 s->io_bits |= mask;
0353 break;
0354
0355 case INSN_CONFIG_DIO_QUERY:
0356 data[1] = (s->io_bits & mask) ? COMEDI_OUTPUT : COMEDI_INPUT;
0357 return insn->n;
0358
0359 default:
0360 return -EINVAL;
0361 }
0362
0363 return 0;
0364 }
0365 EXPORT_SYMBOL_GPL(comedi_dio_insn_config);
0366
0367
0368
0369
0370
0371
0372
0373
0374
0375
0376
0377
0378
0379
0380
0381 unsigned int comedi_dio_update_state(struct comedi_subdevice *s,
0382 unsigned int *data)
0383 {
0384 unsigned int chanmask = (s->n_chan < 32) ? ((1 << s->n_chan) - 1)
0385 : 0xffffffff;
0386 unsigned int mask = data[0] & chanmask;
0387 unsigned int bits = data[1];
0388
0389 if (mask) {
0390 s->state &= ~mask;
0391 s->state |= (bits & mask);
0392 }
0393
0394 return mask;
0395 }
0396 EXPORT_SYMBOL_GPL(comedi_dio_update_state);
0397
0398
0399
0400
0401
0402
0403
0404
0405
0406
0407
0408
0409
0410
0411
0412
0413
0414
0415 unsigned int comedi_bytes_per_scan_cmd(struct comedi_subdevice *s,
0416 struct comedi_cmd *cmd)
0417 {
0418 unsigned int num_samples;
0419 unsigned int bits_per_sample;
0420
0421 switch (s->type) {
0422 case COMEDI_SUBD_DI:
0423 case COMEDI_SUBD_DO:
0424 case COMEDI_SUBD_DIO:
0425 bits_per_sample = 8 * comedi_bytes_per_sample(s);
0426 num_samples = DIV_ROUND_UP(cmd->scan_end_arg, bits_per_sample);
0427 break;
0428 default:
0429 num_samples = cmd->scan_end_arg;
0430 break;
0431 }
0432 return comedi_samples_to_bytes(s, num_samples);
0433 }
0434 EXPORT_SYMBOL_GPL(comedi_bytes_per_scan_cmd);
0435
0436
0437
0438
0439
0440
0441
0442
0443
0444
0445
0446
0447
0448
0449
0450
0451 unsigned int comedi_bytes_per_scan(struct comedi_subdevice *s)
0452 {
0453 struct comedi_cmd *cmd = &s->async->cmd;
0454
0455 return comedi_bytes_per_scan_cmd(s, cmd);
0456 }
0457 EXPORT_SYMBOL_GPL(comedi_bytes_per_scan);
0458
0459 static unsigned int __comedi_nscans_left(struct comedi_subdevice *s,
0460 unsigned int nscans)
0461 {
0462 struct comedi_async *async = s->async;
0463 struct comedi_cmd *cmd = &async->cmd;
0464
0465 if (cmd->stop_src == TRIG_COUNT) {
0466 unsigned int scans_left = 0;
0467
0468 if (async->scans_done < cmd->stop_arg)
0469 scans_left = cmd->stop_arg - async->scans_done;
0470
0471 if (nscans > scans_left)
0472 nscans = scans_left;
0473 }
0474 return nscans;
0475 }
0476
0477
0478
0479
0480
0481
0482
0483
0484
0485
0486
0487
0488
0489
0490
0491 unsigned int comedi_nscans_left(struct comedi_subdevice *s,
0492 unsigned int nscans)
0493 {
0494 if (nscans == 0) {
0495 unsigned int nbytes = comedi_buf_read_n_available(s);
0496
0497 nscans = nbytes / comedi_bytes_per_scan(s);
0498 }
0499 return __comedi_nscans_left(s, nscans);
0500 }
0501 EXPORT_SYMBOL_GPL(comedi_nscans_left);
0502
0503
0504
0505
0506
0507
0508
0509
0510
0511 unsigned int comedi_nsamples_left(struct comedi_subdevice *s,
0512 unsigned int nsamples)
0513 {
0514 struct comedi_async *async = s->async;
0515 struct comedi_cmd *cmd = &async->cmd;
0516 unsigned long long scans_left;
0517 unsigned long long samples_left;
0518
0519 if (cmd->stop_src != TRIG_COUNT)
0520 return nsamples;
0521
0522 scans_left = __comedi_nscans_left(s, cmd->stop_arg);
0523 if (!scans_left)
0524 return 0;
0525
0526 samples_left = scans_left * cmd->scan_end_arg -
0527 comedi_bytes_to_samples(s, async->scan_progress);
0528
0529 if (samples_left < nsamples)
0530 return samples_left;
0531 return nsamples;
0532 }
0533 EXPORT_SYMBOL_GPL(comedi_nsamples_left);
0534
0535
0536
0537
0538
0539
0540
0541
0542
0543
0544
0545 void comedi_inc_scan_progress(struct comedi_subdevice *s,
0546 unsigned int num_bytes)
0547 {
0548 struct comedi_async *async = s->async;
0549 struct comedi_cmd *cmd = &async->cmd;
0550 unsigned int scan_length = comedi_bytes_per_scan(s);
0551
0552
0553 if (!(s->subdev_flags & SDF_PACKED)) {
0554 async->cur_chan += comedi_bytes_to_samples(s, num_bytes);
0555 async->cur_chan %= cmd->chanlist_len;
0556 }
0557
0558 async->scan_progress += num_bytes;
0559 if (async->scan_progress >= scan_length) {
0560 unsigned int nscans = async->scan_progress / scan_length;
0561
0562 if (async->scans_done < (UINT_MAX - nscans))
0563 async->scans_done += nscans;
0564 else
0565 async->scans_done = UINT_MAX;
0566
0567 async->scan_progress %= scan_length;
0568 async->events |= COMEDI_CB_EOS;
0569 }
0570 }
0571 EXPORT_SYMBOL_GPL(comedi_inc_scan_progress);
0572
0573
0574
0575
0576
0577
0578
0579
0580
0581
0582
0583
0584
0585
0586
0587
0588
0589 unsigned int comedi_handle_events(struct comedi_device *dev,
0590 struct comedi_subdevice *s)
0591 {
0592 unsigned int events = s->async->events;
0593
0594 if (events == 0)
0595 return events;
0596
0597 if ((events & COMEDI_CB_CANCEL_MASK) && s->cancel)
0598 s->cancel(dev, s);
0599
0600 comedi_event(dev, s);
0601
0602 return events;
0603 }
0604 EXPORT_SYMBOL_GPL(comedi_handle_events);
0605
0606 static int insn_rw_emulate_bits(struct comedi_device *dev,
0607 struct comedi_subdevice *s,
0608 struct comedi_insn *insn,
0609 unsigned int *data)
0610 {
0611 struct comedi_insn _insn;
0612 unsigned int chan = CR_CHAN(insn->chanspec);
0613 unsigned int base_chan = (chan < 32) ? 0 : chan;
0614 unsigned int _data[2];
0615 int ret;
0616
0617 memset(_data, 0, sizeof(_data));
0618 memset(&_insn, 0, sizeof(_insn));
0619 _insn.insn = INSN_BITS;
0620 _insn.chanspec = base_chan;
0621 _insn.n = 2;
0622 _insn.subdev = insn->subdev;
0623
0624 if (insn->insn == INSN_WRITE) {
0625 if (!(s->subdev_flags & SDF_WRITABLE))
0626 return -EINVAL;
0627 _data[0] = 1 << (chan - base_chan);
0628 _data[1] = data[0] ? (1 << (chan - base_chan)) : 0;
0629 }
0630
0631 ret = s->insn_bits(dev, s, &_insn, _data);
0632 if (ret < 0)
0633 return ret;
0634
0635 if (insn->insn == INSN_READ)
0636 data[0] = (_data[1] >> (chan - base_chan)) & 1;
0637
0638 return 1;
0639 }
0640
0641 static int __comedi_device_postconfig_async(struct comedi_device *dev,
0642 struct comedi_subdevice *s)
0643 {
0644 struct comedi_async *async;
0645 unsigned int buf_size;
0646 int ret;
0647
0648 lockdep_assert_held(&dev->mutex);
0649 if ((s->subdev_flags & (SDF_CMD_READ | SDF_CMD_WRITE)) == 0) {
0650 dev_warn(dev->class_dev,
0651 "async subdevices must support SDF_CMD_READ or SDF_CMD_WRITE\n");
0652 return -EINVAL;
0653 }
0654 if (!s->do_cmdtest) {
0655 dev_warn(dev->class_dev,
0656 "async subdevices must have a do_cmdtest() function\n");
0657 return -EINVAL;
0658 }
0659 if (!s->cancel)
0660 dev_warn(dev->class_dev,
0661 "async subdevices should have a cancel() function\n");
0662
0663 async = kzalloc(sizeof(*async), GFP_KERNEL);
0664 if (!async)
0665 return -ENOMEM;
0666
0667 init_waitqueue_head(&async->wait_head);
0668 s->async = async;
0669
0670 async->max_bufsize = comedi_default_buf_maxsize_kb * 1024;
0671 buf_size = comedi_default_buf_size_kb * 1024;
0672 if (buf_size > async->max_bufsize)
0673 buf_size = async->max_bufsize;
0674
0675 if (comedi_buf_alloc(dev, s, buf_size) < 0) {
0676 dev_warn(dev->class_dev, "Buffer allocation failed\n");
0677 return -ENOMEM;
0678 }
0679 if (s->buf_change) {
0680 ret = s->buf_change(dev, s);
0681 if (ret < 0)
0682 return ret;
0683 }
0684
0685 comedi_alloc_subdevice_minor(s);
0686
0687 return 0;
0688 }
0689
0690 static int __comedi_device_postconfig(struct comedi_device *dev)
0691 {
0692 struct comedi_subdevice *s;
0693 int ret;
0694 int i;
0695
0696 lockdep_assert_held(&dev->mutex);
0697 if (!dev->insn_device_config)
0698 dev->insn_device_config = insn_device_inval;
0699
0700 if (!dev->get_valid_routes)
0701 dev->get_valid_routes = get_zero_valid_routes;
0702
0703 for (i = 0; i < dev->n_subdevices; i++) {
0704 s = &dev->subdevices[i];
0705
0706 if (s->type == COMEDI_SUBD_UNUSED)
0707 continue;
0708
0709 if (s->type == COMEDI_SUBD_DO) {
0710 if (s->n_chan < 32)
0711 s->io_bits = (1 << s->n_chan) - 1;
0712 else
0713 s->io_bits = 0xffffffff;
0714 }
0715
0716 if (s->len_chanlist == 0)
0717 s->len_chanlist = 1;
0718
0719 if (s->do_cmd) {
0720 ret = __comedi_device_postconfig_async(dev, s);
0721 if (ret)
0722 return ret;
0723 }
0724
0725 if (!s->range_table && !s->range_table_list)
0726 s->range_table = &range_unknown;
0727
0728 if (!s->insn_read && s->insn_bits)
0729 s->insn_read = insn_rw_emulate_bits;
0730 if (!s->insn_write && s->insn_bits)
0731 s->insn_write = insn_rw_emulate_bits;
0732
0733 if (!s->insn_read)
0734 s->insn_read = insn_inval;
0735 if (!s->insn_write)
0736 s->insn_write = insn_inval;
0737 if (!s->insn_bits)
0738 s->insn_bits = insn_inval;
0739 if (!s->insn_config)
0740 s->insn_config = insn_inval;
0741
0742 if (!s->poll)
0743 s->poll = poll_invalid;
0744 }
0745
0746 return 0;
0747 }
0748
0749
0750 static int comedi_device_postconfig(struct comedi_device *dev)
0751 {
0752 int ret;
0753
0754 lockdep_assert_held(&dev->mutex);
0755 ret = __comedi_device_postconfig(dev);
0756 if (ret < 0)
0757 return ret;
0758 down_write(&dev->attach_lock);
0759 dev->attached = true;
0760 up_write(&dev->attach_lock);
0761 return 0;
0762 }
0763
0764
0765
0766
0767
0768
0769
0770
0771
0772
0773
0774
0775
0776
0777
0778
0779
0780
0781
0782
0783
0784
0785
0786
0787
0788
0789
0790 static void *comedi_recognize(struct comedi_driver *driv, const char *name)
0791 {
0792 char **name_ptr = (char **)driv->board_name;
0793 int i;
0794
0795 for (i = 0; i < driv->num_names; i++) {
0796 if (strcmp(*name_ptr, name) == 0)
0797 return name_ptr;
0798 name_ptr = (void *)name_ptr + driv->offset;
0799 }
0800
0801 return NULL;
0802 }
0803
0804 static void comedi_report_boards(struct comedi_driver *driv)
0805 {
0806 unsigned int i;
0807 const char *const *name_ptr;
0808
0809 pr_info("comedi: valid board names for %s driver are:\n",
0810 driv->driver_name);
0811
0812 name_ptr = driv->board_name;
0813 for (i = 0; i < driv->num_names; i++) {
0814 pr_info(" %s\n", *name_ptr);
0815 name_ptr = (const char **)((char *)name_ptr + driv->offset);
0816 }
0817
0818 if (driv->num_names == 0)
0819 pr_info(" %s\n", driv->driver_name);
0820 }
0821
0822
0823
0824
0825
0826
0827
0828
0829
0830
0831
0832
0833
0834
0835
0836
0837 int comedi_load_firmware(struct comedi_device *dev,
0838 struct device *device,
0839 const char *name,
0840 int (*cb)(struct comedi_device *dev,
0841 const u8 *data, size_t size,
0842 unsigned long context),
0843 unsigned long context)
0844 {
0845 const struct firmware *fw;
0846 int ret;
0847
0848 if (!cb)
0849 return -EINVAL;
0850
0851 ret = request_firmware(&fw, name, device);
0852 if (ret == 0) {
0853 ret = cb(dev, fw->data, fw->size, context);
0854 release_firmware(fw);
0855 }
0856
0857 return min(ret, 0);
0858 }
0859 EXPORT_SYMBOL_GPL(comedi_load_firmware);
0860
0861
0862
0863
0864
0865
0866
0867
0868
0869
0870
0871
0872
0873 int __comedi_request_region(struct comedi_device *dev,
0874 unsigned long start, unsigned long len)
0875 {
0876 if (!start) {
0877 dev_warn(dev->class_dev,
0878 "%s: a I/O base address must be specified\n",
0879 dev->board_name);
0880 return -EINVAL;
0881 }
0882
0883 if (!request_region(start, len, dev->board_name)) {
0884 dev_warn(dev->class_dev, "%s: I/O port conflict (%#lx,%lu)\n",
0885 dev->board_name, start, len);
0886 return -EIO;
0887 }
0888
0889 return 0;
0890 }
0891 EXPORT_SYMBOL_GPL(__comedi_request_region);
0892
0893
0894
0895
0896
0897
0898
0899
0900
0901
0902
0903
0904
0905
0906
0907
0908 int comedi_request_region(struct comedi_device *dev,
0909 unsigned long start, unsigned long len)
0910 {
0911 int ret;
0912
0913 ret = __comedi_request_region(dev, start, len);
0914 if (ret == 0) {
0915 dev->iobase = start;
0916 dev->iolen = len;
0917 }
0918
0919 return ret;
0920 }
0921 EXPORT_SYMBOL_GPL(comedi_request_region);
0922
0923
0924
0925
0926
0927
0928
0929
0930
0931
0932
0933
0934
0935 void comedi_legacy_detach(struct comedi_device *dev)
0936 {
0937 if (dev->irq) {
0938 free_irq(dev->irq, dev);
0939 dev->irq = 0;
0940 }
0941 if (dev->iobase && dev->iolen) {
0942 release_region(dev->iobase, dev->iolen);
0943 dev->iobase = 0;
0944 dev->iolen = 0;
0945 }
0946 }
0947 EXPORT_SYMBOL_GPL(comedi_legacy_detach);
0948
0949 int comedi_device_attach(struct comedi_device *dev, struct comedi_devconfig *it)
0950 {
0951 struct comedi_driver *driv;
0952 int ret;
0953
0954 lockdep_assert_held(&dev->mutex);
0955 if (dev->attached)
0956 return -EBUSY;
0957
0958 mutex_lock(&comedi_drivers_list_lock);
0959 for (driv = comedi_drivers; driv; driv = driv->next) {
0960 if (!try_module_get(driv->module))
0961 continue;
0962 if (driv->num_names) {
0963 dev->board_ptr = comedi_recognize(driv, it->board_name);
0964 if (dev->board_ptr)
0965 break;
0966 } else if (strcmp(driv->driver_name, it->board_name) == 0) {
0967 break;
0968 }
0969 module_put(driv->module);
0970 }
0971 if (!driv) {
0972
0973
0974 for (driv = comedi_drivers; driv; driv = driv->next) {
0975 if (!try_module_get(driv->module))
0976 continue;
0977 comedi_report_boards(driv);
0978 module_put(driv->module);
0979 }
0980 ret = -EIO;
0981 goto out;
0982 }
0983 if (!driv->attach) {
0984
0985 dev_warn(dev->class_dev,
0986 "driver '%s' does not support attach using comedi_config\n",
0987 driv->driver_name);
0988 module_put(driv->module);
0989 ret = -EIO;
0990 goto out;
0991 }
0992 dev->driver = driv;
0993 dev->board_name = dev->board_ptr ? *(const char **)dev->board_ptr
0994 : dev->driver->driver_name;
0995 ret = driv->attach(dev, it);
0996 if (ret >= 0)
0997 ret = comedi_device_postconfig(dev);
0998 if (ret < 0) {
0999 comedi_device_detach(dev);
1000 module_put(driv->module);
1001 }
1002
1003 out:
1004 mutex_unlock(&comedi_drivers_list_lock);
1005 return ret;
1006 }
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031 int comedi_auto_config(struct device *hardware_device,
1032 struct comedi_driver *driver, unsigned long context)
1033 {
1034 struct comedi_device *dev;
1035 int ret;
1036
1037 if (!hardware_device) {
1038 pr_warn("BUG! %s called with NULL hardware_device\n", __func__);
1039 return -EINVAL;
1040 }
1041 if (!driver) {
1042 dev_warn(hardware_device,
1043 "BUG! %s called with NULL comedi driver\n", __func__);
1044 return -EINVAL;
1045 }
1046
1047 if (!driver->auto_attach) {
1048 dev_warn(hardware_device,
1049 "BUG! comedi driver '%s' has no auto_attach handler\n",
1050 driver->driver_name);
1051 return -EINVAL;
1052 }
1053
1054 dev = comedi_alloc_board_minor(hardware_device);
1055 if (IS_ERR(dev)) {
1056 dev_warn(hardware_device,
1057 "driver '%s' could not create device.\n",
1058 driver->driver_name);
1059 return PTR_ERR(dev);
1060 }
1061
1062 lockdep_assert_held(&dev->mutex);
1063
1064 dev->driver = driver;
1065 dev->board_name = dev->driver->driver_name;
1066 ret = driver->auto_attach(dev, context);
1067 if (ret >= 0)
1068 ret = comedi_device_postconfig(dev);
1069
1070 if (ret < 0) {
1071 dev_warn(hardware_device,
1072 "driver '%s' failed to auto-configure device.\n",
1073 driver->driver_name);
1074 mutex_unlock(&dev->mutex);
1075 comedi_release_hardware_device(hardware_device);
1076 } else {
1077
1078
1079
1080
1081 dev_info(dev->class_dev,
1082 "driver '%s' has successfully auto-configured '%s'.\n",
1083 driver->driver_name, dev->board_name);
1084 mutex_unlock(&dev->mutex);
1085 }
1086 return ret;
1087 }
1088 EXPORT_SYMBOL_GPL(comedi_auto_config);
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106 void comedi_auto_unconfig(struct device *hardware_device)
1107 {
1108 if (!hardware_device)
1109 return;
1110 comedi_release_hardware_device(hardware_device);
1111 }
1112 EXPORT_SYMBOL_GPL(comedi_auto_unconfig);
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125 int comedi_driver_register(struct comedi_driver *driver)
1126 {
1127 mutex_lock(&comedi_drivers_list_lock);
1128 driver->next = comedi_drivers;
1129 comedi_drivers = driver;
1130 mutex_unlock(&comedi_drivers_list_lock);
1131
1132 return 0;
1133 }
1134 EXPORT_SYMBOL_GPL(comedi_driver_register);
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145 void comedi_driver_unregister(struct comedi_driver *driver)
1146 {
1147 struct comedi_driver *prev;
1148 int i;
1149
1150
1151 mutex_lock(&comedi_drivers_list_lock);
1152 if (comedi_drivers == driver) {
1153 comedi_drivers = driver->next;
1154 } else {
1155 for (prev = comedi_drivers; prev->next; prev = prev->next) {
1156 if (prev->next == driver) {
1157 prev->next = driver->next;
1158 break;
1159 }
1160 }
1161 }
1162 mutex_unlock(&comedi_drivers_list_lock);
1163
1164
1165 for (i = 0; i < COMEDI_NUM_BOARD_MINORS; i++) {
1166 struct comedi_device *dev = comedi_dev_get_from_minor(i);
1167
1168 if (!dev)
1169 continue;
1170
1171 mutex_lock(&dev->mutex);
1172 if (dev->attached && dev->driver == driver) {
1173 if (dev->use_count)
1174 dev_warn(dev->class_dev,
1175 "BUG! detaching device with use_count=%d\n",
1176 dev->use_count);
1177 comedi_device_detach(dev);
1178 }
1179 mutex_unlock(&dev->mutex);
1180 comedi_dev_put(dev);
1181 }
1182 }
1183 EXPORT_SYMBOL_GPL(comedi_driver_unregister);