1 /* libsst.c - SPARC sound tools library
3 ** Copyright (C) 1989 by Jef Poskanzer.
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
12 ** Hacked on by jwz for emacs.
16 /* Synched up with: Not in FSF. */
35 int sst_open(play_level, record_level)
36 int play_level, record_level;
38 int fd, i, gr, ger, gx;
39 struct audio_ioctl ai;
42 fd = open("/dev/audio", O_RDWR);
44 perror("sst_open: open /dev/audio");
47 #ifdef AUDIOSETQSIZE /* This no longer exists as of 4.1.2. */
49 /* Shrink audio device's queue size, to cut down time delay. */
51 if (ioctl(fd, AUDIOSETQSIZE, &i) < 0) {
52 perror("sst_open: SETQSIZE");
55 #endif /* AUDIOSETQSIZE */
57 /* Set gains. -10 <= ger <= 18, -18 <= gr <= 12, -18 <= gx <= 12. */
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");
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");
79 play_level = play_level * 59 / 100 - 28;
81 gr = play_level - ger;
84 gr = play_level - ger;
88 ger = play_level - gr;
90 gx = record_level * 31 / 100 - 18;
95 /* Initialize the MMR2 register to send the output to either
96 ** the speaker or the earphone jack, depending on SST_EARPHONES.
98 ai.control = AUDIO_MAP_MMR2;
99 if (ioctl(fd, AUDIOGETREG, &ai) < 0) {
100 perror("sst_open: GETREG MMR2");
103 if ((ep = getenv("SST_EARPHONES")) != NULL)
104 ai.data[0] &= ~AUDIO_MMR2_BITS_LS;
106 ai.data[0] |= AUDIO_MMR2_BITS_LS;
107 if (ioctl(fd, AUDIOSETREG, &ai) < 0) {
108 perror("sst_open: SETREG MMR2");
118 struct audio_ioctl ai;
120 ai.control = AUDIO_MAP_MMR1;
122 if (ioctl(fd, AUDIOSETREG, &ai) < 0) {
123 perror("sst_close: SETREG MMR1");
125 ai.control = AUDIO_MAP_MMR2;
127 if (ioctl(fd, AUDIOSETREG, &ai) < 0) {
128 perror("sst_close: SETREG MMR2");
133 /* These are tables of values to be loaded into various gain registers.
136 static unsigned char ger_table[][2] = {
137 0xaa, 0xaa, /* -10db */
141 0x74, 0x9c, /* -6db */
147 0x00, 0x99, /* 0db */
153 0x40, 0xdd, /* 6db */
159 0x42, 0x10, /* 12db */
165 0x00, 0x0f, /* 18db */
168 static unsigned char gr_gx_table[][2] = {
169 0x8b, 0x7c, /* -18db */
175 0x91, 0xf9, /* -12db */
181 0x9f, 0x91, /* -6db */
187 0x08, 0x08, /* 0db */
193 0x10, 0xf2, /* 6db */
199 0x00, 0x0e, /* 12db */
202 void sst_set_ger(fd, value)
205 struct audio_ioctl ai;
207 if ((value < -10) || (value > 18)) {
209 int sz = snprintf(buf, sizeof(buf), "sst_set_ger: GER %d out of range", value);
210 assert(sz >= 0 && sz < sizeof(buf));
215 /* Add 10 to the value to get the index into the table. */
216 ai.control = AUDIO_MAP_GER;
217 ai.data[0] = ger_table[value + 10][1];
218 ai.data[1] = ger_table[value + 10][0];
220 if (ioctl(fd, AUDIOSETREG, &ai) < 0) {
221 perror("sst_set_ger: SETREG GER");
224 ai.control = AUDIO_MAP_MMR1;
225 if (ioctl(fd, AUDIOGETREG, &ai) < 0) {
226 perror("sst_set_ger: GETREG MMR1");
228 ai.data[0] |= AUDIO_MMR1_BITS_LOAD_GER;
229 if (ioctl(fd, AUDIOSETREG, &ai) < 0) {
230 perror("sst_set_ger: SETREG MMR1");
234 void sst_set_gr(fd, value)
237 struct audio_ioctl ai;
239 if ((value < -18) || (value > 12)) {
241 int sz = sprintf(buf, sizeof(buf), "sst_set_gr: GR %d out of range", value);
242 assert(sz >= 0 && sz < sizeof(buf));
247 ai.control = AUDIO_MAP_GR;
248 ai.data[0] = gr_gx_table[value + 18][1];
249 ai.data[1] = gr_gx_table[value + 18][0];
251 if (ioctl(fd, AUDIOSETREG, &ai) < 0) {
252 perror("sst_set_gr: SETREG GR");
255 ai.control = AUDIO_MAP_MMR1;
256 if (ioctl(fd, AUDIOGETREG, &ai) < 0) {
257 perror("sst_set_gr: GETREG MMR1");
259 ai.data[0] |= AUDIO_MMR1_BITS_LOAD_GR;
260 if (ioctl(fd, AUDIOSETREG, &ai) < 0) {
261 perror("sst_set_gr: SETREG MMR1");
265 void sst_set_gx(fd, value)
268 struct audio_ioctl ai;
271 if ((value < -18) || (value > 12)) {
272 int sz = snprintf(buf, sizeof(buf), "sst_set_gx: GX %d out of range", value);
273 assert(sz >= 0 && sz < sizeof(buf));
278 /* We add 18 to get the index into the table, since entry 0 represents
281 ai.control = AUDIO_MAP_GX;
282 ai.data[0] = gr_gx_table[value + 18][1];
283 ai.data[1] = gr_gx_table[value + 18][0];
285 if (ioctl(fd, AUDIOSETREG, &ai) < 0) {
286 perror("sst_set_gx: SETREG GX");
289 ai.control = AUDIO_MAP_MMR1;
290 if (ioctl(fd, AUDIOGETREG, &ai) < 0) {
291 perror("sst_set_gx: GETREG MMR1");
293 ai.data[0] |= AUDIO_MMR1_BITS_LOAD_GX;
294 if (ioctl(fd, AUDIOSETREG, &ai) < 0) {
295 perror("sst_set_gx: SETREG MMR1");
299 void sst_tones(fd, dhz1, dhz2, thz, rhz, usec)
300 int fd, dhz1, dhz2, thz, rhz, usec;
303 struct audio_ioctl ai;
304 int dval1, dval2, tval, rval;
305 unsigned char oldmmr2, newmmr2;
310 dval1 = (dhz1 * 128 + 63) / 1000;
311 if ((dval1 < 1) || (dval1 > 255)) {
312 int sz = snprintf(buf, sizeof(buf),
313 "sst_tones: dhz1 %d out of range", dhz1);
314 assert(sz >= 0 && sz < sizeof(buf));
323 dval2 = (dhz2 * 128 + 63) / 1000;
324 if ((dval2 < 1) || (dval2 > 255)) {
325 int sz = snprintf(buf, sizeof(buf),
326 "sst_tones: dhz2 %d out of range", dhz2);
327 assert(sz >= 0 && sz < sizeof(buf));
336 tval = (thz * 128 + 63) / 2000;
337 if ((tval < 1) || (tval > 255)) {
338 int sz = snprintf(buf, sizeof(buf),
339 "sst_tones: thz %d out of range", thz);
340 assert(sz >= 0 && sz < sizeof(buf));
349 rval = (rhz * 128 + 63) / 2000;
350 if ((rval < 1) || (rval > 255)) {
351 int sz = snprintf(buf, sizeof(buf),
352 "sst_tones: rhz %d out of range", dhz2);
353 assert(sz >= 0 && sz < sizeof(buf));
359 if ((dval1 != 0 || dval2 != 0) && (tval != 0 || rval != 0)) {
360 int sz = snprintf(buf, sizeof(buf),
361 "sst_tones: cannot use DTMF and TONE or RINGER "
362 "at the same time", dhz2);
363 assert(sz >= 0 && sz < sizeof(buf));
368 if (tval != 0 && rval != 0) {
369 int sz = sprintf(buf, sizeof(buf),
370 "sst_tones: cannot use TONE and RINGER at the same time",
372 assert(sz >= 0 && sz < sizeof(buf));
377 ai.control = AUDIO_MAP_MMR2;
378 if (ioctl(fd, AUDIOGETREG, &ai) < 0) {
379 perror("sst_tones: GETREG MMR2");
381 oldmmr2 = newmmr2 = ai.data[0];
383 if (dval1 != 0 || dval2 != 0) {
384 newmmr2 |= AUDIO_MMR2_BITS_DTMF;
385 ai.control = AUDIO_MAP_FTGR;
388 if (ioctl(fd, AUDIOSETREG, &ai) < 0) {
389 perror("sst_tones: SETREG FTGR");
394 newmmr2 |= AUDIO_MMR2_BITS_TONE;
395 ai.control = AUDIO_MAP_FTGR;
398 if (ioctl(fd, AUDIOSETREG, &ai) < 0) {
399 perror("sst_tones: SETREG FTGR");
404 newmmr2 |= AUDIO_MMR2_BITS_RINGER;
405 ai.control = AUDIO_MAP_FTGR;
408 if (ioctl(fd, AUDIOSETREG, &ai) < 0) {
409 perror("sst_tones: SETREG FTGR");
413 ai.control = AUDIO_MAP_MMR2;
414 ai.data[0] = newmmr2;
415 if (ioctl(fd, AUDIOSETREG, &ai) < 0) {
416 perror("sst_tones: SETREG MMR2");
421 ai.data[0] = oldmmr2;
422 if (ioctl(fd, AUDIOSETREG, &ai) < 0) {
423 perror("sst_tones: SETREG MMR2");
427 void sst_dtmf(fd, dial, usecper, usecpause)
428 int fd, usecper, usecpause;
433 for (cp = dial; *cp != '\0'; cp++) {
436 sst_tones(fd, 703, 1211, 0, 0, usecper);
439 sst_tones(fd, 703, 1336, 0, 0, usecper);
442 sst_tones(fd, 703, 1492, 0, 0, usecper);
445 sst_tones(fd, 703, 1648, 0, 0, usecper);
448 sst_tones(fd, 773, 1211, 0, 0, usecper);
451 sst_tones(fd, 773, 1336, 0, 0, usecper);
454 sst_tones(fd, 773, 1492, 0, 0, usecper);
457 sst_tones(fd, 773, 1648, 0, 0, usecper);
460 sst_tones(fd, 859, 1211, 0, 0, usecper);
463 sst_tones(fd, 859, 1336, 0, 0, usecper);
466 sst_tones(fd, 859, 1492, 0, 0, usecper);
469 sst_tones(fd, 859, 1648, 0, 0, usecper);
472 sst_tones(fd, 945, 1211, 0, 0, usecper);
475 sst_tones(fd, 945, 1336, 0, 0, usecper);
478 sst_tones(fd, 945, 1492, 0, 0, usecper);
481 sst_tones(fd, 945, 1648, 0, 0, usecper);
489 continue; /* ignore */
493 break; /* big pause */
498 int sz = snprintf(buf, sizeof(buf),
499 "sst_dtmf: unknown dialing code '%c'",
501 assert(sz >= 0 && sz < sizeof(buf));