647 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			647 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C++
		
	
	
	
| /* fhandler_dev_dsp: code to emulate OSS sound model /dev/dsp
 | |
| 
 | |
|    Copyright 2001, 2002 Red Hat, Inc
 | |
| 
 | |
|    Written by Andy Younger (andy@snoogie.demon.co.uk)
 | |
| 
 | |
| This file is part of Cygwin.
 | |
| 
 | |
| This software is a copyrighted work licensed under the terms of the
 | |
| Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
 | |
| details. */
 | |
| 
 | |
| #include "winsup.h"
 | |
| #include <stdio.h>
 | |
| #include <errno.h>
 | |
| #include <windows.h>
 | |
| #include <sys/soundcard.h>
 | |
| #include <mmsystem.h>
 | |
| #include "cygerrno.h"
 | |
| #include "security.h"
 | |
| #include "fhandler.h"
 | |
| 
 | |
| //------------------------------------------------------------------------
 | |
| // Simple encapsulation of the win32 audio device.
 | |
| //
 | |
| static void CALLBACK wave_callback (HWAVE hWave, UINT msg, DWORD instance,
 | |
| 				    DWORD param1, DWORD param2);
 | |
| class Audio
 | |
| {
 | |
| public:
 | |
|   enum
 | |
|   {
 | |
|     MAX_BLOCKS = 12,
 | |
|     BLOCK_SIZE = 16384,
 | |
|     TOT_BLOCK_SIZE = BLOCK_SIZE + sizeof (WAVEHDR)
 | |
|    };
 | |
| 
 | |
|     Audio ();
 | |
|    ~Audio ();
 | |
| 
 | |
|   bool open (int rate, int bits, int channels, bool bCallback = false);
 | |
|   void close ();
 | |
|   int getvolume ();
 | |
|   void setvolume (int newVolume);
 | |
|   bool write (const void *pSampleData, int nBytes);
 | |
|   int blocks ();
 | |
|   void callback_sampledone (void *pData);
 | |
|   void setformat (int format) {formattype_ = format;}
 | |
|   int numbytesoutput ();
 | |
| 
 | |
|   void *operator new (size_t, void *p) {return p;}
 | |
| 
 | |
| private:
 | |
|   char *initialisebuffer ();
 | |
|   void waitforcallback ();
 | |
|   bool flush ();
 | |
| 
 | |
|   HWAVEOUT dev_;
 | |
|   volatile int nBlocksInQue_;
 | |
|   int nBytesWritten_;
 | |
|   char *buffer_;
 | |
|   int bufferIndex_;
 | |
|   CRITICAL_SECTION lock_;
 | |
|   char *freeblocks_[MAX_BLOCKS];
 | |
|   int formattype_;
 | |
| 
 | |
|   char bigwavebuffer_[MAX_BLOCKS * TOT_BLOCK_SIZE];
 | |
| };
 | |
| 
 | |
| static char audio_buf[sizeof (class Audio)];
 | |
| 
 | |
| Audio::Audio ()
 | |
| {
 | |
|   InitializeCriticalSection (&lock_);
 | |
|   memset (bigwavebuffer_, 0, sizeof (bigwavebuffer_));
 | |
|   for (int i = 0; i < MAX_BLOCKS; i++)
 | |
|     freeblocks_[i] =  &bigwavebuffer_[i * TOT_BLOCK_SIZE];
 | |
| }
 | |
| 
 | |
| Audio::~Audio ()
 | |
| {
 | |
|   if (dev_)
 | |
|     close ();
 | |
|   DeleteCriticalSection (&lock_);
 | |
| }
 | |
| 
 | |
| bool
 | |
| Audio::open (int rate, int bits, int channels, bool bCallback)
 | |
