xref: /linux/sound/core/seq/oss/seq_oss_midi.c (revision ab669ac2bc418a3ef1a1541ea6e1ef5dc8c87a3f)
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
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 *
91 get_mdev(int dev)
92 {
93 	struct seq_oss_midi *mdev;
94 
95 	guard(spinlock_irqsave)(&register_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 *
106 find_slot(int client, int port)
107 {
108 	int i;
109 	struct seq_oss_midi *mdev;
110 
111 	guard(spinlock_irqsave)(&register_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
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)(&register_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
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, &register_lock) {
214 			/* Only one callback may release the device. */
215 			if (midi_devs[mdev->seq_device] != mdev) {
216 				snd_use_lock_free(&mdev->use_lock);
217 				return 0;
218 			}
219 			midi_devs[mdev->seq_device] = NULL;
220 		}
221 		snd_use_lock_free(&mdev->use_lock);
222 		snd_use_lock_sync(&mdev->use_lock);
223 		snd_midi_event_free(mdev->coder);
224 		kfree(mdev);
225 	}
226 	guard(spinlock_irqsave)(&register_lock);
227 	for (index = max_midi_devs - 1; index >= 0; index--) {
228 		if (midi_devs[index])
229 			break;
230 	}
231 	max_midi_devs = index + 1;
232 	return 0;
233 }
234 
235 
236 /*
237  * release the midi device if it was registered
238  */
239 void
240 snd_seq_oss_midi_clear_all(void)
241 {
242 	int i;
243 	struct seq_oss_midi *mdev;
244 
245 	guard(spinlock_irqsave)(&register_lock);
246 	for (i = 0; i < max_midi_devs; i++) {
247 		mdev = midi_devs[i];
248 		if (mdev) {
249 			snd_midi_event_free(mdev->coder);
250 			kfree(mdev);
251 			midi_devs[i] = NULL;
252 		}
253 	}
254 	max_midi_devs = 0;
255 }
256 
257 
258 /*
259  * set up midi tables
260  */
261 void
262 snd_seq_oss_midi_setup(struct seq_oss_devinfo *dp)
263 {
264 	guard(spinlock_irq)(&register_lock);
265 	dp->max_mididev = max_midi_devs;
266 }
267 
268 /*
269  * clean up midi tables
270  */
271 void
272 snd_seq_oss_midi_cleanup(struct seq_oss_devinfo *dp)
273 {
274 	int i;
275 	for (i = 0; i < dp->max_mididev; i++)
276 		snd_seq_oss_midi_close(dp, i);
277 	dp->max_mididev = 0;
278 }
279 
280 
281 /*
282  * open all midi devices.  ignore errors.
283  */
284 void
285 snd_seq_oss_midi_open_all(struct seq_oss_devinfo *dp, int file_mode)
286 {
287 	int i;
288 	for (i = 0; i < dp->max_mididev; i++)
289 		snd_seq_oss_midi_open(dp, i, file_mode);
290 }
291 
292 
293 /*
294  * get the midi device information
295  */
296 static struct seq_oss_midi *
297 get_mididev(struct seq_oss_devinfo *dp, int dev)
298 {
299 	if (dev < 0 || dev >= dp->max_mididev)
300 		return NULL;
301 	dev = array_index_nospec(dev, dp->max_mididev);
302 	return get_mdev(dev);
303 }
304 
305 
306 /*
307  * open the midi device if not opened yet
308  */
309 int
310 snd_seq_oss_midi_open(struct seq_oss_devinfo *dp, int dev, int fmode)
311 {
312 	int perm;
313 	struct snd_seq_port_subscribe subs;
314 	struct seq_oss_midi *mdev __free(seq_oss_midi) =
315 		get_mididev(dp, dev);
316 
317 	if (!mdev)
318 		return -ENODEV;
319 
320 	guard(mutex)(&mdev->open_mutex);
321 	/* already used? */
322 	if (mdev->opened && mdev->devinfo != dp)
323 		return -EBUSY;
324 
325 	perm = 0;
326 	if (is_write_mode(fmode))
327 		perm |= PERM_WRITE;
328 	if (is_read_mode(fmode))
329 		perm |= PERM_READ;
330 	perm &= mdev->flags;
331 	if (perm == 0)
332 		return -ENXIO;
333 
334 	/* already opened? */
335 	if ((mdev->opened & perm) == perm)
336 		return 0;
337 
338 	perm &= ~mdev->opened;
339 
340 	memset(&subs, 0, sizeof(subs));
341 
342 	if (perm & PERM_WRITE) {
343 		subs.sender = dp->addr;
344 		subs.dest.client = mdev->client;
345 		subs.dest.port = mdev->port;
346 		if (snd_seq_kernel_client_ctl(dp->cseq, SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, &subs) >= 0)
347 			mdev->opened |= PERM_WRITE;
348 	}
349 	if (perm & PERM_READ) {
350 		subs.sender.client = mdev->client;
351 		subs.sender.port = mdev->port;
352 		subs.dest = dp->addr;
353 		subs.flags = SNDRV_SEQ_PORT_SUBS_TIMESTAMP;
354 		subs.queue = dp->queue;		/* queue for timestamps */
355 		if (snd_seq_kernel_client_ctl(dp->cseq, SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, &subs) >= 0)
356 			mdev->opened |= PERM_READ;
357 	}
358 
359 	if (!mdev->opened)
360 		return -ENXIO;
361 
362 	mdev->devinfo = dp;
363 	return 0;
364 }
365 
366 /*
367  * close the midi device if already opened
368  */
369 int
370 snd_seq_oss_midi_close(struct seq_oss_devinfo *dp, int dev)
371 {
372 	struct snd_seq_port_subscribe subs;
373 	struct seq_oss_midi *mdev __free(seq_oss_midi) =
374 		get_mididev(dp, dev);
375 
376 	if (!mdev)
377 		return -ENODEV;
378 	guard(mutex)(&mdev->open_mutex);
379 	if (!mdev->opened || mdev->devinfo != dp)
380 		return 0;
381 
382 	memset(&subs, 0, sizeof(subs));
383 	if (mdev->opened & PERM_WRITE) {
384 		subs.sender = dp->addr;
385 		subs.dest.client = mdev->client;
386 		subs.dest.port = mdev->port;
387 		snd_seq_kernel_client_ctl(dp->cseq, SNDRV_SEQ_IOCTL_UNSUBSCRIBE_PORT, &subs);
388 	}
389 	if (mdev->opened & PERM_READ) {
390 		subs.sender.client = mdev->client;
391 		subs.sender.port = mdev->port;
392 		subs.dest = dp->addr;
393 		snd_seq_kernel_client_ctl(dp->cseq, SNDRV_SEQ_IOCTL_UNSUBSCRIBE_PORT, &subs);
394 	}
395 
396 	mdev->opened = 0;
397 	mdev->devinfo = NULL;
398 	return 0;
399 }
400 
401 /*
402  * change seq capability flags to file mode flags
403  */
404 int
405 snd_seq_oss_midi_filemode(struct seq_oss_devinfo *dp, int dev)
406 {
407 	int mode;
408 	struct seq_oss_midi *mdev __free(seq_oss_midi) =
409 		get_mididev(dp, dev);
410 
411 	if (!mdev)
412 		return 0;
413 
414 	mode = 0;
415 	if (mdev->opened & PERM_WRITE)
416 		mode |= SNDRV_SEQ_OSS_FILE_WRITE;
417 	if (mdev->opened & PERM_READ)
418 		mode |= SNDRV_SEQ_OSS_FILE_READ;
419 
420 	return mode;
421 }
422 
423 /*
424  * reset the midi device and close it:
425  * so far, only close the device.
426  */
427 void
428 snd_seq_oss_midi_reset(struct seq_oss_devinfo *dp, int dev)
429 {
430 	struct seq_oss_midi *mdev __free(seq_oss_midi) =
431 		get_mididev(dp, dev);
432 
433 	if (!mdev)
434 		return;
435 	if (!mdev->opened)
436 		return;
437 
438 	if (mdev->opened & PERM_WRITE) {
439 		struct snd_seq_event ev;
440 		int c;
441 
442 		memset(&ev, 0, sizeof(ev));
443 		ev.dest.client = mdev->client;
444 		ev.dest.port = mdev->port;
445 		ev.queue = dp->queue;
446 		ev.source.port = dp->port;
447 		if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_SYNTH) {
448 			ev.type = SNDRV_SEQ_EVENT_SENSING;
449 			snd_seq_oss_dispatch(dp, &ev, 0, 0);
450 		}
451 		for (c = 0; c < 16; c++) {
452 			ev.type = SNDRV_SEQ_EVENT_CONTROLLER;
453 			ev.data.control.channel = c;
454 			ev.data.control.param = MIDI_CTL_ALL_NOTES_OFF;
455 			snd_seq_oss_dispatch(dp, &ev, 0, 0);
456 			if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC) {
457 				ev.data.control.param =
458 					MIDI_CTL_RESET_CONTROLLERS;
459 				snd_seq_oss_dispatch(dp, &ev, 0, 0);
460 				ev.type = SNDRV_SEQ_EVENT_PITCHBEND;
461 				ev.data.control.value = 0;
462 				snd_seq_oss_dispatch(dp, &ev, 0, 0);
463 			}
464 		}
465 	}
466 	// snd_seq_oss_midi_close(dp, dev);
467 }
468 
469 
470 /*
471  * get client/port of the specified MIDI device
472  */
473 void
474 snd_seq_oss_midi_get_addr(struct seq_oss_devinfo *dp, int dev, struct snd_seq_addr *addr)
475 {
476 	struct seq_oss_midi *mdev __free(seq_oss_midi) =
477 		get_mididev(dp, dev);
478 
479 	if (!mdev)
480 		return;
481 	addr->client = mdev->client;
482 	addr->port = mdev->port;
483 }
484 
485 
486 /*
487  * input callback - this can be atomic
488  */
489 int
490 snd_seq_oss_midi_input(struct snd_seq_event *ev, int direct, void *private_data)
491 {
492 	struct seq_oss_devinfo *dp = (struct seq_oss_devinfo *)private_data;
493 
494 	if (dp->readq == NULL)
495 		return 0;
496 	struct seq_oss_midi *mdev __free(seq_oss_midi) =
497 		find_slot(ev->source.client, ev->source.port);
498 	if (!mdev)
499 		return 0;
500 	if (!(mdev->opened & PERM_READ))
501 		return 0;
502 
503 	if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC)
504 		return send_synth_event(dp, ev, mdev->seq_device);
505 	else
506 		return send_midi_event(dp, ev, mdev);
507 }
508 
509 /*
510  * convert ALSA sequencer event to OSS synth event
511  */
512 static int
513 send_synth_event(struct seq_oss_devinfo *dp, struct snd_seq_event *ev, int dev)
514 {
515 	union evrec ossev;
516 
517 	memset(&ossev, 0, sizeof(ossev));
518 
519 	switch (ev->type) {
520 	case SNDRV_SEQ_EVENT_NOTEON:
521 		ossev.v.cmd = MIDI_NOTEON; break;
522 	case SNDRV_SEQ_EVENT_NOTEOFF:
523 		ossev.v.cmd = MIDI_NOTEOFF; break;
524 	case SNDRV_SEQ_EVENT_KEYPRESS:
525 		ossev.v.cmd = MIDI_KEY_PRESSURE; break;
526 	case SNDRV_SEQ_EVENT_CONTROLLER:
527 		ossev.l.cmd = MIDI_CTL_CHANGE; break;
528 	case SNDRV_SEQ_EVENT_PGMCHANGE:
529 		ossev.l.cmd = MIDI_PGM_CHANGE; break;
530 	case SNDRV_SEQ_EVENT_CHANPRESS:
531 		ossev.l.cmd = MIDI_CHN_PRESSURE; break;
532 	case SNDRV_SEQ_EVENT_PITCHBEND:
533 		ossev.l.cmd = MIDI_PITCH_BEND; break;
534 	default:
535 		return 0; /* not supported */
536 	}
537 
538 	ossev.v.dev = dev;
539 
540 	switch (ev->type) {
541 	case SNDRV_SEQ_EVENT_NOTEON:
542 	case SNDRV_SEQ_EVENT_NOTEOFF:
543 	case SNDRV_SEQ_EVENT_KEYPRESS:
544 		ossev.v.code = EV_CHN_VOICE;
545 		ossev.v.note = ev->data.note.note;
546 		ossev.v.parm = ev->data.note.velocity;
547 		ossev.v.chn = ev->data.note.channel;
548 		break;
549 	case SNDRV_SEQ_EVENT_CONTROLLER:
550 	case SNDRV_SEQ_EVENT_PGMCHANGE:
551 	case SNDRV_SEQ_EVENT_CHANPRESS:
552 		ossev.l.code = EV_CHN_COMMON;
553 		ossev.l.p1 = ev->data.control.param;
554 		ossev.l.val = ev->data.control.value;
555 		ossev.l.chn = ev->data.control.channel;
556 		break;
557 	case SNDRV_SEQ_EVENT_PITCHBEND:
558 		ossev.l.code = EV_CHN_COMMON;
559 		ossev.l.val = ev->data.control.value + 8192;
560 		ossev.l.chn = ev->data.control.channel;
561 		break;
562 	}
563 
564 	snd_seq_oss_readq_put_timestamp(dp->readq, ev->time.tick, dp->seq_mode);
565 	snd_seq_oss_readq_put_event(dp->readq, &ossev);
566 
567 	return 0;
568 }
569 
570 /*
571  * decode event and send MIDI bytes to read queue
572  */
573 static int
574 send_midi_event(struct seq_oss_devinfo *dp, struct snd_seq_event *ev, struct seq_oss_midi *mdev)
575 {
576 	char msg[32];
577 	int len;
578 
579 	snd_seq_oss_readq_put_timestamp(dp->readq, ev->time.tick, dp->seq_mode);
580 	if (!dp->timer->running)
581 		len = snd_seq_oss_timer_start(dp->timer);
582 	if (ev->type == SNDRV_SEQ_EVENT_SYSEX) {
583 		snd_seq_oss_readq_sysex(dp->readq, mdev->seq_device, ev);
584 		snd_midi_event_reset_decode(mdev->coder);
585 	} else {
586 		len = snd_midi_event_decode(mdev->coder, msg, sizeof(msg), ev);
587 		if (len > 0)
588 			snd_seq_oss_readq_puts(dp->readq, mdev->seq_device, msg, len);
589 	}
590 
591 	return 0;
592 }
593 
594 
595 /*
596  * dump midi data
597  * return 0 : enqueued
598  *        non-zero : invalid - ignored
599  */
600 int
601 snd_seq_oss_midi_putc(struct seq_oss_devinfo *dp, int dev, unsigned char c,
602 		      struct snd_seq_event *ev, snd_use_lock_t **lockp)
603 {
604 	struct seq_oss_midi *mdev __free(seq_oss_midi) =
605 		get_mididev(dp, dev);
606 
607 	if (!mdev)
608 		return -ENODEV;
609 	if (snd_midi_event_encode_byte(mdev->coder, c, ev)) {
610 		snd_seq_oss_fill_addr(dp, ev, mdev->client, mdev->port);
611 		/* the caller must release this later */
612 		*lockp = &mdev->use_lock;
613 		snd_use_lock_use(*lockp);
614 		return 0;
615 	}
616 	return -EINVAL;
617 }
618 
619 /*
620  * create OSS compatible midi_info record
621  */
622 int
623 snd_seq_oss_midi_make_info(struct seq_oss_devinfo *dp, int dev, struct midi_info *inf)
624 {
625 	struct seq_oss_midi *mdev __free(seq_oss_midi) =
626 		get_mididev(dp, dev);
627 
628 	if (!mdev)
629 		return -ENXIO;
630 	inf->device = dev;
631 	inf->dev_type = 0; /* FIXME: ?? */
632 	inf->capabilities = 0; /* FIXME: ?? */
633 	strscpy(inf->name, mdev->name, sizeof(inf->name));
634 	return 0;
635 }
636 
637 
638 #ifdef CONFIG_SND_PROC_FS
639 /*
640  * proc interface
641  */
642 static char *
643 capmode_str(int val)
644 {
645 	val &= PERM_READ|PERM_WRITE;
646 	if (val == (PERM_READ|PERM_WRITE))
647 		return "read/write";
648 	else if (val == PERM_READ)
649 		return "read";
650 	else if (val == PERM_WRITE)
651 		return "write";
652 	else
653 		return "none";
654 }
655 
656 void
657 snd_seq_oss_midi_info_read(struct snd_info_buffer *buf)
658 {
659 	int i;
660 
661 	snd_iprintf(buf, "\nNumber of MIDI devices: %d\n", max_midi_devs);
662 	for (i = 0; i < max_midi_devs; i++) {
663 		snd_iprintf(buf, "\nmidi %d: ", i);
664 		struct seq_oss_midi *mdev __free(seq_oss_midi) =
665 			get_mdev(i);
666 		if (mdev == NULL) {
667 			snd_iprintf(buf, "*empty*\n");
668 			continue;
669 		}
670 		snd_iprintf(buf, "[%s] ALSA port %d:%d\n", mdev->name,
671 			    mdev->client, mdev->port);
672 		snd_iprintf(buf, "  capability %s / opened %s\n",
673 			    capmode_str(mdev->flags),
674 			    capmode_str(mdev->opened));
675 	}
676 }
677 #endif /* CONFIG_SND_PROC_FS */
678