source: contrib/API/lib/unictl.c@ 578

Last change on this file since 578 was 541, checked in by David Azarewicz, 15 years ago

Initial import

File size: 17.0 KB
Line 
1/*
2 * This file is part of uniaud.dll.
3 *
4 * Copyright (c) 2010 Mensys BV
5 * Copyright (c) 2007 Vlad Stelmahovsky aka Vladest
6 *
7 * This library is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation, either version 3 of
10 * the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License and the GNU General Public License along with this library.
19 * If not, see <http://www.gnu.org/licenses/>.
20 */
21#define INCL_DOS
22#define INCL_DOSERRORS
23#include <os2.h>
24#include <stdlib.h>
25#include <stdio.h>
26#include <string.h>
27
28#include "internal.h"
29
30
31/* internal mixer API */
32int _uniaud_mixer_get_ctls_number(int card_id)
33{
34 HFILE hFile = 0;
35 ULONG len;
36 ULONG id_len;
37 int ctls = 0;
38 APIRET rc = 0;
39
40 /* checking cards range */
41 if (card_id < 0 || card_id >= cards_num) // counting cards from 0
42 return -UNIAUD_INVALID_CARD;
43
44 //Check if 32 bits PDD was successfully loaded
45 if ((int)(hFile = DriverOpen()) >= 0)
46 {
47 rc = DosDevIOCtl(hFile, CAT_IOCTL_OSS32, IOCTL_OSS32_GET_CNTRLS_NUM,
48 &card_id, sizeof(card_id), &id_len,
49 &ctls, sizeof(ctls), &len);
50 DosClose(hFile);
51
52 if (rc != 0)
53 return -UNIAUD_ERROR_IN_DRIVER;
54
55 return ctls;
56 }
57 else
58 return -UNIAUD_ALSA32OPEN_ERROR;
59}
60
61UniaudControl * _uniaud_mixer_get_ctl_list(int card_id)
62{
63 HFILE hFile = 0;
64 ULONG len;
65 ULONG id_len;
66 int ctls = 0;
67 APIRET rc = 0;
68 UniaudControl *pCtl = NULL;
69
70 /* checking cards range */
71 if (card_id < 0 || card_id >= cards_num) // counting cards from 0
72 return NULL;
73
74 //Check if 32 bits PDD was successfully loaded
75 if ((int)(hFile = DriverOpen()) >= 0)
76 {
77 rc = DosDevIOCtl(hFile, CAT_IOCTL_OSS32, IOCTL_OSS32_GET_CNTRLS_NUM,
78 &card_id, sizeof(card_id), &id_len,
79 &ctls, sizeof(ctls), &len);
80 if (rc == 0)
81 {
82 pCtl = (UniaudControl *)malloc(ctls*sizeof(UniaudControl));
83 if (pCtl)
84 {
85 memset(pCtl,0,ctls*sizeof(UniaudControl));
86 rc = DosDevIOCtl(hFile, CAT_IOCTL_OSS32, IOCTL_OSS32_GET_CNTRLS,
87 &card_id, sizeof(card_id), &id_len,
88 &pCtl, sizeof(pCtl), &len);
89 if (rc != 0)
90 {
91 free(pCtl);
92 pCtl = NULL;
93 }
94 }
95 }
96 DosClose(hFile);
97 }
98
99 return pCtl; // pointer to controls list
100}
101
102int uniaud_get_id_by_name(int card_id, char *name, int index)
103{
104 int i;
105 UniaudControl *pCtl = NULL;
106 /* checking cards range */
107 if (card_id < 0 || card_id >= cards_num) // counting cards from 0
108 return -UNIAUD_INVALID_CARD;
109 if (!name)
110 return -UNIAUD_INVALID_PARAMETER;
111
112 pCtl = UniInst[card_id].ctls_list;
113 for (i=0; i < UniInst[card_id].ctls_num; i++)
114 {
115 //printf("%s\n",pCtl->name);
116 if (strcmp(pCtl->name, name) == 0 && pCtl->index == index)
117 return pCtl->numid;
118 pCtl++;
119 }
120 return -UNIAUD_NOT_FOUND;
121}
122
123/* external mixer API */
124int uniaud_mixer_get_ctls_number(int card_id)
125{
126 /* checking cards range */
127 if (card_id < 0 || card_id >= cards_num) // counting cards from 0
128 return -UNIAUD_INVALID_CARD;
129
130 return UniInst[card_id].ctls_num;
131}
132
133/* internal mixer API */
134
135/* external mixer API */
136UniaudControl * uniaud_mixer_get_ctl_list(int card_id)
137{
138 /* checking cards range */
139 if (card_id < 0 || card_id >= cards_num) // counting cards from 0
140 return NULL;
141
142 return UniInst[card_id].ctls_list; // pointer to controls list
143}
144
145int uniaud_mixer_get_power_state(int card_id, ULONG *state)
146{
147 HFILE hFile = 0;
148 ULONG len;
149 ULONG id, idlen;
150 APIRET rc = 0;
151
152 /* checking cards range */
153 if (card_id < 0 || card_id >= cards_num) // counting cards from 0
154 return -UNIAUD_INVALID_CARD;
155
156 //if (state < 0) return -UNIAUD_INVALID_PARAMETER;
157
158 if ((int)(hFile = DriverOpen()) >= 0)
159 {
160 id = card_id;
161 idlen = sizeof(id);
162 //printf("id: %x, card: %x, ctl: %x\n",id, card_id, pCtl->numid);
163 rc = DosDevIOCtl(hFile, CAT_IOCTL_OSS32,
164 IOCTL_OSS32_GET_POWER_STATE,
165 &id, sizeof(id), &idlen,
166 &state, sizeof(state), &len);
167 DosClose(hFile);
168 }
169 else
170 return UNIAUD_ALSA32OPEN_ERROR;
171
172 return UNIAUD_NO_ERROR;
173}
174
175int uniaud_mixer_set_power_state(int card_id, ULONG *state)
176{
177 HFILE hFile = 0;
178 ULONG len;
179 ULONG id, idlen;
180 APIRET rc = 0;
181
182 /* checking cards range */
183 if (card_id < 0 || card_id >= cards_num) // counting cards from 0
184 return -UNIAUD_INVALID_CARD;
185
186 //if (state < 0) return -UNIAUD_INVALID_PARAMETER;
187
188 if ((int)(hFile = DriverOpen()) >= 0)
189 {
190 id = card_id;
191 idlen = sizeof(id);
192 //printf("id: %x, card: %x, ctl: %x\n",id, card_id, pCtl->numid);
193 rc = DosDevIOCtl(hFile, CAT_IOCTL_OSS32,
194 IOCTL_OSS32_SET_POWER_STATE,
195 &id, sizeof(id), &idlen,
196 &state, sizeof(state), &len);
197 DosClose(hFile);
198 }
199 else
200 return UNIAUD_ALSA32OPEN_ERROR;
201
202 return UNIAUD_NO_ERROR;
203}
204
205int uniaud_mixer_get_ctl_info(int card_id, ULONG list_id,
206 UniaudControlInfo *ctl_info)
207{
208 HFILE hFile = 0;
209 ULONG len;
210 ULONG id, idlen;
211 APIRET rc = 0;
212 UniaudControl *pCtl = NULL;
213 int i = 0;
214
215 /* checking cards range */
216 if (card_id < 0 || card_id >= cards_num) // counting cards from 0
217 return -UNIAUD_INVALID_CARD;
218
219 if (!UniInst[card_id].ctls_list || !ctl_info)
220 return -UNIAUD_INVALID_PARAMETER;
221
222 if ((int)(hFile = DriverOpen()) >= 0)
223 {
224 pCtl = UniInst[card_id].ctls_list;
225 for(i=0; i<UniInst[card_id].ctls_num; i++)
226 {
227 if (list_id == pCtl->numid)
228 {
229 id = card_id << 16;
230 id |= pCtl->numid;
231 idlen = sizeof(id);
232 //printf("id: %x, card: %x, ctl: %x\n",id, card_id, pCtl->numid);
233 rc = DosDevIOCtl(hFile, CAT_IOCTL_OSS32,
234 IOCTL_OSS32_CNTRL_INFO,
235 &id, sizeof(id), &idlen,
236 &ctl_info, sizeof(ctl_info), &len);
237 break;
238 }
239 pCtl++;
240 }
241 DosClose(hFile);
242 }
243 else
244 return UNIAUD_ALSA32OPEN_ERROR;
245
246 return UNIAUD_NO_ERROR;
247}
248
249int uniaud_mixer_get_ctl_val(int card_id, ULONG list_id, UniaudControlValue *ctl_val)
250{
251 HFILE hFile = 0;
252 ULONG len;
253 ULONG id, idlen;
254 UniaudControl *pCtl = NULL;
255 int i = 0;
256
257 /* checking cards range */
258 if (card_id < 0 || card_id >= cards_num) // counting cards from 0
259 return -UNIAUD_INVALID_CARD;
260
261 if (!UniInst[card_id].ctls_list || !ctl_val)
262 return -UNIAUD_INVALID_PARAMETER;
263
264 if ((int)(hFile = DriverOpen()) >= 0)
265 {
266 pCtl = UniInst[card_id].ctls_list;
267 for(i=0; i<UniInst[card_id].ctls_num; i++)
268 {
269 if (list_id == pCtl->numid)
270 {
271 id = card_id << 16;
272 id |= pCtl->numid;
273 DosDevIOCtl(hFile, CAT_IOCTL_OSS32,
274 IOCTL_OSS32_CNTRL_GET,
275 &id, sizeof(id), &idlen,
276 &ctl_val, sizeof(ctl_val), &len);
277 break;
278 }
279 pCtl++;
280 }
281 DosClose(hFile);
282 }
283 else
284 return -UNIAUD_ALSA32OPEN_ERROR;
285
286 return UNIAUD_NO_ERROR;
287}
288
289int uniaud_mixer_put_ctl_val(int card_id, ULONG list_id, UniaudControlValue *ctl_val)
290{
291 HFILE hFile = 0;
292 ULONG len;
293 ULONG id, idlen;
294
295 /* checking cards range */
296 if (card_id < 0 || card_id >= cards_num) // counting cards from 0
297 return -UNIAUD_INVALID_CARD;
298
299 if (!ctl_val) return -UNIAUD_INVALID_PARAMETER;
300
301 if ((int)(hFile = DriverOpen()) >= 0) {
302 id = card_id << 16;
303 id |= list_id;
304 DosDevIOCtl(hFile, CAT_IOCTL_OSS32, IOCTL_OSS32_CNTRL_PUT,
305 &id, sizeof(id), &idlen,
306 &ctl_val, sizeof(ctl_val), &len);
307 DosClose(hFile);
308 } else
309 return -UNIAUD_ALSA32OPEN_ERROR;
310
311 return UNIAUD_NO_ERROR;
312}
313
314/*
315 * Wait for any control change and return changed control number
316 */
317
318int uniaud_mixer_wait(int card_id, int timeout)
319{
320 HFILE hFile = 0;
321 ULONG len, id_len;
322 ULONG rc;
323 int ctl_id = 0;
324 ioctl_pcm io_pcm = {0};
325
326 /* checking cards range */
327 if (card_id < 0 || card_id >= cards_num) // counting cards from 0
328 return -UNIAUD_INVALID_CARD;
329
330 io_pcm.deviceid = card_id;
331 io_pcm.streamtype = timeout;
332
333 if ((int)(hFile = DriverOpen()) >= 0)
334 {
335 rc = DosDevIOCtl(hFile, CAT_IOCTL_OSS32, IOCTL_OSS32_CNTRL_WAIT,
336 &io_pcm, sizeof(io_pcm), &id_len,
337 &ctl_id, sizeof(ctl_id), &len);
338 DosClose(hFile);
339 if (rc != 0)
340 return -UNIAUD_ERROR_IN_DRIVER;
341 return ctl_id;
342 }
343 else
344 return -UNIAUD_ALSA32OPEN_ERROR;
345}
346
347int uniaud_mixer_put_value(int card_id, ULONG put_id, int put_val, int put_cnt)
348{
349 UniaudControlInfo *ctl_info = NULL;
350 UniaudControlValue *ctl_val = NULL;
351 int err = 0;
352
353 if (put_id == 0) return -1;
354
355 ctl_info = (UniaudControlInfo *)malloc(sizeof(UniaudControlInfo));
356 if (!ctl_info) return -1;
357
358 ctl_val = (UniaudControlValue *)malloc(sizeof(UniaudControlValue));
359 if (!ctl_val) {
360 free(ctl_info);
361 return -1;
362 }
363
364 memset(ctl_info,0,sizeof(UniaudControlInfo));
365 memset(ctl_val,0,sizeof(UniaudControlValue));
366
367 if (DebugMode) {
368 printf("&ctl_val=%x, &id=%x sizeof(id)=%x &value=%x\n", ctl_val, &ctl_val->id, sizeof(ctl_val->id), &ctl_val->value);
369 printf("&val0=%x &val1=%x\n", &ctl_val->value.integer.value[0], &ctl_val->value.integer.value[1]);
370
371 printf("uniaud_mixer_put_value: id=%i cnt=%i val=%i\n", put_id, put_cnt, put_val);
372 }
373
374 if (!uniaud_mixer_get_ctl_info(card_id, put_id, ctl_info) &&
375 !uniaud_mixer_get_ctl_val(card_id, put_id, ctl_val)) {
376
377 if (put_cnt >= ctl_info->count) err = -1;
378
379 switch(ctl_info->type) {
380 case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
381 case SNDRV_CTL_ELEM_TYPE_INTEGER:
382 if (put_val >= ctl_info->value.integer.min && put_val <= ctl_info->value.integer.max)
383 ctl_val->value.integer.value[put_cnt] = put_val;
384 else
385 err = -2;
386 break;
387 case SNDRV_CTL_ELEM_TYPE_INTEGER64:
388 if (put_val >= ctl_info->value.integer64.min && put_val <= ctl_info->value.integer64.max)
389 ctl_val->value.integer64.value[put_cnt] = put_val;
390 else
391 err = -2;
392 break;
393 case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
394 if (put_val >= 0 && put_val <= ctl_info->value.enumerated.items-1) {
395 ctl_val->value.enumerated.item[put_cnt] = put_val;
396 ctl_info->value.enumerated.item = put_val; //?????
397 }
398 else
399 err = -2;
400 break;
401 } // switch
402
403 if (err == 0) {
404 if (DebugMode) printf("uniaud_mixer_put_value: card=%i id=%i Eid=%i E0=%i E1=%i\n",
405 card_id, put_id, ctl_val->id.numid, ctl_val->value.integer.value[0], ctl_val->value.integer.value[1]);
406 uniaud_mixer_put_ctl_val(card_id, put_id, ctl_val);
407 }
408 }
409 else
410 err = -3;
411
412 if (ctl_info) free(ctl_info);
413 if (ctl_val) free(ctl_val);
414 return err;
415}
416
417int uniaud_mixer_get_value(int card_id, ULONG put_id, int get_cnt)
418{
419 UniaudControlInfo *ctl_info = NULL;
420 UniaudControlValue *ctl_val = NULL;
421 int err = 0;
422 int val = 0;
423
424 ctl_info = (UniaudControlInfo *)malloc(sizeof(UniaudControlInfo));
425 ctl_val = (UniaudControlValue *)malloc(sizeof(UniaudControlValue));
426
427 if (put_id == 0 || !ctl_info || !ctl_val) return -1;
428
429 memset(ctl_info,0,sizeof(UniaudControlInfo));
430 memset(ctl_val,0,sizeof(UniaudControlValue));
431
432 if (!uniaud_mixer_get_ctl_info(card_id, put_id, ctl_info) &&
433 !uniaud_mixer_get_ctl_val(card_id, put_id, ctl_val))
434 {
435 if (ctl_info->count < get_cnt+1)
436 err = -1;
437
438 switch(ctl_info->type)
439 {
440 case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
441 case SNDRV_CTL_ELEM_TYPE_INTEGER:
442 val = ctl_val->value.integer.value[get_cnt];
443 break;
444 case SNDRV_CTL_ELEM_TYPE_INTEGER64:
445 val = ctl_val->value.integer64.value[get_cnt];
446 break;
447 case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
448 val = ctl_val->value.enumerated.item[get_cnt];
449 break;
450 } // switch
451 }
452 if (ctl_info) free(ctl_info);
453 if (ctl_val) free(ctl_val);
454 return val;
455
456}
457
458int uniaud_mixer_get_min_max(int card_id, ULONG ctl_id, int *min, int*max)
459{
460 UniaudControlInfo *ctl_info = NULL;
461 //int err = 0;
462
463 ctl_info = (UniaudControlInfo *)malloc(sizeof(UniaudControlInfo));
464
465 if (ctl_id == 0 || !ctl_info) return -1;
466
467 memset(ctl_info,0,sizeof(UniaudControlInfo));
468
469 if (!uniaud_mixer_get_ctl_info(card_id, ctl_id, ctl_info))
470 {
471 switch(ctl_info->type)
472 {
473 case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
474 case SNDRV_CTL_ELEM_TYPE_INTEGER:
475 if (min) *min = ctl_info->value.integer.min;
476 if (max) *max = ctl_info->value.integer.max;
477 break;
478 case SNDRV_CTL_ELEM_TYPE_INTEGER64:
479 if (min) *min = ctl_info->value.integer64.min;
480 if (max) *max = ctl_info->value.integer64.max;
481 break;
482 case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
483 if (min) *min = 0;
484 if (max) *max = ctl_info->value.enumerated.items;
485 break;
486 } // switch
487 }
488 if (ctl_info) free(ctl_info);
489 return 0;
490}
491
492int uniaud_mixer_get_count_of_values(int card_id, ULONG ctl_id, int *values_cnt)
493{
494 UniaudControlInfo *ctl_info = NULL;
495 int err = 0;
496
497 ctl_info = (UniaudControlInfo *)malloc(sizeof(UniaudControlInfo));
498
499 if (ctl_id == 0 || !ctl_info) return -1;
500
501 memset(ctl_info,0,sizeof(UniaudControlInfo));
502
503 if (!uniaud_mixer_get_ctl_info(card_id, ctl_id, ctl_info))
504 {
505 if (values_cnt)
506 *values_cnt = ctl_info->count;
507 }
508 if (ctl_info) free(ctl_info);
509 return err;
510}
511
512int uniaud_mixer_put_value_by_name(int card_id, char *name, int put_val, int put_cnt, int index)
513{
514 UniaudControlInfo *ctl_info = NULL;
515 UniaudControlValue *ctl_val = NULL;
516 int err = 0;
517 int put_id = -1;
518
519 ctl_info = (UniaudControlInfo *)malloc(sizeof(UniaudControlInfo));
520 ctl_val = (UniaudControlValue *)malloc(sizeof(UniaudControlValue));
521
522 if (!ctl_info || !ctl_val)
523 return -1;
524
525 put_id = uniaud_get_id_by_name(card_id, name, index);
526
527 if (put_id <= 0)
528 return -UNIAUD_INVALID_PARAMETER;
529
530 memset(ctl_info,0,sizeof(UniaudControlInfo));
531 memset(ctl_val,0,sizeof(UniaudControlValue));
532
533 if (!uniaud_mixer_get_ctl_info(card_id, put_id, ctl_info) &&
534 !uniaud_mixer_get_ctl_val(card_id, put_id, ctl_val))
535 {
536 if (ctl_info->count < put_cnt+1)
537 err = -1;
538
539 switch(ctl_info->type)
540 {
541 case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
542 case SNDRV_CTL_ELEM_TYPE_INTEGER:
543 if (put_val >= ctl_info->value.integer.min &&
544 put_val <= ctl_info->value.integer.max)
545 ctl_val->value.integer.value[put_cnt] = put_val;
546 else
547 err = -1;
548 break;
549 case SNDRV_CTL_ELEM_TYPE_INTEGER64:
550 if (put_val >= ctl_info->value.integer64.min &&
551 put_val <= ctl_info->value.integer64.max)
552 ctl_val->value.integer64.value[put_cnt] = put_val;
553 else
554 err = -1;
555 break;
556 case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
557 if (put_val >= 0 &&
558 put_val <= ctl_info->value.enumerated.items-1)
559 ctl_val->value.enumerated.item[put_cnt] = put_val;
560 else
561 err = -1;
562 break;
563 } // switch
564
565 if (err == 0)
566 uniaud_mixer_put_ctl_val(card_id, put_id, ctl_val);
567 }
568 else
569 err = -3;
570
571 if (ctl_info) free(ctl_info);
572 if (ctl_val) free(ctl_val);
573 return err;
574}
575
576int uniaud_mixer_get_value_by_name(int card_id, char *name, int get_cnt, int index)
577{
578 UniaudControlInfo *ctl_info = NULL;
579 UniaudControlValue *ctl_val = NULL;
580 int err = 0;
581 int val = 0;
582 int put_id = -1;
583
584 ctl_info = (UniaudControlInfo *)malloc(sizeof(UniaudControlInfo));
585 ctl_val = (UniaudControlValue *)malloc(sizeof(UniaudControlValue));
586
587 if (!ctl_info || !ctl_val)
588 return -1;
589
590 put_id = uniaud_get_id_by_name(card_id, name, index);
591
592 if (put_id <= 0)
593 return -UNIAUD_INVALID_PARAMETER;
594
595 memset(ctl_info,0,sizeof(UniaudControlInfo));
596 memset(ctl_val,0,sizeof(UniaudControlValue));
597
598 if (!uniaud_mixer_get_ctl_info(card_id, put_id, ctl_info) &&
599 !uniaud_mixer_get_ctl_val(card_id, put_id, ctl_val))
600 {
601 if (ctl_info->count < get_cnt+1)
602 err = -1;
603
604 switch(ctl_info->type)
605 {
606 case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
607 case SNDRV_CTL_ELEM_TYPE_INTEGER:
608 val = ctl_val->value.integer.value[get_cnt];
609 break;
610 case SNDRV_CTL_ELEM_TYPE_INTEGER64:
611 val = ctl_val->value.integer64.value[get_cnt];
612 break;
613 case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
614 val = ctl_val->value.enumerated.item[get_cnt];
615 break;
616 } // switch
617 }
618 if (ctl_info) free(ctl_info);
619 if (ctl_val) free(ctl_val);
620 return val;
621
622}
623
624int uniaud_mixer_put_spdif_status(int card_id, char *name, int aes0, int aes1, int aes2, int aes3)
625{
626 UniaudControlInfo *ctl_info = NULL;
627 UniaudControlValue *ctl_val = NULL;
628 int err = 0;
629 int put_id = -1;
630 int index = 0;
631
632 ctl_info = (UniaudControlInfo *)malloc(sizeof(UniaudControlInfo));
633 ctl_val = (UniaudControlValue *)malloc(sizeof(UniaudControlValue));
634
635 if (!ctl_info || !ctl_val)
636 return -1;
637
638 put_id = uniaud_get_id_by_name(card_id, name, index);
639
640 if (put_id <= 0)
641 return -UNIAUD_INVALID_PARAMETER;
642
643 memset(ctl_info,0,sizeof(UniaudControlInfo));
644 memset(ctl_val,0,sizeof(UniaudControlValue));
645
646 if (!uniaud_mixer_get_ctl_info(card_id, put_id, ctl_info) &&
647 !uniaud_mixer_get_ctl_val(card_id, put_id, ctl_val))
648 {
649 if (SNDRV_CTL_ELEM_TYPE_IEC958 == ctl_info->type)
650 {
651 ctl_val->value.iec958.status[0] = aes0;
652 ctl_val->value.iec958.status[1] = aes1;
653 ctl_val->value.iec958.status[2] = aes2;
654 ctl_val->value.iec958.status[3] = aes3;
655 }
656
657 if (err == 0)
658 uniaud_mixer_put_ctl_val(card_id, put_id, ctl_val);
659 }
660 else
661 err = -3;
662
663 if (ctl_info) free(ctl_info);
664 if (ctl_val) free(ctl_val);
665 return err;
666}
667
Note: See TracBrowser for help on using the repository browser.