home *** CD-ROM | disk | FTP | other *** search
- /*
- * sound/audio.c
- *
- * Device file manager for /dev/audio
- *
- * Copyright by Hannu Savolainen 1993
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer. 2.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- */
-
- #include "sound_config.h"
-
- #ifdef CONFIGURE_SOUNDCARD
- #ifndef EXCLUDE_AUDIO
-
- #include "ulaw.h"
-
- #define ON 1
- #define OFF 0
-
- static int wr_buff_no[MAX_AUDIO_DEV]; /*
- * != -1, if there is
- * a incomplete output
- * block in the queue.
- */
- static int wr_buff_size[MAX_AUDIO_DEV], wr_buff_ptr[MAX_AUDIO_DEV];
-
- static int audio_mode[MAX_AUDIO_DEV];
-
- #define AM_NONE 0
- #define AM_WRITE 1
- #define AM_READ 2
-
- static char *wr_dma_buf[MAX_AUDIO_DEV];
- static int audio_format[MAX_AUDIO_DEV];
- static int local_conversion[MAX_AUDIO_DEV];
-
- static int
- set_format (int dev, int fmt)
- {
- if (fmt != AFMT_QUERY)
- {
-
- local_conversion[dev] = 0;
-
- if (!(audio_devs[dev]->format_mask & fmt)) /* Not supported */
- if (fmt == AFMT_MU_LAW)
- {
- fmt = AFMT_U8;
- local_conversion[dev] = AFMT_MU_LAW;
- }
- else
- fmt = AFMT_U8; /* This is always supported */
-
- audio_format[dev] = DMAbuf_ioctl (dev, SNDCTL_DSP_SETFMT, fmt, 1);
- }
-
- if (local_conversion[dev]) /* This shadows the HW format */
- return local_conversion[dev];
-
- return audio_format[dev];
- }
-
- int
- audio_open (int dev, struct fileinfo *file)
- {
- int ret;
- int bits;
- int dev_type = dev & 0x0f;
- int mode = file->mode & O_ACCMODE;
-
- dev = dev >> 4;
-
- if (dev_type == SND_DEV_DSP16)
- bits = 16;
- else
- bits = 8;
-
- if ((ret = DMAbuf_open (dev, mode)) < 0)
- return ret;
-
- local_conversion[dev] = 0;
-
- if (DMAbuf_ioctl (dev, SNDCTL_DSP_SETFMT, bits, 1) != bits)
- {
- audio_release (dev, file);
- return RET_ERROR (ENXIO);
- }
-
- if (dev_type == SND_DEV_AUDIO)
- {
- set_format (dev, AFMT_MU_LAW);
- }
- else
- set_format (dev, bits);
-
- wr_buff_no[dev] = -1;
- audio_mode[dev] = AM_NONE;
-
- return ret;
- }
-
- void
- audio_release (int dev, struct fileinfo *file)
- {
- int mode;
-
- dev = dev >> 4;
- mode = file->mode & O_ACCMODE;
-
- if (wr_buff_no[dev] >= 0)
- {
- DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]);
-
- wr_buff_no[dev] = -1;
- }
-
- DMAbuf_release (dev, mode);
- }
-
- #ifdef NO_INLINE_ASM
- static void
- translate_bytes (const unsigned char *table, unsigned char *buff, unsigned long n)
- {
- unsigned long i;
-
- for (i = 0; i < n; ++i)
- buff[i] = table[buff[i]];
- }
-
- #else
- extern inline void
- translate_bytes (const void *table, void *buff, unsigned long n)
- {
- __asm__ ("cld\n"
- "1:\tlodsb\n\t"
- "xlatb\n\t"
- "stosb\n\t"
- "loop 1b\n\t":
- :"b" ((long) table), "c" (n), "D" ((long) buff), "S" ((long) buff)
- :"bx", "cx", "di", "si", "ax");
- }
-
- #endif
-
- int
- audio_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
- {
- int c, p, l;
- int err;
-
- dev = dev >> 4;
-
- p = 0;
- c = count;
-
- if (audio_mode[dev] == AM_READ) /*
- * Direction changed
- */
- {
- wr_buff_no[dev] = -1;
- }
-
- audio_mode[dev] = AM_WRITE;
-
- if (!count) /*
- * Flush output
- */
- {
- if (wr_buff_no[dev] >= 0)
- {
- DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]);
-
- wr_buff_no[dev] = -1;
- }
- return 0;
- }
-
- while (c)
- { /*
- * Perform output blocking
- */
- if (wr_buff_no[dev] < 0) /*
- * There is no incomplete buffers
- */
- {
- if ((wr_buff_no[dev] = DMAbuf_getwrbuffer (dev, &wr_dma_buf[dev], &wr_buff_size[dev])) < 0)
- {
- return wr_buff_no[dev];
- }
- wr_buff_ptr[dev] = 0;
- }
-
- l = c;
- if (l > (wr_buff_size[dev] - wr_buff_ptr[dev]))
- l = (wr_buff_size[dev] - wr_buff_ptr[dev]);
-
- if (!audio_devs[dev]->copy_from_user)
- { /*
- * No device specific copy routine
- */
- COPY_FROM_USER (&wr_dma_buf[dev][wr_buff_ptr[dev]], buf, p, l);
- }
- else
- audio_devs[dev]->copy_from_user (dev,
- wr_dma_buf[dev], wr_buff_ptr[dev], buf, p, l);
-
-
- /*
- * Insert local processing here
- */
-
- if (local_conversion[dev] == AFMT_MU_LAW)
- {
- #ifdef linux
- /*
- * This just allows interrupts while the conversion is running
- */
- __asm__ ("sti");
- #endif
- translate_bytes (ulaw_dsp, (unsigned char *) &wr_dma_buf[dev][wr_buff_ptr[dev]], l);
- }
-
- c -= l;
- p += l;
- wr_buff_ptr[dev] += l;
-
- if (wr_buff_ptr[dev] >= wr_buff_size[dev])
- {
- if ((err = DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev])) < 0)
- {
- return err;
- }
-
- wr_buff_no[dev] = -1;
- }
-
- }
-
- return count;
- }
-
- int
- audio_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
- {
- int c, p, l;
- char *dmabuf;
- int buff_no;
-
- dev = dev >> 4;
- p = 0;
- c = count;
-
- if (audio_mode[dev] == AM_WRITE)
- {
- if (wr_buff_no[dev] >= 0)
- {
- DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]);
-
- wr_buff_no[dev] = -1;
- }
- }
-
- audio_mode[dev] = AM_READ;
-
- while (c)
- {
- if ((buff_no = DMAbuf_getrdbuffer (dev, &dmabuf, &l)) < 0)
- return buff_no;
-
- if (l > c)
- l = c;
-
- /*
- * Insert any local processing here.
- */
-
- if (local_conversion[dev] == AFMT_MU_LAW)
- {
- #ifdef linux
- /*
- * This just allows interrupts while the conversion is running
- */
- __asm__ ("sti");
- #endif
-
- translate_bytes (dsp_ulaw, (unsigned char *) dmabuf, l);
- }
-
- COPY_TO_USER (buf, p, dmabuf, l);
-
- DMAbuf_rmchars (dev, buff_no, l);
-
- p += l;
- c -= l;
- }
-
- return count - c;
- }
-
- int
- audio_ioctl (int dev, struct fileinfo *file,
- unsigned int cmd, unsigned int arg)
- {
-
- dev = dev >> 4;
-
- switch (cmd)
- {
- case SNDCTL_DSP_SYNC:
- if (wr_buff_no[dev] >= 0)
- {
- DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]);
-
- wr_buff_no[dev] = -1;
- }
- return DMAbuf_ioctl (dev, cmd, arg, 0);
- break;
-
- case SNDCTL_DSP_POST:
- if (wr_buff_no[dev] >= 0)
- {
- DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]);
-
- wr_buff_no[dev] = -1;
- }
- return 0;
- break;
-
- case SNDCTL_DSP_RESET:
- wr_buff_no[dev] = -1;
- return DMAbuf_ioctl (dev, cmd, arg, 0);
- break;
-
- case SNDCTL_DSP_GETFMTS:
- return IOCTL_OUT (arg, audio_devs[dev]->format_mask);
- break;
-
- case SNDCTL_DSP_SETFMT:
- return IOCTL_OUT (arg, set_format (dev, IOCTL_IN (arg)));
-
- default:
- return DMAbuf_ioctl (dev, cmd, arg, 0);
- break;
- }
- }
-
- long
- audio_init (long mem_start)
- {
- /*
- * NOTE! This routine could be called several times during boot.
- */
- return mem_start;
- }
-
- #else
- /*
- * Stub versions
- */
-
- int
- audio_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
- {
- return RET_ERROR (EIO);
- }
-
- int
- audio_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
- {
- return RET_ERROR (EIO);
- }
-
- int
- audio_open (int dev, struct fileinfo *file)
- {
- return RET_ERROR (ENXIO);
- }
-
- void
- audio_release (int dev, struct fileinfo *file)
- {
- };
- int
- audio_ioctl (int dev, struct fileinfo *file,
- unsigned int cmd, unsigned int arg)
- {
- return RET_ERROR (EIO);
- }
-
- int
- audio_lseek (int dev, struct fileinfo *file, off_t offset, int orig)
- {
- return RET_ERROR (EIO);
- }
-
- long
- audio_init (long mem_start)
- {
- return mem_start;
- }
-
- #endif
-
- #endif
-