Removed unneeded comedi_insnlist from do_test_for_insn().
[comedilib.git] / lib / filler.c
1 /*
2     lib/filler.c
3     functions to retrieve kernel data
4
5     COMEDILIB - Linux Control and Measurement Device Interface Library
6     Copyright (C) 1997-2001 David A. Schleef <ds@schleef.org>
7
8     This library is free software; you can redistribute it and/or
9     modify it under the terms of the GNU Lesser General Public
10     License as published by the Free Software Foundation, version 2.1
11     of the License.
12
13     This library 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 GNU
16     Lesser General Public License for more details.
17
18     You should have received a copy of the GNU Lesser General Public
19     License along with this library; if not, write to the Free Software
20     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
21     USA.
22 */
23
24 #include <assert.h>
25 #include <stdio.h>
26 #include <math.h>
27 #include <stdlib.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <fcntl.h>
31 #include <unistd.h>
32 #include <sys/ioctl.h>
33 #include <errno.h>
34 #include <string.h>
35
36 #include "libinternal.h"
37
38
39 /* these functions download information from the comedi module. */
40
41 static int do_test_for_cmd(comedi_t *dev,unsigned int subdevice);
42 static int do_test_for_insn(comedi_t *dev);
43 static int do_test_for_insnlist(comedi_t *dev);
44 static int do_test_for_insn_bits(comedi_t *dev,unsigned int subdevice);
45
46
47 int get_subdevices(comedi_t *it)
48 {
49         int i,j;
50         int ret;
51         comedi_subdinfo *s;
52         comedi_chaninfo ci;
53         subdevice *r = NULL;
54
55         s = calloc(it->n_subdevices, sizeof(comedi_subdinfo));
56         if(s == NULL)
57         {
58                 debug_ptr(s);
59                 libc_error();
60                 goto cleanup;
61         }
62
63         ret = comedi_ioctl(it->fd, COMEDI_SUBDINFO, s);
64         if(ret < 0)
65         {
66                 debug_int(ret);
67                 goto cleanup;
68         }
69
70         assert(it->subdevices == NULL);
71         r = it->subdevices = calloc(it->n_subdevices, sizeof(subdevice));
72         if(r == NULL)
73         {
74                 debug_ptr(r);
75                 libc_error();
76                 goto cleanup;
77         }
78
79         it->has_insnlist_ioctl = do_test_for_insnlist(it);
80         it->has_insn_ioctl = do_test_for_insn(it);
81         for(i=0;i<it->n_subdevices;i++){
82                 r[i].type       = s[i].type;
83                 if(r[i].type==COMEDI_SUBD_UNUSED)continue;
84                 r[i].n_chan     = s[i].n_chan;
85                 r[i].subd_flags = s[i].subd_flags;
86                 r[i].timer_type = s[i].timer_type;
87                 r[i].len_chanlist = s[i].len_chanlist;
88                 r[i].maxdata    = s[i].maxdata;
89                 r[i].flags      = s[i].flags;
90                 r[i].range_type = s[i].range_type;
91
92                 if(r[i].subd_flags&SDF_FLAGS){
93                         r[i].flags_list = calloc(r[i].n_chan, sizeof(*r[i].flags_list));
94                         if(r[i].flags_list == NULL){
95                                 debug_ptr(r[i].flags_list);
96                                 libc_error();
97                                 goto cleanup;
98                         }
99
100                 }
101                 if(r[i].subd_flags&SDF_MAXDATA){
102                         r[i].maxdata_list = calloc(r[i].n_chan, sizeof(*r[i].maxdata_list));
103                         if(r[i].maxdata_list == NULL){
104                                 debug_ptr(r[i].maxdata_list);
105                                 libc_error();
106                                 goto cleanup;
107                         }
108                 }
109                 if(r[i].subd_flags&SDF_RANGETYPE){
110                         r[i].range_type_list = calloc(r[i].n_chan, sizeof(*r[i].range_type_list));
111                         if(r[i].range_type_list == NULL){
112                                 debug_ptr(r[i].range_type_list);
113                                 libc_error();
114                                 goto cleanup;
115                         }
116                 }
117                 ci.subdev = i;
118                 ci.flaglist = r[i].flags_list;
119                 ci.rangelist = r[i].range_type_list;
120                 ci.maxdata_list = r[i].maxdata_list;
121                 ret = comedi_ioctl(it->fd, COMEDI_CHANINFO, &ci);
122                 if(ret < 0){
123                         debug_int(ret);
124                         goto cleanup;
125                 }
126
127                 if(r[i].subd_flags&SDF_RANGETYPE){
128                         r[i].rangeinfo_list=calloc(r[i].n_chan, sizeof(*r[i].rangeinfo_list));
129                         if(r[i].rangeinfo_list == NULL){
130                                 debug_ptr(r[i].rangeinfo_list);
131                                 libc_error();
132                                 goto cleanup;
133                         }
134                         for(j=0;j<r[i].n_chan;j++){
135                                 r[i].rangeinfo_list[j]=get_rangeinfo(it->fd,r[i].range_type_list[j]);
136                                 if(r[i].rangeinfo_list[j] == NULL)
137                                         goto cleanup;
138                         }
139                 }else{
140                         r[i].rangeinfo=get_rangeinfo(it->fd,r[i].range_type);
141                         if(r[i].rangeinfo == NULL)
142                                 goto cleanup;
143                 }
144
145                 r[i].has_cmd = do_test_for_cmd(it,i);
146                 switch(s[i].insn_bits_support)
147                 {
148                 case COMEDI_UNKNOWN_SUPPORT:
149                         if(it->has_insnlist_ioctl){
150                                 r[i].has_insn_bits = do_test_for_insn_bits(it,i);
151                         }else{
152                                 r[i].has_insn_bits = 0;
153                         }
154                         break;
155                 case COMEDI_SUPPORTED:
156                         r[i].has_insn_bits = 1;
157                         break;
158                 case COMEDI_UNSUPPORTED:
159                         r[i].has_insn_bits = 0;
160                         break;
161                 default:
162                         assert(0);
163                 }
164         }
165
166         free(s);
167
168         return 0;
169
170 cleanup:
171
172         if(s)
173                 free(s);
174
175         if(r){
176                 for(i=0;i<it->n_subdevices;i++){
177                         if(r[i].flags_list)
178                                 free(r[i].flags_list);
179                         if(r[i].maxdata_list)
180                                 free(r[i].maxdata_list);
181                         if(r[i].range_type_list)
182                                 free(r[i].range_type_list);
183                         if(r[i].rangeinfo_list){
184                                 for(j=0;j<r[i].n_chan;j++){
185                                         if(r[i].rangeinfo_list[j])
186                                                 free(r[i].rangeinfo_list[j]);
187                                 }
188                         }else{
189                                 if(r[i].rangeinfo)
190                                         free(r[i].rangeinfo);
191                         }
192                 }
193                 free(r);
194                 it->subdevices = NULL;
195         }
196
197         return -1;
198 }
199
200 comedi_range *get_rangeinfo(int fd,unsigned int range_type)
201 {
202         comedi_krange *kr;
203         comedi_range *r;
204         comedi_rangeinfo ri;
205         int ret;
206         int i;
207
208         kr = calloc(RANGE_LENGTH(range_type), sizeof(comedi_krange));
209         if(kr == NULL)
210         {
211                 debug_ptr(kr);
212                 libc_error();
213                 return NULL;
214         }
215         r = calloc(RANGE_LENGTH(range_type), sizeof(comedi_range));
216         if(r == NULL)
217         {
218                 debug_ptr(r);
219                 libc_error();
220                 free(kr);
221                 return NULL;
222         }
223
224         memset(&ri, 0, sizeof(ri));
225         ri.range_type = range_type;
226         ri.range_ptr = kr;
227         ret = comedi_ioctl(fd, COMEDI_RANGEINFO, &ri);
228         if(ret<0){
229                 fprintf(stderr,"ioctl(%d,COMEDI_RANGEINFO,0x%08x,%p)\n",fd,range_type,kr);
230                 free(r);
231                 free(kr);
232                 return NULL;
233         }
234
235         for(i=0;i<RANGE_LENGTH(range_type);i++){
236                 r[i].min=kr[i].min*1e-6;
237                 r[i].max=kr[i].max*1e-6;
238                 r[i].unit=kr[i].flags;
239         }
240         free(kr);
241
242         return r;
243 }
244
245
246 /* some command testing */
247
248 static int do_test_for_cmd(comedi_t *dev,unsigned int subdevice)
249 {
250         /* SDF_CMD was added in 0.7.57 */
251         if(dev->devinfo.version_code >= COMEDI_VERSION_CODE(0,7,57)){
252                 if(dev->subdevices[subdevice].subd_flags & SDF_CMD)
253                         return 1;
254                 return 0;
255         }else{
256                 comedi_cmd it;
257                 int ret;
258
259                 memset(&it,0,sizeof(it));
260
261                 it.subdev = subdevice;
262                 it.start_src = TRIG_ANY;
263                 it.scan_begin_src = TRIG_ANY;
264                 it.convert_src = TRIG_ANY;
265                 it.scan_end_src = TRIG_ANY;
266                 it.stop_src = TRIG_ANY;
267
268                 ret = comedi_ioctl(dev->fd, COMEDI_CMDTEST, &it);
269
270                 if(ret<0 && errno==EIO){
271                         return 0;
272                 }
273                 if(ret<0){
274                         fprintf(stderr,"BUG in do_test_for_cmd()\n");
275                         return 0;
276                 }
277                 return 1;
278         }
279 }
280
281 static int do_test_for_insnlist(comedi_t *dev)
282 {
283         comedi_insn insn;
284         comedi_insnlist il;
285         lsampl_t data[2];
286         int ret;
287
288         il.n_insns = 1;
289         il.insns = &insn;
290
291         memset(&insn,0,sizeof(insn));
292         insn.insn = INSN_GTOD;
293         insn.n = 2;
294         insn.data = data;
295         memset(insn.data, 0, insn.n * sizeof(insn.data[0]));
296
297         ret = comedi_ioctl(dev->fd, COMEDI_INSNLIST, &il);
298
299         if(ret<0){
300                 if(errno!=EIO){
301                         fprintf(stderr,"BUG in do_test_for_insnlist()\n");
302                 }
303                 return 0;
304         }
305         return 1;
306 }
307
308 /* the COMEID_INSN ioctl was introduced in comedi-0.7.60 */
309 static int do_test_for_insn(comedi_t *dev)
310 {
311         comedi_insn insn;
312         lsampl_t data[2];
313         int ret;
314
315         memset(&insn,0,sizeof(insn));
316         insn.insn = INSN_GTOD;
317         insn.n = 2;
318         insn.data = data;
319         memset(insn.data, 0, insn.n * sizeof(insn.data[0]));
320
321         ret = comedi_ioctl(dev->fd, COMEDI_INSN, &insn);
322
323         if(ret<0){
324                 if(errno!=EIO){
325                         fprintf(stderr,"BUG in do_test_for_insn()\n");
326                 }
327                 return 0;
328         }
329         return 1;
330 }
331
332 static int do_test_for_insn_bits(comedi_t *dev,unsigned int subdevice)
333 {
334         comedi_insn insn;
335         comedi_insnlist il;
336         lsampl_t data[2];
337         int ret;
338
339         if(dev->subdevices[subdevice].maxdata != 1)
340                 return 0;
341
342         memset(&insn,0,sizeof(insn));
343
344         il.n_insns = 1;
345         il.insns = &insn;
346
347         insn.insn = INSN_BITS;
348         insn.n = 2;
349         insn.data = data;
350         insn.subdev = subdevice;
351         memset(data, 0, insn.n * sizeof(data[0]));
352
353         ret = comedi_do_insnlist(dev,&il);
354
355         if(ret<0 && (errno==EINVAL || errno==EIO)){
356                 return 0;
357         }
358         if(ret<0){
359                 perror("BUG in do_test_for_insn_bits()\n");
360                 return 0;
361         }
362         return 1;
363 }
364
365
366