Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * kcomedilib/kcomedilib.c
0004  * a comedlib interface for kernel modules
0005  *
0006  * COMEDI - Linux Control and Measurement Device Interface
0007  * Copyright (C) 1997-2000 David A. Schleef <ds@schleef.org>
0008  */
0009 
0010 #include <linux/module.h>
0011 
0012 #include <linux/errno.h>
0013 #include <linux/kernel.h>
0014 #include <linux/sched.h>
0015 #include <linux/fcntl.h>
0016 #include <linux/mm.h>
0017 #include <linux/io.h>
0018 
0019 #include <linux/comedi.h>
0020 #include <linux/comedi/comedidev.h>
0021 #include <linux/comedi/comedilib.h>
0022 
0023 MODULE_AUTHOR("David Schleef <ds@schleef.org>");
0024 MODULE_DESCRIPTION("Comedi kernel library");
0025 MODULE_LICENSE("GPL");
0026 
0027 struct comedi_device *comedi_open(const char *filename)
0028 {
0029     struct comedi_device *dev, *retval = NULL;
0030     unsigned int minor;
0031 
0032     if (strncmp(filename, "/dev/comedi", 11) != 0)
0033         return NULL;
0034 
0035     if (kstrtouint(filename + 11, 0, &minor))
0036         return NULL;
0037 
0038     if (minor >= COMEDI_NUM_BOARD_MINORS)
0039         return NULL;
0040 
0041     dev = comedi_dev_get_from_minor(minor);
0042     if (!dev)
0043         return NULL;
0044 
0045     down_read(&dev->attach_lock);
0046     if (dev->attached)
0047         retval = dev;
0048     else
0049         retval = NULL;
0050     up_read(&dev->attach_lock);
0051 
0052     if (!retval)
0053         comedi_dev_put(dev);
0054 
0055     return retval;
0056 }
0057 EXPORT_SYMBOL_GPL(comedi_open);
0058 
0059 int comedi_close(struct comedi_device *dev)
0060 {
0061     comedi_dev_put(dev);
0062     return 0;
0063 }
0064 EXPORT_SYMBOL_GPL(comedi_close);
0065 
0066 static int comedi_do_insn(struct comedi_device *dev,
0067               struct comedi_insn *insn,
0068               unsigned int *data)
0069 {
0070     struct comedi_subdevice *s;
0071     int ret;
0072 
0073     mutex_lock(&dev->mutex);
0074 
0075     if (!dev->attached) {
0076         ret = -EINVAL;
0077         goto error;
0078     }
0079 
0080     /* a subdevice instruction */
0081     if (insn->subdev >= dev->n_subdevices) {
0082         ret = -EINVAL;
0083         goto error;
0084     }
0085     s = &dev->subdevices[insn->subdev];
0086 
0087     if (s->type == COMEDI_SUBD_UNUSED) {
0088         dev_err(dev->class_dev,
0089             "%d not usable subdevice\n", insn->subdev);
0090         ret = -EIO;
0091         goto error;
0092     }
0093 
0094     /* XXX check lock */
0095 
0096     ret = comedi_check_chanlist(s, 1, &insn->chanspec);
0097     if (ret < 0) {
0098         dev_err(dev->class_dev, "bad chanspec\n");
0099         ret = -EINVAL;
0100         goto error;
0101     }
0102 
0103     if (s->busy) {
0104         ret = -EBUSY;
0105         goto error;
0106     }
0107     s->busy = dev;
0108 
0109     switch (insn->insn) {
0110     case INSN_BITS:
0111         ret = s->insn_bits(dev, s, insn, data);
0112         break;
0113     case INSN_CONFIG:
0114         /* XXX should check instruction length */
0115         ret = s->insn_config(dev, s, insn, data);
0116         break;
0117     default:
0118         ret = -EINVAL;
0119         break;
0120     }
0121 
0122     s->busy = NULL;
0123 error:
0124 
0125     mutex_unlock(&dev->mutex);
0126     return ret;
0127 }
0128 
0129 int comedi_dio_get_config(struct comedi_device *dev, unsigned int subdev,
0130               unsigned int chan, unsigned int *io)
0131 {
0132     struct comedi_insn insn;
0133     unsigned int data[2];
0134     int ret;
0135 
0136     memset(&insn, 0, sizeof(insn));
0137     insn.insn = INSN_CONFIG;
0138     insn.n = 2;
0139     insn.subdev = subdev;
0140     insn.chanspec = CR_PACK(chan, 0, 0);
0141     data[0] = INSN_CONFIG_DIO_QUERY;
0142     data[1] = 0;
0143     ret = comedi_do_insn(dev, &insn, data);
0144     if (ret >= 0)
0145         *io = data[1];
0146     return ret;
0147 }
0148 EXPORT_SYMBOL_GPL(comedi_dio_get_config);
0149 
0150 int comedi_dio_config(struct comedi_device *dev, unsigned int subdev,
0151               unsigned int chan, unsigned int io)
0152 {
0153     struct comedi_insn insn;
0154 
0155     memset(&insn, 0, sizeof(insn));
0156     insn.insn = INSN_CONFIG;
0157     insn.n = 1;
0158     insn.subdev = subdev;
0159     insn.chanspec = CR_PACK(chan, 0, 0);
0160 
0161     return comedi_do_insn(dev, &insn, &io);
0162 }
0163 EXPORT_SYMBOL_GPL(comedi_dio_config);
0164 
0165 int comedi_dio_bitfield2(struct comedi_device *dev, unsigned int subdev,
0166              unsigned int mask, unsigned int *bits,
0167              unsigned int base_channel)
0168 {
0169     struct comedi_insn insn;
0170     unsigned int data[2];
0171     unsigned int n_chan;
0172     unsigned int shift;
0173     int ret;
0174 
0175     base_channel = CR_CHAN(base_channel);
0176     n_chan = comedi_get_n_channels(dev, subdev);
0177     if (base_channel >= n_chan)
0178         return -EINVAL;
0179 
0180     memset(&insn, 0, sizeof(insn));
0181     insn.insn = INSN_BITS;
0182     insn.chanspec = base_channel;
0183     insn.n = 2;
0184     insn.subdev = subdev;
0185 
0186     data[0] = mask;
0187     data[1] = *bits;
0188 
0189     /*
0190      * Most drivers ignore the base channel in insn->chanspec.
0191      * Fix this here if the subdevice has <= 32 channels.
0192      */
0193     if (n_chan <= 32) {
0194         shift = base_channel;
0195         if (shift) {
0196             insn.chanspec = 0;
0197             data[0] <<= shift;
0198             data[1] <<= shift;
0199         }
0200     } else {
0201         shift = 0;
0202     }
0203 
0204     ret = comedi_do_insn(dev, &insn, data);
0205     *bits = data[1] >> shift;
0206     return ret;
0207 }
0208 EXPORT_SYMBOL_GPL(comedi_dio_bitfield2);
0209 
0210 int comedi_find_subdevice_by_type(struct comedi_device *dev, int type,
0211                   unsigned int subd)
0212 {
0213     struct comedi_subdevice *s;
0214     int ret = -ENODEV;
0215 
0216     down_read(&dev->attach_lock);
0217     if (dev->attached)
0218         for (; subd < dev->n_subdevices; subd++) {
0219             s = &dev->subdevices[subd];
0220             if (s->type == type) {
0221                 ret = subd;
0222                 break;
0223             }
0224         }
0225     up_read(&dev->attach_lock);
0226     return ret;
0227 }
0228 EXPORT_SYMBOL_GPL(comedi_find_subdevice_by_type);
0229 
0230 int comedi_get_n_channels(struct comedi_device *dev, unsigned int subdevice)
0231 {
0232     int n;
0233 
0234     down_read(&dev->attach_lock);
0235     if (!dev->attached || subdevice >= dev->n_subdevices)
0236         n = 0;
0237     else
0238         n = dev->subdevices[subdevice].n_chan;
0239     up_read(&dev->attach_lock);
0240 
0241     return n;
0242 }
0243 EXPORT_SYMBOL_GPL(comedi_get_n_channels);
0244 
0245 static int __init kcomedilib_module_init(void)
0246 {
0247     return 0;
0248 }
0249 
0250 static void __exit kcomedilib_module_exit(void)
0251 {
0252 }
0253 
0254 module_init(kcomedilib_module_init);
0255 module_exit(kcomedilib_module_exit);