1 /* 2 * Functions for the OPL4 proc file 3 * Copyright (c) 2003 by Clemens Ladisch <clemens@ladisch.de> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 */ 19 20 #include "opl4_local.h" 21 #include <linux/vmalloc.h> 22 #include <sound/info.h> 23 24 #ifdef CONFIG_PROC_FS 25 26 static int snd_opl4_mem_proc_open(struct snd_info_entry *entry, 27 unsigned short mode, void **file_private_data) 28 { 29 struct snd_opl4 *opl4 = entry->private_data; 30 31 down(&opl4->access_mutex); 32 if (opl4->memory_access) { 33 up(&opl4->access_mutex); 34 return -EBUSY; 35 } 36 opl4->memory_access++; 37 up(&opl4->access_mutex); 38 return 0; 39 } 40 41 static int snd_opl4_mem_proc_release(struct snd_info_entry *entry, 42 unsigned short mode, void *file_private_data) 43 { 44 struct snd_opl4 *opl4 = entry->private_data; 45 46 down(&opl4->access_mutex); 47 opl4->memory_access--; 48 up(&opl4->access_mutex); 49 return 0; 50 } 51 52 static long snd_opl4_mem_proc_read(struct snd_info_entry *entry, void *file_private_data, 53 struct file *file, char __user *_buf, 54 unsigned long count, unsigned long pos) 55 { 56 struct snd_opl4 *opl4 = entry->private_data; 57 long size; 58 char* buf; 59 60 size = count; 61 if (pos + size > entry->size) 62 size = entry->size - pos; 63 if (size > 0) { 64 buf = vmalloc(size); 65 if (!buf) 66 return -ENOMEM; 67 snd_opl4_read_memory(opl4, buf, pos, size); 68 if (copy_to_user(_buf, buf, size)) { 69 vfree(buf); 70 return -EFAULT; 71 } 72 vfree(buf); 73 return size; 74 } 75 return 0; 76 } 77 78 static long snd_opl4_mem_proc_write(struct snd_info_entry *entry, void *file_private_data, 79 struct file *file, const char __user *_buf, 80 unsigned long count, unsigned long pos) 81 { 82 struct snd_opl4 *opl4 = entry->private_data; 83 long size; 84 char *buf; 85 86 size = count; 87 if (pos + size > entry->size) 88 size = entry->size - pos; 89 if (size > 0) { 90 buf = vmalloc(size); 91 if (!buf) 92 return -ENOMEM; 93 if (copy_from_user(buf, _buf, size)) { 94 vfree(buf); 95 return -EFAULT; 96 } 97 snd_opl4_write_memory(opl4, buf, pos, size); 98 vfree(buf); 99 return size; 100 } 101 return 0; 102 } 103 104 static long long snd_opl4_mem_proc_llseek(struct snd_info_entry *entry, void *file_private_data, 105 struct file *file, long long offset, int orig) 106 { 107 switch (orig) { 108 case 0: /* SEEK_SET */ 109 file->f_pos = offset; 110 break; 111 case 1: /* SEEK_CUR */ 112 file->f_pos += offset; 113 break; 114 case 2: /* SEEK_END, offset is negative */ 115 file->f_pos = entry->size + offset; 116 break; 117 default: 118 return -EINVAL; 119 } 120 if (file->f_pos > entry->size) 121 file->f_pos = entry->size; 122 return file->f_pos; 123 } 124 125 static struct snd_info_entry_ops snd_opl4_mem_proc_ops = { 126 .open = snd_opl4_mem_proc_open, 127 .release = snd_opl4_mem_proc_release, 128 .read = snd_opl4_mem_proc_read, 129 .write = snd_opl4_mem_proc_write, 130 .llseek = snd_opl4_mem_proc_llseek, 131 }; 132 133 int snd_opl4_create_proc(struct snd_opl4 *opl4) 134 { 135 struct snd_info_entry *entry; 136 137 entry = snd_info_create_card_entry(opl4->card, "opl4-mem", opl4->card->proc_root); 138 if (entry) { 139 if (opl4->hardware < OPL3_HW_OPL4_ML) { 140 /* OPL4 can access 4 MB external ROM/SRAM */ 141 entry->mode |= S_IWUSR; 142 entry->size = 4 * 1024 * 1024; 143 } else { 144 /* OPL4-ML has 1 MB internal ROM */ 145 entry->size = 1 * 1024 * 1024; 146 } 147 entry->content = SNDRV_INFO_CONTENT_DATA; 148 entry->c.ops = &snd_opl4_mem_proc_ops; 149 entry->module = THIS_MODULE; 150 entry->private_data = opl4; 151 if (snd_info_register(entry) < 0) { 152 snd_info_free_entry(entry); 153 entry = NULL; 154 } 155 } 156 opl4->proc_entry = entry; 157 return 0; 158 } 159 160 void snd_opl4_free_proc(struct snd_opl4 *opl4) 161 { 162 if (opl4->proc_entry) 163 snd_info_unregister(opl4->proc_entry); 164 } 165 166 #endif /* CONFIG_PROC_FS */ 167