diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-03-19 01:28:40 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-03-19 01:28:40 +0000 |
commit | 8abb719409c9060a7c0676f76e9182c1e0b8ca46 (patch) | |
tree | b88cc5a6cd513a04a512b7e6215c873c90a1c5dd /drivers/sbus/audio/audio.c | |
parent | f01bd7aeafd95a08aafc9e3636bb26974df69d82 (diff) |
Merge with 2.3.99-pre1.
Diffstat (limited to 'drivers/sbus/audio/audio.c')
-rw-r--r-- | drivers/sbus/audio/audio.c | 410 |
1 files changed, 229 insertions, 181 deletions
diff --git a/drivers/sbus/audio/audio.c b/drivers/sbus/audio/audio.c index 01c76073f..4c7e8003c 100644 --- a/drivers/sbus/audio/audio.c +++ b/drivers/sbus/audio/audio.c @@ -1,4 +1,4 @@ -/* $Id: audio.c,v 1.49 2000/02/17 05:52:41 davem Exp $ +/* $Id: audio.c,v 1.50 2000/03/13 03:54:07 davem Exp $ * drivers/sbus/audio/audio.c * * Copyright 1996 Thomas K. Dyas (tdyas@noc.rutgers.edu) @@ -70,7 +70,8 @@ static void lis_free_elist( strevent_t **list); static void kill_procs( struct strevent *elist, int sig, short e); static struct sparcaudio_driver *drivers[SPARCAUDIO_MAX_DEVICES] = {NULL}; - +static devfs_handle_t devfs_handle = NULL; + /* This crap to be pulled off into a local include file */ #if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x20100 @@ -92,185 +93,6 @@ static struct sparcaudio_driver *drivers[SPARCAUDIO_MAX_DEVICES] = {NULL}; #endif -int register_sparcaudio_driver(struct sparcaudio_driver *drv, int duplex) -{ - int i, dev; - - /* If we've used up SPARCAUDIO_MAX_DEVICES, fail */ - for (dev = 0; dev < SPARCAUDIO_MAX_DEVICES; dev++) { - if (drivers[dev] == NULL) - break; - } - - if (drivers[dev]) - return -EIO; - - /* Ensure that the driver has a proper operations structure. */ - if (!drv->ops || !drv->ops->start_output || !drv->ops->stop_output || - !drv->ops->start_input || !drv->ops->stop_input) - return -EINVAL; - - /* 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 < output_buffer_size), - * 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 input_buffer_size - * bytes of audio data. - * - * TODO: Make number of input/output buffers tunable parameters - */ - -#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x202ff - init_waitqueue_head(&drv->open_wait); - init_waitqueue_head(&drv->output_write_wait); - init_waitqueue_head(&drv->output_drain_wait); - init_waitqueue_head(&drv->input_read_wait); -#endif - - drv->num_output_buffers = 8; - drv->output_buffer_size = (4096 * 2); - drv->playing_count = 0; - drv->output_offset = 0; - drv->output_eof = 0; - drv->output_front = 0; - drv->output_rear = 0; - drv->output_count = 0; - drv->output_active = 0; - drv->output_buffers = kmalloc(drv->num_output_buffers * - sizeof(__u8 *), GFP_KERNEL); - drv->output_sizes = kmalloc(drv->num_output_buffers * - sizeof(size_t), GFP_KERNEL); - drv->output_notify = kmalloc(drv->num_output_buffers * - sizeof(char), GFP_KERNEL); - if (!drv->output_buffers || !drv->output_sizes || !drv->output_notify) - goto kmalloc_failed1; - - drv->output_buffer = kmalloc((drv->output_buffer_size * - drv->num_output_buffers), - GFP_KERNEL); - if (!drv->output_buffer) - goto kmalloc_failed2; - - /* Allocate the pages for each output buffer. */ - for (i = 0; i < drv->num_output_buffers; i++) { - drv->output_buffers[i] = (void *)(drv->output_buffer + - (i * drv->output_buffer_size)); - drv->output_sizes[i] = 0; - drv->output_notify[i] = 0; - } - - /* Setup the circular queue of input buffers. */ - drv->num_input_buffers = 8; - drv->input_buffer_size = (4096 * 2); - drv->recording_count = 0; - drv->input_front = 0; - drv->input_rear = 0; - drv->input_count = 0; - drv->input_offset = 0; - drv->input_size = 0; - drv->input_active = 0; - drv->input_buffers = kmalloc(drv->num_input_buffers * sizeof(__u8 *), - GFP_KERNEL); - drv->input_sizes = kmalloc(drv->num_input_buffers * - sizeof(size_t), GFP_KERNEL); - if (!drv->input_buffers || !drv->input_sizes) - goto kmalloc_failed3; - - /* Allocate the pages for each input buffer. */ - if (duplex == 1) { - drv->input_buffer = kmalloc((drv->input_buffer_size * - drv->num_input_buffers), - GFP_DMA); - if (!drv->input_buffer) - goto kmalloc_failed4; - - for (i = 0; i < drv->num_input_buffers; i++) - drv->input_buffers[i] = (void *)(drv->input_buffer + - (i * drv->input_buffer_size)); - } else { - if (duplex == 2) { - drv->input_buffer = drv->output_buffer; - drv->input_buffer_size = drv->output_buffer_size; - drv->num_input_buffers = drv->num_output_buffers; - for (i = 0; i < drv->num_input_buffers; i++) - drv->input_buffers[i] = drv->output_buffers[i]; - } else { - for (i = 0; i < drv->num_input_buffers; i++) - drv->input_buffers[i] = NULL; - } - } - - /* Take note of our duplexity */ - drv->duplex = duplex; - - /* Ensure that the driver is marked as not being open. */ - drv->flags = 0; - - MOD_INC_USE_COUNT; - - /* Take driver slot, note which we took */ - drv->index = dev; - drivers[dev] = drv; - - return 0; - -kmalloc_failed4: - kfree(drv->input_buffer); - -kmalloc_failed3: - if (drv->input_sizes) - kfree(drv->input_sizes); - if (drv->input_buffers) - kfree(drv->input_buffers); - i = drv->num_output_buffers; - -kmalloc_failed2: - kfree(drv->output_buffer); - -kmalloc_failed1: - if (drv->output_buffers) - kfree(drv->output_buffers); - if (drv->output_sizes) - kfree(drv->output_sizes); - if (drv->output_notify) - kfree(drv->output_notify); - - return -ENOMEM; -} - -int unregister_sparcaudio_driver(struct sparcaudio_driver *drv, int duplex) -{ - /* Figure out which driver is unregistering */ - if (drivers[drv->index] != drv) - return -EIO; - - /* Deallocate the queue of output buffers. */ - kfree(drv->output_buffer); - kfree(drv->output_buffers); - kfree(drv->output_sizes); - kfree(drv->output_notify); - - /* Deallocate the queue of input buffers. */ - if (duplex == 1) { - kfree(drv->input_buffer); - kfree(drv->input_sizes); - } - kfree(drv->input_buffers); - - if (&(drv->sd_siglist) != NULL) - lis_free_elist( &(drv->sd_siglist) ); - - MOD_DEC_USE_COUNT; - - /* Null the appropriate driver */ - drivers[drv->index] = NULL; - - return 0; -} - void sparcaudio_output_done(struct sparcaudio_driver * drv, int status) { /* If !status, just restart current output. @@ -2171,6 +1993,229 @@ static struct file_operations sparcaudio_fops = { release: sparcaudio_release, }; +static struct { + unsigned short minor; + char *name; + umode_t mode; +} dev_list[] = { + { SPARCAUDIO_MIXER_MINOR, "mixer", S_IWUSR | S_IRUGO }, + { SPARCAUDIO_DSP_MINOR, "dsp", S_IWUGO | S_IRUSR | S_IRGRP }, + { SPARCAUDIO_AUDIO_MINOR, "audio", S_IWUGO | S_IRUSR | S_IRGRP }, + { SPARCAUDIO_DSP16_MINOR, "dspW", S_IWUGO | S_IRUSR | S_IRGRP }, + { SPARCAUDIO_STATUS_MINOR, "status", S_IRUGO }, + { SPARCAUDIO_AUDIOCTL_MINOR, "audioctl", S_IRUGO } +}; + +static void sparcaudio_mkname (char *buf, char *name, int dev) +{ + if (dev) + sprintf (buf, "%s%d", name, dev); + else + sprintf (buf, "%s", name); +} + +int register_sparcaudio_driver(struct sparcaudio_driver *drv, int duplex) +{ + int i, dev; + unsigned short minor; + char name_buf[32]; + + /* If we've used up SPARCAUDIO_MAX_DEVICES, fail */ + for (dev = 0; dev < SPARCAUDIO_MAX_DEVICES; dev++) { + if (drivers[dev] == NULL) + break; + } + + if (drivers[dev]) + return -EIO; + + /* Ensure that the driver has a proper operations structure. */ + if (!drv->ops || !drv->ops->start_output || !drv->ops->stop_output || + !drv->ops->start_input || !drv->ops->stop_input) + return -EINVAL; + + /* Register ourselves with devfs */ + for (i=0; i < sizeof (dev_list) / sizeof (*dev_list); i++) { + sparcaudio_mkname (name_buf, dev_list[i].name, dev); + minor = (dev << SPARCAUDIO_DEVICE_SHIFT) | dev_list[i].minor; + devfs_register (devfs_handle, name_buf, 0, DEVFS_FL_NONE, + SOUND_MAJOR, minor, S_IFCHR | dev_list[i].mode, + 0, 0, &sparcaudio_fops, NULL); + } + + /* 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 < output_buffer_size), + * 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 input_buffer_size + * bytes of audio data. + * + * TODO: Make number of input/output buffers tunable parameters + */ + +#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x202ff + init_waitqueue_head(&drv->open_wait); + init_waitqueue_head(&drv->output_write_wait); + init_waitqueue_head(&drv->output_drain_wait); + init_waitqueue_head(&drv->input_read_wait); +#endif + + drv->num_output_buffers = 8; + drv->output_buffer_size = (4096 * 2); + drv->playing_count = 0; + drv->output_offset = 0; + drv->output_eof = 0; + drv->output_front = 0; + drv->output_rear = 0; + drv->output_count = 0; + drv->output_active = 0; + drv->output_buffers = kmalloc(drv->num_output_buffers * + sizeof(__u8 *), GFP_KERNEL); + drv->output_sizes = kmalloc(drv->num_output_buffers * + sizeof(size_t), GFP_KERNEL); + drv->output_notify = kmalloc(drv->num_output_buffers * + sizeof(char), GFP_KERNEL); + if (!drv->output_buffers || !drv->output_sizes || !drv->output_notify) + goto kmalloc_failed1; + + drv->output_buffer = kmalloc((drv->output_buffer_size * + drv->num_output_buffers), + GFP_KERNEL); + if (!drv->output_buffer) + goto kmalloc_failed2; + + /* Allocate the pages for each output buffer. */ + for (i = 0; i < drv->num_output_buffers; i++) { + drv->output_buffers[i] = (void *)(drv->output_buffer + + (i * drv->output_buffer_size)); + drv->output_sizes[i] = 0; + drv->output_notify[i] = 0; + } + + /* Setup the circular queue of input buffers. */ + drv->num_input_buffers = 8; + drv->input_buffer_size = (4096 * 2); + drv->recording_count = 0; + drv->input_front = 0; + drv->input_rear = 0; + drv->input_count = 0; + drv->input_offset = 0; + drv->input_size = 0; + drv->input_active = 0; + drv->input_buffers = kmalloc(drv->num_input_buffers * sizeof(__u8 *), + GFP_KERNEL); + drv->input_sizes = kmalloc(drv->num_input_buffers * + sizeof(size_t), GFP_KERNEL); + if (!drv->input_buffers || !drv->input_sizes) + goto kmalloc_failed3; + + /* Allocate the pages for each input buffer. */ + if (duplex == 1) { + drv->input_buffer = kmalloc((drv->input_buffer_size * + drv->num_input_buffers), + GFP_DMA); + if (!drv->input_buffer) + goto kmalloc_failed4; + + for (i = 0; i < drv->num_input_buffers; i++) + drv->input_buffers[i] = (void *)(drv->input_buffer + + (i * drv->input_buffer_size)); + } else { + if (duplex == 2) { + drv->input_buffer = drv->output_buffer; + drv->input_buffer_size = drv->output_buffer_size; + drv->num_input_buffers = drv->num_output_buffers; + for (i = 0; i < drv->num_input_buffers; i++) + drv->input_buffers[i] = drv->output_buffers[i]; + } else { + for (i = 0; i < drv->num_input_buffers; i++) + drv->input_buffers[i] = NULL; + } + } + + /* Take note of our duplexity */ + drv->duplex = duplex; + + /* Ensure that the driver is marked as not being open. */ + drv->flags = 0; + + MOD_INC_USE_COUNT; + + /* Take driver slot, note which we took */ + drv->index = dev; + drivers[dev] = drv; + + return 0; + +kmalloc_failed4: + kfree(drv->input_buffer); + +kmalloc_failed3: + if (drv->input_sizes) + kfree(drv->input_sizes); + if (drv->input_buffers) + kfree(drv->input_buffers); + i = drv->num_output_buffers; + +kmalloc_failed2: + kfree(drv->output_buffer); + +kmalloc_failed1: + if (drv->output_buffers) + kfree(drv->output_buffers); + if (drv->output_sizes) + kfree(drv->output_sizes); + if (drv->output_notify) + kfree(drv->output_notify); + + return -ENOMEM; +} + +int unregister_sparcaudio_driver(struct sparcaudio_driver *drv, int duplex) +{ + devfs_handle_t de; + int i; + char name_buf[32]; + + /* Figure out which driver is unregistering */ + if (drivers[drv->index] != drv) + return -EIO; + + /* Deallocate the queue of output buffers. */ + kfree(drv->output_buffer); + kfree(drv->output_buffers); + kfree(drv->output_sizes); + kfree(drv->output_notify); + + /* Deallocate the queue of input buffers. */ + if (duplex == 1) { + kfree(drv->input_buffer); + kfree(drv->input_sizes); + } + kfree(drv->input_buffers); + + if (&(drv->sd_siglist) != NULL) + lis_free_elist( &(drv->sd_siglist) ); + + /* Unregister ourselves with devfs */ + for (i=0; i < sizeof (dev_list) / sizeof (*dev_list); i++) { + sparcaudio_mkname (name_buf, dev_list[i].name, drv->index); + de = devfs_find_handle (devfs_handle, name_buf, 0, 0, 0, + DEVFS_SPECIAL_CHR, 0); + devfs_unregister (de); + } + + MOD_DEC_USE_COUNT; + + /* Null the appropriate driver */ + drivers[drv->index] = NULL; + + return 0; +} + #if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x20100 static struct symbol_table sparcaudio_syms = { #include <linux/symtab_begin.h> @@ -2201,6 +2246,8 @@ int __init sparcaudio_init(void) /* Register our character device driver with the VFS. */ if (devfs_register_chrdev(SOUND_MAJOR, "sparcaudio", &sparcaudio_fops)) return -EIO; + + devfs_handle = devfs_mk_dir (NULL, "sound", 0, NULL); #ifdef CONFIG_SPARCAUDIO_AMD7930 amd7930_init(); @@ -2222,6 +2269,7 @@ int __init sparcaudio_init(void) void cleanup_module(void) { devfs_unregister_chrdev(SOUND_MAJOR, "sparcaudio"); + devfs_unregister (devfs_handle); } #endif |