1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Functions for the OPL4 proc file 4 * Copyright (c) 2003 by Clemens Ladisch <clemens@ladisch.de> 5 */ 6 7 #include "opl4_local.h" 8 #include <linux/vmalloc.h> 9 #include <linux/export.h> 10 #include <sound/info.h> 11 12 static int snd_opl4_mem_proc_open(struct snd_info_entry *entry, 13 unsigned short mode, void **file_private_data) 14 { 15 struct snd_opl4 *opl4 = entry->private_data; 16 17 mutex_lock(&opl4->access_mutex); 18 if (opl4->memory_access) { 19 mutex_unlock(&opl4->access_mutex); 20 return -EBUSY; 21 } 22 opl4->memory_access++; 23 mutex_unlock(&opl4->access_mutex); 24 return 0; 25 } 26 27 static int snd_opl4_mem_proc_release(struct snd_info_entry *entry, 28 unsigned short mode, void *file_private_data) 29 { 30 struct snd_opl4 *opl4 = entry->private_data; 31 32 mutex_lock(&opl4->access_mutex); 33 opl4->memory_access--; 34 mutex_unlock(&opl4->access_mutex); 35 return 0; 36 } 37 38 static ssize_t snd_opl4_mem_proc_read(struct snd_info_entry *entry, 39 void *file_private_data, 40 struct file *file, char __user *_buf, 41 size_t count, loff_t pos) 42 { 43 struct snd_opl4 *opl4 = entry->private_data; 44 char* buf; 45 46 buf = vmalloc(count); 47 if (!buf) 48 return -ENOMEM; 49 snd_opl4_read_memory(opl4, buf, pos, count); 50 if (copy_to_user(_buf, buf, count)) { 51 vfree(buf); 52 return -EFAULT; 53 } 54 vfree(buf); 55 return count; 56 } 57 58 static ssize_t snd_opl4_mem_proc_write(struct snd_info_entry *entry, 59 void *file_private_data, 60 struct file *file, 61 const char __user *_buf, 62 size_t count, loff_t pos) 63 { 64 struct snd_opl4 *opl4 = entry->private_data; 65 char *buf; 66 67 buf = vmalloc(count); 68 if (!buf) 69 return -ENOMEM; 70 if (copy_from_user(buf, _buf, count)) { 71 vfree(buf); 72 return -EFAULT; 73 } 74 snd_opl4_write_memory(opl4, buf, pos, count); 75 vfree(buf); 76 return count; 77 } 78 79 static const struct snd_info_entry_ops snd_opl4_mem_proc_ops = { 80 .open = snd_opl4_mem_proc_open, 81 .release = snd_opl4_mem_proc_release, 82 .read = snd_opl4_mem_proc_read, 83 .write = snd_opl4_mem_proc_write, 84 }; 85 86 int snd_opl4_create_proc(struct snd_opl4 *opl4) 87 { 88 struct snd_info_entry *entry; 89 90 entry = snd_info_create_card_entry(opl4->card, "opl4-mem", opl4->card->proc_root); 91 if (entry) { 92 if (opl4->hardware < OPL3_HW_OPL4_ML) { 93 /* OPL4 can access 4 MB external ROM/SRAM */ 94 entry->mode |= 0200; 95 entry->size = 4 * 1024 * 1024; 96 } else { 97 /* OPL4-ML has 1 MB internal ROM */ 98 entry->size = 1 * 1024 * 1024; 99 } 100 entry->content = SNDRV_INFO_CONTENT_DATA; 101 entry->c.ops = &snd_opl4_mem_proc_ops; 102 entry->module = THIS_MODULE; 103 entry->private_data = opl4; 104 } 105 opl4->proc_entry = entry; 106 return 0; 107 } 108 109 void snd_opl4_free_proc(struct snd_opl4 *opl4) 110 { 111 snd_info_free_entry(opl4->proc_entry); 112 } 113