/* $Id: soundmixer.c,v 1.1.1.1 2003/07/02 13:57:02 eleph Exp $ */ /* * MMPM/2 to OSS interface translation layer * * (C) 2000-2002 InnoTek Systemberatung GmbH * (C) 2000-2001 Sander van Leeuwen (sandervl@xs4all.nl) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, * USA. * */ #include #include #include #include #include #include #include #include #define LINUX #include #include #include #include "soundoss.h" extern OpenedHandles opened_handles[8 * 256]; // from sound.c static struct { char *name; unsigned int index; unsigned int recsrc; } ossid[OSS_MIXER_NRDEVICES] = { /* OSS_MIXER_VOLUME */ { "Master", 0 , -1}, /* OSS_MIXER_BASS */ { "Tone Control - Bass", 0, -1}, /* OSS_MIXER_TREBLE */ { "Tone Control - Treble", 0, -1}, /* OSS_MIXER_SYNTH */ { "Synth", 0 , OSS32_MIX_RECSRC_SYNTH}, /* OSS_MIXER_PCM */ { "PCM", 0 , -1}, /* OSS_MIXER_SPEAKER */ { "PC Speaker", 0 , -1}, /* OSS_MIXER_LINE */ { "Line", 0 , OSS32_MIX_RECSRC_LINE}, /* OSS_MIXER_MIC */ { "Mic", 0, OSS32_MIX_RECSRC_MIC}, /* OSS_MIXER_CD */ { "CD", 0 , OSS32_MIX_RECSRC_CD}, /* OSS_MIXER_IMIX */ { "Monitor Mix", 0 , OSS32_MIX_RECSRC_MIXER}, /* OSS_MIXER_ALTPCM */ { "PCM", 1 , -1}, /* OSS_MIXER_RECLEV */ { "-- nothing --", 0 , -1}, /* OSS_MIXER_IGAIN */ { "Capture", 0 , -1}, /* OSS_MIXER_OGAIN */ { "Playback", 0 , -1}, /* OSS_MIXER_LINE1 */ { "Aux", 0 , OSS32_MIX_RECSRC_AUX}, /* OSS_MIXER_LINE2 */ { "Aux", 1 , -1}, /* OSS_MIXER_LINE3 */ { "Aux", 2 , -1}, /* OSS_MIXER_DIGITAL1 */ { "Digital", 0 , -1}, /* OSS_MIXER_DIGITAL2 */ { "Digital", 1 , -1}, /* OSS_MIXER_DIGITAL3 */ { "Digital", 2 , -1}, /* OSS_MIXER_PHONEIN */ { "Phone", 0 , OSS32_MIX_RECSRC_PHONE}, /* OSS_MIXER_PHONEOUT */ { "Phone", 1 , -1}, /* OSS_MIXER_VIDEO */ { "Video", 0 , OSS32_MIX_RECSRC_VIDEO}, /* OSS_MIXER_RADIO */ { "Radio", 0 , -1}, /* OSS_MIXER_MONITOR */ { "Monitor", 0 , -1}, /* OSS_MIXER_3DDEPTH */ { "3D Control - Depth", 0 , -1}, /* OSS_MIXER_3DCENTER */ { "3D Control - Center", 0 , -1}, }; char *szRecSources[OSS32_MIX_RECSRC_MAX] = { "Mic", "CD", "Line", "Video", "Aux", "Mix", "Mix Mono", "Phone", "Synth" }; static unsigned char LinToLog[OSS32_MAX_VOLUME+1] = { 0, 0, 0, 0, 1, 2, 2, 5, 5, 10, 10, 10, 16, 19, 20, 22, 24, 25, 27, 27, 28, 28, 29, 30, 30, 35, 35, 35, 39, 39, 43, 44, 45, 47, 48, 49, 50, 51, 52, 53, 55, 56, 57, 59, 60, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 74, 75, 76, 77, 78, 79, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 92, 93, 93, 94, 94, 95, 95, 96, 96, 97, 97, 98, 98, 99, 99, 99, 99, 100, 100, 100, 100, 100, 100 }; //****************************************************************************** //Convert linear volume to logarithmic //****************************************************************************** ULONG ConvertVolume(ULONG ulLinVolume, ULONG ulLogVolMax) { if(ulLinVolume > OSS32_MAX_VOLUME) { ulLinVolume = OSS32_MAX_VOLUME; } ulLinVolume = LinToLog[ulLinVolume]; return (ulLinVolume * ulLogVolMax) / OSS32_MAX_VOLUME; } //****************************************************************************** //****************************************************************************** OSSRET OSS32_MixOpen(ULONG deviceid, OSSSTREAMID *pStreamId) { mixerhandle *pHandle = NULL; int ret, i, j, sz; if(pStreamId == NULL) { DebugInt3(); return OSSERR_INVALID_PARAMETER; } *pStreamId = 0; if(alsa_fops == NULL) { ret = OSSERR_NO_DEVICE_AVAILABLE; goto failure; } sz = sizeof(mixerhandle); pHandle = kmalloc(sz, GFP_KERNEL); if(pHandle == NULL) { ret = OSSERR_OUT_OF_MEMORY; goto failure; } memset(pHandle, 0, sizeof(mixerhandle)); //set operation to non-blocking pHandle->file.f_flags = O_NONBLOCK; //setup pointers in file structure (used internally by ALSA) pHandle->file.f_dentry = &pHandle->d_entry; pHandle->file.f_dentry->d_inode = &pHandle->inode; pHandle->file.f_mode = FMODE_WRITE; pHandle->inode.i_rdev = SNDRV_MINOR(deviceid, SNDRV_MINOR_CONTROL); ret = alsa_fops->open(&pHandle->inode, &pHandle->file); if(ret) { goto failure; } //retrieve mixer information ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_CTL_IOCTL_CARD_INFO, (ULONG)&pHandle->info); if(ret) { goto failure; } //get the number of mixer elements pHandle->list.offset = 0; pHandle->list.space = 0; ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_CTL_IOCTL_ELEM_LIST, (ULONG)&pHandle->list); if(ret) { goto failure; } //allocate memory for all mixer elements pHandle->pids = (snd_ctl_elem_id_t *)kmalloc(sizeof(snd_ctl_elem_id_t)*pHandle->list.count, GFP_KERNEL); if(pHandle->pids == NULL) { goto failure; } //and retrieve all mixer elements pHandle->list.offset = 0; pHandle->list.space = pHandle->list.count; pHandle->list.pids = pHandle->pids; ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_CTL_IOCTL_ELEM_LIST, (ULONG)&pHandle->list); if(ret) { goto failure; } #if 0 dprintf(("Mixer name: %s", pHandle->info.mixername)); dprintf(("List of mixer elements:")); for(i=0;ilist.count;i++) { 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)); } #endif //Extract standard mixer controls from array with control names for(j=0;jcontrols[j].idxVolume = -1; pHandle->controls[j].idxMute = -1; pHandle->controls[j].idxCustom = -1; pHandle->controls[j].idxCaptureSwitch = -1; for(i=0;ilist.count;i++) { if (pHandle->pids[i].index == ossid[j].index && strncmp(pHandle->pids[i].name, ossid[j].name, namelen) == 0) { int controlnamelen = strlen(pHandle->pids[i].name); if(namelen == controlnamelen) {//control names are identical; found exact match pHandle->controls[j].idxVolume = i; break; } else {//first part of the control name is correct; now find out what //is it exactly char *nextword = &pHandle->pids[i].name[namelen]; while(*nextword && *nextword == ' ') nextword++; if(strncmp(nextword, MIXER_PLAYBACKVOLUME, sizeof(MIXER_PLAYBACKVOLUME)-1) == 0 || strncmp(nextword, MIXER_VOLUME, sizeof(MIXER_VOLUME)-1) == 0) {//volume control pHandle->controls[j].idxVolume = i; } else if(strncmp(nextword, MIXER_PLAYBACKSWITCH, sizeof(MIXER_PLAYBACKSWITCH)-1) == 0 || strncmp(nextword, MIXER_SWITCH, sizeof(MIXER_SWITCH)-1) == 0) {//mute control pHandle->controls[j].idxMute = i; } else if(strncmp(nextword, MIXER_SOURCE, sizeof(MIXER_SOURCE)-1) == 0) {//source control (e.g. recording source) pHandle->controls[j].idxCustom = i; } else if(strncmp(nextword, MIXER_CAPTUREROUTE, sizeof(MIXER_CAPTUREROUTE)-1) == 0 || strncmp(nextword, MIXER_CAPTURESWITCH, sizeof(MIXER_CAPTURESWITCH)-1) == 0) {//source control for recording (per input) pHandle->controls[j].idxCaptureSwitch = i; } else if(i == OSS_MIXER_MIC) { if(strncmp(nextword, MIXER_BOOST, sizeof(MIXER_BOOST)-1) == 0) {//mic boost switch pHandle->controls[j].idxCustom = i; } } } } } } pHandle->reccaps = 0; for(j=0;jidxRecCaps[j] = -1; } //request information about available capture sources if(pHandle->controls[OSS_MIXER_IGAIN].idxCustom != -1) { snd_ctl_elem_info_t *pElemInfo = NULL; int idx, j; idx = pHandle->controls[OSS_MIXER_IGAIN].idxCustom; //set operation to non-blocking pHandle->file.f_flags = O_NONBLOCK; pHandle->rectype = RECTYPE_SELECTOR; //too big to put on the stack pElemInfo = (snd_ctl_elem_info_t *)kmalloc(sizeof(snd_ctl_elem_info_t), GFP_KERNEL); if(pElemInfo == NULL) { DebugInt3(); goto failure; } pElemInfo->value.enumerated.items = 1; for(i=0;ivalue.enumerated.items;i++) { pElemInfo->value.enumerated.item = i; pElemInfo->id.numid = pHandle->pids[idx].numid; ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_CTL_IOCTL_ELEM_INFO, (ULONG)pElemInfo); if(ret) { DebugInt3(); break; } if(pElemInfo->type != SNDRV_CTL_ELEM_TYPE_ENUMERATED) { DebugInt3(); break; } for(j=0;jvalue.enumerated.name, szRecSources[j])) { pHandle->reccaps |= OSS32_MIX_FLAG(j); pHandle->idxRecCaps[j] = i; //save alsa index break; } } } kfree(pElemInfo); } else {//This card has no record source selection, but probably route switches for //each input source (SB mixers (also ALS4000), CMedia) pHandle->rectype = RECTYPE_SWITCH; for(j=0;jidxRecCaps[j] = -1; } for(j=0;jcontrols[j].idxCaptureSwitch != -1) { pHandle->reccaps |= OSS32_MIX_FLAG(ossid[j].recsrc); pHandle->idxRecCaps[ossid[j].recsrc] = pHandle->controls[j].idxCaptureSwitch; //save alsa index } } } pHandle->magic = MAGIC_MIXER_ALSA32; *pStreamId = (ULONG)pHandle; return OSSERR_SUCCESS; failure: if(pHandle) { if(pHandle->pids) kfree(pHandle->pids); kfree(pHandle); } DebugInt3(); return OSSERR_OUT_OF_MEMORY; } //****************************************************************************** //****************************************************************************** OSSRET OSS32_MixClose(OSSSTREAMID streamid) { mixerhandle *pHandle = (mixerhandle *)streamid; int ret; if(pHandle == NULL || pHandle->magic != MAGIC_MIXER_ALSA32) { DebugInt3(); return OSSERR_INVALID_STREAMID; } //set operation to non-blocking pHandle->file.f_flags = O_NONBLOCK; ret = pHandle->file.f_op->release(&pHandle->inode, &pHandle->file); kfree(pHandle->pids); //free mixer element array kfree(pHandle); //free handle data if(ret) { DebugInt3(); return UNIXToOSSError(ret); } return OSSERR_SUCCESS; } //****************************************************************************** //****************************************************************************** OSSRET OSS32_MixGetVolume(OSSSTREAMID streamid, ULONG line, ULONG *pVolume) { mixerhandle *pHandle = (mixerhandle *)streamid; int ret; if(pHandle == NULL || pHandle->magic != MAGIC_MIXER_ALSA32) { DebugInt3(); return OSSERR_INVALID_STREAMID; } //set operation to non-blocking pHandle->file.f_flags = O_NONBLOCK; return OSSERR_NOT_SUPPORTED; } //****************************************************************************** //****************************************************************************** OSSRET OSS32_MixSetVolume(OSSSTREAMID streamid, ULONG line, ULONG volume) { mixerhandle *pHandle = (mixerhandle *)streamid; snd_ctl_elem_value_t *pElem = NULL; snd_ctl_elem_info_t *pElemInfo; int ret, idx, lVol, rVol = 0, idxMute, cnt; if(pHandle == NULL || pHandle->magic != MAGIC_MIXER_ALSA32) { printk("Invalid handle in OSS32_MixSetVolume\n"); DebugInt3(); return OSSERR_INVALID_STREAMID; } //set operation to non-blocking pHandle->file.f_flags = O_NONBLOCK; //too big to put on the stack pElem = (snd_ctl_elem_value_t *)kmalloc(sizeof(snd_ctl_elem_value_t) + sizeof(snd_ctl_elem_info_t), GFP_KERNEL); if(pElem == NULL) { printk("Out of memory in OSS32_MixSetVolume\n"); DebugInt3(); return OSSERR_OUT_OF_MEMORY; } pElemInfo = (snd_ctl_elem_info_t *)(pElem+1); switch(line) { case OSS32_MIX_VOLUME_MASTER_FRONT: idx = pHandle->controls[OSS_MIXER_VOLUME].idxVolume; idxMute = pHandle->controls[OSS_MIXER_VOLUME].idxMute; break; case OSS32_MIX_VOLUME_MASTER_REAR: //TODO: idx = pHandle->controls[OSS_MIXER_VOLUME].idxVolume; idxMute = pHandle->controls[OSS_MIXER_VOLUME].idxMute; break; case OSS32_MIX_VOLUME_PCM: idx = pHandle->controls[OSS_MIXER_PCM].idxVolume; idxMute = pHandle->controls[OSS_MIXER_PCM].idxMute; break; case OSS32_MIX_VOLUME_MIDI: idx = pHandle->controls[OSS_MIXER_SYNTH].idxVolume; idxMute = pHandle->controls[OSS_MIXER_SYNTH].idxMute; break; case OSS32_MIX_VOLUME_LINEIN: idx = pHandle->controls[OSS_MIXER_LINE].idxVolume; idxMute = pHandle->controls[OSS_MIXER_LINE].idxMute; break; case OSS32_MIX_VOLUME_MIC: idx = pHandle->controls[OSS_MIXER_MIC].idxVolume; idxMute = pHandle->controls[OSS_MIXER_MIC].idxMute; break; case OSS32_MIX_VOLUME_CD: idx = pHandle->controls[OSS_MIXER_CD].idxVolume; idxMute = pHandle->controls[OSS_MIXER_CD].idxMute; break; case OSS32_MIX_VOLUME_SPDIF: idx = pHandle->controls[OSS_MIXER_DIGITAL1].idxVolume; idxMute = pHandle->controls[OSS_MIXER_DIGITAL1].idxMute; break; case OSS32_MIX_VOLUME_VIDEO: idx = pHandle->controls[OSS_MIXER_VIDEO].idxVolume; idxMute = pHandle->controls[OSS_MIXER_VIDEO].idxMute; break; case OSS32_MIX_VOLUME_SPEAKER: idx = pHandle->controls[OSS_MIXER_SPEAKER].idxVolume; idxMute = pHandle->controls[OSS_MIXER_SPEAKER].idxMute; break; case OSS32_MIX_VOLUME_PHONE: idx = pHandle->controls[OSS_MIXER_PHONEOUT].idxVolume; idxMute = pHandle->controls[OSS_MIXER_PHONEOUT].idxMute; break; case OSS32_MIX_VOLUME_HEADPHONE: //TODO: idx = pHandle->controls[OSS_MIXER_PHONEOUT].idxVolume; idxMute = pHandle->controls[OSS_MIXER_PHONEOUT].idxMute; break; case OSS32_MIX_VOLUME_AUX: idx = pHandle->controls[OSS_MIXER_LINE1].idxVolume; idxMute = pHandle->controls[OSS_MIXER_LINE1].idxMute; break; case OSS32_MIX_VOLUME_CAPTURE: idx = pHandle->controls[OSS_MIXER_IGAIN].idxVolume; idxMute = pHandle->controls[OSS_MIXER_IGAIN].idxMute; break; default: DebugInt3(); ret = OSSERR_INVALID_PARAMETER; goto fail; } if(idx == -1) { dprintf(("Unknown control %d", line)); ret = OSSERR_INVALID_PARAMETER; goto fail; } if(idxMute != -1 && volume != 0) { //disable mute pElem->id.numid = pHandle->pids[idxMute].numid; pElem->indirect = 0; pElem->value.integer.value[0] = TRUE; //switch, not mute control (inversed) pElem->value.integer.value[1] = TRUE; ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_CTL_IOCTL_ELEM_WRITE, (ULONG)pElem); } //request information about mixer control pElemInfo->id.numid = pHandle->pids[idx].numid; ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_CTL_IOCTL_ELEM_INFO, (ULONG)pElemInfo); if(ret) { ret = UNIXToOSSError(ret); DebugInt3(); goto fail; } if(pElemInfo->type != SNDRV_CTL_ELEM_TYPE_INTEGER) { ret = OSSERR_INVALID_PARAMETER; DebugInt3(); goto fail; } pElem->id.numid = pHandle->pids[idx].numid; pElem->indirect = 0; lVol = ConvertVolume(GET_VOLUME_L(volume), pElemInfo->value.integer.max); pElem->value.integer.value[0] = lVol; if(pElemInfo->count > 1) { //stereo rVol = ConvertVolume(GET_VOLUME_R(volume), pElemInfo->value.integer.max); pElem->value.integer.value[1] = rVol; } printk("OSS32_MixSetVolume of %s streamid %X to (%d,%d)(%d,%d) caps %d\n", pHandle->pids[idx].name, (ULONG)pHandle, GET_VOLUME_L(volume), GET_VOLUME_R(volume), lVol, rVol, pElemInfo->value.integer.max); // looking for more, then one opened streams to prevent of muting active stream cnt = 0; for (idx=0; idx < 8*256; idx++) if (opened_handles[idx].handle != 0) cnt++; // if (((cnt == 1 && (lVol==0 && rVol==0)) || (lVol>0 && rVol>0)) || if (cnt == 1 || line != OSS32_MIX_VOLUME_PCM) { ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_CTL_IOCTL_ELEM_WRITE, (ULONG)pElem); if(idxMute != -1 && volume == 0) { //enable mute pElem->id.numid = pHandle->pids[idxMute].numid; pElem->indirect = 0; pElem->value.integer.value[0] = FALSE; //switch, not mute control (inversed) pElem->value.integer.value[1] = FALSE; ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_CTL_IOCTL_ELEM_WRITE, (ULONG)pElem); } } kfree(pElem); pElem = NULL; if(ret) { printk("ret = %i\n", ret); DebugInt3(); return UNIXToOSSError(ret); } return OSSERR_SUCCESS; fail: printk("OSS32_MixSetVolume failed: %i\n", ret); if(pElem) kfree(pElem); return ret; } //****************************************************************************** //****************************************************************************** OSSRET OSS32_MixSetProperty(OSSSTREAMID streamid, ULONG ulLine, ULONG ulValue) { mixerhandle *pHandle = (mixerhandle *)streamid; snd_ctl_elem_value_t *pElem = NULL; snd_ctl_elem_info_t *pElemInfo; int ret, idx = -1, lVol, rVol = 0, j, i; if(pHandle == NULL || pHandle->magic != MAGIC_MIXER_ALSA32) { DebugInt3(); return OSSERR_INVALID_STREAMID; } //set operation to non-blocking pHandle->file.f_flags = O_NONBLOCK; //too big to put on the stack pElem = (snd_ctl_elem_value_t *)kmalloc(sizeof(snd_ctl_elem_value_t) + sizeof(snd_ctl_elem_info_t), GFP_KERNEL); if(pElem == NULL) { DebugInt3(); return OSSERR_OUT_OF_MEMORY; } pElemInfo = (snd_ctl_elem_info_t *)(pElem+1); switch(ulLine) { case OSS32_MIX_INPUTSRC: idx = pHandle->controls[OSS_MIXER_IGAIN].idxCustom; //is this capture source supported by the hardware?? if(!(pHandle->reccaps & OSS32_MIX_FLAG(ulValue))) { DebugInt3(); ret = OSSERR_INVALID_PARAMETER; goto fail; } if(pHandle->rectype == RECTYPE_SELECTOR) {//input source selector //set left and right capture source pElem->value.enumerated.item[0] = pHandle->idxRecCaps[ulValue]; pElem->value.enumerated.item[1] = pHandle->idxRecCaps[ulValue]; } else {//capture switch for each input source //first turn off all capture switches... for(j=0;jidxRecCaps[j] != -1) { idx = pHandle->idxRecCaps[j]; //request information about mixer control pElemInfo->id.numid = pHandle->pids[idx].numid; ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_CTL_IOCTL_ELEM_INFO, (ULONG)pElemInfo); if(ret) { ret = UNIXToOSSError(ret); DebugInt3(); goto fail; } if(pElemInfo->type != SNDRV_CTL_ELEM_TYPE_BOOLEAN) { ret = OSSERR_INVALID_PARAMETER; DebugInt3(); goto fail; } pElem->id.numid = pHandle->pids[idx].numid; pElem->indirect = 0; for(i=0;icount;i++) { pElem->value.integer.value[i] = 0; } ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_CTL_IOCTL_ELEM_WRITE, (ULONG)pElem); if(ret) { ret = UNIXToOSSError(ret); DebugInt3(); goto fail; } } } //request information about mixer control pElemInfo->id.numid = pHandle->pids[idx].numid; ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_CTL_IOCTL_ELEM_INFO, (ULONG)pElemInfo); if(ret) { ret = UNIXToOSSError(ret); DebugInt3(); goto fail; } //and enable the capture switch for the selected input source idx = pHandle->idxRecCaps[ulValue]; for(i=0;icount;i++) { pElem->value.integer.value[i] = 1; } } break; case OSS32_MIX_SWITCH_MICBOOST: idx = pHandle->controls[OSS_MIXER_MIC].idxCustom; if(idx == -1) { DebugInt3(); ret = OSSERR_INVALID_PARAMETER; goto fail; } //set mic switch value (on/off) pElem->value.integer.value[0] = ulValue; break; case OSS32_MIX_LEVEL_BASS: idx = pHandle->controls[OSS_MIXER_BASS].idxVolume; goto levelcontinue; case OSS32_MIX_LEVEL_TREBLE: idx = pHandle->controls[OSS_MIXER_TREBLE].idxVolume; goto levelcontinue; case OSS32_MIX_LEVEL_3DCENTER: idx = pHandle->controls[OSS_MIXER_3DCENTER].idxVolume; goto levelcontinue; case OSS32_MIX_LEVEL_3DDEPTH: idx = pHandle->controls[OSS_MIXER_3DDEPTH].idxVolume; levelcontinue: if(idx == -1) {//supported? DebugInt3(); ret = OSSERR_INVALID_PARAMETER; goto fail; } //request information about mixer control pElemInfo->id.numid = pHandle->pids[idx].numid; ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_CTL_IOCTL_ELEM_INFO, (ULONG)pElemInfo); if(ret) { ret = UNIXToOSSError(ret); DebugInt3(); goto fail; } if(pElemInfo->type != SNDRV_CTL_ELEM_TYPE_INTEGER) { ret = OSSERR_INVALID_PARAMETER; DebugInt3(); goto fail; } lVol = ConvertVolume(GET_VOLUME_L(ulValue), pElemInfo->value.integer.max); pElem->value.integer.value[0] = lVol; if(pElemInfo->count > 1) { //stereo rVol = ConvertVolume(GET_VOLUME_R(ulValue), pElemInfo->value.integer.max); pElem->value.integer.value[1] = rVol; } break; default: DebugInt3(); ret = OSSERR_INVALID_PARAMETER; goto fail; } pElem->id.numid = pHandle->pids[idx].numid; pElem->indirect = 0; dprintf(("OSS32_MixSetProperty of %s to %x", pHandle->pids[idx].name, ulValue)); ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_CTL_IOCTL_ELEM_WRITE, (ULONG)pElem); kfree(pElem); pElem = NULL; if(ret) { DebugInt3(); return UNIXToOSSError(ret); } return OSSERR_SUCCESS; fail: if(pElem) kfree(pElem); return ret; } //****************************************************************************** //****************************************************************************** OSSRET OSS32_MixGetProperty(OSSSTREAMID streamid, ULONG line, ULONG *pValue) { mixerhandle *pHandle = (mixerhandle *)streamid; int ret; if(pHandle == NULL || pHandle->magic != MAGIC_MIXER_ALSA32) { DebugInt3(); return OSSERR_INVALID_STREAMID; } //set operation to non-blocking pHandle->file.f_flags = O_NONBLOCK; return OSSERR_NOT_SUPPORTED; } //****************************************************************************** //****************************************************************************** ULONG OSSToALSAVolume(ULONG OSSVolIdx) { switch(OSSVolIdx) { case OSS_MIXER_VOLUME: return OSS32_MIX_VOLUME_MASTER_FRONT; #if 0 case OSS_MIXER_VOLUME: //TODO: return OSS32_MIX_VOLUME_MASTER_REAR; #endif case OSS_MIXER_PCM: return OSS32_MIX_VOLUME_PCM; case OSS_MIXER_SYNTH: return OSS32_MIX_VOLUME_MIDI; case OSS_MIXER_LINE: return OSS32_MIX_VOLUME_LINEIN; case OSS_MIXER_MIC: return OSS32_MIX_VOLUME_MIC; case OSS_MIXER_CD: return OSS32_MIX_VOLUME_CD; case OSS_MIXER_DIGITAL1: return OSS32_MIX_VOLUME_SPDIF; case OSS_MIXER_VIDEO: return OSS32_MIX_VOLUME_VIDEO; case OSS_MIXER_SPEAKER: return OSS32_MIX_VOLUME_SPEAKER; case OSS_MIXER_PHONEOUT: return OSS32_MIX_VOLUME_PHONE; case OSS_MIXER_IGAIN: return OSS32_MIX_VOLUME_CAPTURE; case OSS_MIXER_TREBLE: return OSS32_MIX_LEVEL_TREBLE; case OSS_MIXER_BASS: return OSS32_MIX_LEVEL_BASS; #if 0 case OSS_MIXER_PHONEOUT: //TODO: return OSS32_MIX_VOLUME_HEADPHONE; #endif case OSS_MIXER_LINE1: return OSS32_MIX_VOLUME_AUX; } return -1; } //****************************************************************************** //****************************************************************************** OSSRET OSS32_MixQueryCaps(OSSSTREAMID streamid, POSS32_MIXCAPS pCaps) { mixerhandle *pHandle = (mixerhandle *)streamid; int i; if(pHandle == NULL || pHandle->magic != MAGIC_MIXER_ALSA32) { DebugInt3(); return OSSERR_INVALID_STREAMID; } strncpy(pCaps->name, pHandle->info.mixername, sizeof(pCaps->name)); pCaps->fuCtrlCaps = 0; pCaps->fuRecCaps = 0; for(i=0;icontrols[i].idxVolume != -1) { ULONG volidx = OSSToALSAVolume(i); if(volidx != -1) pCaps->fuCtrlCaps |= OSS32_MIX_FLAG(volidx); } } //if it has a capture source control or the card has capture route switches, //then we support intput source selection if(pHandle->controls[OSS_MIXER_IGAIN].idxCustom != -1 || pHandle->rectype == RECTYPE_SWITCH) { pCaps->fuCtrlCaps |= OSS32_MIX_FLAG(OSS32_MIX_INPUTSRC); pCaps->fuRecCaps = pHandle->reccaps; } return OSSERR_SUCCESS; } //****************************************************************************** //****************************************************************************** OSSRET OSS32_MixQueryName(ULONG deviceid, char *pszMixerName, ULONG cbMixerName) { mixerhandle *pHandle = NULL; int ret, i, j; if(alsa_fops == NULL) return OSSERR_NO_DEVICE_AVAILABLE; pHandle = kmalloc(sizeof(mixerhandle), GFP_KERNEL); if(pHandle == NULL) { ret = OSSERR_OUT_OF_MEMORY; goto failure; } memset(pHandle, 0, sizeof(mixerhandle)); //set operation to non-blocking pHandle->file.f_flags = O_NONBLOCK; //setup pointers in file structure (used internally by ALSA) pHandle->file.f_dentry = &pHandle->d_entry; pHandle->file.f_dentry->d_inode = &pHandle->inode; pHandle->file.f_mode = FMODE_WRITE; pHandle->inode.i_rdev = SNDRV_MINOR(deviceid, SNDRV_MINOR_CONTROL); ret = alsa_fops->open(&pHandle->inode, &pHandle->file); if(ret) { goto failure; } //retrieve mixer information ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_CTL_IOCTL_CARD_INFO, (ULONG)&pHandle->info); if(ret) { goto failure; } strncpy(pszMixerName, pHandle->info.mixername, cbMixerName); pHandle->file.f_flags = O_NONBLOCK; ret = pHandle->file.f_op->release(&pHandle->inode, &pHandle->file); if(ret) { goto failure; } kfree(pHandle); return OSSERR_SUCCESS; failure: if(pHandle) { kfree(pHandle); } DebugInt3(); return OSSERR_OUT_OF_MEMORY; } //****************************************************************************** //****************************************************************************** OSSRET OSS32_QueryNames(ULONG deviceid, char *pszDeviceName, ULONG cbDeviceName, char *pszMixerName, ULONG cbMixerName, BOOL fLongName) { mixerhandle *pHandle = NULL; int ret, i, j; if(alsa_fops == NULL) { ret = OSSERR_NO_DEVICE_AVAILABLE; goto failure; } pHandle = kmalloc(sizeof(mixerhandle), GFP_KERNEL); if(pHandle == NULL) { ret = OSSERR_OUT_OF_MEMORY; goto failure; } memset(pHandle, 0, sizeof(mixerhandle)); //set operation to non-blocking pHandle->file.f_flags = O_NONBLOCK; //setup pointers in file structure (used internally by ALSA) pHandle->file.f_dentry = &pHandle->d_entry; pHandle->file.f_dentry->d_inode = &pHandle->inode; pHandle->file.f_mode = FMODE_WRITE; pHandle->inode.i_rdev = SNDRV_MINOR(deviceid, SNDRV_MINOR_CONTROL); ret = alsa_fops->open(&pHandle->inode, &pHandle->file); if(ret) { printk("open ret = %i\n", ret); goto failure; } //retrieve mixer information ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_CTL_IOCTL_CARD_INFO, (ULONG)&pHandle->info); if(ret) { printk("ioctl ret = %i\n", ret); goto failure; } if(pszDeviceName) { if(fLongName == TRUE) { strncpy(pszDeviceName, pHandle->info.longname, cbDeviceName); } else strncpy(pszDeviceName, pHandle->info.name, cbDeviceName); } if(pszMixerName) { strncpy(pszMixerName, pHandle->info.mixername, cbMixerName); } // printk("Card: %s with mixer %s\n",pszDeviceName, pszMixerName); pHandle->file.f_flags = O_NONBLOCK; ret = pHandle->file.f_op->release(&pHandle->inode, &pHandle->file); if(ret) { printk("release ret = %i\n", ret); goto failure; } kfree(pHandle); return OSSERR_SUCCESS; failure: if(pHandle) { kfree(pHandle); } DebugInt3(); printk("OSS32_QueryNames() ret = %i\n", ret); return OSSERR_OUT_OF_MEMORY; } //****************************************************************************** //******************************************************************************