From 19c9bba94152148523ba0f7ef7cffe3d45656b11 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 29 Apr 1997 21:13:14 +0000 Subject: Import of Linux/MIPS 2.1.36 --- drivers/sound/audio.c | 661 ++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 559 insertions(+), 102 deletions(-) (limited to 'drivers/sound/audio.c') diff --git a/drivers/sound/audio.c b/drivers/sound/audio.c index 4ce28d0d1..0ce7c0a9d 100644 --- a/drivers/sound/audio.c +++ b/drivers/sound/audio.c @@ -5,7 +5,7 @@ */ /* - * Copyright (C) by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1997 * * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) * Version 2 (June 1991). See the "COPYING" file distributed with this software @@ -24,6 +24,9 @@ #define ON 1 #define OFF 0 +#define NEUTRAL8 0x80 +#define NEUTRAL16 0x00 + static int audio_mode[MAX_AUDIO_DEV]; static int dev_nblock[MAX_AUDIO_DEV]; /* 1 if in nonblocking mode */ @@ -95,9 +98,6 @@ audio_open (int dev, struct fileinfo *file) local_conversion[dev] = 0; - if (audio_devs[dev]->d->set_bits (dev, bits) != bits) - { - } if (dev_type == SND_DEV_AUDIO) { @@ -113,23 +113,33 @@ audio_open (int dev, struct fileinfo *file) return ret; } -void +static void sync_output (int dev) { - int buf_no, buf_ptr, buf_size, p, i; - char *dma_buf; + int p, i; + int l; struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - if (DMAbuf_get_curr_buffer (dev, &buf_no, &dma_buf, &buf_ptr, &buf_size) >= 0) + if (dmap->fragment_size <= 0) + return; + dmap->flags |= DMA_POST; + + /* Align the write pointer with fragment boundaries */ + if ((l = dmap->user_counter % dmap->fragment_size) > 0) { - int i, n = buf_size & 3; + char *ptr; + int err, dummylen, len = dmap->fragment_size - l; - if (n) /* Not 4 byte aligned */ - { - for (i = 0; i < n; i++) - dma_buf[buf_ptr++] = dmap->neutral_byte; - } - DMAbuf_start_output (dev, buf_no, buf_ptr); + if ((err = DMAbuf_getwrbuffer (dev, &ptr, &dummylen, 1)) >= 0) + if (dummylen >= len && ((long) ptr % dmap->fragment_size) == l) + { + if ((ptr + len) > (dmap->raw_buf + audio_devs[dev]->buffsize)) + printk ("audio: Buffer error 1\n"); + if (ptr < dmap->raw_buf) + printk ("audio: Buffer error 11\n"); + memset (ptr, dmap->neutral_byte, len); + DMAbuf_move_wrpointer (dev, len); + } } /* @@ -137,16 +147,21 @@ sync_output (int dev) */ p = dmap->qtail; + dmap->flags |= DMA_POST; for (i = dmap->qlen + 1; i < dmap->nbufs; i++) { p = (p + 1) % dmap->nbufs; + if (((dmap->raw_buf + p * dmap->fragment_size) + dmap->fragment_size) > + (dmap->raw_buf + audio_devs[dev]->buffsize)) + printk ("audio: Buffer error 2\n"); + memset (dmap->raw_buf + p * dmap->fragment_size, dmap->neutral_byte, dmap->fragment_size); } - dmap->flags |= DMA_CLEAN; + dmap->flags |= DMA_DIRTY; } void @@ -201,7 +216,7 @@ translate_bytes (const void *table, void *buff, int n) int audio_write (int dev, struct fileinfo *file, const char *buf, int count) { - int c, p, l, buf_no, buf_ptr, buf_size; + int c, p, l, buf_size; int err; char *dma_buf; @@ -210,9 +225,8 @@ audio_write (int dev, struct fileinfo *file, const char *buf, int count) p = 0; c = count; - if ((audio_mode[dev] & AM_READ) && !(audio_devs[dev]->flags & DMA_DUPLEX)) - { /* Direction change */ - } + if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) + return -EPERM; if (audio_devs[dev]->flags & DMA_DUPLEX) audio_mode[dev] |= AM_WRITE; @@ -227,34 +241,33 @@ audio_write (int dev, struct fileinfo *file, const char *buf, int count) while (c) { - if (DMAbuf_get_curr_buffer (dev, &buf_no, &dma_buf, &buf_ptr, &buf_size) < 0) + if ((err = DMAbuf_getwrbuffer (dev, &dma_buf, &buf_size, dev_nblock[dev]) < 0)) { - if ((buf_no = DMAbuf_getwrbuffer (dev, &dma_buf, - &buf_size, - dev_nblock[dev])) < 0) - { - /* Handle nonblocking mode */ - if (dev_nblock[dev] && buf_no == -EAGAIN) - return p; /* No more space. Return # of accepted bytes */ - return buf_no; - } - buf_ptr = 0; + /* Handle nonblocking mode */ + if (dev_nblock[dev] && err == -EAGAIN) + return p; /* No more space. Return # of accepted bytes */ + return err; } l = c; - if (l > (buf_size - buf_ptr)) - l = (buf_size - buf_ptr); - + if (l > buf_size) + l = buf_size; if (!audio_devs[dev]->d->copy_user) - { /* - * No device specific copy routine - */ - copy_from_user (&dma_buf[buf_ptr], &(buf)[p], l); + { + if ((dma_buf + l) > + (audio_devs[dev]->dmap_out->raw_buf + audio_devs[dev]->buffsize)) + printk ("audio: Buffer error 3 (%lx,%d), (%lx, %d)\n", + (long) dma_buf, l, + (long) audio_devs[dev]->dmap_out->raw_buf, + (int) audio_devs[dev]->buffsize); + if (dma_buf < audio_devs[dev]->dmap_out->raw_buf) + printk ("audio: Buffer error 13\n"); + copy_from_user (dma_buf, &(buf)[p], l); } else audio_devs[dev]->d->copy_user (dev, - dma_buf, buf_ptr, buf, p, l); + dma_buf, 0, buf, p, l); if (local_conversion[dev] & CNV_MU_LAW) { @@ -262,23 +275,12 @@ audio_write (int dev, struct fileinfo *file, const char *buf, int count) * This just allows interrupts while the conversion is running */ sti (); - translate_bytes (ulaw_dsp, (unsigned char *) &dma_buf[buf_ptr], l); + translate_bytes (ulaw_dsp, (unsigned char *) dma_buf, l); } c -= l; p += l; - buf_ptr += l; - - if (buf_ptr >= buf_size) - { - if ((err = DMAbuf_start_output (dev, buf_no, buf_ptr)) < 0) - { - return err; - } - - } - else - DMAbuf_set_count (dev, buf_no, buf_ptr); + DMAbuf_move_wrpointer (dev, l); } @@ -296,6 +298,9 @@ audio_read (int dev, struct fileinfo *file, char *buf, int count) p = 0; c = count; + if (!(audio_devs[dev]->open_mode & OPEN_READ)) + return -EPERM; + if ((audio_mode[dev] & AM_WRITE) && !(audio_devs[dev]->flags & DMA_DUPLEX)) { sync_output (dev); @@ -352,12 +357,12 @@ audio_read (int dev, struct fileinfo *file, char *buf, int count) } int -audio_ioctl (int dev, struct fileinfo *file, +audio_ioctl (int dev, struct fileinfo *file_must_not_be_used, unsigned int cmd, caddr_t arg) { int val; -/* printk("audio_ioctl(%x, %x)\n", cmd, arg); */ + /* printk("audio_ioctl(%x, %x)\n", (int)cmd, (int)arg); */ dev = dev >> 4; @@ -377,6 +382,8 @@ audio_ioctl (int dev, struct fileinfo *file, if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) return 0; + if (audio_devs[dev]->dmap_out->fragment_size == 0) + return 0; sync_output (dev); DMAbuf_sync (dev); DMAbuf_reset (dev); @@ -386,9 +393,11 @@ audio_ioctl (int dev, struct fileinfo *file, case SNDCTL_DSP_POST: if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) return 0; - audio_devs[dev]->dmap_out->flags |= DMA_POST; + if (audio_devs[dev]->dmap_out->fragment_size == 0) + return 0; + audio_devs[dev]->dmap_out->flags |= DMA_POST | DMA_DIRTY; sync_output (dev); - DMAbuf_ioctl (dev, SNDCTL_DSP_POST, 0, 1); + dma_ioctl (dev, SNDCTL_DSP_POST, (caddr_t) 0); return 0; break; @@ -399,12 +408,12 @@ audio_ioctl (int dev, struct fileinfo *file, break; case SNDCTL_DSP_GETFMTS: - return ioctl_out (arg, audio_devs[dev]->format_mask); + return (*(int *) arg = audio_devs[dev]->format_mask); break; case SNDCTL_DSP_SETFMT: - get_user (val, (int *) arg); - return ioctl_out (arg, set_format (dev, val)); + val = *(int *) arg; + return (*(int *) arg = set_format (dev, val)); case SNDCTL_DSP_GETISPACE: if (!(audio_devs[dev]->open_mode & OPEN_READ)) @@ -415,16 +424,12 @@ audio_ioctl (int dev, struct fileinfo *file, { audio_buf_info info; - int err = DMAbuf_ioctl (dev, cmd, (caddr_t) & info, 1); + int err = dma_ioctl (dev, cmd, (caddr_t) & info); if (err < 0) return err; - { - char *fixit = (char *) &info; - - copy_to_user (&((char *) arg)[0], fixit, sizeof (info)); - }; + memcpy ((&((char *) arg)[0]), (char *) &info, sizeof (info)); return 0; } @@ -436,22 +441,13 @@ audio_ioctl (int dev, struct fileinfo *file, { audio_buf_info info; - char *dma_buf; - int buf_no, buf_ptr, buf_size; - int err = DMAbuf_ioctl (dev, cmd, (caddr_t) & info, 1); + int err = dma_ioctl (dev, cmd, (caddr_t) & info); if (err < 0) return err; - if (DMAbuf_get_curr_buffer (dev, &buf_no, &dma_buf, &buf_ptr, &buf_size) >= 0) - info.bytes -= buf_ptr; - - { - char *fixit = (char *) &info; - - copy_to_user (&((char *) arg)[0], fixit, sizeof (info)); - }; + memcpy ((&((char *) arg)[0]), (char *) &info, sizeof (info)); return 0; } @@ -464,7 +460,8 @@ audio_ioctl (int dev, struct fileinfo *file, { int info = 1; /* Revision level of this ioctl() */ - if (audio_devs[dev]->flags & DMA_DUPLEX) + if (audio_devs[dev]->flags & DMA_DUPLEX && + audio_devs[dev]->open_mode == OPEN_READWRITE) info |= DSP_CAP_DUPLEX; if (audio_devs[dev]->coproc) @@ -478,59 +475,65 @@ audio_ioctl (int dev, struct fileinfo *file, info |= DSP_CAP_MMAP; - { - char *fixit = (char *) &info; - - copy_to_user (&((char *) arg)[0], fixit, sizeof (info)); - }; + memcpy ((&((char *) arg)[0]), (char *) &info, sizeof (info)); return 0; } break; case SOUND_PCM_WRITE_RATE: - get_user (val, (int *) arg); - return ioctl_out (arg, audio_devs[dev]->d->set_speed (dev, val)); + val = *(int *) arg; + return (*(int *) arg = audio_devs[dev]->d->set_speed (dev, val)); case SOUND_PCM_READ_RATE: - return ioctl_out (arg, audio_devs[dev]->d->set_speed (dev, 0)); + return (*(int *) arg = audio_devs[dev]->d->set_speed (dev, 0)); case SNDCTL_DSP_STEREO: { int n; - get_user (n, (int *) arg); + n = *(int *) arg; if (n > 1) { printk ("sound: SNDCTL_DSP_STEREO called with invalid argument %d\n", n); - return ioctl_out (arg, audio_devs[dev]->d->set_channels (dev, n)); + return -EINVAL; } if (n < 0) return -EINVAL; - return ioctl_out (arg, audio_devs[dev]->d->set_channels (dev, n + 1) - 1); + return (*(int *) arg = audio_devs[dev]->d->set_channels (dev, n + 1) - 1); } case SOUND_PCM_WRITE_CHANNELS: - get_user (val, (int *) arg); - return ioctl_out (arg, audio_devs[dev]->d->set_channels (dev, val)); + val = *(int *) arg; + return (*(int *) arg = audio_devs[dev]->d->set_channels (dev, val)); case SOUND_PCM_READ_CHANNELS: - return ioctl_out (arg, audio_devs[dev]->d->set_channels (dev, 0)); + return (*(int *) arg = audio_devs[dev]->d->set_channels (dev, 0)); case SOUND_PCM_READ_BITS: - return ioctl_out (arg, audio_devs[dev]->d->set_bits (dev, 0)); + return (*(int *) arg = audio_devs[dev]->d->set_bits (dev, 0)); case SNDCTL_DSP_SETDUPLEX: + if (audio_devs[dev]->open_mode != OPEN_READWRITE) + return -EPERM; if (audio_devs[dev]->flags & DMA_DUPLEX) return 0; else return -EIO; break; + case SNDCTL_DSP_PROFILE: + if (audio_devs[dev]->open_mode & OPEN_WRITE) + audio_devs[dev]->dmap_out->applic_profile = *(int *) arg; + if (audio_devs[dev]->open_mode & OPEN_READ) + audio_devs[dev]->dmap_in->applic_profile = *(int *) arg; + return 0; + break; + default: - return DMAbuf_ioctl (dev, cmd, arg, 0); + return dma_ioctl (dev, cmd, arg); } } @@ -543,16 +546,15 @@ audio_init_devices (void) } int -audio_select (int dev, struct fileinfo *file, int sel_type, select_table * wait) +audio_select (int dev, struct fileinfo *file, int sel_type, poll_table * wait) { - char *dma_buf; - int buf_no, buf_ptr, buf_size; - dev = dev >> 4; switch (sel_type) { case SEL_IN: + if (!(audio_devs[dev]->open_mode & OPEN_READ)) + return 0; if (audio_mode[dev] & AM_WRITE && !(audio_devs[dev]->flags & DMA_DUPLEX)) { return 0; /* Not recording */ @@ -562,16 +564,13 @@ audio_select (int dev, struct fileinfo *file, int sel_type, select_table * wait) break; case SEL_OUT: + if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) + return 0; if (audio_mode[dev] & AM_READ && !(audio_devs[dev]->flags & DMA_DUPLEX)) { return 0; /* Wrong direction */ } - if (DMAbuf_get_curr_buffer (dev, &buf_no, &dma_buf, &buf_ptr, &buf_size) >= 0) - { - return 1; /* There is space in the current buffer */ - } - return DMAbuf_select (dev, file, sel_type, wait); break; @@ -584,3 +583,461 @@ audio_select (int dev, struct fileinfo *file, int sel_type, select_table * wait) #endif + +void +reorganize_buffers (int dev, struct dma_buffparms *dmap, int recording) +{ + /* + * This routine breaks the physical device buffers to logical ones. + */ + + struct audio_operations *dsp_dev = audio_devs[dev]; + + unsigned i, n; + unsigned sr, nc, sz, bsz; + + if (!dmap->needs_reorg) + return; + + sr = dsp_dev->d->set_speed (dev, 0); + nc = dsp_dev->d->set_channels (dev, 0); + sz = dsp_dev->d->set_bits (dev, 0); + dmap->needs_reorg = 0; + + if (sz == 8) + dmap->neutral_byte = NEUTRAL8; + else + dmap->neutral_byte = NEUTRAL16; + + if (sr < 1 || nc < 1 || sz < 1) + { + printk ("Warning: Invalid PCM parameters[%d] sr=%d, nc=%d, sz=%d\n", + dev, sr, nc, sz); + sr = DSP_DEFAULT_SPEED; + nc = 1; + sz = 8; + } + + sz = sr * nc * sz; + + sz /= 8; /* #bits -> #bytes */ + dmap->data_rate = sz; + + if (dmap->fragment_size == 0) + { /* Compute the fragment size using the default algorithm */ + + /* + * Compute a buffer size for time not exceeding 1 second. + * Usually this algorithm gives a buffer size for 0.5 to 1.0 seconds + * of sound (using the current speed, sample size and #channels). + */ + + bsz = dsp_dev->buffsize; + while (bsz > sz) + bsz /= 2; + + if (bsz == dsp_dev->buffsize) + bsz /= 2; /* Needs at least 2 buffers */ + +/* + * Split the computed fragment to smaller parts. After 3.5a9 + * the default subdivision is 4 which should give better + * results when recording. + */ + + if (dmap->subdivision == 0) /* Not already set */ + { + dmap->subdivision = 4; /* Init to the default value */ + + if ((bsz / dmap->subdivision) > 4096) + dmap->subdivision *= 2; + if ((bsz / dmap->subdivision) < 4096) + dmap->subdivision = 1; + } + + bsz /= dmap->subdivision; + + if (bsz < 16) + bsz = 16; /* Just a sanity check */ + + dmap->fragment_size = bsz; + } + else + { + /* + * The process has specified the buffer size with SNDCTL_DSP_SETFRAGMENT or + * the buffer size computation has already been done. + */ + if (dmap->fragment_size > (audio_devs[dev]->buffsize / 2)) + dmap->fragment_size = (audio_devs[dev]->buffsize / 2); + bsz = dmap->fragment_size; + } + + bsz &= ~0x03; /* Force size which is multiple of 4 bytes */ +#ifdef OS_DMA_ALIGN_CHECK + OS_DMA_ALIGN_CHECK (bsz); +#endif + + n = dsp_dev->buffsize / bsz; + if (n > MAX_SUB_BUFFERS) + n = MAX_SUB_BUFFERS; + if (n > dmap->max_fragments) + n = dmap->max_fragments; + + if (n < 2) + { + n = 2; + bsz /= 2; + } + + dmap->nbufs = n; + dmap->bytes_in_use = n * bsz; + dmap->fragment_size = bsz; + + if (dmap->raw_buf) + { + memset (dmap->raw_buf, + dmap->neutral_byte, + dmap->bytes_in_use); + } + + for (i = 0; i < dmap->nbufs; i++) + { + dmap->counts[i] = 0; + } + + dmap->flags |= DMA_ALLOC_DONE | DMA_EMPTY; +} + +static int +dma_subdivide (int dev, struct dma_buffparms *dmap, caddr_t arg, int fact) +{ + if (fact == 0) + { + fact = dmap->subdivision; + if (fact == 0) + fact = 1; + return (*(int *) arg = fact); + } + + if (dmap->subdivision != 0 || + dmap->fragment_size) /* Too late to change */ + return -EINVAL; + + if (fact > MAX_REALTIME_FACTOR) + return -EINVAL; + + if (fact != 1 && fact != 2 && fact != 4 && fact != 8 && fact != 16) + return -EINVAL; + + dmap->subdivision = fact; + return (*(int *) arg = fact); +} + +static int +dma_set_fragment (int dev, struct dma_buffparms *dmap, caddr_t arg, int fact) +{ + int bytes, count; + + if (fact == 0) + return -EIO; + + if (dmap->subdivision != 0 || + dmap->fragment_size) /* Too late to change */ + return -EINVAL; + + bytes = fact & 0xffff; + count = (fact >> 16) & 0x7fff; + + if (count == 0) + count = MAX_SUB_BUFFERS; + + if (bytes < 4 || bytes > 17) /* <16 || > 512k */ + return -EINVAL; + + if (count < 2) + return -EINVAL; + + if (audio_devs[dev]->min_fragment > 0) + if (bytes < audio_devs[dev]->min_fragment) + bytes = audio_devs[dev]->min_fragment; + +#ifdef OS_DMA_MINBITS + if (bytes < OS_DMA_MINBITS) + bytes = OS_DMA_MINBITS; +#endif + + dmap->fragment_size = (1 << bytes); + dmap->max_fragments = count; + + if (dmap->fragment_size > audio_devs[dev]->buffsize) + dmap->fragment_size = audio_devs[dev]->buffsize; + + if (dmap->fragment_size == audio_devs[dev]->buffsize && + audio_devs[dev]->flags & DMA_AUTOMODE) + dmap->fragment_size /= 2; /* Needs at least 2 buffers */ + + dmap->subdivision = 1; /* Disable SNDCTL_DSP_SUBDIVIDE */ + if (arg) + return (*(int *) arg = bytes | (count << 16)); + else + return 0; +} + +static int +dma_ioctl (int dev, unsigned int cmd, caddr_t arg) +{ + + struct dma_buffparms *dmap_out = audio_devs[dev]->dmap_out; + struct dma_buffparms *dmap_in = audio_devs[dev]->dmap_in; + + switch (cmd) + { + + case SNDCTL_DSP_SUBDIVIDE: + { + int fact; + int ret; + + fact = *(int *) arg; + + ret = dma_subdivide (dev, dmap_out, arg, fact); + if (ret < 0) + return ret; + + if (audio_devs[dev]->flags & DMA_DUPLEX && + audio_devs[dev]->open_mode & OPEN_READ) + ret = dma_subdivide (dev, dmap_in, arg, fact); + + return ret; + } + break; + + case SNDCTL_DSP_GETISPACE: + case SNDCTL_DSP_GETOSPACE: + { + struct dma_buffparms *dmap = dmap_out; + + audio_buf_info *info = (audio_buf_info *) arg; + + if (cmd == SNDCTL_DSP_GETISPACE && + !(audio_devs[dev]->open_mode & OPEN_READ)) + return -EINVAL; + + if (cmd == SNDCTL_DSP_GETISPACE && audio_devs[dev]->flags & DMA_DUPLEX) + dmap = dmap_in; + + if (dmap->mapping_flags & DMA_MAP_MAPPED) + return -EINVAL; + + if (!(dmap->flags & DMA_ALLOC_DONE)) + reorganize_buffers (dev, dmap, (cmd == SNDCTL_DSP_GETISPACE)); + + info->fragstotal = dmap->nbufs; + + if (cmd == SNDCTL_DSP_GETISPACE) + info->fragments = dmap->qlen; + else + { + if (!DMAbuf_space_in_queue (dev)) + info->fragments = 0; + else + { + info->fragments = dmap->nbufs - dmap->qlen; + if (audio_devs[dev]->d->local_qlen) + { + int tmp = audio_devs[dev]->d->local_qlen (dev); + + if (tmp && info->fragments) + tmp--; /* + * This buffer has been counted twice + */ + info->fragments -= tmp; + } + } + } + + if (info->fragments < 0) + info->fragments = 0; + else if (info->fragments > dmap->nbufs) + info->fragments = dmap->nbufs; + + info->fragsize = dmap->fragment_size; + info->bytes = info->fragments * dmap->fragment_size; + + if (cmd == SNDCTL_DSP_GETISPACE && dmap->qlen) + info->bytes -= dmap->counts[dmap->qhead]; + } + return 0; + + case SNDCTL_DSP_SETTRIGGER: + { + unsigned long flags; + + int bits; + int changed; + + bits = *(int *) arg; + bits &= audio_devs[dev]->open_mode; + + if (audio_devs[dev]->d->trigger == NULL) + return -EINVAL; + + if (!(audio_devs[dev]->flags & DMA_DUPLEX)) + if ((bits & PCM_ENABLE_INPUT) && (bits & PCM_ENABLE_OUTPUT)) + { + printk ("Sound: Device doesn't have full duplex capability\n"); + return -EINVAL; + } + + save_flags (flags); + cli (); + changed = audio_devs[dev]->enable_bits ^ bits; + + if ((changed & bits) & PCM_ENABLE_INPUT && audio_devs[dev]->go) + { + int err; + + reorganize_buffers (dev, dmap_in, 1); + + if ((err = audio_devs[dev]->d->prepare_for_input (dev, + dmap_in->fragment_size, dmap_in->nbufs)) < 0) + return -err; + + audio_devs[dev]->enable_bits = bits; + DMAbuf_activate_recording (dev, dmap_in); + } + + + if ((changed & bits) & PCM_ENABLE_OUTPUT && + (dmap_out->mapping_flags & DMA_MAP_MAPPED || dmap_out->qlen > 0) && + audio_devs[dev]->go) + { + + if (!(dmap_out->flags & DMA_ALLOC_DONE)) + { + reorganize_buffers (dev, dmap_out, 0); + } + + ; + dmap_out->counts[dmap_out->qhead] = dmap_out->fragment_size; + DMAbuf_launch_output (dev, dmap_out); + ; + } + + audio_devs[dev]->enable_bits = bits; + if (changed && audio_devs[dev]->d->trigger) + { + audio_devs[dev]->d->trigger (dev, bits * audio_devs[dev]->go); + } + restore_flags (flags); + } + case SNDCTL_DSP_GETTRIGGER: + return (*(int *) arg = audio_devs[dev]->enable_bits); + break; + + case SNDCTL_DSP_SETSYNCRO: + + if (!audio_devs[dev]->d->trigger) + return -EINVAL; + + audio_devs[dev]->d->trigger (dev, 0); + audio_devs[dev]->go = 0; + return 0; + break; + + case SNDCTL_DSP_GETIPTR: + { + count_info info; + unsigned long flags; + + if (!(audio_devs[dev]->open_mode & OPEN_READ)) + return -EINVAL; + + save_flags (flags); + cli (); + info.bytes = audio_devs[dev]->dmap_in->byte_counter; + info.ptr = DMAbuf_get_buffer_pointer (dev, audio_devs[dev]->dmap_in) & ~3; + info.blocks = audio_devs[dev]->dmap_in->qlen; + info.bytes += info.ptr; + memcpy ((&((char *) arg)[0]), (char *) &info, sizeof (info)); + + if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED) + audio_devs[dev]->dmap_in->qlen = 0; /* Reset interrupt counter */ + restore_flags (flags); + return 0; + } + break; + + case SNDCTL_DSP_GETOPTR: + { + count_info info; + unsigned long flags; + + if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) + return -EINVAL; + + save_flags (flags); + cli (); + info.bytes = audio_devs[dev]->dmap_out->byte_counter; + info.ptr = DMAbuf_get_buffer_pointer (dev, audio_devs[dev]->dmap_out) & ~3; + info.blocks = audio_devs[dev]->dmap_out->qlen; + info.bytes += info.ptr; + memcpy ((&((char *) arg)[0]), (char *) &info, sizeof (info)); + + if (audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED) + audio_devs[dev]->dmap_out->qlen = 0; /* Reset interrupt counter */ + + restore_flags (flags); + return 0; + } + break; + + + case SNDCTL_DSP_POST: + ; + if (audio_devs[dev]->dmap_out->qlen > 0) + if (!(audio_devs[dev]->dmap_out->flags & DMA_ACTIVE)) + DMAbuf_launch_output (dev, audio_devs[dev]->dmap_out); + ; + return 0; + break; + + case SNDCTL_DSP_GETBLKSIZE: + if (!(dmap_out->flags & DMA_ALLOC_DONE)) + { + if (audio_devs[dev]->open_mode & OPEN_WRITE) + reorganize_buffers (dev, dmap_out, + (audio_devs[dev]->open_mode == OPEN_READ)); + if (audio_devs[dev]->flags & DMA_DUPLEX && + audio_devs[dev]->open_mode & OPEN_READ) + reorganize_buffers (dev, dmap_in, + (audio_devs[dev]->open_mode == OPEN_READ)); + } + + return (*(int *) arg = dmap_out->fragment_size); + break; + + case SNDCTL_DSP_SETFRAGMENT: + { + int fact; + int ret; + + fact = *(int *) arg; + ret = dma_set_fragment (dev, dmap_out, arg, fact); + if (ret < 0) + return ret; + + if (audio_devs[dev]->flags & DMA_DUPLEX && + audio_devs[dev]->open_mode & OPEN_READ) + ret = dma_set_fragment (dev, dmap_in, arg, fact); + + return ret; + } + break; + + default: + return audio_devs[dev]->d->ioctl (dev, cmd, arg); + } + +} -- cgit v1.2.3