1
2
3
4
5
6
7
8
9
10#include <sound/asoundef.h>
11#include "seq_oss_midi.h"
12#include "seq_oss_readq.h"
13#include "seq_oss_timer.h"
14#include "seq_oss_event.h"
15#include <sound/seq_midi_event.h>
16#include "../seq_lock.h"
17#include <linux/init.h>
18#include <linux/slab.h>
19#include <linux/nospec.h>
20
21
22
23
24
25#define SNDRV_SEQ_OSS_MAX_MIDI_NAME 30
26
27
28
29
30struct seq_oss_midi {
31 int seq_device;
32 int client;
33 int port;
34 unsigned int flags;
35 int opened;
36 unsigned char name[SNDRV_SEQ_OSS_MAX_MIDI_NAME];
37 struct snd_midi_event *coder;
38 struct seq_oss_devinfo *devinfo;
39 snd_use_lock_t use_lock;
40};
41
42
43
44
45
46static int max_midi_devs;
47static struct seq_oss_midi *midi_devs[SNDRV_SEQ_OSS_MAX_MIDI_DEVS];
48
49static DEFINE_SPINLOCK(register_lock);
50
51
52
53
54static struct seq_oss_midi *get_mdev(int dev);
55static struct seq_oss_midi *get_mididev(struct seq_oss_devinfo *dp, int dev);
56static int send_synth_event(struct seq_oss_devinfo *dp, struct snd_seq_event *ev, int dev);
57static int send_midi_event(struct seq_oss_devinfo *dp, struct snd_seq_event *ev, struct seq_oss_midi *mdev);
58
59
60
61
62
63int
64snd_seq_oss_midi_lookup_ports(int client)
65{
66 struct snd_seq_client_info *clinfo;
67 struct snd_seq_port_info *pinfo;
68
69 clinfo = kzalloc(sizeof(*clinfo), GFP_KERNEL);
70 pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL);
71 if (! clinfo || ! pinfo) {
72 kfree(clinfo);
73 kfree(pinfo);
74 return -ENOMEM;
75 }
76 clinfo->client = -1;
77 while (snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_QUERY_NEXT_CLIENT, clinfo) == 0) {
78 if (clinfo->client == client)
79 continue;
80 pinfo->addr.client = clinfo->client;
81 pinfo->addr.port = -1;
82 while (snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT, pinfo) == 0)
83 snd_seq_oss_midi_check_new_port(pinfo);
84 }
85 kfree(clinfo);
86 kfree(pinfo);
87 return 0;
88}
89
90
91
92
93static struct seq_oss_midi *
94get_mdev(int dev)
95{
96 struct seq_oss_midi *mdev;
97 unsigned long flags;
98
99 spin_lock_irqsave(®ister_lock, flags);
100 mdev = midi_devs[dev];
101 if (mdev)
102 snd_use_lock_use(&mdev->use_lock);
103 spin_unlock_irqrestore(®ister_lock, flags);
104 return mdev;
105}
106
107
108
109
110static struct seq_oss_midi *
111find_slot(int client, int port)
112{
113 int i;
114 struct seq_oss_midi *mdev;
115 unsigned long flags;
116
117 spin_lock_irqsave(®ister_lock, flags);
118 for (i = 0; i < max_midi_devs; i++) {
119 mdev = midi_devs[i];
120 if (mdev && mdev->client == client && mdev->port == port) {
121
122 snd_use_lock_use(&mdev->use_lock);
123 spin_unlock_irqrestore(®ister_lock, flags);
124 return mdev;
125 }
126 }
127 spin_unlock_irqrestore(®ister_lock, flags);
128 return NULL;
129}
130
131
132#define PERM_WRITE (SNDRV_SEQ_PORT_CAP_WRITE|SNDRV_SEQ_PORT_CAP_SUBS_WRITE)
133#define PERM_READ (SNDRV_SEQ_PORT_CAP_READ|SNDRV_SEQ_PORT_CAP_SUBS_READ)
134
135
136
137int
138snd_seq_oss_midi_check_new_port(struct snd_seq_port_info *pinfo)
139{
140 int i;
141 struct seq_oss_midi *mdev;
142 unsigned long flags;
143
144
145 if (! (pinfo->type & SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC))
146 return 0;
147
148 if ((pinfo->capability & PERM_WRITE) != PERM_WRITE &&
149 (pinfo->capability & PERM_READ) != PERM_READ)
150 return 0;
151
152
153
154
155 mdev = find_slot(pinfo->addr.client, pinfo->addr.port);
156 if (mdev) {
157
158 snd_use_lock_free(&mdev->use_lock);
159 return 0;
160 }
161
162
163
164
165 mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
166 if (!mdev)
167 return -ENOMEM;
168
169
170 mdev->client = pinfo->addr.client;
171 mdev->port = pinfo->addr.port;
172 mdev->flags = pinfo->capability;
173 mdev->opened = 0;
174 snd_use_lock_init(&mdev->use_lock);
175
176
177 strscpy(mdev->name, pinfo->name, sizeof(mdev->name));
178
179
180 if (snd_midi_event_new(MAX_MIDI_EVENT_BUF, &mdev->coder) < 0) {
181 pr_err("ALSA: seq_oss: can't malloc midi coder\n");
182 kfree(mdev);
183 return -ENOMEM;
184 }
185
186 snd_midi_event_no_status(mdev->coder, 1);
187
188
189
190
191 spin_lock_irqsave(®ister_lock, flags);
192 for (i = 0; i < max_midi_devs; i++) {
193 if (midi_devs[i] == NULL)
194 break;
195 }
196 if (i >= max_midi_devs) {
197 if (max_midi_devs >= SNDRV_SEQ_OSS_MAX_MIDI_DEVS) {
198 spin_unlock_irqrestore(®ister_lock, flags);
199 snd_midi_event