source: GPL/trunk/lib32/soundmixer.c@ 451

Last change on this file since 451 was 451, checked in by Paul Smedley, 16 years ago

Update SPEAKER mixer control to PCSPEAKER

File size: 34.3 KB
Line 
1/* $Id: soundmixer.c,v 1.1.1.1 2003/07/02 13:57:02 eleph Exp $ */
2/*
3 * MMPM/2 to OSS interface translation layer
4 *
5 * (C) 2000-2002 InnoTek Systemberatung GmbH
6 * (C) 2000-2001 Sander van Leeuwen (sandervl@xs4all.nl)
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public
19 * License along with this program; if not, write to the Free
20 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
21 * USA.
22 *
23 */
24
25#include <sound/core.h>
26#include <sound/control.h>
27#include <sound/info.h>
28#include <sound/pcm.h>
29#include <sound/pcm_params.h>
30#include <sound/minors.h>
31#include <linux/file.h>
32#include <linux/soundcard.h>
33
34#define LINUX
35#include <ossidc32.h>
36#include <stacktoflat.h>
37#include <stdlib.h>
38#include "soundoss.h"
39
40extern OpenedHandles opened_handles[8 * 256]; // from sound.c
41
42static struct {
43 char *name;
44 unsigned int index;
45 unsigned int recsrc;
46} ossid[OSS_MIXER_NRDEVICES] = {
47 /* OSS_MIXER_VOLUME */ { "Master", 0 , -1},
48 /* OSS_MIXER_BASS */ { "Tone Control - Bass", 0, -1},
49 /* OSS_MIXER_TREBLE */ { "Tone Control - Treble", 0, -1},
50 /* OSS_MIXER_SYNTH */ { "Synth", 0 , OSS32_MIX_RECSRC_SYNTH},
51 /* OSS_MIXER_PCM */ { "PCM", 0 , -1},
52 /* OSS_MIXER_PCSPEAKER */ { "PC Speaker", 0 , -1},
53 /* OSS_MIXER_LINE */ { "Line", 0 , OSS32_MIX_RECSRC_LINE},
54 /* OSS_MIXER_MIC */ { "Mic", 0, OSS32_MIX_RECSRC_MIC},
55 /* OSS_MIXER_CD */ { "CD", 0 , OSS32_MIX_RECSRC_CD},
56 /* OSS_MIXER_IMIX */ { "Monitor Mix", 0 , OSS32_MIX_RECSRC_MIXER},
57 /* OSS_MIXER_ALTPCM */ { "PCM", 1 , -1},
58 /* OSS_MIXER_RECLEV */ { "-- nothing --", 0 , -1},
59 /* OSS_MIXER_IGAIN */ { "Capture", 0 , -1},
60 /* OSS_MIXER_OGAIN */ { "Playback", 0 , -1},
61 /* OSS_MIXER_LINE1 */ { "Aux", 0 , OSS32_MIX_RECSRC_AUX},
62 /* OSS_MIXER_LINE2 */ { "Aux", 1 , -1},
63 /* OSS_MIXER_LINE3 */ { "Aux", 2 , -1},
64 /* OSS_MIXER_DIGITAL1 */ { "Digital", 0 , -1},
65 /* OSS_MIXER_DIGITAL2 */ { "Digital", 1 , -1},
66 /* OSS_MIXER_DIGITAL3 */ { "Digital", 2 , -1},
67 /* OSS_MIXER_PHONEIN */ { "Phone", 0 , OSS32_MIX_RECSRC_PHONE},
68 /* OSS_MIXER_PHONEOUT */ { "Phone", 1 , -1},
69 /* OSS_MIXER_VIDEO */ { "Video", 0 , OSS32_MIX_RECSRC_VIDEO},
70 /* OSS_MIXER_RADIO */ { "Radio", 0 , -1},
71 /* OSS_MIXER_MONITOR */ { "Monitor", 0 , -1},
72 /* OSS_MIXER_3DDEPTH */ { "3D Control - Depth", 0 , -1},
73 /* OSS_MIXER_3DCENTER */ { "3D Control - Center", 0 , -1},
74 /* OSS_MIXER_FRONT */ { "Front", 0 , -1},
75 /* OSS_MIXER_SPEAKER2 */ { "Speaker", 0 , -1},
76 /* OSS_MIXER_HEADPHONE */ { "Headphone", 0 , -1},
77};
78char *szRecSources[OSS32_MIX_RECSRC_MAX] = {
79 "Mic", "CD", "Line", "Video", "Aux", "Mix", "Mix Mono", "Phone", "Synth"
80};
81
82static unsigned char LinToLog[OSS32_MAX_VOLUME+1] = {
83 0, 0, 0, 0, 1, 2, 2, 5, 5, 10,
84 10, 10, 16, 19, 20, 22, 24, 25, 27, 27,
85 28, 28, 29, 30, 30, 35, 35, 35, 39, 39,
86 43, 44, 45, 47, 48, 49, 50, 51, 52, 53,
87 55, 56, 57, 59, 60, 62, 63, 64, 65, 66,
88 67, 68, 69, 70, 71, 72, 73, 74, 74, 75,
89 76, 77, 78, 79, 79, 80, 81, 82, 83, 84,
90 85, 86, 87, 88, 89, 90, 91, 92, 92, 93,
91 93, 94, 94, 95, 95, 96, 96, 97, 97, 98,
92 98, 99, 99, 99, 99, 100, 100, 100, 100, 100,
93 100
94};
95
96//******************************************************************************
97//Convert linear volume to logarithmic
98//******************************************************************************
99ULONG ConvertVolume(ULONG ulLinVolume, ULONG ulLogVolMax)
100{
101 if(ulLinVolume > OSS32_MAX_VOLUME) {
102 ulLinVolume = OSS32_MAX_VOLUME;
103 }
104 ulLinVolume = LinToLog[ulLinVolume];
105
106 return (ulLinVolume * ulLogVolMax) / OSS32_MAX_VOLUME;
107}
108
109//******************************************************************************
110//******************************************************************************
111OSSRET OSS32_MixOpen(ULONG deviceid, OSSSTREAMID *pStreamId)
112{
113 mixerhandle *pHandle = NULL;
114 int ret, i, j, sz;
115
116 if(pStreamId == NULL) {
117 DebugInt3();
118 return OSSERR_INVALID_PARAMETER;
119 }
120 *pStreamId = 0;
121
122 if(alsa_fops == NULL) {
123 ret = OSSERR_NO_DEVICE_AVAILABLE;
124 goto failure;
125 }
126
127 sz = sizeof(mixerhandle);
128 pHandle = kmalloc(sz, GFP_KERNEL);
129 if(pHandle == NULL) {
130 ret = OSSERR_OUT_OF_MEMORY;
131 goto failure;
132 }
133 memset(pHandle, 0, sizeof(mixerhandle));
134
135 //set operation to non-blocking
136 pHandle->file.f_flags = O_NONBLOCK;
137
138 //setup pointers in file structure (used internally by ALSA)
139 pHandle->file.f_dentry = &pHandle->d_entry;
140 pHandle->file.f_dentry->d_inode = &pHandle->inode;
141
142 pHandle->file.f_mode = FMODE_WRITE;
143 pHandle->inode.i_rdev = SNDRV_MINOR(deviceid, SNDRV_MINOR_CONTROL);
144
145 ret = alsa_fops->open(&pHandle->inode, &pHandle->file);
146 if(ret) {
147 goto failure;
148 }
149 //retrieve mixer information
150 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file,
151 SNDRV_CTL_IOCTL_CARD_INFO,
152 (ULONG)&pHandle->info);
153 if(ret) {
154 goto failure;
155 }
156 //get the number of mixer elements
157 pHandle->list.offset = 0;
158 pHandle->list.space = 0;
159 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file,
160 SNDRV_CTL_IOCTL_ELEM_LIST,
161 (ULONG)&pHandle->list);
162 if(ret) {
163 goto failure;
164 }
165 //allocate memory for all mixer elements
166 pHandle->pids = (struct snd_ctl_elem_id *)kmalloc(sizeof(struct snd_ctl_elem_id)*pHandle->list.count, GFP_KERNEL);
167 if(pHandle->pids == NULL) {
168 goto failure;
169 }
170 //and retrieve all mixer elements
171 pHandle->list.offset = 0;
172 pHandle->list.space = pHandle->list.count;
173 pHandle->list.pids = pHandle->pids;
174 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file,
175 SNDRV_CTL_IOCTL_ELEM_LIST,
176 (ULONG)&pHandle->list);
177 if(ret) {
178 goto failure;
179 }
180
181#if 0
182 dprintf(("Mixer name: %s", pHandle->info.mixername));
183 dprintf(("List of mixer elements:"));
184 for(i=0;i<pHandle->list.count;i++) {
185 dprintf(("index %d name %s id %d device %d subdevice %d", pHandle->pids[i].index, pHandle->pids[i].name, pHandle->pids[i].numid, pHandle->pids[i].device, pHandle->pids[i].subdevice));
186 }
187#endif
188
189 //Extract standard mixer controls from array with control names
190 for(j=0;j<OSS_MIXER_NRDEVICES;j++)
191 {
192 int namelen = strlen(ossid[j].name);
193
194 pHandle->controls[j].idxVolume = -1;
195 pHandle->controls[j].idxMute = -1;
196 pHandle->controls[j].idxCustom = -1;
197 pHandle->controls[j].idxCaptureSwitch = -1;
198
199 for(i=0;i<pHandle->list.count;i++)
200 {
201 if (pHandle->pids[i].index == ossid[j].index &&
202 strncmp(pHandle->pids[i].name, ossid[j].name, namelen) == 0)
203 {
204 int controlnamelen = strlen(pHandle->pids[i].name);
205
206 if(namelen == controlnamelen)
207 {//control names are identical; found exact match
208 pHandle->controls[j].idxVolume = i;
209 break;
210 }
211 else
212 {//first part of the control name is correct; now find out what
213 //is it exactly
214 char *nextword = &pHandle->pids[i].name[namelen];
215 while(*nextword && *nextword == ' ') nextword++;
216
217 if(strncmp(nextword, MIXER_PLAYBACKVOLUME, sizeof(MIXER_PLAYBACKVOLUME)-1) == 0 ||
218 strncmp(nextword, MIXER_VOLUME, sizeof(MIXER_VOLUME)-1) == 0)
219 {//volume control
220 pHandle->controls[j].idxVolume = i;
221 }
222 else
223 if(strncmp(nextword, MIXER_PLAYBACKSWITCH, sizeof(MIXER_PLAYBACKSWITCH)-1) == 0 ||
224 strncmp(nextword, MIXER_SWITCH, sizeof(MIXER_SWITCH)-1) == 0)
225 {//mute control
226 pHandle->controls[j].idxMute = i;
227 }
228 else
229 if(strncmp(nextword, MIXER_SOURCE, sizeof(MIXER_SOURCE)-1) == 0)
230 {//source control (e.g. recording source)
231 pHandle->controls[j].idxCustom = i;
232 }
233 else
234 if(strncmp(nextword, MIXER_CAPTUREROUTE, sizeof(MIXER_CAPTUREROUTE)-1) == 0 ||
235 strncmp(nextword, MIXER_CAPTURESWITCH, sizeof(MIXER_CAPTURESWITCH)-1) == 0)
236 {//source control for recording (per input)
237 pHandle->controls[j].idxCaptureSwitch = i;
238 }
239 else
240 if(i == OSS_MIXER_MIC) {
241 if(strncmp(nextword, MIXER_BOOST, sizeof(MIXER_BOOST)-1) == 0)
242 {//mic boost switch
243 pHandle->controls[j].idxCustom = i;
244 }
245 }
246 }
247 }
248 }
249 }
250
251 pHandle->reccaps = 0;
252 for(j=0;j<OSS32_MIX_RECSRC_MAX;j++) {
253 pHandle->idxRecCaps[j] = -1;
254 }
255
256 //request information about available capture sources
257 if(pHandle->controls[OSS_MIXER_IGAIN].idxCustom != -1)
258 {
259 struct snd_ctl_elem_info *pElemInfo = NULL;
260 int idx, j;
261
262 idx = pHandle->controls[OSS_MIXER_IGAIN].idxCustom;
263
264 //set operation to non-blocking
265 pHandle->file.f_flags = O_NONBLOCK;
266
267 pHandle->rectype = RECTYPE_SELECTOR;
268
269 //too big to put on the stack
270 pElemInfo = (struct snd_ctl_elem_info *)kmalloc(sizeof(struct snd_ctl_elem_info), GFP_KERNEL);
271 if(pElemInfo == NULL) {
272 DebugInt3();
273 goto failure;
274 }
275
276 pElemInfo->value.enumerated.items = 1;
277 for(i=0;i<pElemInfo->value.enumerated.items;i++)
278 {
279 pElemInfo->value.enumerated.item = i;
280 pElemInfo->id.numid = pHandle->pids[idx].numid;
281 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_CTL_IOCTL_ELEM_INFO, (ULONG)pElemInfo);
282 if(ret) {
283 DebugInt3();
284 break;
285 }
286 if(pElemInfo->type != SNDRV_CTL_ELEM_TYPE_ENUMERATED) {
287 DebugInt3();
288 break;
289 }
290 for(j=0;j<OSS32_MIX_RECSRC_MAX;j++) {
291 if(!strcmp(pElemInfo->value.enumerated.name, szRecSources[j])) {
292 pHandle->reccaps |= OSS32_MIX_FLAG(j);
293 pHandle->idxRecCaps[j] = i; //save alsa index
294 break;
295 }
296 }
297 }
298 kfree(pElemInfo);
299 }
300 else
301 {//This card has no record source selection, but probably route switches for
302 //each input source (SB mixers (also ALS4000), CMedia)
303 pHandle->rectype = RECTYPE_SWITCH;
304 for(j=0;j<OSS32_MIX_RECSRC_MAX;j++) {
305 pHandle->idxRecCaps[j] = -1;
306 }
307 for(j=0;j<OSS_MIXER_NRDEVICES;j++)
308 {
309 if(pHandle->controls[j].idxCaptureSwitch != -1) {
310 pHandle->reccaps |= OSS32_MIX_FLAG(ossid[j].recsrc);
311 pHandle->idxRecCaps[ossid[j].recsrc] = pHandle->controls[j].idxCaptureSwitch; //save alsa index
312 }
313 }
314 }
315
316 pHandle->magic = MAGIC_MIXER_ALSA32;
317 *pStreamId = (ULONG)pHandle;
318 return OSSERR_SUCCESS;
319
320failure:
321 if(pHandle) {
322 if(pHandle->pids) kfree(pHandle->pids);
323 kfree(pHandle);
324 }
325 DebugInt3();
326 return OSSERR_OUT_OF_MEMORY;
327}
328//******************************************************************************
329//******************************************************************************
330OSSRET OSS32_MixClose(OSSSTREAMID streamid)
331{
332 mixerhandle *pHandle = (mixerhandle *)streamid;
333 int ret;
334
335 if(pHandle == NULL || pHandle->magic != MAGIC_MIXER_ALSA32) {
336 DebugInt3();
337 return OSSERR_INVALID_STREAMID;
338 }
339 //set operation to non-blocking
340 pHandle->file.f_flags = O_NONBLOCK;
341 ret = pHandle->file.f_op->release(&pHandle->inode, &pHandle->file);
342 kfree(pHandle->pids); //free mixer element array
343 kfree(pHandle); //free handle data
344
345 if(ret) {
346 DebugInt3();
347 return UNIXToOSSError(ret);
348 }
349 return OSSERR_SUCCESS;
350}
351//******************************************************************************
352//******************************************************************************
353OSSRET OSS32_MixGetVolume(OSSSTREAMID streamid, ULONG line, ULONG *pVolume)
354{
355 mixerhandle *pHandle = (mixerhandle *)streamid;
356 int ret;
357
358 if(pHandle == NULL || pHandle->magic != MAGIC_MIXER_ALSA32) {
359 DebugInt3();
360 return OSSERR_INVALID_STREAMID;
361 }
362 //set operation to non-blocking
363 pHandle->file.f_flags = O_NONBLOCK;
364
365 return OSSERR_NOT_SUPPORTED;
366}
367//******************************************************************************
368//******************************************************************************
369OSSRET OSS32_MixSetVolume(OSSSTREAMID streamid, ULONG line, ULONG volume)
370{
371 mixerhandle *pHandle = (mixerhandle *)streamid;
372 struct snd_ctl_elem_value *pElem = NULL;
373 struct snd_ctl_elem_info *pElemInfo;
374 int ret, idx, lVol, rVol = 0, idxMute, cnt;
375
376 if(pHandle == NULL || pHandle->magic != MAGIC_MIXER_ALSA32) {
377 printk("Invalid handle in OSS32_MixSetVolume\n");
378 DebugInt3();
379 return OSSERR_INVALID_STREAMID;
380 }
381 //set operation to non-blocking
382 pHandle->file.f_flags = O_NONBLOCK;
383
384 //too big to put on the stack
385 pElem = (struct snd_ctl_elem_value *)kmalloc(sizeof(struct snd_ctl_elem_value) + sizeof(struct snd_ctl_elem_info), GFP_KERNEL);
386 if(pElem == NULL) {
387 printk("Out of memory in OSS32_MixSetVolume\n");
388 DebugInt3();
389 return OSSERR_OUT_OF_MEMORY;
390 }
391 pElemInfo = (struct snd_ctl_elem_info *)(pElem+1);
392
393 switch(line) {
394 case OSS32_MIX_VOLUME_MASTER_FRONT:
395 idx = pHandle->controls[OSS_MIXER_VOLUME].idxVolume;
396 idxMute = pHandle->controls[OSS_MIXER_VOLUME].idxMute;
397 if (idx == -1)
398 {
399 /* HDA codecs workaround */
400 idx = pHandle->controls[OSS_MIXER_FRONT].idxVolume;
401 idxMute = pHandle->controls[OSS_MIXER_FRONT].idxMute;
402 }
403 break;
404 case OSS32_MIX_VOLUME_MASTER_REAR: //TODO:
405 idx = pHandle->controls[OSS_MIXER_VOLUME].idxVolume;
406 idxMute = pHandle->controls[OSS_MIXER_VOLUME].idxMute;
407 break;
408 case OSS32_MIX_VOLUME_PCM:
409 idx = pHandle->controls[OSS_MIXER_PCM].idxVolume;
410 idxMute = pHandle->controls[OSS_MIXER_PCM].idxMute;
411 if (idx == -1)
412 {
413 /* HDA codecs workaround */
414 idx = pHandle->controls[OSS_MIXER_FRONT].idxVolume;
415 idxMute = pHandle->controls[OSS_MIXER_FRONT].idxMute;
416 }
417 break;
418 case OSS32_MIX_VOLUME_MIDI:
419 idx = pHandle->controls[OSS_MIXER_SYNTH].idxVolume;
420 idxMute = pHandle->controls[OSS_MIXER_SYNTH].idxMute;
421 break;
422 case OSS32_MIX_VOLUME_LINEIN:
423 idx = pHandle->controls[OSS_MIXER_LINE].idxVolume;
424 idxMute = pHandle->controls[OSS_MIXER_LINE].idxMute;
425 break;
426 case OSS32_MIX_VOLUME_MIC:
427 idx = pHandle->controls[OSS_MIXER_MIC].idxVolume;
428 idxMute = pHandle->controls[OSS_MIXER_MIC].idxMute;
429 break;
430 case OSS32_MIX_VOLUME_CD:
431 idx = pHandle->controls[OSS_MIXER_CD].idxVolume;
432 idxMute = pHandle->controls[OSS_MIXER_CD].idxMute;
433 break;
434 case OSS32_MIX_VOLUME_SPDIF:
435 idx = pHandle->controls[OSS_MIXER_DIGITAL1].idxVolume;
436 idxMute = pHandle->controls[OSS_MIXER_DIGITAL1].idxMute;
437 break;
438 case OSS32_MIX_VOLUME_VIDEO:
439 idx = pHandle->controls[OSS_MIXER_VIDEO].idxVolume;
440 idxMute = pHandle->controls[OSS_MIXER_VIDEO].idxMute;
441 break;
442 case OSS32_MIX_VOLUME_PCSPEAKER:
443 idx = pHandle->controls[OSS_MIXER_PCSPEAKER].idxVolume;
444 idxMute = pHandle->controls[OSS_MIXER_PCSPEAKER].idxMute;
445 if (idx == -1)
446 {
447 /* if OSS_MIXER_PCSPEAKER isn't a valid control, try OSS_MIXER_SPEAKER */
448 idx = pHandle->controls[OSS_MIXER_SPEAKER].idxVolume;
449 idxMute = pHandle->controls[OSS_MIXER_SPEAKER].idxMute;
450 }
451 break;
452 case OSS32_MIX_VOLUME_PHONE:
453 idx = pHandle->controls[OSS_MIXER_PHONEOUT].idxVolume;
454 idxMute = pHandle->controls[OSS_MIXER_PHONEOUT].idxMute;
455 break;
456 case OSS32_MIX_VOLUME_HEADPHONE:
457 idx = pHandle->controls[OSS_MIXER_HEADPHONE].idxVolume;
458 idxMute = pHandle->controls[OSS_MIXER_HEADPHONE].idxMute;
459 break;
460 case OSS32_MIX_VOLUME_AUX:
461 idx = pHandle->controls[OSS_MIXER_LINE1].idxVolume;
462 idxMute = pHandle->controls[OSS_MIXER_LINE1].idxMute;
463 break;
464 case OSS32_MIX_VOLUME_CAPTURE:
465 idx = pHandle->controls[OSS_MIXER_IGAIN].idxVolume;
466 idxMute = pHandle->controls[OSS_MIXER_IGAIN].idxMute;
467 break;
468
469 default:
470 DebugInt3();
471 ret = OSSERR_INVALID_PARAMETER;
472 goto fail;
473 }
474 if(idx == -1) {
475 dprintf(("Unknown control %d", line));
476 ret = OSSERR_INVALID_PARAMETER;
477 goto fail;
478 }
479
480 if(idxMute != -1 && volume != 0) {
481 //disable mute
482 pElem->id.numid = pHandle->pids[idxMute].numid;
483 pElem->indirect = 0;
484
485 pElem->value.integer.value[0] = TRUE; //switch, not mute control (inversed)
486 pElem->value.integer.value[1] = TRUE;
487 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_CTL_IOCTL_ELEM_WRITE, (ULONG)pElem);
488 }
489 //request information about mixer control
490 pElemInfo->id.numid = pHandle->pids[idx].numid;
491 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_CTL_IOCTL_ELEM_INFO, (ULONG)pElemInfo);
492 if(ret) {
493 ret = UNIXToOSSError(ret);
494 DebugInt3();
495 goto fail;
496 }
497 if(pElemInfo->type != SNDRV_CTL_ELEM_TYPE_INTEGER) {
498 ret = OSSERR_INVALID_PARAMETER;
499 DebugInt3();
500 goto fail;
501 }
502 pElem->id.numid = pHandle->pids[idx].numid;
503 pElem->indirect = 0;
504
505 lVol = ConvertVolume(GET_VOLUME_L(volume), pElemInfo->value.integer.max);
506 pElem->value.integer.value[0] = lVol;
507
508 if(pElemInfo->count > 1) { //stereo
509 rVol = ConvertVolume(GET_VOLUME_R(volume), pElemInfo->value.integer.max);
510 pElem->value.integer.value[1] = rVol;
511 }
512
513 printk("OSS32_MixSetVolume of %s streamid %X to (%d,%d)(%d,%d) caps %d\n",
514 pHandle->pids[idx].name,
515 (ULONG)pHandle, GET_VOLUME_L(volume),
516 GET_VOLUME_R(volume), lVol, rVol, pElemInfo->value.integer.max);
517
518 // looking for more, then one opened streams to prevent of muting active stream
519 cnt = 0;
520 for (idx=0; idx < 8*256; idx++)
521 if (opened_handles[idx].handle != 0)
522 cnt++;
523
524 // if (((cnt == 1 && (lVol==0 && rVol==0)) || (lVol>0 && rVol>0)) ||
525 if (cnt == 1 || line != OSS32_MIX_VOLUME_PCM)
526 {
527 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_CTL_IOCTL_ELEM_WRITE, (ULONG)pElem);
528
529 if(idxMute != -1 && volume == 0) {
530 //enable mute
531 pElem->id.numid = pHandle->pids[idxMute].numid;
532 pElem->indirect = 0;
533
534 pElem->value.integer.value[0] = FALSE; //switch, not mute control (inversed)
535 pElem->value.integer.value[1] = FALSE;
536 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_CTL_IOCTL_ELEM_WRITE, (ULONG)pElem);
537 }
538 }
539
540 kfree(pElem);
541 pElem = NULL;
542 if(ret) {
543 printk("ret = %i\n", ret);
544 DebugInt3();
545 return UNIXToOSSError(ret);
546 }
547 return OSSERR_SUCCESS;
548
549fail:
550 printk("OSS32_MixSetVolume failed: %i\n", ret);
551 if(pElem) kfree(pElem);
552 return ret;
553}
554//******************************************************************************
555//******************************************************************************
556OSSRET OSS32_MixSetProperty(OSSSTREAMID streamid, ULONG ulLine, ULONG ulValue)
557{
558 mixerhandle *pHandle = (mixerhandle *)streamid;
559 struct snd_ctl_elem_value *pElem = NULL;
560 struct snd_ctl_elem_info *pElemInfo;
561 int ret, idx = -1, lVol, rVol = 0, j, i;
562
563 if(pHandle == NULL || pHandle->magic != MAGIC_MIXER_ALSA32) {
564 DebugInt3();
565 return OSSERR_INVALID_STREAMID;
566 }
567 //set operation to non-blocking
568 pHandle->file.f_flags = O_NONBLOCK;
569
570 //too big to put on the stack
571 pElem = (struct snd_ctl_elem_value *)kmalloc(sizeof(struct snd_ctl_elem_value) + sizeof(struct snd_ctl_elem_info), GFP_KERNEL);
572 if(pElem == NULL) {
573 DebugInt3();
574 return OSSERR_OUT_OF_MEMORY;
575 }
576 pElemInfo = (struct snd_ctl_elem_info *)(pElem+1);
577
578 switch(ulLine) {
579 case OSS32_MIX_INPUTSRC:
580 idx = pHandle->controls[OSS_MIXER_IGAIN].idxCustom;
581 //is this capture source supported by the hardware??
582 if(!(pHandle->reccaps & OSS32_MIX_FLAG(ulValue))) {
583 DebugInt3();
584 ret = OSSERR_INVALID_PARAMETER;
585 goto fail;
586 }
587 if(pHandle->rectype == RECTYPE_SELECTOR) {//input source selector
588 //set left and right capture source
589 pElem->value.enumerated.item[0] = pHandle->idxRecCaps[ulValue];
590 pElem->value.enumerated.item[1] = pHandle->idxRecCaps[ulValue];
591 }
592 else {//capture switch for each input source
593 //first turn off all capture switches...
594 for(j=0;j<OSS32_MIX_RECSRC_MAX;j++)
595 {
596 if(pHandle->idxRecCaps[j] != -1) {
597 idx = pHandle->idxRecCaps[j];
598
599 //request information about mixer control
600 pElemInfo->id.numid = pHandle->pids[idx].numid;
601 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_CTL_IOCTL_ELEM_INFO, (ULONG)pElemInfo);
602 if(ret) {
603 ret = UNIXToOSSError(ret);
604 DebugInt3();
605 goto fail;
606 }
607 if(pElemInfo->type != SNDRV_CTL_ELEM_TYPE_BOOLEAN) {
608 ret = OSSERR_INVALID_PARAMETER;
609 DebugInt3();
610 goto fail;
611 }
612
613 pElem->id.numid = pHandle->pids[idx].numid;
614 pElem->indirect = 0;
615 for(i=0;i<pElemInfo->count;i++) {
616 pElem->value.integer.value[i] = 0;
617 }
618
619 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_CTL_IOCTL_ELEM_WRITE, (ULONG)pElem);
620 if(ret) {
621 ret = UNIXToOSSError(ret);
622 DebugInt3();
623 goto fail;
624 }
625 }
626 }
627 //request information about mixer control
628 pElemInfo->id.numid = pHandle->pids[idx].numid;
629 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_CTL_IOCTL_ELEM_INFO, (ULONG)pElemInfo);
630 if(ret) {
631 ret = UNIXToOSSError(ret);
632 DebugInt3();
633 goto fail;
634 }
635
636 //and enable the capture switch for the selected input source
637 idx = pHandle->idxRecCaps[ulValue];
638 for(i=0;i<pElemInfo->count;i++) {
639 pElem->value.integer.value[i] = 1;
640 }
641 }
642
643 break;
644
645 case OSS32_MIX_SWITCH_MICBOOST:
646 idx = pHandle->controls[OSS_MIXER_MIC].idxCustom;
647 if(idx == -1) {
648 DebugInt3();
649 ret = OSSERR_INVALID_PARAMETER;
650 goto fail;
651 }
652 //set mic switch value (on/off)
653 pElem->value.integer.value[0] = ulValue;
654 break;
655
656 case OSS32_MIX_LEVEL_BASS:
657 idx = pHandle->controls[OSS_MIXER_BASS].idxVolume;
658 goto levelcontinue;
659 case OSS32_MIX_LEVEL_TREBLE:
660 idx = pHandle->controls[OSS_MIXER_TREBLE].idxVolume;
661 goto levelcontinue;
662 case OSS32_MIX_LEVEL_3DCENTER:
663 idx = pHandle->controls[OSS_MIXER_3DCENTER].idxVolume;
664 goto levelcontinue;
665 case OSS32_MIX_LEVEL_3DDEPTH:
666 idx = pHandle->controls[OSS_MIXER_3DDEPTH].idxVolume;
667levelcontinue:
668
669 if(idx == -1) {//supported?
670 DebugInt3();
671 ret = OSSERR_INVALID_PARAMETER;
672 goto fail;
673 }
674 //request information about mixer control
675 pElemInfo->id.numid = pHandle->pids[idx].numid;
676 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_CTL_IOCTL_ELEM_INFO, (ULONG)pElemInfo);
677 if(ret) {
678 ret = UNIXToOSSError(ret);
679 DebugInt3();
680 goto fail;
681 }
682 if(pElemInfo->type != SNDRV_CTL_ELEM_TYPE_INTEGER) {
683 ret = OSSERR_INVALID_PARAMETER;
684 DebugInt3();
685 goto fail;
686 }
687 lVol = ConvertVolume(GET_VOLUME_L(ulValue), pElemInfo->value.integer.max);
688 pElem->value.integer.value[0] = lVol;
689
690 if(pElemInfo->count > 1) { //stereo
691 rVol = ConvertVolume(GET_VOLUME_R(ulValue), pElemInfo->value.integer.max);
692 pElem->value.integer.value[1] = rVol;
693 }
694 break;
695
696 default:
697 DebugInt3();
698 ret = OSSERR_INVALID_PARAMETER;
699 goto fail;
700 }
701 pElem->id.numid = pHandle->pids[idx].numid;
702 pElem->indirect = 0;
703
704 dprintf(("OSS32_MixSetProperty of %s to %x", pHandle->pids[idx].name, ulValue));
705 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_CTL_IOCTL_ELEM_WRITE, (ULONG)pElem);
706
707 kfree(pElem);
708 pElem = NULL;
709 if(ret) {
710 DebugInt3();
711 return UNIXToOSSError(ret);
712 }
713 return OSSERR_SUCCESS;
714
715fail:
716 if(pElem) kfree(pElem);
717 return ret;
718}
719//******************************************************************************
720//******************************************************************************
721OSSRET OSS32_MixGetProperty(OSSSTREAMID streamid, ULONG line, ULONG *pValue)
722{
723 mixerhandle *pHandle = (mixerhandle *)streamid;
724 int ret;
725
726 if(pHandle == NULL || pHandle->magic != MAGIC_MIXER_ALSA32) {
727 DebugInt3();
728 return OSSERR_INVALID_STREAMID;
729 }
730 //set operation to non-blocking
731 pHandle->file.f_flags = O_NONBLOCK;
732
733 return OSSERR_NOT_SUPPORTED;
734}
735//******************************************************************************
736//******************************************************************************
737ULONG OSSToALSAVolume(ULONG OSSVolIdx)
738{
739 switch(OSSVolIdx) {
740 case OSS_MIXER_VOLUME:
741 return OSS32_MIX_VOLUME_MASTER_FRONT;
742#if 0
743 case OSS_MIXER_VOLUME: //TODO:
744 return OSS32_MIX_VOLUME_MASTER_REAR;
745#endif
746 case OSS_MIXER_PCM:
747 return OSS32_MIX_VOLUME_PCM;
748 case OSS_MIXER_SYNTH:
749 return OSS32_MIX_VOLUME_MIDI;
750 case OSS_MIXER_LINE:
751 return OSS32_MIX_VOLUME_LINEIN;
752 case OSS_MIXER_MIC:
753 return OSS32_MIX_VOLUME_MIC;
754 case OSS_MIXER_CD:
755 return OSS32_MIX_VOLUME_CD;
756 case OSS_MIXER_DIGITAL1:
757 return OSS32_MIX_VOLUME_SPDIF;
758 case OSS_MIXER_VIDEO:
759 return OSS32_MIX_VOLUME_VIDEO;
760 case OSS_MIXER_PCSPEAKER:
761 return OSS32_MIX_VOLUME_PCSPEAKER;
762 case OSS_MIXER_PHONEOUT:
763 return OSS32_MIX_VOLUME_PHONE;
764 case OSS_MIXER_IGAIN:
765 return OSS32_MIX_VOLUME_CAPTURE;
766 case OSS_MIXER_TREBLE:
767 return OSS32_MIX_LEVEL_TREBLE;
768 case OSS_MIXER_BASS:
769 return OSS32_MIX_LEVEL_BASS;
770 case OSS_MIXER_HEADPHONE:
771 return OSS32_MIX_VOLUME_HEADPHONE;
772 case OSS_MIXER_LINE1:
773 return OSS32_MIX_VOLUME_AUX;
774 }
775 return -1;
776}
777//******************************************************************************
778//******************************************************************************
779OSSRET OSS32_MixQueryCaps(OSSSTREAMID streamid, POSS32_MIXCAPS pCaps)
780{
781 mixerhandle *pHandle = (mixerhandle *)streamid;
782 int i;
783
784 if(pHandle == NULL || pHandle->magic != MAGIC_MIXER_ALSA32) {
785 DebugInt3();
786 return OSSERR_INVALID_STREAMID;
787 }
788
789 strncpy(pCaps->name, pHandle->info.mixername, sizeof(pCaps->name));
790 pCaps->fuCtrlCaps = 0;
791 pCaps->fuRecCaps = 0;
792
793 for(i=0;i<OSS_MIXER_NRDEVICES;i++)
794 {
795 if(pHandle->controls[i].idxVolume != -1) {
796 ULONG volidx = OSSToALSAVolume(i);
797 if(volidx != -1)
798 pCaps->fuCtrlCaps |= OSS32_MIX_FLAG(volidx);
799 }
800 }
801
802 //if it has a capture source control or the card has capture route switches,
803 //then we support intput source selection
804 if(pHandle->controls[OSS_MIXER_IGAIN].idxCustom != -1 ||
805 pHandle->rectype == RECTYPE_SWITCH)
806 {
807 pCaps->fuCtrlCaps |= OSS32_MIX_FLAG(OSS32_MIX_INPUTSRC);
808 pCaps->fuRecCaps = pHandle->reccaps;
809 }
810 return OSSERR_SUCCESS;
811}
812//******************************************************************************
813//******************************************************************************
814OSSRET OSS32_MixQueryName(ULONG deviceid, char *pszMixerName, ULONG cbMixerName)
815{
816 mixerhandle *pHandle = NULL;
817 int ret, i, j;
818
819 if(alsa_fops == NULL)
820 return OSSERR_NO_DEVICE_AVAILABLE;
821
822 pHandle = kmalloc(sizeof(mixerhandle), GFP_KERNEL);
823 if(pHandle == NULL) {
824 ret = OSSERR_OUT_OF_MEMORY;
825 goto failure;
826 }
827 memset(pHandle, 0, sizeof(mixerhandle));
828
829 //set operation to non-blocking
830 pHandle->file.f_flags = O_NONBLOCK;
831
832 //setup pointers in file structure (used internally by ALSA)
833 pHandle->file.f_dentry = &pHandle->d_entry;
834 pHandle->file.f_dentry->d_inode = &pHandle->inode;
835
836 pHandle->file.f_mode = FMODE_WRITE;
837 pHandle->inode.i_rdev = SNDRV_MINOR(deviceid, SNDRV_MINOR_CONTROL);
838
839 ret = alsa_fops->open(&pHandle->inode, &pHandle->file);
840 if(ret) {
841 goto failure;
842 }
843 //retrieve mixer information
844 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file,
845 SNDRV_CTL_IOCTL_CARD_INFO,
846 (ULONG)&pHandle->info);
847 if(ret) {
848 goto failure;
849 }
850
851 strncpy(pszMixerName, pHandle->info.mixername, cbMixerName);
852
853 pHandle->file.f_flags = O_NONBLOCK;
854 ret = pHandle->file.f_op->release(&pHandle->inode, &pHandle->file);
855 if(ret) {
856 goto failure;
857 }
858 kfree(pHandle);
859 return OSSERR_SUCCESS;
860
861failure:
862 if(pHandle) {
863 kfree(pHandle);
864 }
865 DebugInt3();
866 return OSSERR_OUT_OF_MEMORY;
867}
868//******************************************************************************
869//******************************************************************************
870OSSRET OSS32_QueryNames(ULONG deviceid, char *pszDeviceName, ULONG cbDeviceName,
871 char *pszMixerName, ULONG cbMixerName, BOOL fLongName)
872{
873 mixerhandle *pHandle = NULL;
874 int ret, i, j;
875
876 if(alsa_fops == NULL) {
877 ret = OSSERR_NO_DEVICE_AVAILABLE;
878 printk("ret = OSSERR_NO_DEVICE_AVAILABLE\n");
879 goto failure;
880 }
881
882 pHandle = kmalloc(sizeof(mixerhandle), GFP_KERNEL);
883 if(pHandle == NULL) {
884 ret = OSSERR_OUT_OF_MEMORY;
885 goto failure;
886 }
887 memset(pHandle, 0, sizeof(mixerhandle));
888
889 //set operation to non-blocking
890 pHandle->file.f_flags = O_NONBLOCK;
891
892 //setup pointers in file structure (used internally by ALSA)
893 pHandle->file.f_dentry = &pHandle->d_entry;
894 pHandle->file.f_dentry->d_inode = &pHandle->inode;
895
896 pHandle->file.f_mode = FMODE_WRITE;
897 pHandle->inode.i_rdev = SNDRV_MINOR(deviceid, SNDRV_MINOR_CONTROL);
898
899 ret = alsa_fops->open(&pHandle->inode, &pHandle->file);
900 if(ret) {
901 printk("open ret = %i\n", ret);
902 goto failure;
903 }
904 //retrieve mixer information
905 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file,
906 SNDRV_CTL_IOCTL_CARD_INFO,
907 (ULONG)&pHandle->info);
908 if(ret) {
909 printk("ioctl ret = %i\n", ret);
910 goto failure;
911 }
912
913 if(pszDeviceName) {
914 if(fLongName == TRUE) {
915 strncpy(pszDeviceName, pHandle->info.longname, cbDeviceName);
916 }
917 else strncpy(pszDeviceName, pHandle->info.name, cbDeviceName);
918 }
919 if(pszMixerName) {
920 strncpy(pszMixerName, pHandle->info.mixername, cbMixerName);
921 }
922
923// printk("Card: %s with mixer %s\n",pszDeviceName, pszMixerName);
924
925 pHandle->file.f_flags = O_NONBLOCK;
926 ret = pHandle->file.f_op->release(&pHandle->inode, &pHandle->file);
927 if(ret) {
928 printk("release ret = %i\n", ret);
929 goto failure;
930 }
931 kfree(pHandle);
932 return OSSERR_SUCCESS;
933
934failure:
935 if(pHandle) {
936 kfree(pHandle);
937 }
938 DebugInt3();
939 printk("OSS32_QueryNames() ret = %i\n", ret);
940 return OSSERR_OUT_OF_MEMORY;
941}
942//******************************************************************************
943//******************************************************************************
944
Note: See TracBrowser for help on using the repository browser.