source: GPL/branches/uniaud32-2.1.x/lib32/soundmixer.c@ 531

Last change on this file since 531 was 531, checked in by David Azarewicz, 15 years ago

merge changes from trunk

File size: 30.0 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_SPEAKER */ { "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 if (pHandle->pids[i].index == ossid[j].index && strncmp(pHandle->pids[i].name, ossid[j].name, namelen) == 0) {
201 int controlnamelen = strlen(pHandle->pids[i].name);
202
203 if(namelen == controlnamelen) { //control names are identical; found exact match
204 pHandle->controls[j].idxVolume = i;
205 break;
206 } else { //first part of the control name is correct; now find out what is it exactly
207 char *nextword = &pHandle->pids[i].name[namelen];
208 while(*nextword && *nextword == ' ') nextword++;
209
210 if(strncmp(nextword, MIXER_PLAYBACKVOLUME, sizeof(MIXER_PLAYBACKVOLUME)-1) == 0 ||
211 strncmp(nextword, MIXER_VOLUME, sizeof(MIXER_VOLUME)-1) == 0)
212 { //volume control
213 pHandle->controls[j].idxVolume = i;
214 }
215 else
216 if(strncmp(nextword, MIXER_PLAYBACKSWITCH, sizeof(MIXER_PLAYBACKSWITCH)-1) == 0 ||
217 strncmp(nextword, MIXER_SWITCH, sizeof(MIXER_SWITCH)-1) == 0)
218 { //mute control
219 pHandle->controls[j].idxMute = i;
220 if (pHandle->controls[j].idxVolume == -1) pHandle->controls[j].idxVolume = i;
221 }
222 else
223 if(strncmp(nextword, MIXER_SOURCE, sizeof(MIXER_SOURCE)-1) == 0)
224 { //source control (e.g. recording source)
225 pHandle->controls[j].idxCustom = i;
226 }
227 else
228 if(strncmp(nextword, MIXER_CAPTUREROUTE, sizeof(MIXER_CAPTUREROUTE)-1) == 0 ||
229 strncmp(nextword, MIXER_CAPTURESWITCH, sizeof(MIXER_CAPTURESWITCH)-1) == 0)
230 { //source control for recording (per input)
231 pHandle->controls[j].idxCaptureSwitch = i;
232 }
233 else
234 if(i == OSS_MIXER_MIC) {
235 if(strncmp(nextword, MIXER_BOOST, sizeof(MIXER_BOOST)-1) == 0) { //mic boost switch
236 pHandle->controls[j].idxCustom = i;
237 }
238 }
239 }
240 }
241 }
242 }
243
244 pHandle->reccaps = 0;
245 for (j=0;j<OSS32_MIX_RECSRC_MAX;j++) {
246 pHandle->idxRecCaps[j] = -1;
247 }
248
249 //request information about available capture sources
250 if (pHandle->controls[OSS_MIXER_IGAIN].idxCustom != -1) {
251 struct snd_ctl_elem_info *pElemInfo = NULL;
252 int idx, j;
253
254 idx = pHandle->controls[OSS_MIXER_IGAIN].idxCustom;
255
256 //set operation to non-blocking
257 pHandle->file.f_flags = O_NONBLOCK;
258
259 pHandle->rectype = RECTYPE_SELECTOR;
260
261 //too big to put on the stack
262 pElemInfo = (struct snd_ctl_elem_info *)kmalloc(sizeof(struct snd_ctl_elem_info), GFP_KERNEL);
263 if(pElemInfo == NULL) {
264 DebugInt3();
265 goto failure;
266 }
267
268 pElemInfo->value.enumerated.items = 1;
269 for(i=0;i<pElemInfo->value.enumerated.items;i++)
270 {
271 pElemInfo->value.enumerated.item = i;
272 pElemInfo->id.numid = pHandle->pids[idx].numid;
273 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_CTL_IOCTL_ELEM_INFO, (ULONG)pElemInfo);
274 if(ret) {
275 DebugInt3();
276 break;
277 }
278 if(pElemInfo->type != SNDRV_CTL_ELEM_TYPE_ENUMERATED) {
279 DebugInt3();
280 break;
281 }
282 for(j=0;j<OSS32_MIX_RECSRC_MAX;j++) {
283 if(!strcmp(pElemInfo->value.enumerated.name, szRecSources[j])) {
284 pHandle->reccaps |= OSS32_MIX_FLAG(j);
285 pHandle->idxRecCaps[j] = i; //save alsa index
286 break;
287 }
288 }
289 }
290 kfree(pElemInfo);
291 }
292 else
293 {//This card has no record source selection, but probably route switches for
294 //each input source (SB mixers (also ALS4000), CMedia)
295 pHandle->rectype = RECTYPE_SWITCH;
296 for(j=0;j<OSS32_MIX_RECSRC_MAX;j++) {
297 pHandle->idxRecCaps[j] = -1;
298 }
299 for(j=0;j<OSS_MIXER_NRDEVICES;j++)
300 {
301 if(pHandle->controls[j].idxCaptureSwitch != -1) {
302 pHandle->reccaps |= OSS32_MIX_FLAG(ossid[j].recsrc);
303 pHandle->idxRecCaps[ossid[j].recsrc] = pHandle->controls[j].idxCaptureSwitch; //save alsa index
304 }
305 }
306 }
307
308 pHandle->magic = MAGIC_MIXER_ALSA32;
309 *pStreamId = (ULONG)pHandle;
310 return OSSERR_SUCCESS;
311
312failure:
313 if(pHandle) {
314 if(pHandle->pids) kfree(pHandle->pids);
315 kfree(pHandle);
316 }
317 DebugInt3();
318 return OSSERR_OUT_OF_MEMORY;
319}
320//******************************************************************************
321//******************************************************************************
322OSSRET OSS32_MixClose(OSSSTREAMID streamid)
323{
324 mixerhandle *pHandle = (mixerhandle *)streamid;
325 int ret;
326
327 if(pHandle == NULL || pHandle->magic != MAGIC_MIXER_ALSA32) {
328 DebugInt3();
329 return OSSERR_INVALID_STREAMID;
330 }
331 //set operation to non-blocking
332 pHandle->file.f_flags = O_NONBLOCK;
333 ret = pHandle->file.f_op->release(&pHandle->inode, &pHandle->file);
334 kfree(pHandle->pids); //free mixer element array
335 kfree(pHandle); //free handle data
336
337 if(ret) {
338 DebugInt3();
339 return UNIXToOSSError(ret);
340 }
341 return OSSERR_SUCCESS;
342}
343//******************************************************************************
344//******************************************************************************
345OSSRET OSS32_MixGetVolume(OSSSTREAMID streamid, ULONG line, ULONG *pVolume)
346{
347 mixerhandle *pHandle = (mixerhandle *)streamid;
348 int ret;
349
350 if(pHandle == NULL || pHandle->magic != MAGIC_MIXER_ALSA32) {
351 DebugInt3();
352 return OSSERR_INVALID_STREAMID;
353 }
354 //set operation to non-blocking
355 pHandle->file.f_flags = O_NONBLOCK;
356
357 return OSSERR_NOT_SUPPORTED;
358}
359//******************************************************************************
360//******************************************************************************
361OSSRET OSS32_MixSetVolume(OSSSTREAMID streamid, ULONG line, ULONG volume)
362{
363 mixerhandle *pHandle = (mixerhandle *)streamid;
364 struct snd_ctl_elem_value *pElem = NULL;
365 struct snd_ctl_elem_info *pElemInfo;
366 int ret, idx, lVol, rVol = 0, idxMute, cnt;
367
368 //dprintf(("OSS32_MixSetVolume line=%d\n", line));
369 if(pHandle == NULL || pHandle->magic != MAGIC_MIXER_ALSA32) {
370 printk("Invalid handle in OSS32_MixSetVolume\n");
371 DebugInt3();
372 return OSSERR_INVALID_STREAMID;
373 }
374 //set operation to non-blocking
375 pHandle->file.f_flags = O_NONBLOCK;
376
377 //too big to put on the stack
378 pElem = (struct snd_ctl_elem_value *)kmalloc(sizeof(struct snd_ctl_elem_value) + sizeof(struct snd_ctl_elem_info), GFP_KERNEL);
379 if(pElem == NULL) {
380 printk("Out of memory in OSS32_MixSetVolume\n");
381 DebugInt3();
382 return OSSERR_OUT_OF_MEMORY;
383 }
384 pElemInfo = (struct snd_ctl_elem_info *)(pElem+1);
385
386 switch(line) {
387 case OSS32_MIX_VOLUME_MASTER_FRONT:
388 idx = pHandle->controls[OSS_MIXER_VOLUME].idxVolume;
389 idxMute = pHandle->controls[OSS_MIXER_VOLUME].idxMute;
390 if (idx == -1)
391 {
392 /* HDA codecs workaround */
393 idx = pHandle->controls[OSS_MIXER_FRONT].idxVolume;
394 idxMute = pHandle->controls[OSS_MIXER_FRONT].idxMute;
395 }
396 break;
397 case OSS32_MIX_VOLUME_MASTER_REAR: //TODO:
398 idx = pHandle->controls[OSS_MIXER_VOLUME].idxVolume;
399 idxMute = pHandle->controls[OSS_MIXER_VOLUME].idxMute;
400 break;
401 case OSS32_MIX_VOLUME_PCM:
402 idx = pHandle->controls[OSS_MIXER_PCM].idxVolume;
403 idxMute = pHandle->controls[OSS_MIXER_PCM].idxMute;
404 if (idx == -1)
405 {
406 /* HDA codecs workaround */
407 idx = pHandle->controls[OSS_MIXER_FRONT].idxVolume;
408 idxMute = pHandle->controls[OSS_MIXER_FRONT].idxMute;
409 }
410 break;
411 case OSS32_MIX_VOLUME_MIDI:
412 idx = pHandle->controls[OSS_MIXER_SYNTH].idxVolume;
413 idxMute = pHandle->controls[OSS_MIXER_SYNTH].idxMute;
414 break;
415 case OSS32_MIX_VOLUME_LINEIN:
416 idx = pHandle->controls[OSS_MIXER_LINE].idxVolume;
417 idxMute = pHandle->controls[OSS_MIXER_LINE].idxMute;
418 break;
419 case OSS32_MIX_VOLUME_MIC:
420 idx = pHandle->controls[OSS_MIXER_MIC].idxVolume;
421 idxMute = pHandle->controls[OSS_MIXER_MIC].idxMute;
422 break;
423 case OSS32_MIX_VOLUME_CD:
424 idx = pHandle->controls[OSS_MIXER_CD].idxVolume;
425 idxMute = pHandle->controls[OSS_MIXER_CD].idxMute;
426 break;
427 case OSS32_MIX_VOLUME_SPDIF:
428 idx = pHandle->controls[OSS_MIXER_DIGITAL1].idxVolume;
429 idxMute = pHandle->controls[OSS_MIXER_DIGITAL1].idxMute;
430 break;
431 case OSS32_MIX_VOLUME_VIDEO:
432 idx = pHandle->controls[OSS_MIXER_VIDEO].idxVolume;
433 idxMute = pHandle->controls[OSS_MIXER_VIDEO].idxMute;
434 break;
435 case OSS32_MIX_VOLUME_PCSPEAKER:
436 idx = pHandle->controls[OSS_MIXER_PCSPEAKER].idxVolume;
437 idxMute = pHandle->controls[OSS_MIXER_PCSPEAKER].idxMute;
438 break;
439 case OSS32_MIX_VOLUME_PHONE:
440 idx = pHandle->controls[OSS_MIXER_PHONEOUT].idxVolume;
441 idxMute = pHandle->controls[OSS_MIXER_PHONEOUT].idxMute;
442 break;
443 case OSS32_MIX_VOLUME_HEADPHONE:
444 idx = pHandle->controls[OSS_MIXER_HEADPHONE].idxVolume;
445 idxMute = pHandle->controls[OSS_MIXER_HEADPHONE].idxMute;
446 break;
447 case OSS32_MIX_VOLUME_SPEAKER:
448 idx = pHandle->controls[OSS_MIXER_SPEAKER].idxVolume;
449 idxMute = pHandle->controls[OSS_MIXER_SPEAKER].idxMute;
450 break;
451 case OSS32_MIX_VOLUME_AUX:
452 idx = pHandle->controls[OSS_MIXER_LINE1].idxVolume;
453 idxMute = pHandle->controls[OSS_MIXER_LINE1].idxMute;
454 break;
455 case OSS32_MIX_VOLUME_CAPTURE:
456 idx = pHandle->controls[OSS_MIXER_IGAIN].idxVolume;
457 idxMute = pHandle->controls[OSS_MIXER_IGAIN].idxMute;
458 break;
459
460 default:
461 DebugInt3();
462 ret = OSSERR_INVALID_PARAMETER;
463 goto fail;
464 }
465 if(idx == -1) {
466 rprintf(("Unknown control %d", line));
467 ret = OSSERR_INVALID_PARAMETER;
468 goto fail;
469 }
470
471 if(idxMute != -1 && volume != 0) {
472 //disable mute
473 pElem->id.numid = pHandle->pids[idxMute].numid;
474 pElem->indirect = 0;
475
476 pElem->value.integer.value[0] = TRUE; //switch, not mute control (inversed)
477 pElem->value.integer.value[1] = TRUE;
478 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_CTL_IOCTL_ELEM_WRITE, (ULONG)pElem);
479 }
480 //request information about mixer control
481 pElemInfo->id.numid = pHandle->pids[idx].numid;
482 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_CTL_IOCTL_ELEM_INFO, (ULONG)pElemInfo);
483 if(ret) {
484 ret = UNIXToOSSError(ret);
485 DebugInt3();
486 goto fail;
487 }
488 if(pElemInfo->type != SNDRV_CTL_ELEM_TYPE_INTEGER) {
489 ret = OSSERR_INVALID_PARAMETER;
490 DebugInt3();
491 goto fail;
492 }
493 pElem->id.numid = pHandle->pids[idx].numid;
494 pElem->indirect = 0;
495
496 lVol = ConvertVolume(GET_VOLUME_L(volume), pElemInfo->value.integer.max);
497 pElem->value.integer.value[0] = lVol;
498
499 if(pElemInfo->count > 1) { //stereo
500 rVol = ConvertVolume(GET_VOLUME_R(volume), pElemInfo->value.integer.max);
501 pElem->value.integer.value[1] = rVol;
502 }
503
504 dprintf(("OSS32_MixSetVolume of %s streamid %X to (%d,%d)(%d,%d) caps %d",
505 pHandle->pids[idx].name, (ULONG)pHandle,
506 GET_VOLUME_L(volume), GET_VOLUME_R(volume), lVol, rVol, pElemInfo->value.integer.max));
507
508#if 1
509 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_CTL_IOCTL_ELEM_WRITE, (ULONG)pElem);
510#else
511 // looking for more, then one opened streams to prevent of muting active stream
512 cnt = 0;
513 for (idx=0; idx < 8*256; idx++)
514 if (opened_handles[idx].handle != 0)
515 cnt++;
516
517 dprintf(("OSS32_MixSetVolume old cnt=%X line=%x lVol=%x rVol=%x", cnt, line, lVol, rVol));
518 // if (((cnt == 1 && (lVol==0 && rVol==0)) || (lVol>0 && rVol>0)) ||
519 if (cnt == 1 || line != OSS32_MIX_VOLUME_PCM)
520 {
521 dprintf(("OSS32_MixSetVolume Ioctl"));
522 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_CTL_IOCTL_ELEM_WRITE, (ULONG)pElem);
523
524 if(idxMute != -1 && volume == 0) {
525 //enable mute
526 pElem->id.numid = pHandle->pids[idxMute].numid;
527 pElem->indirect = 0;
528
529 pElem->value.integer.value[0] = FALSE; //switch, not mute control (inversed)
530 pElem->value.integer.value[1] = FALSE;
531 dprintf(("OSS32_MixSetVolume Ioctl mute"));
532 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_CTL_IOCTL_ELEM_WRITE, (ULONG)pElem);
533 }
534 }
535#endif
536
537 kfree(pElem);
538 pElem = NULL;
539 if(ret) {
540 rprintf(("OSS32_MixSetVolume ret=%x", ret));
541 DebugInt3();
542 return UNIXToOSSError(ret);
543 }
544 return OSSERR_SUCCESS;
545
546fail:
547 if(pElem) kfree(pElem);
548 return ret;
549}
550//******************************************************************************
551//******************************************************************************
552OSSRET OSS32_MixSetProperty(OSSSTREAMID streamid, ULONG ulLine, ULONG ulValue)
553{
554 mixerhandle *pHandle = (mixerhandle *)streamid;
555 struct snd_ctl_elem_value *pElem = NULL;
556 struct snd_ctl_elem_info *pElemInfo;
557 int ret, idx = -1, lVol, rVol = 0, j, i;
558
559 if(pHandle == NULL || pHandle->magic != MAGIC_MIXER_ALSA32) {
560 DebugInt3();
561 return OSSERR_INVALID_STREAMID;
562 }
563 //set operation to non-blocking
564 pHandle->file.f_flags = O_NONBLOCK;
565
566 //too big to put on the stack
567 pElem = (struct snd_ctl_elem_value *)kmalloc(sizeof(struct snd_ctl_elem_value) + sizeof(struct snd_ctl_elem_info), GFP_KERNEL);
568 if(pElem == NULL) {
569 DebugInt3();
570 return OSSERR_OUT_OF_MEMORY;
571 }
572 pElemInfo = (struct snd_ctl_elem_info *)(pElem+1);
573
574 switch(ulLine) {
575 case OSS32_MIX_INPUTSRC:
576 idx = pHandle->controls[OSS_MIXER_IGAIN].idxCustom;
577 //is this capture source supported by the hardware??
578 if(!(pHandle->reccaps & OSS32_MIX_FLAG(ulValue))) {
579 DebugInt3();
580 ret = OSSERR_INVALID_PARAMETER;
581 goto fail;
582 }
583 if(pHandle->rectype == RECTYPE_SELECTOR) {//input source selector
584 //set left and right capture source
585 pElem->value.enumerated.item[0] = pHandle->idxRecCaps[ulValue];
586 pElem->value.enumerated.item[1] = pHandle->idxRecCaps[ulValue];
587 }
588 else {//capture switch for each input source
589 //first turn off all capture switches...
590 for(j=0;j<OSS32_MIX_RECSRC_MAX;j++)
591 {
592 if(pHandle->idxRecCaps[j] != -1) {
593 idx = pHandle->idxRecCaps[j];
594
595 //request information about mixer control
596 pElemInfo->id.numid = pHandle->pids[idx].numid;
597 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_CTL_IOCTL_ELEM_INFO, (ULONG)pElemInfo);
598 if(ret) {
599 ret = UNIXToOSSError(ret);
600 DebugInt3();
601 goto fail;
602 }
603 if(pElemInfo->type != SNDRV_CTL_ELEM_TYPE_BOOLEAN) {
604 ret = OSSERR_INVALID_PARAMETER;
605 DebugInt3();
606 goto fail;
607 }
608
609 pElem->id.numid = pHandle->pids[idx].numid;
610 pElem->indirect = 0;
611 for(i=0;i<pElemInfo->count;i++) {
612 pElem->value.integer.value[i] = 0;
613 }
614
615 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_CTL_IOCTL_ELEM_WRITE, (ULONG)pElem);
616 if(ret) {
617 ret = UNIXToOSSError(ret);
618 DebugInt3();
619 goto fail;
620 }
621 }
622 }
623 //request information about mixer control
624 pElemInfo->id.numid = pHandle->pids[idx].numid;
625 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_CTL_IOCTL_ELEM_INFO, (ULONG)pElemInfo);
626 if(ret) {
627 ret = UNIXToOSSError(ret);
628 DebugInt3();
629 goto fail;
630 }
631
632 //and enable the capture switch for the selected input source
633 idx = pHandle->idxRecCaps[ulValue];
634 for(i=0;i<pElemInfo->count;i++) {
635 pElem->value.integer.value[i] = 1;
636 }
637 }
638
639 break;
640
641 case OSS32_MIX_SWITCH_MICBOOST:
642 idx = pHandle->controls[OSS_MIXER_MIC].idxCustom;
643 if(idx == -1) {
644 DebugInt3();
645 ret = OSSERR_INVALID_PARAMETER;
646 goto fail;
647 }
648 //set mic switch value (on/off)
649 pElem->value.integer.value[0] = ulValue;
650 break;
651
652 case OSS32_MIX_LEVEL_BASS:
653 idx = pHandle->controls[OSS_MIXER_BASS].idxVolume;
654 goto levelcontinue;
655 case OSS32_MIX_LEVEL_TREBLE:
656 idx = pHandle->controls[OSS_MIXER_TREBLE].idxVolume;
657 goto levelcontinue;
658 case OSS32_MIX_LEVEL_3DCENTER:
659 idx = pHandle->controls[OSS_MIXER_3DCENTER].idxVolume;
660 goto levelcontinue;
661 case OSS32_MIX_LEVEL_3DDEPTH:
662 idx = pHandle->controls[OSS_MIXER_3DDEPTH].idxVolume;
663levelcontinue:
664
665 if(idx == -1) {//supported?
666 DebugInt3();
667 ret = OSSERR_INVALID_PARAMETER;
668 goto fail;
669 }
670 //request information about mixer control
671 pElemInfo->id.numid = pHandle->pids[idx].numid;
672 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_CTL_IOCTL_ELEM_INFO, (ULONG)pElemInfo);
673 if(ret) {
674 ret = UNIXToOSSError(ret);
675 DebugInt3();
676 goto fail;
677 }
678 if(pElemInfo->type != SNDRV_CTL_ELEM_TYPE_INTEGER) {
679 ret = OSSERR_INVALID_PARAMETER;
680 DebugInt3();
681 goto fail;
682 }
683 lVol = ConvertVolume(GET_VOLUME_L(ulValue), pElemInfo->value.integer.max);
684 pElem->value.integer.value[0] = lVol;
685
686 if(pElemInfo->count > 1) { //stereo
687 rVol = ConvertVolume(GET_VOLUME_R(ulValue), pElemInfo->value.integer.max);
688 pElem->value.integer.value[1] = rVol;
689 }
690 break;
691
692 default:
693 DebugInt3();
694 ret = OSSERR_INVALID_PARAMETER;
695 goto fail;
696 }
697 pElem->id.numid = pHandle->pids[idx].numid;
698 pElem->indirect = 0;
699
700 dprintf(("OSS32_MixSetProperty of %s to %x", pHandle->pids[idx].name, ulValue));
701 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_CTL_IOCTL_ELEM_WRITE, (ULONG)pElem);
702
703 kfree(pElem);
704 pElem = NULL;
705 if(ret) {
706 DebugInt3();
707 return UNIXToOSSError(ret);
708 }
709 return OSSERR_SUCCESS;
710
711fail:
712 if(pElem) kfree(pElem);
713 return ret;
714}
715//******************************************************************************
716//******************************************************************************
717OSSRET OSS32_MixGetProperty(OSSSTREAMID streamid, ULONG line, ULONG *pValue)
718{
719 mixerhandle *pHandle = (mixerhandle *)streamid;
720 int ret;
721
722 if(pHandle == NULL || pHandle->magic != MAGIC_MIXER_ALSA32) {
723 DebugInt3();
724 return OSSERR_INVALID_STREAMID;
725 }
726 //set operation to non-blocking
727 pHandle->file.f_flags = O_NONBLOCK;
728
729 return OSSERR_NOT_SUPPORTED;
730}
731//******************************************************************************
732//******************************************************************************
733ULONG OSSToALSAVolume(ULONG OSSVolIdx)
734{
735 switch(OSSVolIdx) {
736 case OSS_MIXER_VOLUME:
737 return OSS32_MIX_VOLUME_MASTER_FRONT;
738#if 0
739 case OSS_MIXER_VOLUME: //TODO:
740 return OSS32_MIX_VOLUME_MASTER_REAR;
741#endif
742 case OSS_MIXER_PCM:
743 return OSS32_MIX_VOLUME_PCM;
744 case OSS_MIXER_SYNTH:
745 return OSS32_MIX_VOLUME_MIDI;
746 case OSS_MIXER_LINE:
747 return OSS32_MIX_VOLUME_LINEIN;
748 case OSS_MIXER_MIC:
749 return OSS32_MIX_VOLUME_MIC;
750 case OSS_MIXER_CD:
751 return OSS32_MIX_VOLUME_CD;
752 case OSS_MIXER_DIGITAL1:
753 return OSS32_MIX_VOLUME_SPDIF;
754 case OSS_MIXER_VIDEO:
755 return OSS32_MIX_VOLUME_VIDEO;
756 case OSS_MIXER_PCSPEAKER:
757 return OSS32_MIX_VOLUME_PCSPEAKER;
758 case OSS_MIXER_PHONEOUT:
759 return OSS32_MIX_VOLUME_PHONE;
760 case OSS_MIXER_IGAIN:
761 return OSS32_MIX_VOLUME_CAPTURE;
762 case OSS_MIXER_TREBLE:
763 return OSS32_MIX_LEVEL_TREBLE;
764 case OSS_MIXER_BASS:
765 return OSS32_MIX_LEVEL_BASS;
766 case OSS_MIXER_HEADPHONE:
767 return OSS32_MIX_VOLUME_HEADPHONE;
768 case OSS_MIXER_SPEAKER:
769 return OSS32_MIX_VOLUME_SPEAKER;
770 case OSS_MIXER_LINE1:
771 return OSS32_MIX_VOLUME_AUX;
772 }
773 return -1;
774}
775//******************************************************************************
776//******************************************************************************
777OSSRET OSS32_MixQueryCaps(OSSSTREAMID streamid, POSS32_MIXCAPS pCaps)
778{
779 mixerhandle *pHandle = (mixerhandle *)streamid;
780 int i;
781
782 if(pHandle == NULL || pHandle->magic != MAGIC_MIXER_ALSA32) {
783 DebugInt3();
784 return OSSERR_INVALID_STREAMID;
785 }
786
787 strncpy(pCaps->name, pHandle->info.mixername, sizeof(pCaps->name));
788 pCaps->fuCtrlCaps = 0;
789 pCaps->fuRecCaps = 0;
790
791 for(i=0;i<OSS_MIXER_NRDEVICES;i++)
792 {
793 if(pHandle->controls[i].idxVolume != -1) {
794 ULONG volidx = OSSToALSAVolume(i);
795 if(volidx != -1)
796 pCaps->fuCtrlCaps |= OSS32_MIX_FLAG(volidx);
797 }
798 }
799
800 //if it has a capture source control or the card has capture route switches,
801 //then we support intput source selection
802 if(pHandle->controls[OSS_MIXER_IGAIN].idxCustom != -1 ||
803 pHandle->rectype == RECTYPE_SWITCH)
804 {
805 pCaps->fuCtrlCaps |= OSS32_MIX_FLAG(OSS32_MIX_INPUTSRC);
806 pCaps->fuRecCaps = pHandle->reccaps;
807 }
808 return OSSERR_SUCCESS;
809}
810//******************************************************************************
811//******************************************************************************
812OSSRET OSS32_MixQueryName(ULONG deviceid, char *pszMixerName, ULONG cbMixerName)
813{
814 mixerhandle *pHandle = NULL;
815 int ret, i, j;
816
817 if(alsa_fops == NULL)
818 return OSSERR_NO_DEVICE_AVAILABLE;
819
820 pHandle = kmalloc(sizeof(mixerhandle), GFP_KERNEL);
821 if(pHandle == NULL) {
822 ret = OSSERR_OUT_OF_MEMORY;
823 goto failure;
824 }
825 memset(pHandle, 0, sizeof(mixerhandle));
826
827 //set operation to non-blocking
828 pHandle->file.f_flags = O_NONBLOCK;
829
830 //setup pointers in file structure (used internally by ALSA)
831 pHandle->file.f_dentry = &pHandle->d_entry;
832 pHandle->file.f_dentry->d_inode = &pHandle->inode;
833
834 pHandle->file.f_mode = FMODE_WRITE;
835 pHandle->inode.i_rdev = SNDRV_MINOR(deviceid, SNDRV_MINOR_CONTROL);
836
837 ret = alsa_fops->open(&pHandle->inode, &pHandle->file);
838 if(ret) {
839 goto failure;
840 }
841 //retrieve mixer information
842 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file,
843 SNDRV_CTL_IOCTL_CARD_INFO,
844 (ULONG)&pHandle->info);
845 if(ret) {
846 goto failure;
847 }
848
849 strncpy(pszMixerName, pHandle->info.mixername, cbMixerName);
850
851 pHandle->file.f_flags = O_NONBLOCK;
852 ret = pHandle->file.f_op->release(&pHandle->inode, &pHandle->file);
853 if(ret) {
854 goto failure;
855 }
856 kfree(pHandle);
857 return OSSERR_SUCCESS;
858
859failure:
860 if(pHandle) {
861 kfree(pHandle);
862 }
863 DebugInt3();
864 return OSSERR_OUT_OF_MEMORY;
865}
866//******************************************************************************
867//******************************************************************************
868OSSRET OSS32_QueryNames(ULONG deviceid, char *pszDeviceName, ULONG cbDeviceName,
869 char *pszMixerName, ULONG cbMixerName, BOOL fLongName)
870{
871 mixerhandle *pHandle = NULL;
872 int ret, i, j;
873
874 if(alsa_fops == NULL) {
875 ret = OSSERR_NO_DEVICE_AVAILABLE;
876 printk("ret = OSSERR_NO_DEVICE_AVAILABLE\n");
877 goto failure;
878 }
879
880 pHandle = kmalloc(sizeof(mixerhandle), GFP_KERNEL);
881 if(pHandle == NULL) {
882 ret = OSSERR_OUT_OF_MEMORY;
883 goto failure;
884 }
885 memset(pHandle, 0, sizeof(mixerhandle));
886
887 //set operation to non-blocking
888 pHandle->file.f_flags = O_NONBLOCK;
889
890 //setup pointers in file structure (used internally by ALSA)
891 pHandle->file.f_dentry = &pHandle->d_entry;
892 pHandle->file.f_dentry->d_inode = &pHandle->inode;
893
894 pHandle->file.f_mode = FMODE_WRITE;
895 pHandle->inode.i_rdev = SNDRV_MINOR(deviceid, SNDRV_MINOR_CONTROL);
896
897 ret = alsa_fops->open(&pHandle->inode, &pHandle->file);
898 if(ret) {
899 printk("open ret = %i\n", ret);
900 goto failure;
901 }
902 //retrieve mixer information
903 ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file,
904 SNDRV_CTL_IOCTL_CARD_INFO,
905 (ULONG)&pHandle->info);
906 if(ret) {
907 printk("ioctl ret = %i\n", ret);
908 goto failure;
909 }
910
911 if(pszDeviceName) {
912 if(fLongName == TRUE) {
913 strncpy(pszDeviceName, pHandle->info.longname, cbDeviceName);
914 }
915 else strncpy(pszDeviceName, pHandle->info.name, cbDeviceName);
916 }
917 if(pszMixerName) {
918 strncpy(pszMixerName, pHandle->info.mixername, cbMixerName);
919 }
920
921// printk("Card: %s with mixer %s\n",pszDeviceName, pszMixerName);
922
923 pHandle->file.f_flags = O_NONBLOCK;
924 ret = pHandle->file.f_op->release(&pHandle->inode, &pHandle->file);
925 if(ret) {
926 printk("release ret = %i\n", ret);
927 goto failure;
928 }
929 kfree(pHandle);
930 return OSSERR_SUCCESS;
931
932failure:
933 if(pHandle) {
934 kfree(pHandle);
935 }
936 DebugInt3();
937 printk("OSS32_QueryNames() ret = %i\n", ret);
938 return OSSERR_OUT_OF_MEMORY;
939}
940//******************************************************************************
941//******************************************************************************
942
Note: See TracBrowser for help on using the repository browser.