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