range.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. /*
  2. module/range.c
  3. comedi routines for voltage ranges
  4. COMEDI - Linux Control and Measurement Device Interface
  5. Copyright (C) 1997-8 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. #include <linux/uaccess.h>
  19. #include "comedidev.h"
  20. #include "internal.h"
  21. const struct comedi_lrange range_bipolar10 = { 1, {BIP_RANGE(10)} };
  22. EXPORT_SYMBOL(range_bipolar10);
  23. const struct comedi_lrange range_bipolar5 = { 1, {BIP_RANGE(5)} };
  24. EXPORT_SYMBOL(range_bipolar5);
  25. const struct comedi_lrange range_bipolar2_5 = { 1, {BIP_RANGE(2.5)} };
  26. EXPORT_SYMBOL(range_bipolar2_5);
  27. const struct comedi_lrange range_unipolar10 = { 1, {UNI_RANGE(10)} };
  28. EXPORT_SYMBOL(range_unipolar10);
  29. const struct comedi_lrange range_unipolar5 = { 1, {UNI_RANGE(5)} };
  30. EXPORT_SYMBOL(range_unipolar5);
  31. const struct comedi_lrange range_unknown = { 1, {{0, 1000000, UNIT_none} } };
  32. EXPORT_SYMBOL(range_unknown);
  33. /*
  34. COMEDI_RANGEINFO
  35. range information ioctl
  36. arg:
  37. pointer to rangeinfo structure
  38. reads:
  39. range info structure
  40. writes:
  41. n struct comedi_krange structures to rangeinfo->range_ptr
  42. */
  43. int do_rangeinfo_ioctl(struct comedi_device *dev,
  44. struct comedi_rangeinfo __user *arg)
  45. {
  46. struct comedi_rangeinfo it;
  47. int subd, chan;
  48. const struct comedi_lrange *lr;
  49. struct comedi_subdevice *s;
  50. if (copy_from_user(&it, arg, sizeof(struct comedi_rangeinfo)))
  51. return -EFAULT;
  52. subd = (it.range_type >> 24) & 0xf;
  53. chan = (it.range_type >> 16) & 0xff;
  54. if (!dev->attached)
  55. return -EINVAL;
  56. if (subd >= dev->n_subdevices)
  57. return -EINVAL;
  58. s = dev->subdevices + subd;
  59. if (s->range_table) {
  60. lr = s->range_table;
  61. } else if (s->range_table_list) {
  62. if (chan >= s->n_chan)
  63. return -EINVAL;
  64. lr = s->range_table_list[chan];
  65. } else {
  66. return -EINVAL;
  67. }
  68. if (RANGE_LENGTH(it.range_type) != lr->length) {
  69. DPRINTK("wrong length %d should be %d (0x%08x)\n",
  70. RANGE_LENGTH(it.range_type), lr->length, it.range_type);
  71. return -EINVAL;
  72. }
  73. if (copy_to_user(it.range_ptr, lr->range,
  74. sizeof(struct comedi_krange) * lr->length))
  75. return -EFAULT;
  76. return 0;
  77. }
  78. static int aref_invalid(struct comedi_subdevice *s, unsigned int chanspec)
  79. {
  80. unsigned int aref;
  81. /* disable reporting invalid arefs... maybe someday */
  82. return 0;
  83. aref = CR_AREF(chanspec);
  84. switch (aref) {
  85. case AREF_DIFF:
  86. if (s->subdev_flags & SDF_DIFF)
  87. return 0;
  88. break;
  89. case AREF_COMMON:
  90. if (s->subdev_flags & SDF_COMMON)
  91. return 0;
  92. break;
  93. case AREF_GROUND:
  94. if (s->subdev_flags & SDF_GROUND)
  95. return 0;
  96. break;
  97. case AREF_OTHER:
  98. if (s->subdev_flags & SDF_OTHER)
  99. return 0;
  100. break;
  101. default:
  102. break;
  103. }
  104. DPRINTK("subdevice does not support aref %i", aref);
  105. return 1;
  106. }
  107. /*
  108. This function checks each element in a channel/gain list to make
  109. make sure it is valid.
  110. */
  111. int comedi_check_chanlist(struct comedi_subdevice *s, int n,
  112. unsigned int *chanlist)
  113. {
  114. int i;
  115. int chan;
  116. if (s->range_table) {
  117. for (i = 0; i < n; i++)
  118. if (CR_CHAN(chanlist[i]) >= s->n_chan ||
  119. CR_RANGE(chanlist[i]) >= s->range_table->length
  120. || aref_invalid(s, chanlist[i])) {
  121. printk(KERN_ERR "bad chanlist[%d]=0x%08x "
  122. "in_chan=%d range length=%d\n", i,
  123. chanlist[i], s->n_chan,
  124. s->range_table->length);
  125. return -EINVAL;
  126. }
  127. } else if (s->range_table_list) {
  128. for (i = 0; i < n; i++) {
  129. chan = CR_CHAN(chanlist[i]);
  130. if (chan >= s->n_chan ||
  131. CR_RANGE(chanlist[i]) >=
  132. s->range_table_list[chan]->length
  133. || aref_invalid(s, chanlist[i])) {
  134. printk(KERN_ERR "bad chanlist[%d]=0x%08x\n",
  135. i, chanlist[i]);
  136. return -EINVAL;
  137. }
  138. }
  139. } else {
  140. printk(KERN_ERR "comedi: (bug) no range type list!\n");
  141. return -EINVAL;
  142. }
  143. return 0;
  144. }
  145. EXPORT_SYMBOL(comedi_check_chanlist);