| .. | .. |
|---|
| 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 |
|---|