source: GPL/lib32/soundmixer.c@ 18

Last change on this file since 18 was 18, checked in by vladest, 20 years ago

initial import

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