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(lock: &opl4->access_mutex); |
20 | return -EBUSY; |
21 | } |
22 | opl4->memory_access++; |
23 | mutex_unlock(lock: &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(lock: &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(size: count); |
47 | if (!buf) |
48 | return -ENOMEM; |
49 | snd_opl4_read_memory(opl4, buf, offset: pos, size: count); |
50 | if (copy_to_user(to: _buf, from: buf, n: count)) { |
51 | vfree(addr: buf); |
52 | return -EFAULT; |
53 | } |
54 | vfree(addr: 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(size: count); |
68 | if (!buf) |
69 | return -ENOMEM; |
70 | if (copy_from_user(to: buf, from: _buf, n: count)) { |
71 | vfree(addr: buf); |
72 | return -EFAULT; |
73 | } |
74 | snd_opl4_write_memory(opl4, buf, offset: pos, size: count); |
75 | vfree(addr: 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(card: opl4->card, name: "opl4-mem" , parent: 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(entry: opl4->proc_entry); |
112 | } |
113 | |