2 * Copyright 2004-2005 Timo Hirvonen
4 * mixer_sun.c by alex <pukpuk@gmx.de>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
22 #include <sys/types.h>
23 #include <sys/ioctl.h>
24 #include <sys/audioio.h>
36 static int sun_mixer_device_id
= -1;
37 static int sun_mixer_channels
= -1;
38 static int sun_mixer_volume_delta
= -1;
39 static int mixer_fd
= -1;
41 static char *sun_mixer_device
= NULL
;
42 static char *sun_mixer_channel
= NULL
;
44 static int mixer_open(const char *);
45 static int min_delta(int, int, int);
46 static int sun_device_exists(const char *);
47 static int sun_mixer_init(void);
48 static int sun_mixer_exit(void);
49 static int sun_mixer_open(int *);
50 static int sun_mixer_close(void);
51 static int sun_mixer_set_volume(int, int);
52 static int sun_mixer_get_volume(int *, int *);
53 static int sun_mixer_set_option(int, const char *);
54 static int sun_mixer_get_option(int, char **);
56 static int mixer_open(const char *dev
)
58 struct mixer_devinfo minf
;
61 mixer_fd
= open(dev
, O_RDWR
);
66 sun_mixer_device_id
= -1;
67 /* determine output class */
69 while (ioctl(mixer_fd
, AUDIO_MIXER_DEVINFO
, &minf
) != -1) {
70 if (minf
.type
== AUDIO_MIXER_CLASS
) {
71 if (strcmp(minf
.label
.name
, AudioCoutputs
) == 0)
72 output_class
= minf
.index
;
76 /* no output class found?? something must be wrong */
77 if (output_class
== -1)
81 /* query all mixer devices and try choose the correct one */
82 while (ioctl(mixer_fd
, AUDIO_MIXER_DEVINFO
, &minf
) != -1) {
83 /* only scan output channels */
84 if (minf
.type
== AUDIO_MIXER_VALUE
&& minf
.prev
== AUDIO_MIXER_LAST
&&
85 minf
.mixer_class
== output_class
) {
86 if (strcasecmp(minf
.label
.name
, sun_mixer_channel
) == 0) {
87 sun_mixer_volume_delta
= minf
.un
.v
.delta
;
88 sun_mixer_device_id
= minf
.index
;
89 sun_mixer_channels
= minf
.un
.v
.num_channels
;
95 if (sun_mixer_device_id
== -1)
98 d_print("sun: found mixer-channel: %s, devid: %d, delta: %d, channels: %d\n", sun_mixer_channel
,
99 sun_mixer_device_id
, sun_mixer_volume_delta
, sun_mixer_channels
);
101 if (sun_mixer_volume_delta
== 0)
102 sun_mixer_volume_delta
= 1;
108 static int min_delta(int oval
, int nval
, int delta
)
110 if (oval
> nval
&& oval
- nval
< delta
)
112 else if (oval
< nval
&& nval
- oval
< delta
)
115 nval
= (nval
< 0) ? 0 : nval
;
116 nval
= (nval
> AUDIO_MAX_GAIN
) ? AUDIO_MAX_GAIN
: nval
;
121 static int sun_device_exists(const char *dev
)
125 if (stat(dev
, &s
) == 0) {
126 d_print("device %s exists\n", dev
);
129 d_print("device %s does not exist\n", dev
);
134 static int sun_mixer_init(void)
136 const char *mixer_dev
= "/dev/mixer";
138 if (sun_mixer_device
!= NULL
) {
139 if (sun_device_exists(sun_mixer_device
))
141 free(sun_mixer_device
);
142 sun_mixer_device
= NULL
;
145 if (sun_device_exists(mixer_dev
)) {
146 sun_mixer_device
= xstrdup(mixer_dev
);
153 static int sun_mixer_exit(void)
155 if (sun_mixer_device
!= NULL
) {
156 free (sun_mixer_device
);
157 sun_mixer_device
= NULL
;
159 if (sun_mixer_channel
!= NULL
) {
160 free(sun_mixer_channel
);
161 sun_mixer_channel
= NULL
;
167 static int sun_mixer_open(int *vol_max
)
169 const char *mixer_channel
= "master";
171 /* set default mixer channel */
172 if (sun_mixer_channel
== NULL
)
173 sun_mixer_channel
= xstrdup(mixer_channel
);
175 if (mixer_open(sun_mixer_device
) == 0) {
176 *vol_max
= AUDIO_MAX_GAIN
;
183 static int sun_mixer_close(void)
185 if (mixer_fd
!= -1) {
193 static int sun_mixer_set_volume(int l
, int r
)
195 struct mixer_ctrl minf
;
198 if (sun_mixer_get_volume(&ovall
, &ovalr
) == -1)
201 /* OpenBSD mixer values are `discrete' */
202 l
= min_delta(ovall
, l
, sun_mixer_volume_delta
);
203 r
= min_delta(ovalr
, r
, sun_mixer_volume_delta
);
205 minf
.type
= AUDIO_MIXER_VALUE
;
206 minf
.dev
= sun_mixer_device_id
;
208 if (sun_mixer_channels
== 1)
209 minf
.un
.value
.level
[AUDIO_MIXER_LEVEL_MONO
] = l
;
211 minf
.un
.value
.level
[AUDIO_MIXER_LEVEL_LEFT
] = l
;
212 minf
.un
.value
.level
[AUDIO_MIXER_LEVEL_RIGHT
] = r
;
214 minf
.un
.value
.num_channels
= sun_mixer_channels
;
216 if (ioctl(mixer_fd
, AUDIO_MIXER_WRITE
, &minf
) == -1)
222 static int sun_mixer_get_volume(int *l
, int *r
)
224 struct mixer_ctrl minf
;
226 minf
.dev
= sun_mixer_device_id
;
227 minf
.type
= AUDIO_MIXER_VALUE
;
228 minf
.un
.value
.num_channels
= sun_mixer_channels
;
230 if (ioctl(mixer_fd
, AUDIO_MIXER_READ
, &minf
) == -1)
233 if (sun_mixer_channels
== 1) {
234 *l
= minf
.un
.value
.level
[AUDIO_MIXER_LEVEL_MONO
];
237 *l
= minf
.un
.value
.level
[AUDIO_MIXER_LEVEL_LEFT
];
238 *r
= minf
.un
.value
.level
[AUDIO_MIXER_LEVEL_RIGHT
];
244 static int sun_mixer_set_option(int key
, const char *val
)
248 if (sun_mixer_channel
!= NULL
)
249 free(sun_mixer_channel
);
250 sun_mixer_channel
= xstrdup(val
);
253 free(sun_mixer_device
);
254 sun_mixer_device
= xstrdup(val
);
257 return -OP_ERROR_NOT_OPTION
;
263 static int sun_mixer_get_option(int key
, char **val
)
267 if (sun_mixer_channel
)
268 *val
= xstrdup(sun_mixer_channel
);
271 if (sun_mixer_device
)
272 *val
= xstrdup(sun_mixer_device
);
275 return -OP_ERROR_NOT_OPTION
;
281 const struct mixer_plugin_ops op_mixer_ops
= {
282 .init
= sun_mixer_init
,
283 .exit
= sun_mixer_exit
,
284 .open
= sun_mixer_open
,
285 .close
= sun_mixer_close
,
286 .set_volume
= sun_mixer_set_volume
,
287 .get_volume
= sun_mixer_get_volume
,
288 .set_option
= sun_mixer_set_option
,
289 .get_option
= sun_mixer_get_option
292 const char * const op_mixer_options
[] = {