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