.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * ALSA sequencer Client Manager |
---|
3 | 4 | * Copyright (c) 1998-2001 by Frank van de Pol <fvdpol@coil.demon.nl> |
---|
4 | 5 | * Jaroslav Kysela <perex@perex.cz> |
---|
5 | 6 | * Takashi Iwai <tiwai@suse.de> |
---|
6 | | - * |
---|
7 | | - * |
---|
8 | | - * This program is free software; you can redistribute it and/or modify |
---|
9 | | - * it under the terms of the GNU General Public License as published by |
---|
10 | | - * the Free Software Foundation; either version 2 of the License, or |
---|
11 | | - * (at your option) any later version. |
---|
12 | | - * |
---|
13 | | - * This program is distributed in the hope that it will be useful, |
---|
14 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
15 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
16 | | - * GNU General Public License for more details. |
---|
17 | | - * |
---|
18 | | - * You should have received a copy of the GNU General Public License |
---|
19 | | - * along with this program; if not, write to the Free Software |
---|
20 | | - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
---|
21 | | - * |
---|
22 | 7 | */ |
---|
23 | 8 | |
---|
24 | 9 | #include <linux/init.h> |
---|
.. | .. |
---|
136 | 121 | spin_unlock_irqrestore(&clients_lock, flags); |
---|
137 | 122 | #ifdef CONFIG_MODULES |
---|
138 | 123 | if (!in_interrupt()) { |
---|
139 | | - static char client_requested[SNDRV_SEQ_GLOBAL_CLIENTS]; |
---|
140 | | - static char card_requested[SNDRV_CARDS]; |
---|
| 124 | + static DECLARE_BITMAP(client_requested, SNDRV_SEQ_GLOBAL_CLIENTS); |
---|
| 125 | + static DECLARE_BITMAP(card_requested, SNDRV_CARDS); |
---|
| 126 | + |
---|
141 | 127 | if (clientid < SNDRV_SEQ_GLOBAL_CLIENTS) { |
---|
142 | 128 | int idx; |
---|
143 | 129 | |
---|
144 | | - if (!client_requested[clientid]) { |
---|
145 | | - client_requested[clientid] = 1; |
---|
| 130 | + if (!test_and_set_bit(clientid, client_requested)) { |
---|
146 | 131 | for (idx = 0; idx < 15; idx++) { |
---|
147 | 132 | if (seq_client_load[idx] < 0) |
---|
148 | 133 | break; |
---|
.. | .. |
---|
157 | 142 | int card = (clientid - SNDRV_SEQ_GLOBAL_CLIENTS) / |
---|
158 | 143 | SNDRV_SEQ_CLIENTS_PER_CARD; |
---|
159 | 144 | if (card < snd_ecards_limit) { |
---|
160 | | - if (! card_requested[card]) { |
---|
161 | | - card_requested[card] = 1; |
---|
| 145 | + if (!test_and_set_bit(card, card_requested)) |
---|
162 | 146 | snd_request_card(card); |
---|
163 | | - } |
---|
164 | 147 | snd_seq_device_load_drivers(); |
---|
165 | 148 | } |
---|
166 | 149 | } |
---|
.. | .. |
---|
178 | 161 | spin_unlock_irqrestore(&clients_lock, flags); |
---|
179 | 162 | return client; |
---|
180 | 163 | } |
---|
| 164 | + |
---|
| 165 | +/* Take refcount and perform ioctl_mutex lock on the given client; |
---|
| 166 | + * used only for OSS sequencer |
---|
| 167 | + * Unlock via snd_seq_client_ioctl_unlock() below |
---|
| 168 | + */ |
---|
| 169 | +bool snd_seq_client_ioctl_lock(int clientid) |
---|
| 170 | +{ |
---|
| 171 | + struct snd_seq_client *client; |
---|
| 172 | + |
---|
| 173 | + client = snd_seq_client_use_ptr(clientid); |
---|
| 174 | + if (!client) |
---|
| 175 | + return false; |
---|
| 176 | + mutex_lock(&client->ioctl_mutex); |
---|
| 177 | + /* The client isn't unrefed here; see snd_seq_client_ioctl_unlock() */ |
---|
| 178 | + return true; |
---|
| 179 | +} |
---|
| 180 | +EXPORT_SYMBOL_GPL(snd_seq_client_ioctl_lock); |
---|
| 181 | + |
---|
| 182 | +/* Unlock and unref the given client; for OSS sequencer use only */ |
---|
| 183 | +void snd_seq_client_ioctl_unlock(int clientid) |
---|
| 184 | +{ |
---|
| 185 | + struct snd_seq_client *client; |
---|
| 186 | + |
---|
| 187 | + client = snd_seq_client_use_ptr(clientid); |
---|
| 188 | + if (WARN_ON(!client)) |
---|
| 189 | + return; |
---|
| 190 | + mutex_unlock(&client->ioctl_mutex); |
---|
| 191 | + /* The doubly unrefs below are intentional; the first one releases the |
---|
| 192 | + * leftover from snd_seq_client_ioctl_lock() above, and the second one |
---|
| 193 | + * is for releasing snd_seq_client_use_ptr() in this function |
---|
| 194 | + */ |
---|
| 195 | + snd_seq_client_unlock(client); |
---|
| 196 | + snd_seq_client_unlock(client); |
---|
| 197 | +} |
---|
| 198 | +EXPORT_SYMBOL_GPL(snd_seq_client_ioctl_unlock); |
---|
181 | 199 | |
---|
182 | 200 | static void usage_alloc(struct snd_seq_usage *res, int num) |
---|
183 | 201 | { |
---|
.. | .. |
---|
203 | 221 | |
---|
204 | 222 | static struct snd_seq_client *seq_create_client1(int client_index, int poolsize) |
---|
205 | 223 | { |
---|
206 | | - unsigned long flags; |
---|
207 | 224 | int c; |
---|
208 | 225 | struct snd_seq_client *client; |
---|
209 | 226 | |
---|
.. | .. |
---|
224 | 241 | mutex_init(&client->ioctl_mutex); |
---|
225 | 242 | |
---|
226 | 243 | /* find free slot in the client table */ |
---|
227 | | - spin_lock_irqsave(&clients_lock, flags); |
---|
| 244 | + spin_lock_irq(&clients_lock); |
---|
228 | 245 | if (client_index < 0) { |
---|
229 | 246 | for (c = SNDRV_SEQ_DYNAMIC_CLIENTS_BEGIN; |
---|
230 | 247 | c < SNDRV_SEQ_MAX_CLIENTS; |
---|
.. | .. |
---|
232 | 249 | if (clienttab[c] || clienttablock[c]) |
---|
233 | 250 | continue; |
---|
234 | 251 | clienttab[client->number = c] = client; |
---|
235 | | - spin_unlock_irqrestore(&clients_lock, flags); |
---|
| 252 | + spin_unlock_irq(&clients_lock); |
---|
236 | 253 | return client; |
---|
237 | 254 | } |
---|
238 | 255 | } else { |
---|
239 | 256 | if (clienttab[client_index] == NULL && !clienttablock[client_index]) { |
---|
240 | 257 | clienttab[client->number = client_index] = client; |
---|
241 | | - spin_unlock_irqrestore(&clients_lock, flags); |
---|
| 258 | + spin_unlock_irq(&clients_lock); |
---|
242 | 259 | return client; |
---|
243 | 260 | } |
---|
244 | 261 | } |
---|
245 | | - spin_unlock_irqrestore(&clients_lock, flags); |
---|
| 262 | + spin_unlock_irq(&clients_lock); |
---|
246 | 263 | snd_seq_pool_delete(&client->pool); |
---|
247 | 264 | kfree(client); |
---|
248 | 265 | return NULL; /* no free slot found or busy, return failure code */ |
---|
.. | .. |
---|
251 | 268 | |
---|
252 | 269 | static int seq_free_client1(struct snd_seq_client *client) |
---|
253 | 270 | { |
---|
254 | | - unsigned long flags; |
---|
255 | | - |
---|
256 | 271 | if (!client) |
---|
257 | 272 | return 0; |
---|
258 | | - spin_lock_irqsave(&clients_lock, flags); |
---|
| 273 | + spin_lock_irq(&clients_lock); |
---|
259 | 274 | clienttablock[client->number] = 1; |
---|
260 | 275 | clienttab[client->number] = NULL; |
---|
261 | | - spin_unlock_irqrestore(&clients_lock, flags); |
---|
| 276 | + spin_unlock_irq(&clients_lock); |
---|
262 | 277 | snd_seq_delete_all_ports(client); |
---|
263 | 278 | snd_seq_queue_client_leave(client->number); |
---|
264 | 279 | snd_use_lock_sync(&client->use_lock); |
---|
265 | 280 | snd_seq_queue_client_termination(client->number); |
---|
266 | 281 | if (client->pool) |
---|
267 | 282 | snd_seq_pool_delete(&client->pool); |
---|
268 | | - spin_lock_irqsave(&clients_lock, flags); |
---|
| 283 | + spin_lock_irq(&clients_lock); |
---|
269 | 284 | clienttablock[client->number] = 0; |
---|
270 | | - spin_unlock_irqrestore(&clients_lock, flags); |
---|
| 285 | + spin_unlock_irq(&clients_lock); |
---|
271 | 286 | return 0; |
---|
272 | 287 | } |
---|
273 | 288 | |
---|
.. | .. |
---|
307 | 322 | struct snd_seq_user_client *user; |
---|
308 | 323 | int err; |
---|
309 | 324 | |
---|
310 | | - err = nonseekable_open(inode, file); |
---|
| 325 | + err = stream_open(inode, file); |
---|
311 | 326 | if (err < 0) |
---|
312 | 327 | return err; |
---|
313 | 328 | |
---|
.. | .. |
---|
393 | 408 | if (!(snd_seq_file_flags(file) & SNDRV_SEQ_LFLG_INPUT)) |
---|
394 | 409 | return -ENXIO; |
---|
395 | 410 | |
---|
396 | | - if (!access_ok(VERIFY_WRITE, buf, count)) |
---|
| 411 | + if (!access_ok(buf, count)) |
---|
397 | 412 | return -EFAULT; |
---|
398 | 413 | |
---|
399 | 414 | /* check client structures are in place */ |
---|
.. | .. |
---|
2229 | 2244 | } |
---|
2230 | 2245 | EXPORT_SYMBOL(snd_seq_delete_kernel_client); |
---|
2231 | 2246 | |
---|
2232 | | -/* skeleton to enqueue event, called from snd_seq_kernel_client_enqueue |
---|
2233 | | - * and snd_seq_kernel_client_enqueue_blocking |
---|
| 2247 | +/* |
---|
| 2248 | + * exported, called by kernel clients to enqueue events (w/o blocking) |
---|
| 2249 | + * |
---|
| 2250 | + * RETURN VALUE: zero if succeed, negative if error |
---|
2234 | 2251 | */ |
---|
2235 | | -static int kernel_client_enqueue(int client, struct snd_seq_event *ev, |
---|
2236 | | - struct file *file, int blocking, |
---|
2237 | | - int atomic, int hop) |
---|
| 2252 | +int snd_seq_kernel_client_enqueue(int client, struct snd_seq_event *ev, |
---|
| 2253 | + struct file *file, bool blocking) |
---|
2238 | 2254 | { |
---|
2239 | 2255 | struct snd_seq_client *cptr; |
---|
2240 | 2256 | int result; |
---|
.. | .. |
---|
2257 | 2273 | if (cptr == NULL) |
---|
2258 | 2274 | return -EINVAL; |
---|
2259 | 2275 | |
---|
2260 | | - if (! cptr->accept_output) |
---|
| 2276 | + if (!cptr->accept_output) { |
---|
2261 | 2277 | result = -EPERM; |
---|
2262 | | - else /* send it */ |
---|
| 2278 | + } else { /* send it */ |
---|
| 2279 | + mutex_lock(&cptr->ioctl_mutex); |
---|
2263 | 2280 | result = snd_seq_client_enqueue_event(cptr, ev, file, blocking, |
---|
2264 | | - atomic, hop, NULL); |
---|
| 2281 | + false, 0, |
---|
| 2282 | + &cptr->ioctl_mutex); |
---|
| 2283 | + mutex_unlock(&cptr->ioctl_mutex); |
---|
| 2284 | + } |
---|
2265 | 2285 | |
---|
2266 | 2286 | snd_seq_client_unlock(cptr); |
---|
2267 | 2287 | return result; |
---|
2268 | 2288 | } |
---|
2269 | | - |
---|
2270 | | -/* |
---|
2271 | | - * exported, called by kernel clients to enqueue events (w/o blocking) |
---|
2272 | | - * |
---|
2273 | | - * RETURN VALUE: zero if succeed, negative if error |
---|
2274 | | - */ |
---|
2275 | | -int snd_seq_kernel_client_enqueue(int client, struct snd_seq_event * ev, |
---|
2276 | | - int atomic, int hop) |
---|
2277 | | -{ |
---|
2278 | | - return kernel_client_enqueue(client, ev, NULL, 0, atomic, hop); |
---|
2279 | | -} |
---|
2280 | 2289 | EXPORT_SYMBOL(snd_seq_kernel_client_enqueue); |
---|
2281 | | - |
---|
2282 | | -/* |
---|
2283 | | - * exported, called by kernel clients to enqueue events (with blocking) |
---|
2284 | | - * |
---|
2285 | | - * RETURN VALUE: zero if succeed, negative if error |
---|
2286 | | - */ |
---|
2287 | | -int snd_seq_kernel_client_enqueue_blocking(int client, struct snd_seq_event * ev, |
---|
2288 | | - struct file *file, |
---|
2289 | | - int atomic, int hop) |
---|
2290 | | -{ |
---|
2291 | | - return kernel_client_enqueue(client, ev, file, 1, atomic, hop); |
---|
2292 | | -} |
---|
2293 | | -EXPORT_SYMBOL(snd_seq_kernel_client_enqueue_blocking); |
---|
2294 | 2290 | |
---|
2295 | 2291 | /* |
---|
2296 | 2292 | * exported, called by kernel clients to dispatch events directly to other |
---|