![]() |
RTXI 1.3
|
00001 /* 00002 module/range.c 00003 comedi routines for voltage ranges 00004 00005 COMEDI - Linux Control and Measurement Device Interface 00006 Copyright (C) 1997-8 David A. Schleef <ds@schleef.org> 00007 00008 This program is free software; you can redistribute it and/or modify 00009 it under the terms of the GNU General Public License as published by 00010 the Free Software Foundation; either version 2 of the License, or 00011 (at your option) any later version. 00012 00013 This program is distributed in the hope that it will be useful, 00014 but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 GNU General Public License for more details. 00017 00018 You should have received a copy of the GNU General Public License 00019 along with this program; if not, write to the Free Software 00020 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00021 00022 */ 00023 00024 #include <linux/comedidev.h> 00025 #include <asm/uaccess.h> 00026 00027 const comedi_lrange range_bipolar10 = { 1, {BIP_RANGE(10)} }; 00028 const comedi_lrange range_bipolar5 = { 1, {BIP_RANGE(5)} }; 00029 const comedi_lrange range_bipolar2_5 = { 1, {BIP_RANGE(2.5)} }; 00030 const comedi_lrange range_unipolar10 = { 1, {UNI_RANGE(10)} }; 00031 const comedi_lrange range_unipolar5 = { 1, {UNI_RANGE(5)} }; 00032 const comedi_lrange range_unknown = { 1, {{0, 1000000, UNIT_none}} }; 00033 00034 /* 00035 COMEDI_RANGEINFO 00036 range information ioctl 00037 00038 arg: 00039 pointer to rangeinfo structure 00040 00041 reads: 00042 range info structure 00043 00044 writes: 00045 n comedi_krange structures to rangeinfo->range_ptr 00046 */ 00047 int do_rangeinfo_ioctl(comedi_device * dev, comedi_rangeinfo * arg) 00048 { 00049 comedi_rangeinfo it; 00050 int subd, chan; 00051 const comedi_lrange *lr; 00052 comedi_subdevice *s; 00053 00054 if (copy_from_user(&it, arg, sizeof(comedi_rangeinfo))) 00055 return -EFAULT; 00056 subd = (it.range_type >> 24) & 0xf; 00057 chan = (it.range_type >> 16) & 0xff; 00058 00059 if (!dev->attached) 00060 return -EINVAL; 00061 if (subd >= dev->n_subdevices) 00062 return -EINVAL; 00063 s = dev->subdevices + subd; 00064 if (s->range_table) { 00065 lr = s->range_table; 00066 } else if (s->range_table_list) { 00067 if (chan >= s->n_chan) 00068 return -EINVAL; 00069 lr = s->range_table_list[chan]; 00070 } else { 00071 return -EINVAL; 00072 } 00073 00074 if (RANGE_LENGTH(it.range_type) != lr->length) { 00075 DPRINTK("wrong length %d should be %d (0x%08x)\n", 00076 RANGE_LENGTH(it.range_type), lr->length, it.range_type); 00077 return -EINVAL; 00078 } 00079 00080 if (copy_to_user(it.range_ptr, lr->range, 00081 sizeof(comedi_krange) * lr->length)) 00082 return -EFAULT; 00083 00084 return 0; 00085 } 00086 00087 static int aref_invalid(comedi_subdevice * s, unsigned int chanspec) 00088 { 00089 unsigned int aref; 00090 00091 // disable reporting invalid arefs... maybe someday 00092 return 0; 00093 00094 aref = CR_AREF(chanspec); 00095 switch (aref) { 00096 case AREF_DIFF: 00097 if (s->subdev_flags & SDF_DIFF) 00098 return 0; 00099 break; 00100 case AREF_COMMON: 00101 if (s->subdev_flags & SDF_COMMON) 00102 return 0; 00103 break; 00104 case AREF_GROUND: 00105 if (s->subdev_flags & SDF_GROUND) 00106 return 0; 00107 break; 00108 case AREF_OTHER: 00109 if (s->subdev_flags & SDF_OTHER) 00110 return 0; 00111 break; 00112 default: 00113 break; 00114 } 00115 DPRINTK("subdevice does not support aref %i", aref); 00116 return 1; 00117 } 00118 00119 /* 00120 This function checks each element in a channel/gain list to make 00121 make sure it is valid. 00122 */ 00123 int check_chanlist(comedi_subdevice * s, int n, unsigned int *chanlist) 00124 { 00125 int i; 00126 int chan; 00127 00128 if (s->range_table) { 00129 for (i = 0; i < n; i++) 00130 if (CR_CHAN(chanlist[i]) >= s->n_chan || 00131 CR_RANGE(chanlist[i]) >= s->range_table->length 00132 || aref_invalid(s, chanlist[i])) { 00133 rt_printk 00134 ("bad chanlist[%d]=0x%08x n_chan=%d range length=%d\n", 00135 i, chanlist[i], s->n_chan, 00136 s->range_table->length); 00137 #if 0 00138 for (i = 0; i < n; i++) { 00139 printk("[%d]=0x%08x\n", i, chanlist[i]); 00140 } 00141 #endif 00142 return -EINVAL; 00143 } 00144 } else if (s->range_table_list) { 00145 for (i = 0; i < n; i++) { 00146 chan = CR_CHAN(chanlist[i]); 00147 if (chan >= s->n_chan || 00148 CR_RANGE(chanlist[i]) >= 00149 s->range_table_list[chan]->length 00150 || aref_invalid(s, chanlist[i])) { 00151 rt_printk("bad chanlist[%d]=0x%08x\n", i, 00152 chanlist[i]); 00153 return -EINVAL; 00154 } 00155 } 00156 } else { 00157 rt_printk("comedi: (bug) no range type list!\n"); 00158 return -EINVAL; 00159 } 00160 return 0; 00161 }