xref: /openbmc/linux/sound/core/seq/oss/seq_oss_midi.c (revision 297224fc)
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(&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 *
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(&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
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(&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
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(&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
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(&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
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(&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
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