/* $Id: dispatch.c,v 1.1.1.1 2003/07/02 13:56:56 eleph Exp $ */ /* * Strategy handlers for IOCtl and close * * (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. * */ #define INCL_NOPMAPI #define INCL_DOSMISC #include #include #include #include #include "devown.h" #include #include #include extern "C" int cdecl printk(const char * fmt, ...); //****************************************************************************** // Dispatch IOCtl requests received from the Strategy routine //****************************************************************************** extern "C" int GetUniaudCardInfo(ULONG deviceid, void *info); extern "C" int GetUniaudControlNum(ULONG deviceid); extern "C" int GetUniaudControls(ULONG deviceid, void *pids); extern "C" int GetUniaudControlInfo(ULONG deviceid, ULONG id, void *info); extern "C" int GetUniaudControlValueGet(ULONG deviceid, ULONG id, void *value); extern "C" int GetUniaudControlValuePut(ULONG deviceid, ULONG id, void *value); extern "C" int GetNumberOfPcm(int card_id); extern "C" int GetUniaudPcmCaps(ULONG deviceid, void *caps); extern "C" int SetPCMInstance(int card_id, int pcm); extern "C" int WaitForControlChange(int card_id, int timeout); extern "C" int GetNumberOfCards(void); extern "C" OSSRET OSS32_WaveOpen(ULONG deviceid, ULONG streamtype, OSSSTREAMID *pStreamId, int pcm, USHORT fileid); extern "C" OSSRET OSS32_WaveClose(OSSSTREAMID streamid); extern "C" int UniaudIoctlHWRefine(OSSSTREAMID streamid, void *pHwParams); extern "C" int UniaudIoctlHWParamSet(OSSSTREAMID streamid, void *pHwParams); extern "C" int UniaudIoctlSWParamSet(OSSSTREAMID streamid, void *pSwParams); extern "C" int UniaudIoctlPCMStatus(OSSSTREAMID streamid, void *pstatus); extern "C" int UniaudIoctlPCMWrite(OSSSTREAMID streamid, char *buf, int size); extern "C" int UniaudIoctlPCMRead(OSSSTREAMID streamid, char *buf, int size); extern "C" int UniaudIoctlPCMPrepare(OSSSTREAMID streamid); extern "C" int UniaudIoctlPCMStart(OSSSTREAMID streamid); extern "C" int UniaudIoctlPCMDrop(OSSSTREAMID streamid); extern "C" int UniaudIoctlPCMResume(OSSSTREAMID streamid, int pause); extern "C" void UniaudCloseAll(USHORT fileid); extern "C" int WaitForPCMInterrupt(void *file, int timeout); extern "C" int unlock_all; extern "C" int OSS32_CloseUNI16(void); extern "C" int UniaudCtlGetPowerState(ULONG deviceid, void *state); extern "C" int UniaudCtlSetPowerState(ULONG deviceid, void *state); typedef UCHAR LOCKHANDLE[12]; /* * structure passed to pcm open ioctl */ #pragma pack(1) typedef struct ioctl_pcm { ULONG deviceid; // card number ULONG streamtype; // type of stream (play or record) ULONG pcm; // pcm instance int size; // data size ULONG ret; // return code } ioctl_pcm; #pragma pack() ULONG StratIOCtl(RP __far* _rp) { RPIOCtl __far* rp = (RPIOCtl __far*)_rp; USHORT rc = 0;; LOCKHANDLE lhParm, lhData; LINEAR linParm, linData; ULONG pages; ULONG *pData; ULONG card_id; ULONG ctl_id; if (rp->Category != CAT_IOCTL_OSS32) { // printk("not our cat %x. func %x\n", rp->Category, rp->Function); // not our category, exit with error return (RPERR_COMMAND | RPDONE); } // printk("cmd: %x, len: %i, pack: %x\n",rp->Function, rp->ParmLength, rp->ParmPacket); // work with Parm Packet if ((rp->ParmLength != 0 || rp->Function == IOCTL_OSS32_ATTACH /*16 bit ioctl*/) && ((rp->ParmPacket & 0xfffcffff) != 0)) { // got Parm Packet rc = DevVirtToLin((USHORT)((ULONG)(rp->ParmPacket) >> 16), (ULONG)((USHORT)(rp->ParmPacket)), (UCHAR * __far *)&linParm); if (rc == 0) { if (rp->Function == IOCTL_OSS32_ATTACH) { rc = DevVMLock(VMDHL_LONG, (ULONG)linParm, 4, (LINEAR)-1L, lhParm, (UCHAR*)&pages); }else { rc = DevVMLock(VMDHL_LONG, (ULONG)linParm, rp->ParmLength, (LINEAR)-1L, lhParm, (UCHAR*)&pages); } if (rc != 0) { printk("error in DevVMLock rc = %i\n",rc); return (RPERR_PARAMETER | RPDONE); } } else { printk("error in VirtToLin rc = %i\n",rc); return (RPERR_PARAMETER | RPDONE); } } else { // no Parm Packet linParm = NULL; } // work with Data Packet if ((rp->DataLength != 0) && ((rp->DataPacket & 0xfffcffff) != 0)) { // got Data Packet rc = DevVirtToLin((USHORT)((ULONG)(rp->DataPacket) >> 16), (ULONG)((USHORT)(rp->DataPacket)), (UCHAR * __far *)&linData); if (rc == 0) { rc = DevVMLock(VMDHL_LONG, (ULONG)linData, rp->DataLength, (LINEAR)-1L, lhData, (UCHAR*)&pages); } else printk("error in VirtToLin rc = %i\n",rc); if (rc != 0) { printk("error in DevVMLock rc = %i\n",rc); // error in VirtToLin or DevVMLock if (linParm != NULL) { // linParm present & locked, must to unlock it DevVMUnLock(lhParm); } return (RPERR_PARAMETER | RPDONE); } } else { // no Data Packet linData = NULL; } // functions handling rc = RPDONE; // ok by default switch(rp->Function) { case IOCTL_OSS32_ATTACH: { card_id = (ULONG) *linParm; // Check if audio init was successful if (OSS32_QueryNames(card_id, NULL, 0, NULL, 0, FALSE) != OSSERR_SUCCESS) { rc = RPERR_GENERAL | RPDONE; } } break; case IOCTL_OSS32_VERSION: { if (rp->DataLength < sizeof(ULONG)) { // invalid Data Pkt rc = RPERR_PARAMETER | RPDONE; break; } pData = (ULONG *) linData; (*pData) = UNIAUD_VERSION; } break; case IOCTL_OSS32_GET_PCM_NUM: { if (rp->DataLength < sizeof(ULONG)) { // invalid Data Pkt rc = RPERR_PARAMETER | RPDONE; break; } card_id = (ULONG) *linParm; pData = (ULONG *) linData; (*pData) = GetNumberOfPcm(card_id); } break; case IOCTL_OSS32_CARDS_NUM: if (rp->DataLength < sizeof(ULONG)) { // invalid Data Pkt rc = RPERR_PARAMETER | RPDONE; break; } pData = (ULONG *) linData; (*pData) = GetNumberOfCards(); break; case IOCTL_OSS32_PCM_CAPS: { if (rp->DataLength < sizeof(ULONG)) { // invalid Data Pkt rc = RPERR_PARAMETER | RPDONE; break; } card_id = (ULONG) *linParm; pData = (ULONG *) linData; GetUniaudPcmCaps(card_id,(void*)*pData); } break; case IOCTL_OSS32_CARD_INFO: { if (rp->DataLength < sizeof(ULONG)) { // invalid Data Pkt rc = RPERR_PARAMETER | RPDONE; break; } pData = (ULONG *) linData; card_id = (ULONG) *linParm; GetUniaudCardInfo(card_id,(void*)*pData); } break; case IOCTL_OSS32_GET_POWER_STATE: { if (rp->DataLength < sizeof(ULONG)) { // invalid Data Pkt rc = RPERR_PARAMETER | RPDONE; break; } pData = (ULONG *) linData; card_id = (ULONG) *linParm; UniaudCtlGetPowerState(card_id,(void*)*pData); } break; case IOCTL_OSS32_SET_POWER_STATE: { if (rp->DataLength < sizeof(ULONG)) { // invalid Data Pkt rc = RPERR_PARAMETER | RPDONE; break; } pData = (ULONG *) linData; card_id = (ULONG) *linParm; UniaudCtlSetPowerState(card_id,(void*)*pData); } break; case IOCTL_OSS32_GET_CNTRLS_NUM: { if (rp->DataLength < sizeof(ULONG)) { // invalid Data Pkt rc = RPERR_PARAMETER | RPDONE; break; } pData = (ULONG *) linData; card_id = (ULONG) *linParm; (*pData) = GetUniaudControlNum(card_id); } break; case IOCTL_OSS32_GET_CNTRLS: { if (rp->DataLength < sizeof(ULONG)) { // invalid Data Pkt rc = RPERR_PARAMETER | RPDONE; break; } pData = (ULONG *) linData; card_id = (ULONG) *linParm; GetUniaudControls(card_id,(void*)*pData); } break; case IOCTL_OSS32_CNTRL_INFO: { if (rp->DataLength < sizeof(ULONG)) { // invalid Data Pkt rc = RPERR_PARAMETER | RPDONE; break; } if (rp->ParmLength < sizeof(ULONG)) { // invalid Data Pkt rc = RPERR_PARAMETER | RPDONE; break; } pData = (ULONG *) linData; ULONG id = *((ULONG *)linParm); card_id = (id >> 16) & 0x0000FFFF; ctl_id = id & 0x0000FFFF; // printk("id: %x, card: %x, ctl: %x\n",id, card_id, ctl_id); GetUniaudControlInfo(card_id, ctl_id, (void*)*pData); } break; case IOCTL_OSS32_CNTRL_GET: { if (rp->DataLength < sizeof(ULONG)) { // invalid Data Pkt rc = RPERR_PARAMETER | RPDONE; break; } if (rp->ParmLength < sizeof(ULONG)) { // invalid Data Pkt rc = RPERR_PARAMETER | RPDONE; break; } pData = (ULONG *) linData; ULONG id = *((ULONG *)linParm); card_id = (id >> 16) & 0x0000FFFF; ctl_id = id & 0x0000FFFF; GetUniaudControlValueGet(card_id, ctl_id,(void*)*pData); } break; case IOCTL_OSS32_CNTRL_PUT: { if (rp->DataLength < sizeof(ULONG)) { // invalid Data Pkt rc = RPERR_PARAMETER | RPDONE; break; } if (rp->ParmLength < sizeof(ULONG)) { // invalid Data Pkt rc = RPERR_PARAMETER | RPDONE; break; } pData = (ULONG *) linData; ULONG id = *((ULONG *)linParm); card_id = (id >> 16) & 0x0000FFFF; ctl_id = id & 0x0000FFFF; // printk("put ID %i\n",id); GetUniaudControlValuePut(card_id, ctl_id,(void*)*pData); } break; case IOCTL_OSS32_SET_PCM: { if (rp->ParmLength < sizeof(ULONG)) { // invalid Data Pkt rc = RPERR_PARAMETER | RPDONE; break; } ULONG pcm = (ULONG) *linParm; printk("set PCM %i\n",pcm); SetPCMInstance(0, pcm); } break; case IOCTL_OSS32_CNTRL_WAIT: { if (rp->DataLength < sizeof(ULONG)) { // invalid Data Pkt rc = RPERR_PARAMETER | RPDONE; break; } ioctl_pcm *pcm = (ioctl_pcm *)linParm; pData = (ULONG *) linData; (*pData) = WaitForControlChange(pcm->deviceid, pcm->streamtype); } break; case IOCTL_OSS32_PCM_OPEN: { pData = (ULONG *)linData; ioctl_pcm *pcm = (ioctl_pcm *)linParm; // close all pcms from uniaud16 first pcm->ret = OSS32_WaveOpen(pcm->deviceid, pcm->streamtype, pData, pcm->pcm, rp->FileID); } break; case IOCTL_OSS32_PCM_CLOSE: { ULONG alsa_id = *((ULONG *)linParm); OSS32_WaveClose(alsa_id); } break; case IOCTL_OSS32_PCM_READ: { char *pData1 = (char *)linData; ioctl_pcm *pcm = (ioctl_pcm *)linParm; pcm->ret = UniaudIoctlPCMRead(pcm->deviceid, pData1, pcm->size); } break; case IOCTL_OSS32_PCM_WRITE: { char *pData1 = (char *)linData; ioctl_pcm *pcm = (ioctl_pcm *)linParm; pcm->ret = UniaudIoctlPCMWrite(pcm->deviceid, pData1, pcm->size); } break; case IOCTL_OSS32_PCM_PAUSE: { ioctl_pcm *pcm = (ioctl_pcm *)linParm; pcm->ret = UniaudIoctlPCMResume(pcm->deviceid, 0); } break; case IOCTL_OSS32_PCM_RESUME: { ioctl_pcm *pcm = (ioctl_pcm *)linParm; pcm->ret = UniaudIoctlPCMResume(pcm->deviceid, 1); } break; case IOCTL_OSS32_PCM_START: { ioctl_pcm *pcm = (ioctl_pcm *)linParm; pcm->ret = UniaudIoctlPCMStart(pcm->deviceid); } break; case IOCTL_OSS32_PCM_DROP: { ioctl_pcm *pcm = (ioctl_pcm *)linParm; pcm->ret = UniaudIoctlPCMDrop(pcm->deviceid); } break; case IOCTL_OSS32_PCM_DRAIN: break; case IOCTL_OSS32_PCM_STATUS: { void *pData1 = (void *)linData; ioctl_pcm *pcm = (ioctl_pcm *)linParm; pcm->ret = UniaudIoctlPCMStatus(pcm->deviceid, pData1); } break; case IOCTL_OSS32_PCM_REFINEHWPARAMS: { void *pData1 = (void *)linData; ioctl_pcm *pcm = (ioctl_pcm *)linParm; pcm->ret = UniaudIoctlHWRefine(pcm->deviceid, pData1); } break; case IOCTL_OSS32_PCM_SETHWPARAMS: { void *pData1 = (void *)linData; ioctl_pcm *pcm = (ioctl_pcm *)linParm; pcm->ret = UniaudIoctlHWParamSet(pcm->deviceid, pData1); } break; case IOCTL_OSS32_PCM_SETSWPARAMS: { void *pData1 = (void *)linData; ioctl_pcm *pcm = (ioctl_pcm *)linParm; pcm->ret = UniaudIoctlSWParamSet(pcm->deviceid, pData1); } break; case IOCTL_OSS32_PCM_PREPARE: { ioctl_pcm *pcm = (ioctl_pcm *)linParm; pcm->ret = UniaudIoctlPCMPrepare(pcm->deviceid); } break; case IOCTL_OSS32_PCM_CLOSE_ALL: { int unlock = (int)*linParm; if (unlock) unlock_all = 1; else UniaudCloseAll(0); } break; case IOCTL_OSS32_PCM_CLOSE_16: OSS32_CloseUNI16(); break; case IOCTL_OSS32_PCM_WAIT_INT: { ioctl_pcm *pcm = (ioctl_pcm *)linParm; pcm->ret = WaitForPCMInterrupt((void*)pcm->deviceid, pcm->streamtype); } break; default: { printk("invalid function code %i\n",rp->Function); // invalid function code rc = RPERR_PARAMETER | RPDONE; } break; } // unlock Parm & Data if needed if (linParm != NULL) { // linParm present & locked, must to unlock it DevVMUnLock(lhParm); } if (linData != NULL) { // linData present & locked, must to unlock it DevVMUnLock(lhData); } // all done return (rc); } //****************************************************************************** // Dispatch Close requests received from the strategy routine //****************************************************************************** ULONG StratClose(RP __far* _rp) { RPOpenClose __far* rp = (RPOpenClose __far*)_rp; // only called if device successfully opened // printk("strat close\n"); numOS2Opens--; UniaudCloseAll(rp->FileID); if (numOS2Opens == 0) { deviceOwner = DEV_NO_OWNER; } return(RPDONE); } //****************************************************************************** //******************************************************************************