kcomedilib_main.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * kcomedilib/kcomedilib.c
  4. * a comedlib interface for kernel modules
  5. *
  6. * COMEDI - Linux Control and Measurement Device Interface
  7. * Copyright (C) 1997-2000 David A. Schleef <[email protected]>
  8. */
  9. #include <linux/module.h>
  10. #include <linux/errno.h>
  11. #include <linux/kernel.h>
  12. #include <linux/sched.h>
  13. #include <linux/fcntl.h>
  14. #include <linux/mm.h>
  15. #include <linux/io.h>
  16. #include <linux/comedi.h>
  17. #include <linux/comedi/comedidev.h>
  18. #include <linux/comedi/comedilib.h>
  19. MODULE_AUTHOR("David Schleef <[email protected]>");
  20. MODULE_DESCRIPTION("Comedi kernel library");
  21. MODULE_LICENSE("GPL");
  22. struct comedi_device *comedi_open(const char *filename)
  23. {
  24. struct comedi_device *dev, *retval = NULL;
  25. unsigned int minor;
  26. if (strncmp(filename, "/dev/comedi", 11) != 0)
  27. return NULL;
  28. if (kstrtouint(filename + 11, 0, &minor))
  29. return NULL;
  30. if (minor >= COMEDI_NUM_BOARD_MINORS)
  31. return NULL;
  32. dev = comedi_dev_get_from_minor(minor);
  33. if (!dev)
  34. return NULL;
  35. down_read(&dev->attach_lock);
  36. if (dev->attached)
  37. retval = dev;
  38. else
  39. retval = NULL;
  40. up_read(&dev->attach_lock);
  41. if (!retval)
  42. comedi_dev_put(dev);
  43. return retval;
  44. }
  45. EXPORT_SYMBOL_GPL(comedi_open);
  46. int comedi_close(struct comedi_device *dev)
  47. {
  48. comedi_dev_put(dev);
  49. return 0;
  50. }
  51. EXPORT_SYMBOL_GPL(comedi_close);
  52. static int comedi_do_insn(struct comedi_device *dev,
  53. struct comedi_insn *insn,
  54. unsigned int *data)
  55. {
  56. struct comedi_subdevice *s;
  57. int ret;
  58. mutex_lock(&dev->mutex);
  59. if (!dev->attached) {
  60. ret = -EINVAL;
  61. goto error;
  62. }
  63. /* a subdevice instruction */
  64. if (insn->subdev >= dev->n_subdevices) {
  65. ret = -EINVAL;
  66. goto error;
  67. }
  68. s = &dev->subdevices[insn->subdev];
  69. if (s->type == COMEDI_SUBD_UNUSED) {
  70. dev_err(dev->class_dev,
  71. "%d not usable subdevice\n", insn->subdev);
  72. ret = -EIO;
  73. goto error;
  74. }
  75. /* XXX check lock */
  76. ret = comedi_check_chanlist(s, 1, &insn->chanspec);
  77. if (ret < 0) {
  78. dev_err(dev->class_dev, "bad chanspec\n");
  79. ret = -EINVAL;
  80. goto error;
  81. }
  82. if (s->busy) {
  83. ret = -EBUSY;
  84. goto error;
  85. }
  86. s->busy = dev;
  87. switch (insn->insn) {
  88. case INSN_BITS:
  89. ret = s->insn_bits(dev, s, insn, data);
  90. break;
  91. case INSN_CONFIG:
  92. /* XXX should check instruction length */
  93. ret = s->insn_config(dev, s, insn, data);
  94. break;
  95. default:
  96. ret = -EINVAL;
  97. break;
  98. }
  99. s->busy = NULL;
  100. error:
  101. mutex_unlock(&dev->mutex);
  102. return ret;
  103. }
  104. int comedi_dio_get_config(struct comedi_device *dev, unsigned int subdev,
  105. unsigned int chan, unsigned int *io)
  106. {
  107. struct comedi_insn insn;
  108. unsigned int data[2];
  109. int ret;
  110. memset(&insn, 0, sizeof(insn));
  111. insn.insn = INSN_CONFIG;
  112. insn.n = 2;
  113. insn.subdev = subdev;
  114. insn.chanspec = CR_PACK(chan, 0, 0);
  115. data[0] = INSN_CONFIG_DIO_QUERY;
  116. data[1] = 0;
  117. ret = comedi_do_insn(dev, &insn, data);
  118. if (ret >= 0)
  119. *io = data[1];
  120. return ret;
  121. }
  122. EXPORT_SYMBOL_GPL(comedi_dio_get_config);
  123. int comedi_dio_config(struct comedi_device *dev, unsigned int subdev,
  124. unsigned int chan, unsigned int io)
  125. {
  126. struct comedi_insn insn;
  127. memset(&insn, 0, sizeof(insn));
  128. insn.insn = INSN_CONFIG;
  129. insn.n = 1;
  130. insn.subdev = subdev;
  131. insn.chanspec = CR_PACK(chan, 0, 0);
  132. return comedi_do_insn(dev, &insn, &io);
  133. }
  134. EXPORT_SYMBOL_GPL(comedi_dio_config);
  135. int comedi_dio_bitfield2(struct comedi_device *dev, unsigned int subdev,
  136. unsigned int mask, unsigned int *bits,
  137. unsigned int base_channel)
  138. {
  139. struct comedi_insn insn;
  140. unsigned int data[2];
  141. unsigned int n_chan;
  142. unsigned int shift;
  143. int ret;
  144. base_channel = CR_CHAN(base_channel);
  145. n_chan = comedi_get_n_channels(dev, subdev);
  146. if (base_channel >= n_chan)
  147. return -EINVAL;
  148. memset(&insn, 0, sizeof(insn));
  149. insn.insn = INSN_BITS;
  150. insn.chanspec = base_channel;
  151. insn.n = 2;
  152. insn.subdev = subdev;
  153. data[0] = mask;
  154. data[1] = *bits;
  155. /*
  156. * Most drivers ignore the base channel in insn->chanspec.
  157. * Fix this here if the subdevice has <= 32 channels.
  158. */
  159. if (n_chan <= 32) {
  160. shift = base_channel;
  161. if (shift) {
  162. insn.chanspec = 0;
  163. data[0] <<= shift;
  164. data[1] <<= shift;
  165. }
  166. } else {
  167. shift = 0;
  168. }
  169. ret = comedi_do_insn(dev, &insn, data);
  170. *bits = data[1] >> shift;
  171. return ret;
  172. }
  173. EXPORT_SYMBOL_GPL(comedi_dio_bitfield2);
  174. int comedi_find_subdevice_by_type(struct comedi_device *dev, int type,
  175. unsigned int subd)
  176. {
  177. struct comedi_subdevice *s;
  178. int ret = -ENODEV;
  179. down_read(&dev->attach_lock);
  180. if (dev->attached)
  181. for (; subd < dev->n_subdevices; subd++) {
  182. s = &dev->subdevices[subd];
  183. if (s->type == type) {
  184. ret = subd;
  185. break;
  186. }
  187. }
  188. up_read(&dev->attach_lock);
  189. return ret;
  190. }
  191. EXPORT_SYMBOL_GPL(comedi_find_subdevice_by_type);
  192. int comedi_get_n_channels(struct comedi_device *dev, unsigned int subdevice)
  193. {
  194. int n;
  195. down_read(&dev->attach_lock);
  196. if (!dev->attached || subdevice >= dev->n_subdevices)
  197. n = 0;
  198. else
  199. n = dev->subdevices[subdevice].n_chan;
  200. up_read(&dev->attach_lock);
  201. return n;
  202. }
  203. EXPORT_SYMBOL_GPL(comedi_get_n_channels);
  204. static int __init kcomedilib_module_init(void)
  205. {
  206. return 0;
  207. }
  208. static void __exit kcomedilib_module_exit(void)
  209. {
  210. }
  211. module_init(kcomedilib_module_init);
  212. module_exit(kcomedilib_module_exit);