/kern_oII/drivers/staging/comedi/kcomedilib/kcomedilib_main.c

http://omnia2droid.googlecode.com/ · C · 560 lines · 362 code · 108 blank · 90 comment · 94 complexity · 1d1a05c0324bb109bae1cf0e64019251 MD5 · raw file

  1. /*
  2. kcomedilib/kcomedilib.c
  3. a comedlib interface for kernel modules
  4. COMEDI - Linux Control and Measurement Device Interface
  5. Copyright (C) 1997-2000 David A. Schleef <ds@schleef.org>
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2 of the License, or
  9. (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program; if not, write to the Free Software
  16. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. */
  18. #define __NO_VERSION__
  19. #include <linux/module.h>
  20. #include <linux/errno.h>
  21. #include <linux/kernel.h>
  22. #include <linux/sched.h>
  23. #include <linux/fcntl.h>
  24. #include <linux/delay.h>
  25. #include <linux/ioport.h>
  26. #include <linux/mm.h>
  27. #include <linux/slab.h>
  28. #include <asm/io.h>
  29. #include "../comedi.h"
  30. #include "../comedilib.h"
  31. #include "../comedidev.h"
  32. MODULE_AUTHOR("David Schleef <ds@schleef.org>");
  33. MODULE_DESCRIPTION("Comedi kernel library");
  34. MODULE_LICENSE("GPL");
  35. void *comedi_open(const char *filename)
  36. {
  37. struct comedi_device_file_info *dev_file_info;
  38. struct comedi_device *dev;
  39. unsigned int minor;
  40. if (strncmp(filename, "/dev/comedi", 11) != 0)
  41. return NULL;
  42. minor = simple_strtoul(filename + 11, NULL, 0);
  43. if (minor >= COMEDI_NUM_BOARD_MINORS)
  44. return NULL;
  45. dev_file_info = comedi_get_device_file_info(minor);
  46. if (dev_file_info == NULL)
  47. return NULL;
  48. dev = dev_file_info->device;
  49. if (dev == NULL || !dev->attached)
  50. return NULL;
  51. if (!try_module_get(dev->driver->module))
  52. return NULL;
  53. return (void *) dev;
  54. }
  55. void *comedi_open_old(unsigned int minor)
  56. {
  57. struct comedi_device_file_info *dev_file_info;
  58. struct comedi_device *dev;
  59. if (minor >= COMEDI_NUM_MINORS)
  60. return NULL;
  61. dev_file_info = comedi_get_device_file_info(minor);
  62. if (dev_file_info == NULL)
  63. return NULL;
  64. dev = dev_file_info->device;
  65. if (dev == NULL || !dev->attached)
  66. return NULL;
  67. return (void *) dev;
  68. }
  69. int comedi_close(void *d)
  70. {
  71. struct comedi_device *dev = (struct comedi_device *) d;
  72. module_put(dev->driver->module);
  73. return 0;
  74. }
  75. int comedi_loglevel(int newlevel)
  76. {
  77. return 0;
  78. }
  79. void comedi_perror(const char *message)
  80. {
  81. printk("%s: unknown error\n", message);
  82. }
  83. char *comedi_strerror(int err)
  84. {
  85. return "unknown error";
  86. }
  87. int comedi_fileno(void *d)
  88. {
  89. struct comedi_device *dev = (struct comedi_device *) d;
  90. /* return something random */
  91. return dev->minor;
  92. }
  93. int comedi_command(void *d, struct comedi_cmd *cmd)
  94. {
  95. struct comedi_device *dev = (struct comedi_device *) d;
  96. struct comedi_subdevice *s;
  97. struct comedi_async *async;
  98. unsigned runflags;
  99. if (cmd->subdev >= dev->n_subdevices)
  100. return -ENODEV;
  101. s = dev->subdevices + cmd->subdev;
  102. if (s->type == COMEDI_SUBD_UNUSED)
  103. return -EIO;
  104. async = s->async;
  105. if (async == NULL)
  106. return -ENODEV;
  107. if (s->busy)
  108. return -EBUSY;
  109. s->busy = d;
  110. if (async->cb_mask & COMEDI_CB_EOS)
  111. cmd->flags |= TRIG_WAKE_EOS;
  112. async->cmd = *cmd;
  113. runflags = SRF_RUNNING;
  114. comedi_set_subdevice_runflags(s, ~0, runflags);
  115. comedi_reset_async_buf(async);
  116. return s->do_cmd(dev, s);
  117. }
  118. int comedi_command_test(void *d, struct comedi_cmd *cmd)
  119. {
  120. struct comedi_device *dev = (struct comedi_device *) d;
  121. struct comedi_subdevice *s;
  122. if (cmd->subdev >= dev->n_subdevices)
  123. return -ENODEV;
  124. s = dev->subdevices + cmd->subdev;
  125. if (s->type == COMEDI_SUBD_UNUSED)
  126. return -EIO;
  127. if (s->async == NULL)
  128. return -ENODEV;
  129. return s->do_cmdtest(dev, s, cmd);
  130. }
  131. /*
  132. * COMEDI_INSN
  133. * perform an instruction
  134. */
  135. int comedi_do_insn(void *d, struct comedi_insn *insn)
  136. {
  137. struct comedi_device *dev = (struct comedi_device *) d;
  138. struct comedi_subdevice *s;
  139. int ret = 0;
  140. if (insn->insn & INSN_MASK_SPECIAL) {
  141. switch (insn->insn) {
  142. case INSN_GTOD:
  143. {
  144. struct timeval tv;
  145. do_gettimeofday(&tv);
  146. insn->data[0] = tv.tv_sec;
  147. insn->data[1] = tv.tv_usec;
  148. ret = 2;
  149. break;
  150. }
  151. case INSN_WAIT:
  152. /* XXX isn't the value supposed to be nanosecs? */
  153. if (insn->n != 1 || insn->data[0] >= 100) {
  154. ret = -EINVAL;
  155. break;
  156. }
  157. udelay(insn->data[0]);
  158. ret = 1;
  159. break;
  160. case INSN_INTTRIG:
  161. if (insn->n != 1) {
  162. ret = -EINVAL;
  163. break;
  164. }
  165. if (insn->subdev >= dev->n_subdevices) {
  166. printk("%d not usable subdevice\n",
  167. insn->subdev);
  168. ret = -EINVAL;
  169. break;
  170. }
  171. s = dev->subdevices + insn->subdev;
  172. if (!s->async) {
  173. printk("no async\n");
  174. ret = -EINVAL;
  175. break;
  176. }
  177. if (!s->async->inttrig) {
  178. printk("no inttrig\n");
  179. ret = -EAGAIN;
  180. break;
  181. }
  182. ret = s->async->inttrig(dev, s, insn->data[0]);
  183. if (ret >= 0)
  184. ret = 1;
  185. break;
  186. default:
  187. ret = -EINVAL;
  188. }
  189. } else {
  190. /* a subdevice instruction */
  191. if (insn->subdev >= dev->n_subdevices) {
  192. ret = -EINVAL;
  193. goto error;
  194. }
  195. s = dev->subdevices + insn->subdev;
  196. if (s->type == COMEDI_SUBD_UNUSED) {
  197. printk("%d not useable subdevice\n", insn->subdev);
  198. ret = -EIO;
  199. goto error;
  200. }
  201. /* XXX check lock */
  202. ret = check_chanlist(s, 1, &insn->chanspec);
  203. if (ret < 0) {
  204. printk("bad chanspec\n");
  205. ret = -EINVAL;
  206. goto error;
  207. }
  208. if (s->busy) {
  209. ret = -EBUSY;
  210. goto error;
  211. }
  212. s->busy = d;
  213. switch (insn->insn) {
  214. case INSN_READ:
  215. ret = s->insn_read(dev, s, insn, insn->data);
  216. break;
  217. case INSN_WRITE:
  218. ret = s->insn_write(dev, s, insn, insn->data);
  219. break;
  220. case INSN_BITS:
  221. ret = s->insn_bits(dev, s, insn, insn->data);
  222. break;
  223. case INSN_CONFIG:
  224. /* XXX should check instruction length */
  225. ret = s->insn_config(dev, s, insn, insn->data);
  226. break;
  227. default:
  228. ret = -EINVAL;
  229. break;
  230. }
  231. s->busy = NULL;
  232. }
  233. if (ret < 0)
  234. goto error;
  235. #if 0
  236. /* XXX do we want this? -- abbotti #if'ed it out for now. */
  237. if (ret != insn->n) {
  238. printk("BUG: result of insn != insn.n\n");
  239. ret = -EINVAL;
  240. goto error;
  241. }
  242. #endif
  243. error:
  244. return ret;
  245. }
  246. /*
  247. COMEDI_LOCK
  248. lock subdevice
  249. arg:
  250. subdevice number
  251. reads:
  252. none
  253. writes:
  254. none
  255. necessary locking:
  256. - ioctl/rt lock (this type)
  257. - lock while subdevice busy
  258. - lock while subdevice being programmed
  259. */
  260. int comedi_lock(void *d, unsigned int subdevice)
  261. {
  262. struct comedi_device *dev = (struct comedi_device *) d;
  263. struct comedi_subdevice *s;
  264. unsigned long flags;
  265. int ret = 0;
  266. if (subdevice >= dev->n_subdevices)
  267. return -EINVAL;
  268. s = dev->subdevices + subdevice;
  269. spin_lock_irqsave(&s->spin_lock, flags);
  270. if (s->busy) {
  271. ret = -EBUSY;
  272. } else {
  273. if (s->lock) {
  274. ret = -EBUSY;
  275. } else {
  276. s->lock = d;
  277. }
  278. }
  279. spin_unlock_irqrestore(&s->spin_lock, flags);
  280. return ret;
  281. }
  282. /*
  283. COMEDI_UNLOCK
  284. unlock subdevice
  285. arg:
  286. subdevice number
  287. reads:
  288. none
  289. writes:
  290. none
  291. */
  292. int comedi_unlock(void *d, unsigned int subdevice)
  293. {
  294. struct comedi_device *dev = (struct comedi_device *) d;
  295. struct comedi_subdevice *s;
  296. unsigned long flags;
  297. struct comedi_async *async;
  298. int ret;
  299. if (subdevice >= dev->n_subdevices)
  300. return -EINVAL;
  301. s = dev->subdevices + subdevice;
  302. async = s->async;
  303. spin_lock_irqsave(&s->spin_lock, flags);
  304. if (s->busy) {
  305. ret = -EBUSY;
  306. } else if (s->lock && s->lock != (void *)d) {
  307. ret = -EACCES;
  308. } else {
  309. s->lock = NULL;
  310. if (async) {
  311. async->cb_mask = 0;
  312. async->cb_func = NULL;
  313. async->cb_arg = NULL;
  314. }
  315. ret = 0;
  316. }
  317. spin_unlock_irqrestore(&s->spin_lock, flags);
  318. return ret;
  319. }
  320. /*
  321. COMEDI_CANCEL
  322. cancel acquisition ioctl
  323. arg:
  324. subdevice number
  325. reads:
  326. nothing
  327. writes:
  328. nothing
  329. */
  330. int comedi_cancel(void *d, unsigned int subdevice)
  331. {
  332. struct comedi_device *dev = (struct comedi_device *) d;
  333. struct comedi_subdevice *s;
  334. int ret = 0;
  335. if (subdevice >= dev->n_subdevices)
  336. return -EINVAL;
  337. s = dev->subdevices + subdevice;
  338. if (s->lock && s->lock != d)
  339. return -EACCES;
  340. #if 0
  341. if (!s->busy)
  342. return 0;
  343. if (s->busy != d)
  344. return -EBUSY;
  345. #endif
  346. if (!s->cancel || !s->async)
  347. return -EINVAL;
  348. ret = s->cancel(dev, s);
  349. if (ret)
  350. return ret;
  351. comedi_set_subdevice_runflags(s, SRF_RUNNING | SRF_RT, 0);
  352. s->async->inttrig = NULL;
  353. s->busy = NULL;
  354. return 0;
  355. }
  356. /*
  357. registration of callback functions
  358. */
  359. int comedi_register_callback(void *d, unsigned int subdevice,
  360. unsigned int mask, int (*cb) (unsigned int, void *), void *arg)
  361. {
  362. struct comedi_device *dev = (struct comedi_device *) d;
  363. struct comedi_subdevice *s;
  364. struct comedi_async *async;
  365. if (subdevice >= dev->n_subdevices)
  366. return -EINVAL;
  367. s = dev->subdevices + subdevice;
  368. async = s->async;
  369. if (s->type == COMEDI_SUBD_UNUSED || !async)
  370. return -EIO;
  371. /* are we locked? (ioctl lock) */
  372. if (s->lock && s->lock != d)
  373. return -EACCES;
  374. /* are we busy? */
  375. if (s->busy)
  376. return -EBUSY;
  377. if (!mask) {
  378. async->cb_mask = 0;
  379. async->cb_func = NULL;
  380. async->cb_arg = NULL;
  381. } else {
  382. async->cb_mask = mask;
  383. async->cb_func = cb;
  384. async->cb_arg = arg;
  385. }
  386. return 0;
  387. }
  388. int comedi_poll(void *d, unsigned int subdevice)
  389. {
  390. struct comedi_device *dev = (struct comedi_device *) d;
  391. struct comedi_subdevice *s = dev->subdevices;
  392. struct comedi_async *async;
  393. if (subdevice >= dev->n_subdevices)
  394. return -EINVAL;
  395. s = dev->subdevices + subdevice;
  396. async = s->async;
  397. if (s->type == COMEDI_SUBD_UNUSED || !async)
  398. return -EIO;
  399. /* are we locked? (ioctl lock) */
  400. if (s->lock && s->lock != d)
  401. return -EACCES;
  402. /* are we running? XXX wrong? */
  403. if (!s->busy)
  404. return -EIO;
  405. return s->poll(dev, s);
  406. }
  407. /* WARNING: not portable */
  408. int comedi_map(void *d, unsigned int subdevice, void *ptr)
  409. {
  410. struct comedi_device *dev = (struct comedi_device *) d;
  411. struct comedi_subdevice *s;
  412. if (subdevice >= dev->n_subdevices)
  413. return -EINVAL;
  414. s = dev->subdevices + subdevice;
  415. if (!s->async)
  416. return -EINVAL;
  417. if (ptr)
  418. *((void **)ptr) = s->async->prealloc_buf;
  419. /* XXX no reference counting */
  420. return 0;
  421. }
  422. /* WARNING: not portable */
  423. int comedi_unmap(void *d, unsigned int subdevice)
  424. {
  425. struct comedi_device *dev = (struct comedi_device *) d;
  426. struct comedi_subdevice *s;
  427. if (subdevice >= dev->n_subdevices)
  428. return -EINVAL;
  429. s = dev->subdevices + subdevice;
  430. if (!s->async)
  431. return -EINVAL;
  432. /* XXX no reference counting */
  433. return 0;
  434. }