diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1998-08-25 09:12:35 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1998-08-25 09:12:35 +0000 |
commit | c7fc24dc4420057f103afe8fc64524ebc25c5d37 (patch) | |
tree | 3682407a599b8f9f03fc096298134cafba1c9b2f /drivers/sbus/audio/audio.c | |
parent | 1d793fade8b063fde3cf275bf1a5c2d381292cd9 (diff) |
o Merge with Linux 2.1.116.
o New Newport console code.
o New G364 console code.
Diffstat (limited to 'drivers/sbus/audio/audio.c')
-rw-r--r-- | drivers/sbus/audio/audio.c | 682 |
1 files changed, 434 insertions, 248 deletions
diff --git a/drivers/sbus/audio/audio.c b/drivers/sbus/audio/audio.c index ba9563449..ab14e2767 100644 --- a/drivers/sbus/audio/audio.c +++ b/drivers/sbus/audio/audio.c @@ -2,6 +2,12 @@ * drivers/sbus/audio/audio.c * * Copyright (C) 1996,1997 Thomas K. Dyas (tdyas@eden.rutgers.edu) + * Copyright (C) 1997 Derrick J. Brashear (shadow@dementia.org) + * Copyright (C) 1997 Brent Baccala (baccala@freesoft.org) + * + * Mixer code adapted from code contributed by and + * Copyright (C) 1998 Michael Mraka (michael@fi.muni.cz) + * * * This is the audio midlayer that sits between the VFS character * devices and the low-level audio hardware device drivers. @@ -21,8 +27,9 @@ #include <linux/init.h> #include <linux/soundcard.h> #include <asm/uaccess.h> +#include <asm/pgtable.h> -#include "audio.h" +#include <asm/audioio.h> /* @@ -47,17 +54,18 @@ int register_sparcaudio_driver(struct sparcaudio_driver *drv) /* Setup the circular queues of output and input buffers * * Each buffer is a single page, but output buffers might - * be partially filled (by a write with count < PAGE_SIZE), + * be partially filled (by a write with count < 4096), * so each output buffer also has a paired output size. * * Input buffers, on the other hand, always fill completely, - * so we don't need input counts - each contains PAGE_SIZE + * so we don't need input counts - each contains 4096 * bytes of audio data. * * TODO: Make number of input/output buffers tunable parameters */ drv->num_output_buffers = 32; + drv->playing_count = 0; drv->output_front = 0; drv->output_rear = 0; drv->output_count = 0; @@ -74,6 +82,7 @@ int register_sparcaudio_driver(struct sparcaudio_driver *drv) /* Setup the circular queue of input buffers. */ drv->num_input_buffers = 32; + drv->recording_count = 0; drv->input_front = 0; drv->input_rear = 0; drv->input_count = 0; @@ -143,28 +152,25 @@ int unregister_sparcaudio_driver(struct sparcaudio_driver *drv) return 0; } -static void sparcaudio_output_done_task(void * arg) +void sparcaudio_output_done(struct sparcaudio_driver * drv, int reclaim) { - struct sparcaudio_driver *drv = (struct sparcaudio_driver *)arg; - unsigned long flags; + /* Reclaim a buffer unless it's still in the DMA pipe */ + if (reclaim) { + if (drv->output_count > 0) + drv->output_count--; + else + if (drv->playing_count > 0) + drv->playing_count--; + } else + drv->playing_count++; - save_and_cli(flags); - drv->ops->start_output(drv, - drv->output_buffers[drv->output_front], - drv->output_sizes[drv->output_front]); - drv->output_active = 1; - restore_flags(flags); -} - -void sparcaudio_output_done(struct sparcaudio_driver * drv) -{ /* Point the queue after the "done" buffer. */ drv->output_size -= drv->output_sizes[drv->output_front]; drv->output_front = (drv->output_front + 1) % drv->num_output_buffers; - drv->output_count--; /* If the output queue is empty, shutdown the driver. */ if (drv->output_count == 0) { + if (drv->playing_count == 0) { /* Stop the lowlevel driver from outputing. */ drv->ops->stop_output(drv); drv->output_active = 0; @@ -173,19 +179,17 @@ void sparcaudio_output_done(struct sparcaudio_driver * drv) wake_up_interruptible(&drv->output_write_wait); wake_up_interruptible(&drv->output_drain_wait); return; + } } - /* Otherwise, queue a task to give the driver the next buffer. */ - drv->tqueue.next = NULL; - drv->tqueue.sync = 0; - drv->tqueue.routine = sparcaudio_output_done_task; - drv->tqueue.data = drv; + /* If we got back a buffer, see if anyone wants to write to it */ + if (reclaim || ((drv->output_count + drv->playing_count) + < drv->num_output_buffers)) + wake_up_interruptible(&drv->output_write_wait); + + drv->ops->start_output(drv, drv->output_buffers[drv->output_front], + drv->output_sizes[drv->output_front]); - queue_task(&drv->tqueue, &tq_immediate); - mark_bh(IMMEDIATE_BH); - - /* Wake up any tasks that are waiting. */ - wake_up_interruptible(&drv->output_write_wait); } void sparcaudio_input_done(struct sparcaudio_driver * drv) @@ -202,7 +206,7 @@ void sparcaudio_input_done(struct sparcaudio_driver * drv) } else { /* Otherwise, give the driver the next buffer. */ drv->ops->start_input(drv, drv->input_buffers[drv->input_front], - PAGE_SIZE); + 4096); } /* Wake up any tasks that are waiting. */ @@ -234,7 +238,7 @@ static ssize_t sparcaudio_read(struct file * file, return -EINTR; } - bytes_to_copy = PAGE_SIZE - driver->input_offset; + bytes_to_copy = 4096 - driver->input_offset; if (bytes_to_copy > count) bytes_to_copy = count; @@ -242,7 +246,7 @@ static ssize_t sparcaudio_read(struct file * file, bytes_to_copy, -EFAULT); driver->input_offset += bytes_to_copy; - if (driver->input_offset >= PAGE_SIZE) { + if (driver->input_offset >= 4096) { driver->input_rear = (driver->input_rear + 1) % driver->num_input_buffers; driver->input_count--; driver->input_offset = 0; @@ -263,11 +267,11 @@ static void sparcaudio_sync_output(struct sparcaudio_driver * driver) /* If the low-level driver is not active, activate it. */ save_and_cli(flags); - if (! driver->output_active) { - driver->ops->start_output(driver, - driver->output_buffers[driver->output_front], - driver->output_sizes[driver->output_front]); - driver->output_active = 1; + if ((!driver->output_active) && (driver->output_count > 0)) { + driver->ops->start_output(driver, + driver->output_buffers[driver->output_front], + driver->output_sizes[driver->output_front]); + driver->output_active = 1; } restore_flags(flags); } @@ -277,59 +281,184 @@ static ssize_t sparcaudio_write(struct file * file, const char *buf, { int bytes_written = 0, bytes_to_copy; - /* Ensure that we have something to write. */ - if (count < 1) { - sparcaudio_sync_output(driver); - return 0; - } + if (! file->f_mode & FMODE_WRITE) + return -EINVAL; /* Loop until all output is written to device. */ while (count > 0) { - /* Check to make sure that an output buffer is available. */ - /* If not, make valiant attempt */ - if (driver->output_count == driver->num_output_buffers) - sparcaudio_reorganize_buffers(driver); - - if (driver->output_count == driver->num_output_buffers) { - /* We need buffers, so... */ - sparcaudio_sync_output(driver); - interruptible_sleep_on(&driver->output_write_wait); - if (signal_pending(current)) - return bytes_written > 0 ? bytes_written : -EINTR; + /* Check to make sure that an output buffer is available. */ + /* If not, make valiant attempt */ + if (driver->num_output_buffers == + (driver->output_count + driver->playing_count)) + sparcaudio_reorganize_buffers(driver); + + if (driver->num_output_buffers == + (driver->output_count + driver->playing_count)) { + /* We need buffers, so... */ + sparcaudio_sync_output(driver); + interruptible_sleep_on(&driver->output_write_wait); + if (signal_pending(current)) + return bytes_written > 0 ? bytes_written : -EINTR; } - /* Determine how much we can copy in this iteration. */ - bytes_to_copy = count; - if (bytes_to_copy > PAGE_SIZE) - bytes_to_copy = PAGE_SIZE; + /* No buffers were freed. Go back to sleep */ + if (driver->num_output_buffers == + (driver->output_count + driver->playing_count)) + continue; + + /* Determine how much we can copy in this iteration. */ + bytes_to_copy = count; + if (bytes_to_copy > 4096) + bytes_to_copy = 4096; - copy_from_user_ret(driver->output_buffers[driver->output_rear], + copy_from_user_ret(driver->output_buffers[driver->output_rear], buf, bytes_to_copy, -EFAULT); - /* Update the queue pointers. */ - buf += bytes_to_copy; - count -= bytes_to_copy; - bytes_written += bytes_to_copy; - driver->output_sizes[driver->output_rear] = bytes_to_copy; - driver->output_rear = (driver->output_rear + 1) % driver->num_output_buffers; - driver->output_count++; - driver->output_size += bytes_to_copy; - - /* Activate the driver if more than page of data is waiting. */ - if (driver->output_size > 4096) - sparcaudio_sync_output(driver); + /* Update the queue pointers. */ + buf += bytes_to_copy; + count -= bytes_to_copy; + bytes_written += bytes_to_copy; + driver->output_sizes[driver->output_rear] = bytes_to_copy; + driver->output_rear = (driver->output_rear + 1) % driver->num_output_buffers; + driver->output_count++; + driver->output_size += bytes_to_copy; } + sparcaudio_sync_output(driver); /* Return the number of bytes written to the caller. */ return bytes_written; } +#define COPY_IN(arg, get) get_user(get, (int *)arg) +#define COPY_OUT(arg, ret) put_user(ret, (int *)arg) + +/* Add these in as new devices are supported. Belongs in audioio.h, actually */ +#define SUPPORTED_MIXER_DEVICES (SOUND_MASK_VOLUME) +#define MONO_DEVICES (SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_SPEAKER | SOUND_MASK_MIC) + +static inline int sparcaudio_mixer_ioctl(struct inode * inode, struct file * file, + unsigned int cmd, unsigned long arg) +{ + int i = 0, j = 0; + if (_IOC_DIR(cmd) & _IOC_WRITE) { + /* For any missing routines, pretend we changed things anyhow for now */ + switch (cmd & 0xff) { + case SOUND_MIXER_VOLUME: + if (driver->ops->get_output_channels) + j = driver->ops->get_output_channels(driver); + COPY_IN(arg, i); + if (j == 1) { + i = s_to_m(i); + if (driver->ops->set_output_volume) + driver->ops->set_output_volume(driver, i * 255/100); + if (driver->ops->get_output_volume) + i = driver->ops->get_output_volume(driver); + i = m_to_s(i); + } else { + /* there should be stuff here which calculates balance and + volume on a stereo device. will do it eventually */ + i = s_to_g(i); + if (driver->ops->set_output_volume) + driver->ops->set_output_volume(driver, i * 255/100); + if (driver->ops->get_output_volume) + i = driver->ops->get_output_volume(driver); + j = s_to_b(i); + if (driver->ops->set_output_balance) + driver->ops->set_output_balance(driver, j); + if (driver->ops->get_output_balance) + j = driver->ops->get_output_balance(driver); + i = b_to_s(i,j); + } + return COPY_OUT(arg, i); + default: + /* Play like we support other things */ + return COPY_OUT(arg, i); + } + } else { + switch (cmd & 0xff) { + case SOUND_MIXER_RECSRC: + if (driver->ops->get_input_port) + i = driver->ops->get_input_port(driver); + /* only one should ever be selected */ + if (i & AUDIO_ANALOG_LOOPBACK) j = SOUND_MASK_IMIX; /* ? */ + if (i & AUDIO_CD) j = SOUND_MASK_CD; + if (i & AUDIO_LINE_IN) j = SOUND_MASK_LINE; + if (i & AUDIO_MICROPHONE) j = SOUND_MASK_MIC; + + return COPY_OUT(arg, j); + + case SOUND_MIXER_RECMASK: + if (driver->ops->get_input_ports) + i = driver->ops->get_input_ports(driver); + /* what do we support? */ + if (i & AUDIO_MICROPHONE) j |= SOUND_MASK_MIC; + if (i & AUDIO_LINE_IN) j |= SOUND_MASK_LINE; + if (i & AUDIO_CD) j |= SOUND_MASK_CD; + if (i & AUDIO_ANALOG_LOOPBACK) j |= SOUND_MASK_IMIX; /* ? */ + + return COPY_OUT(arg, j); + + case SOUND_MIXER_CAPS: /* mixer capabilities */ + i = SOUND_CAP_EXCL_INPUT; + return COPY_OUT(arg, i); + + case SOUND_MIXER_DEVMASK: /* all supported devices */ + case SOUND_MIXER_STEREODEVS: /* what supports stereo */ + if (driver->ops->get_input_ports) + i = driver->ops->get_input_ports(driver); + /* what do we support? */ + if (i & AUDIO_MICROPHONE) j |= SOUND_MASK_MIC; + if (i & AUDIO_LINE_IN) j |= SOUND_MASK_LINE; + if (i & AUDIO_CD) j |= SOUND_MASK_CD; + if (i & AUDIO_ANALOG_LOOPBACK) j |= SOUND_MASK_IMIX; /* ? */ + + if (driver->ops->get_output_ports) + i = driver->ops->get_output_ports(driver); + if (i & AUDIO_SPEAKER) j |= SOUND_MASK_SPEAKER; + if (i & AUDIO_HEADPHONE) j |= SOUND_MASK_LINE; /* ? */ + if (i & AUDIO_LINE_OUT) j |= SOUND_MASK_LINE; + + j |= SOUND_MASK_VOLUME; + + if ((cmd & 0xff) == SOUND_MIXER_STEREODEVS) + j &= ~(MONO_DEVICES); + return COPY_OUT(arg, j); + + case SOUND_MIXER_VOLUME: + if (driver->ops->get_output_channels) + j = driver->ops->get_output_channels(driver); + if (j == 1) { + if (driver->ops->get_output_volume) + i = driver->ops->get_output_volume(driver); + i = m_to_s(i); + } else { + /* there should be stuff here which calculates balance and + volume on a stereo device. will do it eventually */ + if (driver->ops->get_output_volume) + i = driver->ops->get_output_volume(driver); + if (driver->ops->get_output_balance) + j = driver->ops->get_output_balance(driver); + i = b_to_s(i,j); + } + return COPY_OUT(arg, i); + + default: + /* Play like we support other things */ + return COPY_OUT(arg, i); + } + } +} + static int sparcaudio_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg) { int retval = 0; struct audio_info ainfo; + if (((cmd >> 8) & 0xff) == 'M') { + return sparcaudio_mixer_ioctl(inode, file, cmd, arg); + } + switch (cmd) { case SNDCTL_DSP_SYNC: case AUDIO_DRAIN: @@ -339,6 +468,40 @@ static int sparcaudio_ioctl(struct inode * inode, struct file * file, } break; + case AUDIO_FLUSH: + if (driver->output_active && (file->f_mode & FMODE_WRITE)) { + wake_up_interruptible(&driver->output_write_wait); + driver->ops->stop_output(driver); + driver->output_active = 0; + driver->output_front = 0; + driver->output_rear = 0; + driver->output_count = 0; + driver->output_size = 0; + driver->playing_count = 0; + } + if (driver->input_active && (file->f_mode & FMODE_READ)) { + wake_up_interruptible(&driver->input_read_wait); + driver->ops->stop_input(driver); + driver->input_active = 0; + driver->input_front = 0; + driver->input_rear = 0; + driver->input_count = 0; + driver->recording_count = 0; + } + if ((file->f_mode & FMODE_READ) && + !(driver->flags & SDF_OPEN_READ)) { + driver->ops->start_input(driver, + driver->input_buffers[driver->input_front], + 4096); + driver->input_active = 1; + } + if ((file->f_mode & FMODE_WRITE) && + !(driver->flags & SDF_OPEN_WRITE)) { + sparcaudio_sync_output(driver); + } + break; + + case AUDIO_GETDEV: if (driver->ops->sunaudio_getdev) { audio_device_t tmp; @@ -349,18 +512,17 @@ static int sparcaudio_ioctl(struct inode * inode, struct file * file, } else retval = -EINVAL; - printk(KERN_INFO "sparcaudio_ioctl: AUDIO_GETDEV\n"); break; case AUDIO_GETDEV_SUNOS: if (driver->ops->sunaudio_getdev_sunos) { int tmp=driver->ops->sunaudio_getdev_sunos(driver); - copy_to_user_ret((int *)arg, &tmp, sizeof(tmp), -EFAULT); + if (put_user(tmp, (int *)arg)) + retval = -EFAULT; } else retval = -EINVAL; - printk(KERN_INFO "sparcaudio_ioctl: AUDIO_GETDEV_SUNOS\n"); break; case AUDIO_GETINFO: @@ -388,7 +550,7 @@ static int sparcaudio_ioctl(struct inode * inode, struct file * file, if (driver->ops->get_input_ports) ainfo.record.avail_ports = driver->ops->get_input_ports(driver); - ainfo.record.buffer_size = PAGE_SIZE; + ainfo.record.buffer_size = 4096; ainfo.record.samples = 0; ainfo.record.eof = 0; ainfo.record.pause = 0; @@ -422,7 +584,8 @@ static int sparcaudio_ioctl(struct inode * inode, struct file * file, if (driver->ops->get_output_ports) ainfo.play.avail_ports = driver->ops->get_output_ports(driver); - ainfo.play.buffer_size = PAGE_SIZE; + /* This is not defined in the play context in Solaris */ + ainfo.play.buffer_size = 0; ainfo.play.samples = 0; ainfo.play.eof = 0; ainfo.play.pause = 0; @@ -430,7 +593,7 @@ static int sparcaudio_ioctl(struct inode * inode, struct file * file, ainfo.play.waiting = waitqueue_active(&driver->open_wait); if (driver->ops->get_output_balance) ainfo.play.balance = - driver->ops->get_output_balance(driver); + (unsigned char)driver->ops->get_output_balance(driver); ainfo.play.minordev = 4; ainfo.play.open = 1; ainfo.play.active = driver->output_active; @@ -441,9 +604,7 @@ static int sparcaudio_ioctl(struct inode * inode, struct file * file, if (driver->ops->get_output_muted) ainfo.output_muted = - driver->ops->get_output_muted(driver); - - printk("sparcaudio_ioctl: AUDIO_GETINFO\n"); + (unsigned char)driver->ops->get_output_muted(driver); copy_to_user_ret((struct audio_info *)arg, &ainfo, sizeof(ainfo), -EFAULT); @@ -452,7 +613,7 @@ static int sparcaudio_ioctl(struct inode * inode, struct file * file, case AUDIO_SETINFO: { - audio_info_t curinfo; + audio_info_t curinfo, newinfo; copy_from_user_ret(&ainfo, (audio_info_t *) arg, sizeof(audio_info_t), -EFAULT); @@ -531,61 +692,56 @@ static int sparcaudio_ioctl(struct inode * inode, struct file * file, break; } - curinfo.record.encoding = (Modify(ainfo.record.encoding) ? - ainfo.record.encoding : - driver->ops->get_input_encoding(driver)); - curinfo.record.sample_rate = (Modify(ainfo.record.sample_rate) ? - ainfo.record.sample_rate : - driver->ops->get_input_rate(driver)); - curinfo.record.precision = (Modify(ainfo.record.precision) ? - ainfo.record.precision : - driver->ops->get_input_precision(driver)); - curinfo.record.channels = (Modify(ainfo.record.channels) ? - ainfo.record.channels : - driver->ops->get_input_channels(driver)); - switch (curinfo.record.encoding) { + curinfo.record.encoding = driver->ops->get_input_encoding(driver); + curinfo.record.sample_rate = driver->ops->get_input_rate(driver); + curinfo.record.precision = driver->ops->get_input_precision(driver); + curinfo.record.channels = driver->ops->get_input_channels(driver); + newinfo.record.encoding = Modify(ainfo.record.encoding) ? + ainfo.record.encoding : curinfo.record.encoding; + newinfo.record.sample_rate = Modify(ainfo.record.sample_rate)? + ainfo.record.sample_rate : curinfo.record.sample_rate; + newinfo.record.precision = Modify(ainfo.record.precision) ? + ainfo.record.precision : curinfo.record.precision; + newinfo.record.channels = Modify(ainfo.record.channels) ? + ainfo.record.channels : curinfo.record.channels; + + switch (newinfo.record.encoding) { case AUDIO_ENCODING_ALAW: case AUDIO_ENCODING_ULAW: - if (Modify(ainfo.record.precision) && - ainfo.record.precision != 8) { - retval = -EINVAL; - break; - } - if (Modify(ainfo.record.channels) && - ainfo.record.channels != 1) { - retval = -EINVAL; - break; - } - break; - case AUDIO_ENCODING_LINEAR: - case AUDIO_ENCODING_LINEARLE: - if (Modify(ainfo.record.precision) && - ainfo.record.precision != 16) { - retval = -EINVAL; - break; - } - if (Modify(ainfo.record.channels) && - (ainfo.record.channels != 1 && - ainfo.record.channels != 2)) - { - retval = -EINVAL; - break; - } - break; - case AUDIO_ENCODING_LINEAR8: - if (Modify(ainfo.record.precision) && - ainfo.record.precision != 8) { - retval = -EINVAL; - break; - } - if (Modify(ainfo.record.channels) && - (ainfo.record.channels != 1 && - ainfo.record.channels != 2)) - { - retval = -EINVAL; - break; - } - } + if (newinfo.record.precision != 8) { + retval = -EINVAL; + break; + } + if (newinfo.record.channels != 1) { + retval = -EINVAL; + break; + } + break; + case AUDIO_ENCODING_LINEAR: + case AUDIO_ENCODING_LINEARLE: + if (newinfo.record.precision != 16) { + retval = -EINVAL; + break; + } + if (newinfo.record.channels != 1 && + newinfo.record.channels != 2) + { + retval = -EINVAL; + break; + } + break; + case AUDIO_ENCODING_LINEAR8: + if (newinfo.record.precision != 8) { + retval = -EINVAL; + break; + } + if (newinfo.record.channels != 1 && + newinfo.record.channels != 2) + { + retval = -EINVAL; + break; + } + } if (retval < 0) break; @@ -604,61 +760,56 @@ static int sparcaudio_ioctl(struct inode * inode, struct file * file, break; } - curinfo.play.encoding = (Modify(ainfo.play.encoding) ? - ainfo.play.encoding : - driver->ops->get_output_encoding(driver)); - curinfo.play.sample_rate = (Modify(ainfo.play.sample_rate) ? - ainfo.play.sample_rate : - driver->ops->get_output_rate(driver)); - curinfo.play.precision = (Modify(ainfo.play.precision) ? - ainfo.play.precision : - driver->ops->get_output_precision(driver)); - curinfo.play.channels = (Modify(ainfo.play.channels) ? - ainfo.play.channels : - driver->ops->get_output_channels(driver)); - switch (curinfo.play.encoding) { + curinfo.play.encoding = driver->ops->get_output_encoding(driver); + curinfo.play.sample_rate = driver->ops->get_output_rate(driver); + curinfo.play.precision = driver->ops->get_output_precision(driver); + curinfo.play.channels = driver->ops->get_output_channels(driver); + newinfo.play.encoding = Modify(ainfo.play.encoding) ? + ainfo.play.encoding : curinfo.play.encoding; + newinfo.play.sample_rate = Modify(ainfo.play.sample_rate) ? + ainfo.play.sample_rate : curinfo.play.sample_rate; + newinfo.play.precision = Modify(ainfo.play.precision) ? + ainfo.play.precision : curinfo.play.precision; + newinfo.play.channels = Modify(ainfo.play.channels) ? + ainfo.play.channels : curinfo.play.channels; + + switch (newinfo.play.encoding) { case AUDIO_ENCODING_ALAW: case AUDIO_ENCODING_ULAW: - if (Modify(ainfo.play.precision) && - ainfo.play.precision != 8) { - retval = -EINVAL; - break; - } - if (Modify(ainfo.play.channels) && - ainfo.play.channels != 1) { - retval = -EINVAL; - break; - } - break; - case AUDIO_ENCODING_LINEAR: - case AUDIO_ENCODING_LINEARLE: - if (Modify(ainfo.play.precision) && - ainfo.play.precision != 16) { - retval = -EINVAL; - break; - } - if (Modify(ainfo.play.channels) && - (ainfo.play.channels != 1 && - ainfo.play.channels != 2)) - { - retval = -EINVAL; - break; - } - break; - case AUDIO_ENCODING_LINEAR8: - if (Modify(ainfo.play.precision) && - ainfo.play.precision != 8) { - retval = -EINVAL; - break; - } - if (Modify(ainfo.play.channels) && - (ainfo.play.channels != 1 && - ainfo.play.channels != 2)) - { - retval = -EINVAL; - break; - } - } + if (newinfo.play.precision != 8) { + retval = -EINVAL; + break; + } + if (newinfo.play.channels != 1) { + retval = -EINVAL; + break; + } + break; + case AUDIO_ENCODING_LINEAR: + case AUDIO_ENCODING_LINEARLE: + if (newinfo.play.precision != 16) { + retval = -EINVAL; + break; + } + if (newinfo.play.channels != 1 && + newinfo.play.channels != 2) + { + retval = -EINVAL; + break; + } + break; + case AUDIO_ENCODING_LINEAR8: + if (newinfo.play.precision != 8) { + retval = -EINVAL; + break; + } + if (newinfo.play.channels != 1 && + newinfo.play.channels != 2) + { + retval = -EINVAL; + break; + } + } if (retval < 0) break; @@ -686,8 +837,20 @@ static int sparcaudio_ioctl(struct inode * inode, struct file * file, } } + /* Maybe this should be a routine instead of a macro */ +#define IF_SET_DO(x,y) if ((x) && Modify(y)) x(driver, y) +#define IF_SETC_DO(x,y) if ((x) && Modifyc(y)) x(driver, y) + IF_SETC_DO(driver->ops->set_input_balance, (int)ainfo.record.balance); + IF_SETC_DO(driver->ops->set_output_balance, (int)ainfo.play.balance); + IF_SET_DO(driver->ops->set_input_volume, ainfo.record.gain); + IF_SET_DO(driver->ops->set_output_volume, ainfo.play.gain); + IF_SET_DO(driver->ops->set_input_port, ainfo.record.port); + IF_SET_DO(driver->ops->set_output_port, ainfo.play.port); + IF_SET_DO(driver->ops->set_monitor_volume, ainfo.monitor_gain); + IF_SETC_DO(driver->ops->set_output_muted, (int)ainfo.output_muted); +#undef IF_SET_DO +#undef IF_SETC_DO - printk("sparcaudio_ioctl: AUDIO_SETINFO\n"); break; } @@ -696,8 +859,6 @@ static int sparcaudio_ioctl(struct inode * inode, struct file * file, retval = driver->ops->ioctl(inode,file,cmd,arg,driver); else { retval = -EINVAL; - - printk("sparcaudio_ioctl: 0x%x\n", cmd); } } @@ -725,77 +886,83 @@ static struct file_operations sparcaudioctl_fops = { static int sparcaudio_open(struct inode * inode, struct file * file) { - int err; - - /* A low-level audio driver must exist. */ - if (!driver) - return -ENODEV; - - if (MINOR(inode->i_rdev) == 5) { - - file->f_op = &sparcaudioctl_fops; - - MOD_INC_USE_COUNT; - - return 0; - } - - /* We only support minor #4 (/dev/audio) right now. */ - if (MINOR(inode->i_rdev) != 4) - return -ENXIO; - - /* If the driver is busy, then wait to get through. */ - retry_open: + int minor = MINOR(inode->i_rdev); + int err; + + /* A low-level audio driver must exist. */ + if (!driver) + return -ENODEV; + + switch (minor) { + case SPARCAUDIO_AUDIOCTL_MINOR: + file->f_op = &sparcaudioctl_fops; + break; + + case SPARCAUDIO_DSP16_MINOR: + case SPARCAUDIO_DSP_MINOR: + case SPARCAUDIO_AUDIO_MINOR: + /* If the driver is busy, then wait to get through. */ + retry_open: if (file->f_mode & FMODE_READ && driver->flags & SDF_OPEN_READ) { - if (file->f_flags & O_NONBLOCK) - return -EBUSY; - - interruptible_sleep_on(&driver->open_wait); - if (signal_pending(current)) - return -EINTR; - goto retry_open; + if (file->f_flags & O_NONBLOCK) + return -EBUSY; + + interruptible_sleep_on(&driver->open_wait); + if (signal_pending(current)) + return -EINTR; + goto retry_open; } if (file->f_mode & FMODE_WRITE && driver->flags & SDF_OPEN_WRITE) { - if (file->f_flags & O_NONBLOCK) - return -EBUSY; - - interruptible_sleep_on(&driver->open_wait); - if (signal_pending(current)) - return -EINTR; - goto retry_open; + if (file->f_flags & O_NONBLOCK) + return -EBUSY; + + interruptible_sleep_on(&driver->open_wait); + if (signal_pending(current)) + return -EINTR; + goto retry_open; } + /* Allow the low-level driver to initialize itself. */ + if (driver->ops->open) { + err = driver->ops->open(inode,file,driver); + if (err < 0) + return err; + } + /* Mark the driver as locked for read and/or write. */ if (file->f_mode & FMODE_READ) { - driver->input_offset = 0; - driver->input_front = 0; - driver->input_rear = 0; - driver->input_count = 0; - driver->ops->start_input(driver, driver->input_buffers[driver->input_front], - PAGE_SIZE); - driver->input_active = 1; - driver->flags |= SDF_OPEN_READ; + driver->input_offset = 0; + driver->input_front = 0; + driver->input_rear = 0; + driver->input_count = 0; + driver->recording_count = 0; + driver->ops->start_input(driver, driver->input_buffers[driver->input_front], + 4096); + driver->input_active = 1; + driver->flags |= SDF_OPEN_READ; } if (file->f_mode & FMODE_WRITE) { - driver->output_size = 0; - driver->output_front = 0; - driver->output_rear = 0; - driver->output_count = 0; - driver->output_active = 0; - driver->flags |= SDF_OPEN_WRITE; + driver->playing_count = 0; + driver->output_size = 0; + driver->output_front = 0; + driver->output_rear = 0; + driver->output_count = 0; + driver->output_active = 0; + driver->flags |= SDF_OPEN_WRITE; } - - /* Allow the low-level driver to initialize itself. */ - if (driver->ops->open) { - err = driver->ops->open(inode,file,driver); - if (err < 0) - return err; - } - - MOD_INC_USE_COUNT; - - /* Success! */ - return 0; + break; + case SPARCAUDIO_MIXER_MINOR: + file->f_op = &sparcaudioctl_fops; + break; + + default: + return -ENXIO; + } + + MOD_INC_USE_COUNT; + + /* Success! */ + return 0; } static int sparcaudio_release(struct inode * inode, struct file * file) @@ -876,3 +1043,22 @@ void cleanup_module(void) unregister_chrdev(SOUND_MAJOR, "sparcaudio"); } #endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-indent-level: 4 + * c-brace-imaginary-offset: 0 + * c-brace-offset: -4 + * c-argdecl-indent: 4 + * c-label-offset: -4 + * c-continued-statement-offset: 4 + * c-continued-brace-offset: 0 + * indent-tabs-mode: nil + * tab-width: 8 + * End: + */ |