Coverity fixes
[sxemacs] / src / libsst.c
1 /* libsst.c - SPARC sound tools library
2 **
3 ** Copyright (C) 1989 by Jef Poskanzer.
4 **
5 ** Permission to use, copy, modify, and distribute this software and its
6 ** documentation for any purpose and without fee is hereby granted, provided
7 ** that the above copyright notice appear in all copies and that both that
8 ** copyright notice and this permission notice appear in supporting
9 ** documentation.  This software is provided "as is" without express or
10 ** implied warranty.
11
12 ** Hacked on by jwz for emacs.
13
14 */
15
16 /* Synched up with: Not in FSF. */
17
18 #ifdef emacs
19 #include <config.h>
20 #include "lisp.h"
21 #endif
22
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <fcntl.h>
26
27 #ifdef HAVE_UNISTD_H
28 #include <unistd.h>
29 #endif
30
31 #include "libsst.h"
32
33 #define AUDBUF 1024
34
35 int sst_open(play_level, record_level)
36 int play_level, record_level;
37 {
38         int fd, i, gr, ger, gx;
39         struct audio_ioctl ai;
40         char *ep;
41
42         fd = open("/dev/audio", O_RDWR);
43         if (fd < 0) {
44                 perror("sst_open: open /dev/audio");
45                 return (fd);
46         }
47 #ifdef AUDIOSETQSIZE            /* This no longer exists as of 4.1.2. */
48
49         /* Shrink audio device's queue size, to cut down time delay. */
50         i = AUDBUF;
51         if (ioctl(fd, AUDIOSETQSIZE, &i) < 0) {
52                 perror("sst_open: SETQSIZE");
53                 return (fd);
54         }
55 #endif                          /* AUDIOSETQSIZE */
56
57         /* Set gains.  -10 <= ger <= 18,  -18 <= gr <= 12,  -18 <= gx <= 12. */
58         if (!play_level) {
59                 play_level = 75;
60                 if ((ep = getenv("SST_PLAY")) != NULL) {
61                         play_level = atoi(ep);
62                         if (play_level < 0 || play_level > 99) {
63                                 warn("sst_open: SST_PLAY must be between 0 and 99");
64                                 return (-1);
65                         }
66                 }
67         }
68         if (!record_level) {
69                 record_level = 75;
70                 if ((ep = getenv("SST_RECORD")) != NULL) {
71                         record_level = atoi(ep);
72                         if (record_level < 0 || record_level > 99) {
73                                 warn("sst_open: SST_RECORD must be between 0 and 99");
74                                 return (-1);
75                         }
76                 }
77         }
78
79         play_level = play_level * 59 / 100 - 28;
80         ger = play_level / 2;
81         gr = play_level - ger;
82         if (ger < -10) {
83                 ger = -10;
84                 gr = play_level - ger;
85         }
86         if (gr > 12) {
87                 gr = 12;
88                 ger = play_level - gr;
89         }
90         gx = record_level * 31 / 100 - 18;
91         sst_set_gr(fd, gr);
92         sst_set_ger(fd, ger);
93         sst_set_gx(fd, gx);
94
95         /*  Initialize the MMR2 register to send the output to either
96          **  the speaker or the earphone jack, depending on SST_EARPHONES.
97          */
98         ai.control = AUDIO_MAP_MMR2;
99         if (ioctl(fd, AUDIOGETREG, &ai) < 0) {
100                 perror("sst_open: GETREG MMR2");
101                 return (-1);
102         }
103         if ((ep = getenv("SST_EARPHONES")) != NULL)
104                 ai.data[0] &= ~AUDIO_MMR2_BITS_LS;
105         else
106                 ai.data[0] |= AUDIO_MMR2_BITS_LS;
107         if (ioctl(fd, AUDIOSETREG, &ai) < 0) {
108                 perror("sst_open: SETREG MMR2");
109                 return (fd);
110         }
111
112         return fd;
113 }
114
115 void sst_close(fd)
116 int fd;
117 {
118         struct audio_ioctl ai;
119
120         ai.control = AUDIO_MAP_MMR1;
121         ai.data[0] = 0;
122         if (ioctl(fd, AUDIOSETREG, &ai) < 0) {
123                 perror("sst_close: SETREG MMR1");
124         }
125         ai.control = AUDIO_MAP_MMR2;
126         ai.data[0] = 0;
127         if (ioctl(fd, AUDIOSETREG, &ai) < 0) {
128                 perror("sst_close: SETREG MMR2");
129         }
130         close(fd);
131 }
132
133 /* These are tables of values to be loaded into various gain registers.
134 */
135
136 static unsigned char ger_table[][2] = {
137         0xaa, 0xaa,             /* -10db */
138         0x79, 0xac,
139         0x41, 0x99,
140         0x9c, 0xde,
141         0x74, 0x9c,             /* -6db */
142         0x6a, 0xae,
143         0xab, 0xdf,
144         0x64, 0xab,
145         0x2a, 0xbd,
146         0x5c, 0xce,
147         0x00, 0x99,             /* 0db */
148         0x43, 0xdd,
149         0x52, 0xef,
150         0x55, 0x42,
151         0x31, 0xdd,
152         0x43, 0x1f,
153         0x40, 0xdd,             /* 6db */
154         0x44, 0x0f,
155         0x31, 0x1f,
156         0x10, 0xdd,
157         0x41, 0x0f,
158         0x60, 0x0b,
159         0x42, 0x10,             /* 12db */
160         0x11, 0x0f,
161         0x72, 0x00,
162         0x21, 0x10,
163         0x22, 0x00,
164         0x00, 0x0b,
165         0x00, 0x0f,             /* 18db */
166 };
167
168 static unsigned char gr_gx_table[][2] = {
169         0x8b, 0x7c,             /* -18db */
170         0x8b, 0x35,
171         0x8b, 0x24,
172         0x91, 0x23,
173         0x91, 0x2a,
174         0x91, 0x3b,
175         0x91, 0xf9,             /* -12db */
176         0x91, 0xb6,
177         0x91, 0xa4,
178         0x92, 0x32,
179         0x92, 0xaa,
180         0x93, 0xb3,
181         0x9f, 0x91,             /* -6db */
182         0x9b, 0xf9,
183         0x9a, 0x4a,
184         0xa2, 0xa2,
185         0xaa, 0xa3,
186         0xbb, 0x52,
187         0x08, 0x08,             /* 0db */
188         0x3d, 0xac,
189         0x25, 0x33,
190         0x21, 0x22,
191         0x12, 0xa2,
192         0x11, 0x3b,
193         0x10, 0xf2,             /* 6db */
194         0x02, 0xca,
195         0x01, 0x5a,
196         0x01, 0x12,
197         0x00, 0x32,
198         0x00, 0x13,
199         0x00, 0x0e,             /* 12db */
200 };
201
202 void sst_set_ger(fd, value)
203 int fd, value;
204 {
205         struct audio_ioctl ai;
206
207         if ((value < -10) || (value > 18)) {
208                 char buf[255];
209                 sprintf(buf, "sst_set_ger: GER %d out of range", value);
210                 warn(buf);
211                 return;
212         }
213
214         /*  Add 10 to the value to get the index into the table.  */
215         ai.control = AUDIO_MAP_GER;
216         ai.data[0] = ger_table[value + 10][1];
217         ai.data[1] = ger_table[value + 10][0];
218
219         if (ioctl(fd, AUDIOSETREG, &ai) < 0) {
220                 perror("sst_set_ger: SETREG GER");
221         }
222
223         ai.control = AUDIO_MAP_MMR1;
224         if (ioctl(fd, AUDIOGETREG, &ai) < 0) {
225                 perror("sst_set_ger: GETREG MMR1");
226         }
227         ai.data[0] |= AUDIO_MMR1_BITS_LOAD_GER;
228         if (ioctl(fd, AUDIOSETREG, &ai) < 0) {
229                 perror("sst_set_ger: SETREG MMR1");
230         }
231 }
232
233 void sst_set_gr(fd, value)
234 int fd, value;
235 {
236         struct audio_ioctl ai;
237
238         if ((value < -18) || (value > 12)) {
239                 char buf[255];
240                 sprintf(buf, "sst_set_gr: GR %d out of range", value);
241                 warn(buf);
242                 return;
243         }
244
245         ai.control = AUDIO_MAP_GR;
246         ai.data[0] = gr_gx_table[value + 18][1];
247         ai.data[1] = gr_gx_table[value + 18][0];
248
249         if (ioctl(fd, AUDIOSETREG, &ai) < 0) {
250                 perror("sst_set_gr: SETREG GR");
251         }
252
253         ai.control = AUDIO_MAP_MMR1;
254         if (ioctl(fd, AUDIOGETREG, &ai) < 0) {
255                 perror("sst_set_gr: GETREG MMR1");
256         }
257         ai.data[0] |= AUDIO_MMR1_BITS_LOAD_GR;
258         if (ioctl(fd, AUDIOSETREG, &ai) < 0) {
259                 perror("sst_set_gr: SETREG MMR1");
260         }
261 }
262
263 void sst_set_gx(fd, value)
264 int fd, value;
265 {
266         struct audio_ioctl ai;
267         char buf[255];
268
269         if ((value < -18) || (value > 12)) {
270                 sprintf(buf, "sst_set_gx: GX %d out of range", value);
271                 warn(buf);
272                 return;
273         }
274
275         /*  We add 18 to get the index into the table, since entry 0 represents
276          *  -18db.
277          */
278         ai.control = AUDIO_MAP_GX;
279         ai.data[0] = gr_gx_table[value + 18][1];
280         ai.data[1] = gr_gx_table[value + 18][0];
281
282         if (ioctl(fd, AUDIOSETREG, &ai) < 0) {
283                 perror("sst_set_gx: SETREG GX");
284         }
285
286         ai.control = AUDIO_MAP_MMR1;
287         if (ioctl(fd, AUDIOGETREG, &ai) < 0) {
288                 perror("sst_set_gx: GETREG MMR1");
289         }
290         ai.data[0] |= AUDIO_MMR1_BITS_LOAD_GX;
291         if (ioctl(fd, AUDIOSETREG, &ai) < 0) {
292                 perror("sst_set_gx: SETREG MMR1");
293         }
294 }
295
296 void sst_tones(fd, dhz1, dhz2, thz, rhz, usec)
297 int fd, dhz1, dhz2, thz, rhz, usec;
298 {
299         char buf[255];
300         struct audio_ioctl ai;
301         int dval1, dval2, tval, rval;
302         unsigned char oldmmr2, newmmr2;
303
304         if (dhz1 == 0)
305                 dval1 = 0;
306         else {
307                 dval1 = (dhz1 * 128 + 63) / 1000;
308                 if ((dval1 < 1) || (dval1 > 255)) {
309                         sprintf(buf, "sst_tones: dhz1 %d out of range", dhz1);
310                         warn(buf);
311                         return;
312                 }
313         }
314
315         if (dhz2 == 0)
316                 dval2 = 0;
317         else {
318                 dval2 = (dhz2 * 128 + 63) / 1000;
319                 if ((dval2 < 1) || (dval2 > 255)) {
320                         sprintf(buf, "sst_tones: dhz2 %d out of range", dhz2);
321                         warn(buf);
322                         return;
323                 }
324         }
325
326         if (thz == 0)
327                 tval = 0;
328         else {
329                 tval = (thz * 128 + 63) / 2000;
330                 if ((tval < 1) || (tval > 255)) {
331                         sprintf(buf, "sst_tones: thz %d out of range", thz);
332                         warn(buf);
333                         return;
334                 }
335         }
336
337         if (rhz == 0)
338                 rval = 0;
339         else {
340                 rval = (rhz * 128 + 63) / 2000;
341                 if ((rval < 1) || (rval > 255)) {
342                         sprintf(buf, "sst_tones: rhz %d out of range", dhz2);
343                         warn(buf);
344                         return;
345                 }
346         }
347
348         if ((dval1 != 0 || dval2 != 0) && (tval != 0 || rval != 0)) {
349                 sprintf(buf,
350                         "sst_tones: cannot use DTMF and TONE or RINGER at the same time",
351                         dhz2);
352                 warn(buf);
353                 return;
354         }
355
356         if (tval != 0 && rval != 0) {
357                 sprintf(buf,
358                         "sst_tones: cannot use TONE and RINGER at the same time",
359                         dhz2);
360                 warn(buf);
361                 return;
362         }
363
364         ai.control = AUDIO_MAP_MMR2;
365         if (ioctl(fd, AUDIOGETREG, &ai) < 0) {
366                 perror("sst_tones: GETREG MMR2");
367         }
368         oldmmr2 = newmmr2 = ai.data[0];
369
370         if (dval1 != 0 || dval2 != 0) {
371                 newmmr2 |= AUDIO_MMR2_BITS_DTMF;
372                 ai.control = AUDIO_MAP_FTGR;
373                 ai.data[0] = dval1;
374                 ai.data[1] = dval2;
375                 if (ioctl(fd, AUDIOSETREG, &ai) < 0) {
376                         perror("sst_tones: SETREG FTGR");
377                 }
378         }
379
380         if (tval != 0) {
381                 newmmr2 |= AUDIO_MMR2_BITS_TONE;
382                 ai.control = AUDIO_MAP_FTGR;
383                 ai.data[0] = tval;
384                 ai.data[1] = 0;
385                 if (ioctl(fd, AUDIOSETREG, &ai) < 0) {
386                         perror("sst_tones: SETREG FTGR");
387                 }
388         }
389
390         if (rval != 0) {
391                 newmmr2 |= AUDIO_MMR2_BITS_RINGER;
392                 ai.control = AUDIO_MAP_FTGR;
393                 ai.data[0] = rval;
394                 ai.data[1] = 0;
395                 if (ioctl(fd, AUDIOSETREG, &ai) < 0) {
396                         perror("sst_tones: SETREG FTGR");
397                 }
398         }
399
400         ai.control = AUDIO_MAP_MMR2;
401         ai.data[0] = newmmr2;
402         if (ioctl(fd, AUDIOSETREG, &ai) < 0) {
403                 perror("sst_tones: SETREG MMR2");
404         }
405
406         usleep(usec);
407
408         ai.data[0] = oldmmr2;
409         if (ioctl(fd, AUDIOSETREG, &ai) < 0) {
410                 perror("sst_tones: SETREG MMR2");
411         }
412 }
413
414 void sst_dtmf(fd, dial, usecper, usecpause)
415 int fd, usecper, usecpause;
416 char *dial;
417 {
418         char *cp;
419
420         for (cp = dial; *cp != '\0'; cp++) {
421                 switch (*cp) {
422                 case '1':
423                         sst_tones(fd, 703, 1211, 0, 0, usecper);
424                         break;
425                 case '2':
426                         sst_tones(fd, 703, 1336, 0, 0, usecper);
427                         break;
428                 case '3':
429                         sst_tones(fd, 703, 1492, 0, 0, usecper);
430                         break;
431                 case 'A':
432                         sst_tones(fd, 703, 1648, 0, 0, usecper);
433                         break;
434                 case '4':
435                         sst_tones(fd, 773, 1211, 0, 0, usecper);
436                         break;
437                 case '5':
438                         sst_tones(fd, 773, 1336, 0, 0, usecper);
439                         break;
440                 case '6':
441                         sst_tones(fd, 773, 1492, 0, 0, usecper);
442                         break;
443                 case 'B':
444                         sst_tones(fd, 773, 1648, 0, 0, usecper);
445                         break;
446                 case '7':
447                         sst_tones(fd, 859, 1211, 0, 0, usecper);
448                         break;
449                 case '8':
450                         sst_tones(fd, 859, 1336, 0, 0, usecper);
451                         break;
452                 case '9':
453                         sst_tones(fd, 859, 1492, 0, 0, usecper);
454                         break;
455                 case 'C':
456                         sst_tones(fd, 859, 1648, 0, 0, usecper);
457                         break;
458                 case '*':
459                         sst_tones(fd, 945, 1211, 0, 0, usecper);
460                         break;
461                 case '0':
462                         sst_tones(fd, 945, 1336, 0, 0, usecper);
463                         break;
464                 case '#':
465                         sst_tones(fd, 945, 1492, 0, 0, usecper);
466                         break;
467                 case 'D':
468                         sst_tones(fd, 945, 1648, 0, 0, usecper);
469                         break;
470
471                 case ' ':
472                 case '-':
473                 case '(':
474                 case ')':
475                 case '+':
476                         continue;       /* ignore */
477
478                 case ',':
479                         usleep(usecper);
480                         break;  /* big pause */
481
482                 default:
483                         {
484                                 char buf[255];
485                                 sprintf(buf,
486                                         "sst_dtmf: unknown dialing code '%c'",
487                                         *cp);
488                                 warn(buf);
489                         }
490                 }
491                 usleep(usecpause);
492         }
493 }