| {
 | |
|   WAVEFORMATEX format;
 | |
|   int nDevices = waveOutGetNumDevs ();
 | |
| 
 | |
|   nBytesWritten_ = 0L;
 | |
|   bufferIndex_ = 0;
 | |
|   buffer_ = 0L;
 | |
|   debug_printf ("number devices %d", nDevices);
 | |
|   if (nDevices <= 0)
 | |
|     return false;
 | |
| 
 | |
|   debug_printf ("trying to map device freq %d, bits %d, "
 | |
| 		"channels %d, callback %d", rate, bits, channels,
 | |
| 		bCallback);
 | |
| 
 | |
|   int bytesperSample = bits / 8;
 | |
| 
 | |
|   memset (&format, 0, sizeof (format));
 | |
|   format.wFormatTag = WAVE_FORMAT_PCM;
 | |
|   format.wBitsPerSample = bits;
 | |
|   format.nChannels = channels;
 | |
|   format.nSamplesPerSec = rate;
 | |
|   format.nAvgBytesPerSec = format.nSamplesPerSec * format.nChannels *
 | |
|     bytesperSample;
 | |
|   format.nBlockAlign = format.nChannels * bytesperSample;
 | |
| 
 | |
|   nBlocksInQue_ = 0;
 | |
|   HRESULT res = waveOutOpen (&dev_, WAVE_MAPPER, &format, (DWORD) wave_callback,
 | |
| 			     (DWORD) this, bCallback ? CALLBACK_FUNCTION : 0);
 | |
|   if (res == S_OK)
 | |
|     {
 | |
|       debug_printf ("Sucessfully opened!");
 | |
|       return true;
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       debug_printf ("failed to open");
 | |
|       return false;
 | |
|     }
 | |
| }
 | |
| 
 | |
| void
 | |
| Audio::close ()
 | |
| {
 | |
|   if (dev_)
 | |
|     {
 | |
|       flush ();			// force out last block whatever size..
 | |
| 
 | |
|       while (blocks ())		// block till finished..
 | |
| 	waitforcallback ();
 | |
| 
 | |
|       waveOutReset (dev_);
 | |
|       waveOutClose (dev_);
 | |
|       dev_ = 0L;
 | |
|     }
 | |
|   nBytesWritten_ = 0L;
 | |
| }
 | |
| 
 | |
| int
 | |
| Audio::numbytesoutput ()
 | |
| {
 | |
|   return nBytesWritten_;
 | |
| }
 | |
| 
 | |
| int
 | |
| Audio::getvolume ()
 | |
| {
 | |
|   DWORD volume;
 | |
| 
 | |
|   waveOutGetVolume (dev_, &volume);
 | |
|   return ((volume >> 16) + (volume & 0xffff)) >> 1;
 | |
| }
 | |
| 
 | |
| void
 | |
| Audio::setvolume (int newVolume)
 | |
| {
 | |
|   waveOutSetVolume (dev_, (newVolume << 16) | newVolume);
 | |
| }
 | |
| 
 | |
| char *
 | |
| Audio::initialisebuffer ()
 | |
| {
 | |
|   EnterCriticalSection (&lock_);
 | |
|   WAVEHDR *pHeader = 0L;
 | |
|   for (int i = 0; i < MAX_BLOCKS; i++)
 | |
|     {
 | |
|       char *pData = freeblocks_[i];
 | |
|       if (pData)
 | |
| 	{
 | |
| 	  pHeader = (WAVEHDR *) pData;
 | |
| 	  if (pHeader->dwFlags & WHDR_DONE)
 | |
| 	    {
 | |
| 	      waveOutUnprepareHeader (dev_, pHeader, sizeof (WAVEHDR));
 | |
| 	    }
 | |
| 	  freeblocks_[i] = 0L;
 | |
| 	  break;
 | |
| 	}
 | |
|     }
 | |
|   LeaveCriticalSection (&lock_);
 | |
| 
 | |
|   if (pHeader)
 | |
|     {
 | |
|       memset (pHeader, 0, sizeof (WAVEHDR));
 | |
|       pHeader->dwBufferLength = BLOCK_SIZE;
 | |
|       pHeader->lpData = (LPSTR) (&pHeader[1]);
 | |
|       return (char *) pHeader->lpData;
 | |
|     }
 | |
|   return 0L;
 | |
| }
 | |
| 
 | |
| bool
 | |
| Audio::write (const void *pSampleData, int nBytes)
 | |
