0001
0002
0003
0004
0005
0006
0007
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
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
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
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
0191
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);