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
snd_seq_oss_midi_lookup_ports(int client)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 *
get_mdev(int dev)95 get_mdev(int dev)
96 {
97 struct seq_oss_midi *mdev;
98 unsigned long flags;
99
100 spin_lock_irqsave(®ister_lock, flags);
101 mdev = midi_devs[dev];
102 if (mdev)
103 snd_use_lock_use(&mdev->use_lock);
104 spin_unlock_irqrestore(®ister_lock, flags);
105 return mdev;
106 }
107
108 /*
109 * look for the identical slot
110 */
111 static struct seq_oss_midi *
find_slot(int client,int port)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(®ister_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(®ister_lock, flags);
125 return mdev;
126 }
127 }
128 spin_unlock_irqrestore(®ister_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
snd_seq_oss_midi_check_new_port(struct snd_seq_port_info * pinfo)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(®ister_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(®ister_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(®ister_lock, flags);
210
211 return 0;
212 }
213
214 /*
215 * release the midi device if it was registered
216 */
217 int
snd_seq_oss_midi_check_exit_port(int client,int port)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(®ister_lock, flags);
227 midi_devs[mdev->seq_device] = NULL;
228 spin_unlock_irqrestore(®ister_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(®ister_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(®ister_lock, flags);
241 return 0;
242 }
243
244
245 /*
246 * release the midi device if it was registered
247 */
248 void
snd_seq_oss_midi_clear_all(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(®ister_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(®ister_lock, flags);
266 }
267
268
269 /*
270 * set up midi tables
271 */
272 void
snd_seq_oss_midi_setup(struct seq_oss_devinfo * dp)273 snd_seq_oss_midi_setup(struct seq_oss_devinfo *dp)
274 {
275 spin_lock_irq(®ister_lock);
276 dp->max_mididev = max_midi_devs;
277 spin_unlock_irq(®ister_lock);
278 }
279
280 /*
281 * clean up midi tables
282 */
283 void
snd_seq_oss_midi_cleanup(struct seq_oss_devinfo * dp)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
snd_seq_oss_midi_open_all(struct seq_oss_devinfo * dp,int file_mode)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 *
get_mididev(struct seq_oss_devinfo * dp,int dev)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
snd_seq_oss_midi_open(struct seq_oss_devinfo * dp,int dev,int fmode)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
snd_seq_oss_midi_close(struct seq_oss_devinfo * dp,int dev)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
snd_seq_oss_midi_filemode(struct seq_oss_devinfo * dp,int dev)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
snd_seq_oss_midi_reset(struct seq_oss_devinfo * dp,int dev)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
snd_seq_oss_midi_get_addr(struct seq_oss_devinfo * dp,int dev,struct snd_seq_addr * addr)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
snd_seq_oss_midi_input(struct snd_seq_event * ev,int direct,void * private_data)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
send_synth_event(struct seq_oss_devinfo * dp,struct snd_seq_event * ev,int dev)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
send_midi_event(struct seq_oss_devinfo * dp,struct snd_seq_event * ev,struct seq_oss_midi * mdev)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
snd_seq_oss_midi_putc(struct seq_oss_devinfo * dp,int dev,unsigned char c,struct snd_seq_event * ev)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
snd_seq_oss_midi_make_info(struct seq_oss_devinfo * dp,int dev,struct midi_info * inf)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 *
capmode_str(int val)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
snd_seq_oss_midi_info_read(struct snd_info_buffer * buf)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 */
719