| {
 | |
|   // split up big blocks into smaller BLOCK_SIZE chunks
 | |
|   while (nBytes > BLOCK_SIZE)
 | |
|     {
 | |
|       write (pSampleData, BLOCK_SIZE);
 | |
|       nBytes -= BLOCK_SIZE;
 | |
|       pSampleData = (void *) ((char *) pSampleData + BLOCK_SIZE);
 | |
|     }
 | |
| 
 | |
|   // Block till next sound is flushed
 | |
|   if (blocks () == MAX_BLOCKS)
 | |
|     waitforcallback ();
 | |
| 
 | |
|   // Allocate new wave buffer if necessary
 | |
|   if (buffer_ == 0L)
 | |
|     {
 | |
|       buffer_ = initialisebuffer ();
 | |
|       if (buffer_ == 0L)
 | |
| 	return false;
 | |
|     }
 | |
| 
 | |
| 
 | |
|   // Handle gathering blocks into larger buffer
 | |
|   int sizeleft = BLOCK_SIZE - bufferIndex_;
 | |
|   if (nBytes < sizeleft)
 | |
|     {
 | |
|       memcpy (&buffer_[bufferIndex_], pSampleData, nBytes);
 | |
|       bufferIndex_ += nBytes;
 | |
|       nBytesWritten_ += nBytes;
 | |
|       return true;
 | |
|     }
 | |
| 
 | |
|   // flushing when we reach our limit of BLOCK_SIZE
 | |
|   memcpy (&buffer_[bufferIndex_], pSampleData, sizeleft);
 | |
|   bufferIndex_ += sizeleft;
 | |
|   nBytesWritten_ += sizeleft;
 | |
|   flush ();
 | |
| 
 | |
|   // change pointer to rest of sample, and size accordingly
 | |
|   pSampleData = (void *) ((char *) pSampleData + sizeleft);
 | |
|   nBytes -= sizeleft;
 | |
| 
 | |
|   // if we still have some sample left over write it out
 | |
|   if (nBytes)
 | |
|     return write (pSampleData, nBytes);
 | |
| 
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // return number of blocks back.
 | |
| int
 | |
| Audio::blocks ()
 | |
| {
 | |
|   EnterCriticalSection (&lock_);
 | |
|   int ret = nBlocksInQue_;
 | |
|   LeaveCriticalSection (&lock_);
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| // This is called on an interupt so use locking.. Note nBlocksInQue_ is
 | |
| // modified by it so we should wrap all references to it in locks.
 | |
| void
 | |
| Audio::callback_sampledone (void *pData)
 | |
| {
 | |
|   EnterCriticalSection (&lock_);
 | |
| 
 | |
|   nBlocksInQue_--;
 | |
|   for (int i = 0; i < MAX_BLOCKS; i++)
 | |
|     if (!freeblocks_[i])
 | |
|       {
 | |
| 	freeblocks_[i] = (char *) pData;
 | |
| 	break;
 | |
|       }
 | |
| 
 | |
|   LeaveCriticalSection (&lock_);
 | |
| }
 | |
| 
 | |
| void
 | |
| Audio::waitforcallback ()
 | |
| {
 | |
|   int n = blocks ();
 | |
|   if (!n)
 | |
|     return;
 | |
|   do
 | |
|     {
 | |
|       Sleep (250);
 | |
|     }
 | |
|   while (n == blocks ());
 | |
| }
 | |
| 
 | |
| bool
 | |
| Audio::flush ()
 | |
| {
 | |
|   if (!buffer_)
 | |
|     return false;
 | |
| 
 | |
|   // Send internal buffer out to the soundcard
 | |
|   WAVEHDR *pHeader = ((WAVEHDR *) buffer_) - 1;
 | |
|   pHeader->dwBufferLength = bufferIndex_;
 | |
| 
 | |
|   // Quick bit of sample buffer conversion
 | |
|   if (formattype_ == AFMT_S8)
 | |
|     {
 | |
|       unsigned char *p = ((unsigned char *) buffer_);
 | |
|       for (int i = 0; i < bufferIndex_; i++)
 | |
| 	{
 | |
| 	  p[i] -= 0x7f;
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|   if (waveOutPrepareHeader (dev_, pHeader, sizeof (WAVEHDR)) == S_OK &&
 | |
|       waveOutWrite (dev_, pHeader, sizeof (WAVEHDR)) == S_OK)
 | |
|     {
 | |
|       EnterCriticalSection (&lock_);
 | |
|       nBlocksInQue_++;
 | |
|       LeaveCriticalSection (&lock_);
 | |
|       bufferIndex_ = 0;
 | |
|       buffer_ = 0L;
 | |
|       return true;
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       EnterCriticalSection (&lock_);
 | |
|       for (int i = 0; i < MAX_BLOCKS; i++)
 | |
| 	if (!freeblocks_[i])
 | |
| 	  {
 | |
| 	    freeblocks_[i] = (char *) pHeader;
 | |
| 	    break;
 | |
| 	  }
 | |
|       LeaveCriticalSection (&lock_);
 | |
|     }
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| //------------------------------------------------------------------------
 | |
| // Call back routine
 | |
| static void CALLBACK
 | |
| wave_callback (HWAVE hWave, UINT msg, DWORD instance, DWORD param1,
 | |
| 	       DWORD param2)
 | |
| {
 | |
|   if (msg == WOM_DONE)
 | |
|     {
 | |
|       Audio *ptr = (Audio *) instance;
 | |
|       ptr->callback_sampledone ((void *) param1);
 | |
|     }
 | |
| }
 | |
| 
 | |
| //------------------------------------------------------------------------
 | |
| // /dev/dsp handler
 | |
| static Audio *s_audio;		// static instance of the Audio handler
 | |
| 
 | |
| //------------------------------------------------------------------------
 | |
| // wav file detection..
 | |
| #pragma pack(1)
 | |
| struct wavchunk
 | |
| {
 | |
|   char id[4];
 | |
|   unsigned int len;
 | |
| };
 | |
| struct wavformat
 | |
| {
 | |
|   unsigned short wFormatTag;
 | |
|   unsigned short wChannels;
 | |
|   unsigned int dwSamplesPerSec;
 | |
|   unsigned int dwAvgBytesPerSec;
 | |
|   unsigned short wBlockAlign;
 | |
|   unsigned short wBitsPerSample;
 | |
| };
 | |
| #pragma pack()
 | |
| 
 | |
| bool
 | |
| fhandler_dev_dsp::setupwav (const char *pData, int nBytes)
 | |
| {
 | |
|   int len;
 | |
|   const char *end = pData + nBytes;
 | |
| 
 | |
|   if (!(pData[0] == 'R' && pData[1] == 'I' &&
 | |
| 	pData[2] == 'F' && pData[3] == 'F'))
 | |
|     return false;
 | |
|   if (!(pData[8] == 'W' && pData[9] == 'A' &&
 | |
| 	pData[10] == 'V' && pData[11] == 'E'))
 | |
|     return false;
 | |
| 
 | |
|   len = *(int *) &pData[4];
 | |
|   pData += 12;
 | |
|   while (len && pData < end)
 | |
|     {
 | |
|       wavchunk * pChunk = (wavchunk *) pData;
 | |
|       int blklen = pChunk-> len;
 | |
|       if (pChunk->id[0] == 'f' && pChunk->id[1] == 'm' &&
 | |
| 	  pChunk->id[2] == 't' && pChunk->id[3] == ' ')
 | |
| 	{
 | |
| 	  wavformat *format = (wavformat *) (pChunk + 1);
 | |
| 	  if ((char *) (format + 1) > end)
 | |
| 	    return false;
 | |
| 
 | |
| 	  // Open up audio device with correct frequency for wav file
 | |
| 	  //
 | |
| 	  // FIXME: should through away all the header & not output
 | |
| 	  // it to the soundcard.
 | |
| 	  s_audio->close ();
 | |
| 	  if (s_audio->open (format->dwSamplesPerSec, format->wBitsPerSample,
 | |
| 			     format->wChannels) == false)
 | |
| 	    {
 | |
| 	      s_audio->open (audiofreq_, audiobits_, audiochannels_);
 | |
| 	    }
 | |
| 	  else
 | |
| 	    {
 | |
| 	      audiofreq_ = format->dwSamplesPerSec;
 | |
| 	      audiobits_ = format->wBitsPerSample;
 | |
| 	      audiochannels_ = format->wChannels;
 | |
| 	    }
 | |
| 	  return true;
 | |
| 	}
 | |
| 
 | |
|       pData += blklen + sizeof (wavchunk);
 | |
|     }
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| //------------------------------------------------------------------------
 | |
| fhandler_dev_dsp::fhandler_dev_dsp ():
 | |
|   fhandler_base (FH_OSS_DSP)
 | |
| {
 | |
| }
 | |
| 
 | |
| fhandler_dev_dsp::~fhandler_dev_dsp ()
 | |
| {
 | |
| }
 | |
| 
 | |
| int
 | |
| fhandler_dev_dsp::open (path_conv *, int flags, mode_t mode)
 | |
| {
 | |
|   // currently we only support writing
 | |
|   if ((flags & (O_WRONLY | O_RDONLY | O_RDWR)) != O_WRONLY)
 | |
|     {
 | |
|       set_errno (EACCES);
 | |
|       return 0;
 | |
|     }
 | |
| 
 | |
|   set_flags ((flags & ~O_TEXT) | O_BINARY);
 | |
| 
 | |
|   if (!s_audio)
 | |
|     s_audio = new (audio_buf) Audio;
 | |
| 
 | |
|   // Work out initial sample format & frequency
 | |
|       // dev/dsp defaults
 | |
|   audioformat_ = AFMT_S8;
 | |
|   audiofreq_ = 8000;
 | |
|   audiobits_ = 8;
 | |
|   audiochannels_ = 1;
 | |
| 
 | |
|   int res;
 | |
|   if (!s_audio->open (audiofreq_, audiobits_, audiochannels_))
 | |
|     res = 0;
 | |
|   else
 | |
|     {
 | |
|       set_open_status ();
 | |
|       res = 1;
 | |
|     }
 | |
| 
 | |
|   debug_printf ("returns %d", res);
 | |
|   return res;
 | |
| }
 | |
| 
 | |
| int
 | |
| fhandler_dev_dsp::write (const void *ptr, size_t len)
 | |
| {
 | |
|   if (s_audio->numbytesoutput () == 0)
 | |
|     {
 | |
|       // check for wave file & setup frequencys properly if possible.
 | |
|       setupwav ((const char *) ptr, len);
 | |
| 
 | |
|       // Open audio device properly with callbacks.
 | |
|       s_audio->close ();
 | |
|       if (!s_audio->open (audiofreq_, audiobits_, audiochannels_, true))
 | |
| 	return 0;
 | |
|     }
 | |
| 
 | |
|   s_audio->write (ptr, len);
 | |
|   return len;
 | |
| }
 | |
| 
 | |
| int __stdcall
 | |
| fhandler_dev_dsp::read (void *ptr, size_t len)
 | |
| {
 | |
|   return len;
 | |
| }
 | |
| 
 | |
| __off64_t
 | |
| fhandler_dev_dsp::lseek (__off64_t offset, int whence)
 | |
| {
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| int
 | |
| fhandler_dev_dsp::close (void)
 | |
| {
 | |
|   s_audio->close ();
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| int
 | |
| fhandler_dev_dsp::dup (fhandler_base * child)
 | |
| {
 | |
|   fhandler_dev_dsp *fhc = (fhandler_dev_dsp *) child;
 | |
| 
 | |
|   fhc->set_flags (get_flags ());
 | |
|   fhc->audiochannels_ = audiochannels_;
 | |
|   fhc->audiobits_ = audiobits_;
 | |
|   fhc->audiofreq_ = audiofreq_;
 | |
|   fhc->audioformat_ = audioformat_;
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| int
 | |
| fhandler_dev_dsp::ioctl (unsigned int cmd, void *ptr)
 | |
| {
 | |
|   int *intptr = (int *) ptr;
 | |
|   switch (cmd)
 | |
|     {
 | |
| #define CASE(a) case a : debug_printf("/dev/dsp: ioctl %s", #a);
 | |
| 
 | |
|       CASE (SNDCTL_DSP_RESET)
 | |
| 	audioformat_ = AFMT_S8;
 | |
| 	audiofreq_ = 8000;
 | |
| 	audiobits_ = 8;
 | |
| 	audiochannels_ = 1;
 | |
| 	return 0;
 | |
| 
 | |
|       CASE (SNDCTL_DSP_GETBLKSIZE)
 | |
| 	*intptr = Audio::BLOCK_SIZE;
 | |
| 	return 0;
 | |
| 
 | |
|       CASE (SNDCTL_DSP_SETFMT)
 | |
|       {
 | |
| 	int nBits = 0;
 | |
| 	if (*intptr == AFMT_S16_LE)
 | |
| 	  nBits = 16;
 | |
| 	else if (*intptr == AFMT_U8)
 | |
| 	  nBits = 8;
 | |
| 	else if (*intptr == AFMT_S8)
 | |
| 	  nBits = 8;
 | |
| 	if (nBits)
 | |
| 	  {
 | |
| 	    s_audio->setformat (*intptr);
 | |
| 	    s_audio->close ();
 | |
| 	    if (s_audio->open (audiofreq_, nBits, audiochannels_) == true)
 | |
| 	      {
 | |
| 		audiobits_ = nBits;
 | |
| 		return 0;
 | |
| 	      }
 | |
| 	    else
 | |
| 	      {
 | |
| 		s_audio->open (audiofreq_, audiobits_, audiochannels_);
 | |
| 		return -1;
 | |
| 	      }
 | |
| 	  }
 | |
|       }
 | |
|       break;
 | |
| 
 | |
|       CASE (SNDCTL_DSP_SPEED)
 | |
| 	s_audio->close ();
 | |
| 	if (s_audio->open (*intptr, audiobits_, audiochannels_) == true)
 | |
| 	  {
 | |
| 	    audiofreq_ = *intptr;
 | |
| 	    return 0;
 | |
| 	  }
 | |
| 	else
 | |
| 	  {
 | |
| 	    s_audio->open (audiofreq_, audiobits_, audiochannels_);
 | |
| 	    return -1;
 | |
| 	  }
 | |
| 	break;
 | |
| 
 | |
|       CASE (SNDCTL_DSP_STEREO)
 | |
|       {
 | |
| 	int nChannels = *intptr + 1;
 | |
| 
 | |
| 	s_audio->close ();
 | |
| 	if (s_audio->open (audiofreq_, audiobits_, nChannels) == true)
 | |
| 	  {
 | |
| 	    audiochannels_ = nChannels;
 | |
| 	    return 0;
 | |
| 	  }
 | |
| 	else
 | |
| 	  {
 | |
| 	    s_audio->open (audiofreq_, audiobits_, audiochannels_);
 | |
| 	    return -1;
 | |
| 	  }
 | |
|       }
 | |
|       break;
 | |
| 
 | |
|       CASE (SNDCTL_DSP_GETOSPACE)
 | |
|       {
 | |
| 	audio_buf_info *p = (audio_buf_info *) ptr;
 | |
| 
 | |
| 	int nBlocks = s_audio->blocks ();
 | |
| 	int leftblocks = ((Audio::MAX_BLOCKS - nBlocks) - 1);
 | |
| 	if (leftblocks < 0)
 | |
| 	  leftblocks = 0;
 | |
| 	if (leftblocks > 1)
 | |
| 	  leftblocks = 1;
 | |
| 	int left = leftblocks * Audio::BLOCK_SIZE;
 | |
| 
 | |
| 	p->fragments = leftblocks;
 | |
| 	p->fragstotal = Audio::MAX_BLOCKS;
 | |
| 	p->fragsize = Audio::BLOCK_SIZE;
 | |
| 	p->bytes = left;
 | |
| 
 | |
| 	debug_printf ("ptr %p nblocks %d leftblocks %d left bytes %d ",
 | |
| 		      ptr, nBlocks, leftblocks, left);
 | |
| 
 | |
| 	return 0;
 | |
|       }
 | |
|       break;
 | |
| 
 | |
|       CASE (SNDCTL_DSP_SETFRAGMENT)
 | |
|       {
 | |
| 	// Fake!! esound & mikmod require this on non PowerPC platforms.
 | |
| 	//
 | |
| 	return 0;
 | |
|       }
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       debug_printf ("/dev/dsp: ioctl not handled yet! FIXME:");
 | |
|       break;
 | |
| 
 | |
| #undef CASE
 | |
|     };
 | |
|   return -1;
 | |
| }
 | |
| 
 | |
| void
 | |
| fhandler_dev_dsp::dump ()
 | |
| {
 | |
|   paranoid_printf ("here, fhandler_dev_dsp");
 | |
| }
 | |
| 
 | |
| void
 | |
| fhandler_dev_dsp::fixup_after_exec (HANDLE)
 | |
| {
 | |
|   /* FIXME:  Is there a better way to do this? */
 | |
|   s_audio = new (audio_buf) Audio;
 | |
| }
 |