1 /* Extended Module Player
2 * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr
3 *
4 * This file is part of the Extended Module Player and is distributed
5 * under the terms of the GNU General Public License. See the COPYING
6 * file for more information.
7 */
8
9 /* CS4231 code tested on Sparc 20 and Ultra 1 running Solaris 2.5.1
10 * with mono/stereo, 16 bit, 22.05 kHz and 44.1 kHz using the internal
11 * speaker and headphones.
12 *
13 * AMD 7930 code tested on Axil 240 running Solaris 2.5.1 and an Axil
14 * 220 running Linux 2.0.33.
15 */
16
17 /* Fixed and improved by Keith Hargrove <Keith.Hargrove@Eng.Sun.COM>
18 * Wed, 30 Jun 1999 14:23:52 -0700 (PDT)
19 */
20
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <string.h>
24 #include <sys/ioctl.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <fcntl.h>
28
29 #if defined(HAVE_SYS_AUDIOIO_H)
30 #include <sys/audioio.h>
31 #elif defined(HAVE_SYS_AUDIO_IO_H)
32 #include <sys/audio.io.h>
33 #elif defined(HAVE_SUN_AUDIOIO_H)
34 #include <sun/audioio.h>
35 #endif
36 #include <sys/stropts.h>
37
38 /* This is for Linux on Sparc */
39 #if defined(HAVE_SBUS_AUDIO_AUDIO_H)
40 #include <sbus/audio/audio.h>
41 #endif
42
43 #include "sound.h"
44
45 static int audio_fd;
46 static int audioctl_fd;
47
init(struct options * options)48 static int init(struct options *options)
49 {
50 char **parm = options->driver_parm;
51 audio_info_t ainfo, ainfo2;
52 int gain;
53 int bsize = 32 * 1024;
54 int port;
55 AUDIO_INITINFO(&ainfo);
56
57 if ((audio_fd = open("/dev/audio", O_WRONLY)) == -1)
58 return -1;
59
60 /* try to open audioctl device */
61 if ((audioctl_fd = open("/dev/audioctl", O_RDWR)) < 0) {
62 fprintf(stderr, "couldn't open audioctl device\n");
63 close(audio_fd);
64 return -1;
65 }
66
67 /* sleep(2); -- Really needed? */
68
69 /* empty buffers before change config */
70 ioctl(audio_fd, AUDIO_DRAIN, 0); /* drain everything out */
71 ioctl(audio_fd, I_FLUSH, FLUSHRW); /* flush everything */
72 ioctl(audioctl_fd, I_FLUSH, FLUSHRW); /* flush everything */
73
74 /* get audio parameters. */
75 if (ioctl(audioctl_fd, AUDIO_GETINFO, &ainfo) < 0) {
76 fprintf(stderr, "AUDIO_GETINFO failed!\n");
77 close(audio_fd);
78 close(audioctl_fd);
79 return -1;
80 }
81
82 close(audioctl_fd);
83
84 /* KH: Sun Dbri doesn't support 8bits linear. I dont muck with the gain
85 * or the port setting. I hate when a program does that. There is
86 * nothing more frustrating then having a program change your volume
87 * and change from external speakers to the tiny one
88 */
89
90 gain = ainfo.play.gain;
91 port = ainfo.play.port;
92
93 parm_init(parm);
94 chkparm1("gain", gain = strtoul(token, NULL, 0));
95 chkparm1("buffer", bsize = strtoul(token, NULL, 0));
96 chkparm1("port", port = (int)*token)
97 parm_end();
98
99 switch (port) {
100 case 'h':
101 port = AUDIO_HEADPHONE;
102 break;
103 case 'l':
104 port = AUDIO_LINE_OUT;
105 break;
106 case 's':
107 port = AUDIO_SPEAKER;
108 }
109
110 if (gain < AUDIO_MIN_GAIN)
111 gain = AUDIO_MIN_GAIN;
112 if (gain > AUDIO_MAX_GAIN)
113 gain = AUDIO_MAX_GAIN;
114
115 AUDIO_INITINFO(&ainfo); /* For CS4231 */
116 AUDIO_INITINFO(&ainfo2); /* For AMD 7930 if needed */
117
118 ainfo.play.sample_rate = options->rate;
119 ainfo.play.channels = options->format & XMP_FORMAT_MONO ? 1 : 2;
120 ainfo.play.precision = options->format & XMP_FORMAT_8BIT ? 8 : 16;
121 ainfo.play.encoding = AUDIO_ENCODING_LINEAR;
122 ainfo2.play.gain = ainfo.play.gain = gain;
123 ainfo2.play.port = ainfo.play.port = port;
124 ainfo2.play.buffer_size = ainfo.play.buffer_size = bsize;
125
126 if (ioctl(audio_fd, AUDIO_SETINFO, &ainfo) == -1) {
127 /* CS4231 initialization Failed, perhaps we have an AMD 7930 */
128 if (ioctl(audio_fd, AUDIO_SETINFO, &ainfo2) == -1) {
129 close(audio_fd);
130 return -1;
131 }
132
133 /* Sorry, AMD7930 uLaw not supported anymore */
134 /* sound_solaris.description = "Solaris AMD7930 PCM audio"; */
135 return -1;
136 } else {
137 /* sound_solaris.description = "Solaris CS4231 PCM audio"; */
138 }
139
140 return 0;
141 }
142
play(void * b,int i)143 static void play(void *b, int i)
144 {
145 int j;
146
147 while (i) {
148 if ((j = write(audio_fd, b, i)) > 0) {
149 i -= j;
150 b = (char *)b + j;
151 } else
152 break;
153 }
154 }
155
deinit(void)156 static void deinit(void)
157 {
158 close(audio_fd);
159 }
160
flush(void)161 static void flush(void)
162 {
163 }
164
onpause(void)165 static void onpause(void)
166 {
167 }
168
onresume(void)169 static void onresume(void)
170 {
171 }
172
173 static const char *const help[] = {
174 "gain=val", "Audio output gain (0 to 255)",
175 "port={s|h|l}", "Audio port (s[peaker], h[eadphones], l[ineout])",
176 "buffer=val", "Audio buffer size (default is 32768)",
177 NULL
178 };
179
180 struct sound_driver sound_solaris = {
181 "solaris",
182 "Solaris PCM audio",
183 help,
184 init,
185 deinit,
186 play,
187 flush,
188 onpause,
189 onresume
190 };
191
192