2 * Copyright 2004-2005 Timo Hirvonen
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
28 #include <sys/ioctl.h>
29 #if defined(__OpenBSD__)
30 #include <soundcard.h>
32 #include <sys/soundcard.h>
36 OSS_MIXER_CHANNEL_VOLUME
,
37 OSS_MIXER_CHANNEL_BASS
,
38 OSS_MIXER_CHANNEL_TREBLE
,
39 OSS_MIXER_CHANNEL_SYNTH
,
40 OSS_MIXER_CHANNEL_PCM
,
41 OSS_MIXER_CHANNEL_SPEAKER
,
42 OSS_MIXER_CHANNEL_LINE
,
43 OSS_MIXER_CHANNEL_MIC
,
45 OSS_MIXER_CHANNEL_IMIX
,
46 OSS_MIXER_CHANNEL_ALTPCM
,
47 OSS_MIXER_CHANNEL_RECLEV
,
48 OSS_MIXER_CHANNEL_IGAIN
,
49 OSS_MIXER_CHANNEL_OGAIN
,
50 OSS_MIXER_CHANNEL_LINE1
,
51 OSS_MIXER_CHANNEL_LINE2
,
52 OSS_MIXER_CHANNEL_LINE3
,
53 OSS_MIXER_CHANNEL_DIGITAL1
,
54 OSS_MIXER_CHANNEL_DIGITAL2
,
55 OSS_MIXER_CHANNEL_DIGITAL3
,
56 OSS_MIXER_CHANNEL_PHONEIN
,
57 OSS_MIXER_CHANNEL_PHONEOUT
,
58 OSS_MIXER_CHANNEL_VIDEO
,
59 OSS_MIXER_CHANNEL_RADIO
,
60 OSS_MIXER_CHANNEL_MONITOR
,
64 static int mixer_fd
= -1;
65 static int mixer_devmask
;
66 /* static int mixer_recmask; */
67 /* static int mixer_recsrc; */
68 /* static int mixer_stereodevs; */
69 static char mixer_channels
[OSS_MIXER_CHANNEL_MAX
];
72 static char *oss_mixer_device
= NULL
;
73 static int oss_volume_controls_pcm
= 1;
75 static int mixer_open(const char *device
)
79 mixer_fd
= open(device
, O_RDWR
);
82 ioctl(mixer_fd
, SOUND_MIXER_READ_DEVMASK
, &mixer_devmask
);
83 /* ioctl(mixer_fd, SOUND_MIXER_READ_RECMASK, &mixer_recmask); */
84 /* ioctl(mixer_fd, SOUND_MIXER_READ_RECSRC, &mixer_recsrc); */
85 /* ioctl(mixer_fd, SOUND_MIXER_READ_STEREODEVS, &mixer_stereodevs); */
87 while (i
< min(SOUND_MIXER_NRDEVICES
, OSS_MIXER_CHANNEL_MAX
)) {
88 mixer_channels
[i
] = (mixer_devmask
>> i
) & 1;
91 while (i
< OSS_MIXER_CHANNEL_MAX
)
92 mixer_channels
[i
++] = 0;
96 static int mixer_set_level(int channel
, int l
, int r
)
100 tmp
= (l
& 0x7f) + ((r
& 0x7f) << 8);
101 if (ioctl(mixer_fd
, MIXER_WRITE(channel
), &tmp
) == -1)
106 static int mixer_get_level(int channel
, int *l
, int *r
)
110 if (ioctl(mixer_fd
, MIXER_READ(channel
), &tmp
) == -1)
113 *r
= (tmp
>> 8) & 0x7f;
117 static int oss_device_exists(const char *device
)
121 if (stat(device
, &s
) == 0) {
122 d_print("device %s exists\n", device
);
125 d_print("device %s does not exist\n", device
);
129 static int oss_mixer_init(void)
131 const char *new_mixer_dev
= "/dev/sound/mixer";
132 const char *mixer_dev
= "/dev/mixer";
134 if (oss_mixer_device
) {
135 if (oss_device_exists(oss_mixer_device
))
137 free(oss_mixer_device
);
138 oss_mixer_device
= NULL
;
141 if (oss_device_exists(new_mixer_dev
)) {
142 oss_mixer_device
= xstrdup(new_mixer_dev
);
145 if (oss_device_exists(mixer_dev
)) {
146 oss_mixer_device
= xstrdup(mixer_dev
);
152 static int oss_mixer_exit(void)
154 if (oss_mixer_device
) {
155 free(oss_mixer_device
);
156 oss_mixer_device
= NULL
;
161 static int oss_mixer_open(int *volume_max
)
164 if (mixer_open(oss_mixer_device
) == 0)
169 static int oss_mixer_close(void)
176 static int oss_mixer_set_volume(int l
, int r
)
178 if (oss_volume_controls_pcm
) {
179 return mixer_set_level(OSS_MIXER_CHANNEL_PCM
, l
, r
);
181 return mixer_set_level(OSS_MIXER_CHANNEL_VOLUME
, l
, r
);
185 static int oss_mixer_get_volume(int *l
, int *r
)
187 if (oss_volume_controls_pcm
) {
188 return mixer_get_level(OSS_MIXER_CHANNEL_PCM
, l
, r
);
190 return mixer_get_level(OSS_MIXER_CHANNEL_VOLUME
, l
, r
);
194 static int oss_mixer_set_option(int key
, const char *val
)
198 if (strcasecmp(val
, "pcm") == 0) {
199 oss_volume_controls_pcm
= 1;
200 } else if (strcasecmp(val
, "master") == 0) {
201 oss_volume_controls_pcm
= 0;
204 return -OP_ERROR_ERRNO
;
208 free(oss_mixer_device
);
209 oss_mixer_device
= xstrdup(val
);
212 return -OP_ERROR_NOT_OPTION
;
217 static int oss_mixer_get_option(int key
, char **val
)
221 if (oss_volume_controls_pcm
) {
222 *val
= xstrdup("PCM");
224 *val
= xstrdup("Master");
228 if (oss_mixer_device
)
229 *val
= xstrdup(oss_mixer_device
);
232 return -OP_ERROR_NOT_OPTION
;
237 const struct mixer_plugin_ops op_mixer_ops
= {
238 .init
= oss_mixer_init
,
239 .exit
= oss_mixer_exit
,
240 .open
= oss_mixer_open
,
241 .close
= oss_mixer_close
,
242 .set_volume
= oss_mixer_set_volume
,
243 .get_volume
= oss_mixer_get_volume
,
244 .set_option
= oss_mixer_set_option
,
245 .get_option
= oss_mixer_get_option
248 const char * const op_mixer_options
[] = {