1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * OSS compatible sequencer driver
4 *
5 * MIDI device handlers
6 *
7 * Copyright (C) 1998,99 Takashi Iwai <tiwai@suse.de>
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 * constants
24 */
25 #define SNDRV_SEQ_OSS_MAX_MIDI_NAME 30
26
27 /*
28 * definition of midi device record
29 */
30 struct seq_oss_midi {
31 int seq_device; /* device number */
32 int client; /* sequencer client number */
33 int port; /* sequencer port number */
34 unsigned int flags; /* port capability */
35 int opened; /* flag for opening */
36 unsigned char name[SNDRV_SEQ_OSS_MAX_MIDI_NAME];
37 struct snd_midi_event *coder; /* MIDI event coder */
38 struct seq_oss_devinfo *devinfo; /* assigned OSSseq device */
39 snd_use_lock_t use_lock;
40 struct mutex open_mutex;
41 };
42
43 DEFINE_FREE(seq_oss_midi, struct seq_oss_midi *, if (!IS_ERR_OR_NULL(_T)) snd_use_lock_free(&(_T)->use_lock))
44
45 /*
46 * midi device table
47 */
48 static int max_midi_devs;
49 static struct seq_oss_midi *midi_devs[SNDRV_SEQ_OSS_MAX_MIDI_DEVS];
50
51 static DEFINE_SPINLOCK(register_lock);
52
53 /*
54 * prototypes
55 */
56 static struct seq_oss_midi *get_mdev(int dev);
57 static struct seq_oss_midi *get_mididev(struct seq_oss_devinfo *dp, int dev);
58 static int send_synth_event(struct seq_oss_devinfo *dp, struct snd_seq_event *ev, int dev);
59 static int send_midi_event(struct seq_oss_devinfo *dp, struct snd_seq_event *ev, struct seq_oss_midi *mdev);
60
61 /*
62 * look up the existing ports
63 * this looks a very exhausting job.
64 */
65 int
snd_seq_oss_midi_lookup_ports(int client)66 snd_seq_oss_midi_lookup_ports(int client)
67 {
68 struct snd_seq_client_info *clinfo __free(kfree) =
69 kzalloc_obj(*clinfo);
70 struct snd_seq_port_info *pinfo __free(kfree) =
71 kzalloc_obj(*pinfo);
72
73 if (!clinfo || !pinfo)
74 return -ENOMEM;
75 clinfo->client = -1;
76 while (snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_QUERY_NEXT_CLIENT, clinfo) == 0) {
77 if (clinfo->client == client)
78 continue; /* ignore myself */
79 pinfo->addr.client = clinfo->client;
80 pinfo->addr.port = -1;
81 while (snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT, pinfo) == 0)
82 snd_seq_oss_midi_check_new_port(pinfo);
83 }
84 return 0;
85 }
86
87
88 /*
89 */
90 static struct seq_oss_midi *
get_mdev(int dev)91 get_mdev(int dev)
92 {
93 struct seq_oss_midi *mdev;
94
95 guard(spinlock_irqsave)(®ister_lock);
96 mdev = midi_devs[dev];
97 if (mdev)
98 snd_use_lock_use(&mdev->use_lock);
99 return mdev;
100 }
101
102 /*
103 * look for the identical slot
104 */
105 static struct seq_oss_midi *
find_slot(int client,int port)106 find_slot(int client, int port)
107 {
108 int i;
109 struct seq_oss_midi *mdev;
110
111 guard(spinlock_irqsave)(®ister_lock);
112 for (i = 0; i < max_midi_devs; i++) {
113 mdev = midi_devs[i];
114 if (mdev && mdev->client == client && mdev->port == port) {
115 /* found! */
116 snd_use_lock_use(&mdev->use_lock);
117 return mdev;
118 }
119 }
120 return NULL;
121 }
122
123
124 #define PERM_WRITE (SNDRV_SEQ_PORT_CAP_WRITE|SNDRV_SEQ_PORT_CAP_SUBS_WRITE)
125 #define PERM_READ (SNDRV_SEQ_PORT_CAP_READ|SNDRV_SEQ_PORT_CAP_SUBS_READ)
126 /*
127 * register a new port if it doesn't exist yet
128 */
129 int
snd_seq_oss_midi_check_new_port(struct snd_seq_port_info * pinfo)130 snd_seq_oss_midi_check_new_port(struct snd_seq_port_info *pinfo)
131 {
132 int i;
133 struct seq_oss_midi *mdev;
134
135 /* the port must include generic midi */
136 if (! (pinfo->type & SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC))
137 return 0;
138 /* either read or write subscribable */
139 if ((pinfo->capability & PERM_WRITE) != PERM_WRITE &&
140 (pinfo->capability & PERM_READ) != PERM_READ)
141 return 0;
142
143 /*
144 * look for the identical slot
145 */
146 mdev = find_slot(pinfo->addr.client, pinfo->addr.port);
147 if (mdev) {
148 /* already exists */
149 snd_use_lock_free(&mdev->use_lock);
150 return 0;
151 }
152
153 /*
154 * allocate midi info record
155 */
156 mdev = kzalloc_obj(*mdev);
157 if (!mdev)
158 return -ENOMEM;
159
160 /* copy the port information */
161 mdev->client = pinfo->addr.client;
162 mdev->port = pinfo->addr.port;
163 mdev->flags = pinfo->capability;
164 mdev->opened = 0;
165 snd_use_lock_init(&mdev->use_lock);
166 mutex_init(&mdev->open_mutex);
167
168 /* copy and truncate the name of synth device */
169 strscpy(mdev->name, pinfo->name, sizeof(mdev->name));
170
171 /* create MIDI coder */
172 if (snd_midi_event_new(MAX_MIDI_EVENT_BUF, &mdev->coder) < 0) {
173 pr_err("ALSA: seq_oss: can't malloc midi coder\n");
174 kfree(mdev);
175 return -ENOMEM;
176 }
177 /* OSS sequencer adds running status to all sequences */
178 snd_midi_event_no_status(mdev->coder, 1);
179
180 /*
181 * look for en empty slot
182 */
183 guard(spinlock_irqsave)(®ister_lock);
184 for (i = 0; i < max_midi_devs; i++) {
185 if (midi_devs[i] == NULL)
186 break;
187 }
188 if (i >= max_midi_devs) {
189 if (max_midi_devs >= SNDRV_SEQ_OSS_MAX_MIDI_DEVS) {
190 snd_midi_event_free(mdev->coder);
191 kfree(mdev);
192 return -ENOMEM;
193 }
194 max_midi_devs++;
195 }
196 mdev->seq_device = i;
197 midi_devs[mdev->seq_device] = mdev;
198
199 return 0;
200 }
201
202 /*
203 * release the midi device if it was registered
204 */
205 int
snd_seq_oss_midi_check_exit_port(int client,int port)206 snd_seq_oss_midi_check_exit_port(int client, int port)
207 {
208 struct seq_oss_midi *mdev;
209 int index;
210
211 mdev = find_slot(client, port);
212 if (mdev) {
213 scoped_guard(spinlock_irqsave, ®ister_lock) {
214 midi_devs[mdev->seq_device] = NULL;
215 }
216 snd_use_lock_free(&mdev->use_lock);
217 snd_use_lock_sync(&mdev->use_lock);
218 snd_midi_event_free(mdev->coder);
219 kfree(mdev);
220 }
221 guard(spinlock_irqsave)(®ister_lock);
222 for (index = max_midi_devs - 1; index >= 0; index--) {
223 if (midi_devs[index])
224 break;
225 }
226 max_midi_devs = index + 1;
227 return 0;
228 }
229
230
231 /*
232 * release the midi device if it was registered
233 */
234 void
snd_seq_oss_midi_clear_all(void)235 snd_seq_oss_midi_clear_all(void)
236 {
237 int i;
238 struct seq_oss_midi *mdev;
239
240 guard(spinlock_irqsave)(®ister_lock);
241 for (i = 0; i < max_midi_devs; i++) {
242 mdev = midi_devs[i];
243 if (mdev) {
244 snd_midi_event_free(mdev->coder);
245 kfree(mdev);
246 midi_devs[i] = NULL;
247 }
248 }
249 max_midi_devs = 0;
250 }
251
252
253 /*
254 * set up midi tables
255 */
256 void
snd_seq_oss_midi_setup(struct seq_oss_devinfo * dp)257 snd_seq_oss_midi_setup(struct seq_oss_devinfo *dp)
258 {
259 guard(spinlock_irq)(®ister_lock);
260 dp->max_mididev = max_midi_devs;
261 }
262
263 /*
264 * clean up midi tables
265 */
266 void
snd_seq_oss_midi_cleanup(struct seq_oss_devinfo * dp)267 snd_seq_oss_midi_cleanup(struct seq_oss_devinfo *dp)
268 {
269 int i;
270 for (i = 0; i < dp->max_mididev; i++)
271 snd_seq_oss_midi_close(dp, i);
272 dp->max_mididev = 0;
273 }
274
275
276 /*
277 * open all midi devices. ignore errors.
278 */
279 void
snd_seq_oss_midi_open_all(struct seq_oss_devinfo * dp,int file_mode)280 snd_seq_oss_midi_open_all(struct seq_oss_devinfo *dp, int file_mode)
281 {
282 int i;
283 for (i = 0; i < dp->max_mididev; i++)
284 snd_seq_oss_midi_open(dp, i, file_mode);
285 }
286
287
288 /*
289 * get the midi device information
290 */
291 static struct seq_oss_midi *
get_mididev(struct seq_oss_devinfo * dp,int dev)292 get_mididev(struct seq_oss_devinfo *dp, int dev)
293 {
294 if (dev < 0 || dev >= dp->max_mididev)
295 return NULL;
296 dev = array_index_nospec(dev, dp->max_mididev);
297 return get_mdev(dev);
298 }
299
300
301 /*
302 * open the midi device if not opened yet
303 */
304 int
snd_seq_oss_midi_open(struct seq_oss_devinfo * dp,int dev,int fmode)305 snd_seq_oss_midi_open(struct seq_oss_devinfo *dp, int dev, int fmode)
306 {
307 int perm;
308 struct snd_seq_port_subscribe subs;
309 struct seq_oss_midi *mdev __free(seq_oss_midi) =
310 get_mididev(dp, dev);
311
312 if (!mdev)
313 return -ENODEV;
314
315 guard(mutex)(&mdev->open_mutex);
316 /* already used? */
317 if (mdev->opened && mdev->devinfo != dp)
318 return -EBUSY;
319
320 perm = 0;
321 if (is_write_mode(fmode))
322 perm |= PERM_WRITE;
323 if (is_read_mode(fmode))
324 perm |= PERM_READ;
325 perm &= mdev->flags;
326 if (perm == 0)
327 return -ENXIO;
328
329 /* already opened? */
330 if ((mdev->opened & perm) == perm)
331 return 0;
332
333 perm &= ~mdev->opened;
334
335 memset(&subs, 0, sizeof(subs));
336
337 if (perm & PERM_WRITE) {
338 subs.sender = dp->addr;
339 subs.dest.client = mdev->client;
340 subs.dest.port = mdev->port;
341 if (snd_seq_kernel_client_ctl(dp->cseq, SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, &subs) >= 0)
342 mdev->opened |= PERM_WRITE;
343 }
344 if (perm & PERM_READ) {
345 subs.sender.client = mdev->client;
346 subs.sender.port = mdev->port;
347 subs.dest = dp->addr;
348 subs.flags = SNDRV_SEQ_PORT_SUBS_TIMESTAMP;
349 subs.queue = dp->queue; /* queue for timestamps */
350 if (snd_seq_kernel_client_ctl(dp->cseq, SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, &subs) >= 0)
351 mdev->opened |= PERM_READ;
352 }
353
354 if (!mdev->opened)
355 return -ENXIO;
356
357 mdev->devinfo = dp;
358 return 0;
359 }
360
361 /*
362 * close the midi device if already opened
363 */
364 int
snd_seq_oss_midi_close(struct seq_oss_devinfo * dp,int dev)365 snd_seq_oss_midi_close(struct seq_oss_devinfo *dp, int dev)
366 {
367 struct snd_seq_port_subscribe subs;
368 struct seq_oss_midi *mdev __free(seq_oss_midi) =
369 get_mididev(dp, dev);
370
371 if (!mdev)
372 return -ENODEV;
373 guard(mutex)(&mdev->open_mutex);
374 if (!mdev->opened || mdev->devinfo != dp)
375 return 0;
376
377 memset(&subs, 0, sizeof(subs));
378 if (mdev->opened & PERM_WRITE) {
379 subs.sender = dp->addr;
380 subs.dest.client = mdev->client;
381 subs.dest.port = mdev->port;
382 snd_seq_kernel_client_ctl(dp->cseq, SNDRV_SEQ_IOCTL_UNSUBSCRIBE_PORT, &subs);
383 }
384 if (mdev->opened & PERM_READ) {
385 subs.sender.client = mdev->client;
386 subs.sender.port = mdev->port;
387 subs.dest = dp->addr;
388 snd_seq_kernel_client_ctl(dp->cseq, SNDRV_SEQ_IOCTL_UNSUBSCRIBE_PORT, &subs);
389 }
390
391 mdev->opened = 0;
392 mdev->devinfo = NULL;
393 return 0;
394 }
395
396 /*
397 * change seq capability flags to file mode flags
398 */
399 int
snd_seq_oss_midi_filemode(struct seq_oss_devinfo * dp,int dev)400 snd_seq_oss_midi_filemode(struct seq_oss_devinfo *dp, int dev)
401 {
402 int mode;
403 struct seq_oss_midi *mdev __free(seq_oss_midi) =
404 get_mididev(dp, dev);
405
406 if (!mdev)
407 return 0;
408
409 mode = 0;
410 if (mdev->opened & PERM_WRITE)
411 mode |= SNDRV_SEQ_OSS_FILE_WRITE;
412 if (mdev->opened & PERM_READ)
413 mode |= SNDRV_SEQ_OSS_FILE_READ;
414
415 return mode;
416 }
417
418 /*
419 * reset the midi device and close it:
420 * so far, only close the device.
421 */
422 void
snd_seq_oss_midi_reset(struct seq_oss_devinfo * dp,int dev)423 snd_seq_oss_midi_reset(struct seq_oss_devinfo *dp, int dev)
424 {
425 struct seq_oss_midi *mdev __free(seq_oss_midi) =
426 get_mididev(dp, dev);
427
428 if (!mdev)
429 return;
430 if (!mdev->opened)
431 return;
432
433 if (mdev->opened & PERM_WRITE) {
434 struct snd_seq_event ev;
435 int c;
436
437 memset(&ev, 0, sizeof(ev));
438 ev.dest.client = mdev->client;
439 ev.dest.port = mdev->port;
440 ev.queue = dp->queue;
441 ev.source.port = dp->port;
442 if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_SYNTH) {
443 ev.type = SNDRV_SEQ_EVENT_SENSING;
444 snd_seq_oss_dispatch(dp, &ev, 0, 0);
445 }
446 for (c = 0; c < 16; c++) {
447 ev.type = SNDRV_SEQ_EVENT_CONTROLLER;
448 ev.data.control.channel = c;
449 ev.data.control.param = MIDI_CTL_ALL_NOTES_OFF;
450 snd_seq_oss_dispatch(dp, &ev, 0, 0);
451 if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC) {
452 ev.data.control.param =
453 MIDI_CTL_RESET_CONTROLLERS;
454 snd_seq_oss_dispatch(dp, &ev, 0, 0);
455 ev.type = SNDRV_SEQ_EVENT_PITCHBEND;
456 ev.data.control.value = 0;
457 snd_seq_oss_dispatch(dp, &ev, 0, 0);
458 }
459 }
460 }
461 // snd_seq_oss_midi_close(dp, dev);
462 }
463
464
465 /*
466 * get client/port of the specified MIDI device
467 */
468 void
snd_seq_oss_midi_get_addr(struct seq_oss_devinfo * dp,int dev,struct snd_seq_addr * addr)469 snd_seq_oss_midi_get_addr(struct seq_oss_devinfo *dp, int dev, struct snd_seq_addr *addr)
470 {
471 struct seq_oss_midi *mdev __free(seq_oss_midi) =
472 get_mididev(dp, dev);
473
474 if (!mdev)
475 return;
476 addr->client = mdev->client;
477 addr->port = mdev->port;
478 }
479
480
481 /*
482 * input callback - this can be atomic
483 */
484 int
snd_seq_oss_midi_input(struct snd_seq_event * ev,int direct,void * private_data)485 snd_seq_oss_midi_input(struct snd_seq_event *ev, int direct, void *private_data)
486 {
487 struct seq_oss_devinfo *dp = (struct seq_oss_devinfo *)private_data;
488
489 if (dp->readq == NULL)
490 return 0;
491 struct seq_oss_midi *mdev __free(seq_oss_midi) =
492 find_slot(ev->source.client, ev->source.port);
493 if (!mdev)
494 return 0;
495 if (!(mdev->opened & PERM_READ))
496 return 0;
497
498 if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC)
499 return send_synth_event(dp, ev, mdev->seq_device);
500 else
501 return send_midi_event(dp, ev, mdev);
502 }
503
504 /*
505 * convert ALSA sequencer event to OSS synth event
506 */
507 static int
send_synth_event(struct seq_oss_devinfo * dp,struct snd_seq_event * ev,int dev)508 send_synth_event(struct seq_oss_devinfo *dp, struct snd_seq_event *ev, int dev)
509 {
510 union evrec ossev;
511
512 memset(&ossev, 0, sizeof(ossev));
513
514 switch (ev->type) {
515 case SNDRV_SEQ_EVENT_NOTEON:
516 ossev.v.cmd = MIDI_NOTEON; break;
517 case SNDRV_SEQ_EVENT_NOTEOFF:
518 ossev.v.cmd = MIDI_NOTEOFF; break;
519 case SNDRV_SEQ_EVENT_KEYPRESS:
520 ossev.v.cmd = MIDI_KEY_PRESSURE; break;
521 case SNDRV_SEQ_EVENT_CONTROLLER:
522 ossev.l.cmd = MIDI_CTL_CHANGE; break;
523 case SNDRV_SEQ_EVENT_PGMCHANGE:
524 ossev.l.cmd = MIDI_PGM_CHANGE; break;
525 case SNDRV_SEQ_EVENT_CHANPRESS:
526 ossev.l.cmd = MIDI_CHN_PRESSURE; break;
527 case SNDRV_SEQ_EVENT_PITCHBEND:
528 ossev.l.cmd = MIDI_PITCH_BEND; break;
529 default:
530 return 0; /* not supported */
531 }
532
533 ossev.v.dev = dev;
534
535 switch (ev->type) {
536 case SNDRV_SEQ_EVENT_NOTEON:
537 case SNDRV_SEQ_EVENT_NOTEOFF:
538 case SNDRV_SEQ_EVENT_KEYPRESS:
539 ossev.v.code = EV_CHN_VOICE;
540 ossev.v.note = ev->data.note.note;
541 ossev.v.parm = ev->data.note.velocity;
542 ossev.v.chn = ev->data.note.channel;
543 break;
544 case SNDRV_SEQ_EVENT_CONTROLLER:
545 case SNDRV_SEQ_EVENT_PGMCHANGE:
546 case SNDRV_SEQ_EVENT_CHANPRESS:
547 ossev.l.code = EV_CHN_COMMON;
548 ossev.l.p1 = ev->data.control.param;
549 ossev.l.val = ev->data.control.value;
550 ossev.l.chn = ev->data.control.channel;
551 break;
552 case SNDRV_SEQ_EVENT_PITCHBEND:
553 ossev.l.code = EV_CHN_COMMON;
554 ossev.l.val = ev->data.control.value + 8192;
555 ossev.l.chn = ev->data.control.channel;
556 break;
557 }
558
559 snd_seq_oss_readq_put_timestamp(dp->readq, ev->time.tick, dp->seq_mode);
560 snd_seq_oss_readq_put_event(dp->readq, &ossev);
561
562 return 0;
563 }
564
565 /*
566 * decode event and send MIDI bytes to read queue
567 */
568 static int
send_midi_event(struct seq_oss_devinfo * dp,struct snd_seq_event * ev,struct seq_oss_midi * mdev)569 send_midi_event(struct seq_oss_devinfo *dp, struct snd_seq_event *ev, struct seq_oss_midi *mdev)
570 {
571 char msg[32];
572 int len;
573
574 snd_seq_oss_readq_put_timestamp(dp->readq, ev->time.tick, dp->seq_mode);
575 if (!dp->timer->running)
576 len = snd_seq_oss_timer_start(dp->timer);
577 if (ev->type == SNDRV_SEQ_EVENT_SYSEX) {
578 snd_seq_oss_readq_sysex(dp->readq, mdev->seq_device, ev);
579 snd_midi_event_reset_decode(mdev->coder);
580 } else {
581 len = snd_midi_event_decode(mdev->coder, msg, sizeof(msg), ev);
582 if (len > 0)
583 snd_seq_oss_readq_puts(dp->readq, mdev->seq_device, msg, len);
584 }
585
586 return 0;
587 }
588
589
590 /*
591 * dump midi data
592 * return 0 : enqueued
593 * non-zero : invalid - ignored
594 */
595 int
snd_seq_oss_midi_putc(struct seq_oss_devinfo * dp,int dev,unsigned char c,struct snd_seq_event * ev)596 snd_seq_oss_midi_putc(struct seq_oss_devinfo *dp, int dev, unsigned char c, struct snd_seq_event *ev)
597 {
598 struct seq_oss_midi *mdev __free(seq_oss_midi) =
599 get_mididev(dp, dev);
600
601 if (!mdev)
602 return -ENODEV;
603 if (snd_midi_event_encode_byte(mdev->coder, c, ev)) {
604 snd_seq_oss_fill_addr(dp, ev, mdev->client, mdev->port);
605 return 0;
606 }
607 return -EINVAL;
608 }
609
610 /*
611 * create OSS compatible midi_info record
612 */
613 int
snd_seq_oss_midi_make_info(struct seq_oss_devinfo * dp,int dev,struct midi_info * inf)614 snd_seq_oss_midi_make_info(struct seq_oss_devinfo *dp, int dev, struct midi_info *inf)
615 {
616 struct seq_oss_midi *mdev __free(seq_oss_midi) =
617 get_mididev(dp, dev);
618
619 if (!mdev)
620 return -ENXIO;
621 inf->device = dev;
622 inf->dev_type = 0; /* FIXME: ?? */
623 inf->capabilities = 0; /* FIXME: ?? */
624 strscpy(inf->name, mdev->name, sizeof(inf->name));
625 return 0;
626 }
627
628
629 #ifdef CONFIG_SND_PROC_FS
630 /*
631 * proc interface
632 */
633 static char *
capmode_str(int val)634 capmode_str(int val)
635 {
636 val &= PERM_READ|PERM_WRITE;
637 if (val == (PERM_READ|PERM_WRITE))
638 return "read/write";
639 else if (val == PERM_READ)
640 return "read";
641 else if (val == PERM_WRITE)
642 return "write";
643 else
644 return "none";
645 }
646
647 void
snd_seq_oss_midi_info_read(struct snd_info_buffer * buf)648 snd_seq_oss_midi_info_read(struct snd_info_buffer *buf)
649 {
650 int i;
651
652 snd_iprintf(buf, "\nNumber of MIDI devices: %d\n", max_midi_devs);
653 for (i = 0; i < max_midi_devs; i++) {
654 snd_iprintf(buf, "\nmidi %d: ", i);
655 struct seq_oss_midi *mdev __free(seq_oss_midi) =
656 get_mdev(i);
657 if (mdev == NULL) {
658 snd_iprintf(buf, "*empty*\n");
659 continue;
660 }
661 snd_iprintf(buf, "[%s] ALSA port %d:%d\n", mdev->name,
662 mdev->client, mdev->port);
663 snd_iprintf(buf, " capability %s / opened %s\n",
664 capmode_str(mdev->flags),
665 capmode_str(mdev->opened));
666 }
667 }
668 #endif /* CONFIG_SND_PROC_FS */
669