diff options
Diffstat (limited to 'sound/drivers/opl4/opl4_proc.c')
-rw-r--r-- | sound/drivers/opl4/opl4_proc.c | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/sound/drivers/opl4/opl4_proc.c b/sound/drivers/opl4/opl4_proc.c new file mode 100644 index 000000000000..6a1486258acf --- /dev/null +++ b/sound/drivers/opl4/opl4_proc.c @@ -0,0 +1,166 @@ +/* + * Functions for the OPL4 proc file + * Copyright (c) 2003 by Clemens Ladisch <clemens@ladisch.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "opl4_local.h" +#include <linux/vmalloc.h> +#include <sound/info.h> + +#ifdef CONFIG_PROC_FS + +static int snd_opl4_mem_proc_open(snd_info_entry_t *entry, + unsigned short mode, void **file_private_data) +{ + opl4_t *opl4 = entry->private_data; + + down(&opl4->access_mutex); + if (opl4->memory_access) { + up(&opl4->access_mutex); + return -EBUSY; + } + opl4->memory_access++; + up(&opl4->access_mutex); + return 0; +} + +static int snd_opl4_mem_proc_release(snd_info_entry_t *entry, + unsigned short mode, void *file_private_data) +{ + opl4_t *opl4 = entry->private_data; + + down(&opl4->access_mutex); + opl4->memory_access--; + up(&opl4->access_mutex); + return 0; +} + +static long snd_opl4_mem_proc_read(snd_info_entry_t *entry, void *file_private_data, + struct file *file, char __user *_buf, + unsigned long count, unsigned long pos) +{ + opl4_t *opl4 = entry->private_data; + long size; + char* buf; + + size = count; + if (pos + size > entry->size) + size = entry->size - pos; + if (size > 0) { + buf = vmalloc(size); + if (!buf) + return -ENOMEM; + snd_opl4_read_memory(opl4, buf, pos, size); + if (copy_to_user(_buf, buf, size)) { + vfree(buf); + return -EFAULT; + } + vfree(buf); + return size; + } + return 0; +} + +static long snd_opl4_mem_proc_write(snd_info_entry_t *entry, void *file_private_data, + struct file *file, const char __user *_buf, + unsigned long count, unsigned long pos) +{ + opl4_t *opl4 = entry->private_data; + long size; + char *buf; + + size = count; + if (pos + size > entry->size) + size = entry->size - pos; + if (size > 0) { + buf = vmalloc(size); + if (!buf) + return -ENOMEM; + if (copy_from_user(buf, _buf, size)) { + vfree(buf); + return -EFAULT; + } + snd_opl4_write_memory(opl4, buf, pos, size); + vfree(buf); + return size; + } + return 0; +} + +static long long snd_opl4_mem_proc_llseek(snd_info_entry_t *entry, void *file_private_data, + struct file *file, long long offset, int orig) +{ + switch (orig) { + case 0: /* SEEK_SET */ + file->f_pos = offset; + break; + case 1: /* SEEK_CUR */ + file->f_pos += offset; + break; + case 2: /* SEEK_END, offset is negative */ + file->f_pos = entry->size + offset; + break; + default: + return -EINVAL; + } + if (file->f_pos > entry->size) + file->f_pos = entry->size; + return file->f_pos; +} + +static struct snd_info_entry_ops snd_opl4_mem_proc_ops = { + .open = snd_opl4_mem_proc_open, + .release = snd_opl4_mem_proc_release, + .read = snd_opl4_mem_proc_read, + .write = snd_opl4_mem_proc_write, + .llseek = snd_opl4_mem_proc_llseek, +}; + +int snd_opl4_create_proc(opl4_t *opl4) +{ + snd_info_entry_t *entry; + + entry = snd_info_create_card_entry(opl4->card, "opl4-mem", opl4->card->proc_root); + if (entry) { + if (opl4->hardware < OPL3_HW_OPL4_ML) { + /* OPL4 can access 4 MB external ROM/SRAM */ + entry->mode |= S_IWUSR; + entry->size = 4 * 1024 * 1024; + } else { + /* OPL4-ML has 1 MB internal ROM */ + entry->size = 1 * 1024 * 1024; + } + entry->content = SNDRV_INFO_CONTENT_DATA; + entry->c.ops = &snd_opl4_mem_proc_ops; + entry->module = THIS_MODULE; + entry->private_data = opl4; + if (snd_info_register(entry) < 0) { + snd_info_free_entry(entry); + entry = NULL; + } + } + opl4->proc_entry = entry; + return 0; +} + +void snd_opl4_free_proc(opl4_t *opl4) +{ + if (opl4->proc_entry) + snd_info_unregister(opl4->proc_entry); +} + +#endif /* CONFIG_PROC_FS */ |