kcomedilib_main.c revision 88cccef0193a7f8c6a73326404c0b2f9ad27f71a
1/* 2 kcomedilib/kcomedilib.c 3 a comedlib interface for kernel modules 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. 17 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. 21 22*/ 23 24#define __NO_VERSION__ 25#include <linux/module.h> 26 27#include <linux/errno.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> 33#include <linux/mm.h> 34#include <linux/io.h> 35 36#include "../comedi.h" 37#include "../comedilib.h" 38#include "../comedidev.h" 39 40MODULE_AUTHOR("David Schleef <ds@schleef.org>"); 41MODULE_DESCRIPTION("Comedi kernel library"); 42MODULE_LICENSE("GPL"); 43 44void *comedi_open(const char *filename) 45{ 46 struct comedi_device_file_info *dev_file_info; 47 struct comedi_device *dev; 48 unsigned int minor; 49 50 if (strncmp(filename, "/dev/comedi", 11) != 0) 51 return NULL; 52 53 minor = simple_strtoul(filename + 11, NULL, 0); 54 55 if (minor >= COMEDI_NUM_BOARD_MINORS) 56 return NULL; 57 58 dev_file_info = comedi_get_device_file_info(minor); 59 if (dev_file_info == NULL) 60 return NULL; 61 dev = dev_file_info->device; 62 63 if (dev == NULL || !dev->attached) 64 return NULL; 65 66 if (!try_module_get(dev->driver->module)) 67 return NULL; 68 69 return (void *)dev; 70} 71EXPORT_SYMBOL(comedi_open); 72 73int comedi_close(void *d) 74{ 75 struct comedi_device *dev = (struct comedi_device *)d; 76 77 module_put(dev->driver->module); 78 79 return 0; 80} 81EXPORT_SYMBOL(comedi_close); 82 83/* 84 * COMEDI_INSN 85 * perform an instruction 86 */ 87static int comedi_do_insn(void *d, struct comedi_insn *insn) 88{ 89 struct comedi_device *dev = (struct comedi_device *)d; 90 struct comedi_subdevice *s; 91 int ret = 0; 92 93 if (insn->insn & INSN_MASK_SPECIAL) { 94 switch (insn->insn) { 95 case INSN_GTOD: 96 { 97 struct timeval tv; 98 99 do_gettimeofday(&tv); 100 insn->data[0] = tv.tv_sec; 101 insn->data[1] = tv.tv_usec; 102 ret = 2; 103 104 break; 105 } 106 case INSN_WAIT: 107 /* XXX isn't the value supposed to be nanosecs? */ 108 if (insn->n != 1 || insn->data[0] >= 100) { 109 ret = -EINVAL; 110 break; 111 } 112 udelay(insn->data[0]); 113 ret = 1; 114 break; 115 case INSN_INTTRIG: 116 if (insn->n != 1) { 117 ret = -EINVAL; 118 break; 119 } 120 if (insn->subdev >= dev->n_subdevices) { 121 printk("%d not usable subdevice\n", 122 insn->subdev); 123 ret = -EINVAL; 124 break; 125 } 126 s = dev->subdevices + insn->subdev; 127 if (!s->async) { 128 printk("no async\n"); 129 ret = -EINVAL; 130 break; 131 } 132 if (!s->async->inttrig) { 133 printk("no inttrig\n"); 134 ret = -EAGAIN; 135 break; 136 } 137 ret = s->async->inttrig(dev, s, insn->data[0]); 138 if (ret >= 0) 139 ret = 1; 140 break; 141 default: 142 ret = -EINVAL; 143 } 144 } else { 145 /* a subdevice instruction */ 146 if (insn->subdev >= dev->n_subdevices) { 147 ret = -EINVAL; 148 goto error; 149 } 150 s = dev->subdevices + insn->subdev; 151 152 if (s->type == COMEDI_SUBD_UNUSED) { 153 printk("%d not useable subdevice\n", insn->subdev); 154 ret = -EIO; 155 goto error; 156 } 157 158 /* XXX check lock */ 159 160 ret = comedi_check_chanlist(s, 1, &insn->chanspec); 161 if (ret < 0) { 162 printk("bad chanspec\n"); 163 ret = -EINVAL; 164 goto error; 165 } 166 167 if (s->busy) { 168 ret = -EBUSY; 169 goto error; 170 } 171 s->busy = d; 172 173 switch (insn->insn) { 174 case INSN_READ: 175 ret = s->insn_read(dev, s, insn, insn->data); 176 break; 177 case INSN_WRITE: 178 ret = s->insn_write(dev, s, insn, insn->data); 179 break; 180 case INSN_BITS: 181 ret = s->insn_bits(dev, s, insn, insn->data); 182 break; 183 case INSN_CONFIG: 184 /* XXX should check instruction length */ 185 ret = s->insn_config(dev, s, insn, insn->data); 186 break; 187 default: 188 ret = -EINVAL; 189 break; 190 } 191 192 s->busy = NULL; 193 } 194 if (ret < 0) 195 goto error; 196#if 0 197 /* XXX do we want this? -- abbotti #if'ed it out for now. */ 198 if (ret != insn->n) { 199 printk("BUG: result of insn != insn.n\n"); 200 ret = -EINVAL; 201 goto error; 202 } 203#endif 204error: 205 206 return ret; 207} 208 209int comedi_dio_config(void *dev, unsigned int subdev, unsigned int chan, 210 unsigned int io) 211{ 212 struct comedi_insn insn; 213 214 memset(&insn, 0, sizeof(insn)); 215 insn.insn = INSN_CONFIG; 216 insn.n = 1; 217 insn.data = &io; 218 insn.subdev = subdev; 219 insn.chanspec = CR_PACK(chan, 0, 0); 220 221 return comedi_do_insn(dev, &insn); 222} 223EXPORT_SYMBOL(comedi_dio_config); 224 225int comedi_dio_bitfield(void *dev, unsigned int subdev, unsigned int mask, 226 unsigned int *bits) 227{ 228 struct comedi_insn insn; 229 unsigned int data[2]; 230 int ret; 231 232 memset(&insn, 0, sizeof(insn)); 233 insn.insn = INSN_BITS; 234 insn.n = 2; 235 insn.data = data; 236 insn.subdev = subdev; 237 238 data[0] = mask; 239 data[1] = *bits; 240 241 ret = comedi_do_insn(dev, &insn); 242 243 *bits = data[1]; 244 245 return ret; 246} 247EXPORT_SYMBOL(comedi_dio_bitfield); 248 249int comedi_find_subdevice_by_type(void *d, int type, unsigned int subd) 250{ 251 struct comedi_device *dev = (struct comedi_device *)d; 252 253 if (subd > dev->n_subdevices) 254 return -ENODEV; 255 256 for (; subd < dev->n_subdevices; subd++) { 257 if (dev->subdevices[subd].type == type) 258 return subd; 259 } 260 return -1; 261} 262EXPORT_SYMBOL(comedi_find_subdevice_by_type); 263 264int comedi_get_n_channels(void *d, unsigned int subdevice) 265{ 266 struct comedi_device *dev = (struct comedi_device *)d; 267 struct comedi_subdevice *s = dev->subdevices + subdevice; 268 269 return s->n_chan; 270} 271EXPORT_SYMBOL(comedi_get_n_channels); 272