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

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

work on volume problem for capture

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