Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * OSS compatible sequencer driver
0004  *
0005  * MIDI device handlers
0006  *
0007  * Copyright (C) 1998,99 Takashi Iwai <tiwai@suse.de>
0008  */
0009 
0010 #include <sound/asoundef.h>
0011 #include "seq_oss_midi.h"
0012 #include "seq_oss_readq.h"
0013 #include "seq_oss_timer.h"
0014 #include "seq_oss_event.h"
0015 #include <sound/seq_midi_event.h>
0016 #include "../seq_lock.h"
0017 #include <linux/init.h>
0018 #include <linux/slab.h>
0019 #include <linux/nospec.h>
0020 
0021 
0022 /*
0023  * constants
0024  */
0025 #define SNDRV_SEQ_OSS_MAX_MIDI_NAME 30
0026 
0027 /*
0028  * definition of midi device record
0029  */
0030 struct seq_oss_midi {
0031     int seq_device;     /* device number */
0032     int client;     /* sequencer client number */
0033     int port;       /* sequencer port number */
0034     unsigned int flags; /* port capability */
0035     int opened;     /* flag for opening */
0036     unsigned char name[SNDRV_SEQ_OSS_MAX_MIDI_NAME];
0037     struct snd_midi_event *coder;   /* MIDI event coder */
0038     struct seq_oss_devinfo *devinfo;    /* assigned OSSseq device */
0039     snd_use_lock_t use_lock;
0040 };
0041 
0042 
0043 /*
0044  * midi device table
0045  */
0046 static int max_midi_devs;
0047 static struct seq_oss_midi *midi_devs[SNDRV_SEQ_OSS_MAX_MIDI_DEVS];
0048 
0049 static DEFINE_SPINLOCK(register_lock);
0050 
0051 /*
0052  * prototypes
0053  */
0054 static struct seq_oss_midi *get_mdev(int dev);
0055 static struct seq_oss_midi *get_mididev(struct seq_oss_devinfo *dp, int dev);
0056 static int send_synth_event(struct seq_oss_devinfo *dp, struct snd_seq_event *ev, int dev);
0057 static int send_midi_event(struct seq_oss_devinfo *dp, struct snd_seq_event *ev, struct seq_oss_midi *mdev);
0058 
0059 /*
0060  * look up the existing ports
0061  * this looks a very exhausting job.
0062  */
0063 int
0064 snd_seq_oss_midi_lookup_ports(int client)
0065 {
0066     struct snd_seq_client_info *clinfo;
0067     struct snd_seq_port_info *pinfo;
0068 
0069     clinfo = kzalloc(sizeof(*clinfo), GFP_KERNEL);
0070     pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL);
0071     if (! clinfo || ! pinfo) {
0072         kfree(clinfo);
0073         kfree(pinfo);
0074         return -ENOMEM;
0075     }
0076     clinfo->client = -1;
0077     while (snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_QUERY_NEXT_CLIENT, clinfo) == 0) {
0078         if (clinfo->client == client)
0079             continue; /* ignore myself */
0080         pinfo->addr.client = clinfo->client;
0081         pinfo->addr.port = -1;
0082         while (snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT, pinfo) == 0)
0083             snd_seq_oss_midi_check_new_port(pinfo);
0084     }
0085     kfree(clinfo);
0086     kfree(pinfo);
0087     return 0;
0088 }
0089 
0090 
0091 /*
0092  */
0093 static struct seq_oss_midi *
0094 get_mdev(int dev)
0095 {
0096     struct seq_oss_midi *mdev;
0097     unsigned long flags;
0098 
0099     spin_lock_irqsave(&register_lock, flags);
0100     mdev = midi_devs[dev];
0101     if (mdev)
0102         snd_use_lock_use(&mdev->use_lock);
0103     spin_unlock_irqrestore(&register_lock, flags);
0104     return mdev;
0105 }
0106 
0107 /*
0108  * look for the identical slot
0109  */
0110 static struct seq_oss_midi *
0111 find_slot(int client, int port)
0112 {
0113     int i;
0114     struct seq_oss_midi *mdev;
0115     unsigned long flags;
0116 
0117     spin_lock_irqsave(&register_lock, flags);
0118     for (i = 0; i < max_midi_devs; i++) {
0119         mdev = midi_devs[i];
0120         if (mdev && mdev->client == client && mdev->port == port) {
0121             /* found! */
0122             snd_use_lock_use(&mdev->use_lock);
0123             spin_unlock_irqrestore(&register_lock, flags);
0124             return mdev;
0125         }
0126     }
0127     spin_unlock_irqrestore(&register_lock, flags);
0128     return NULL;
0129 }
0130 
0131 
0132 #define PERM_WRITE (SNDRV_SEQ_PORT_CAP_WRITE|SNDRV_SEQ_PORT_CAP_SUBS_WRITE)
0133 #define PERM_READ (SNDRV_SEQ_PORT_CAP_READ|SNDRV_SEQ_PORT_CAP_SUBS_READ)
0134 /*
0135  * register a new port if it doesn't exist yet
0136  */
0137 int
0138 snd_seq_oss_midi_check_new_port(struct snd_seq_port_info *pinfo)
0139 {
0140     int i;
0141     struct seq_oss_midi *mdev;
0142     unsigned long flags;
0143 
0144     /* the port must include generic midi */
0145     if (! (pinfo->type & SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC))
0146         return 0;
0147     /* either read or write subscribable */
0148     if ((pinfo->capability & PERM_WRITE) != PERM_WRITE &&
0149         (pinfo->capability & PERM_READ) != PERM_READ)
0150         return 0;
0151 
0152     /*
0153      * look for the identical slot
0154      */
0155     mdev = find_slot(pinfo->addr.client, pinfo->addr.port);
0156     if (mdev) {
0157         /* already exists */
0158         snd_use_lock_free(&mdev->use_lock);
0159         return 0;
0160     }
0161 
0162     /*
0163      * allocate midi info record
0164      */
0165     mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
0166     if (!mdev)
0167         return -ENOMEM;
0168 
0169     /* copy the port information */
0170     mdev->client = pinfo->addr.client;
0171     mdev->port = pinfo->addr.port;
0172     mdev->flags = pinfo->capability;
0173     mdev->opened = 0;
0174     snd_use_lock_init(&mdev->use_lock);
0175 
0176     /* copy and truncate the name of synth device */
0177     strscpy(mdev->name, pinfo->name, sizeof(mdev->name));
0178 
0179     /* create MIDI coder */
0180     if (snd_midi_event_new(MAX_MIDI_EVENT_BUF, &mdev->coder) < 0) {
0181         pr_err("ALSA: seq_oss: can't malloc midi coder\n");
0182         kfree(mdev);
0183         return -ENOMEM;
0184     }
0185     /* OSS sequencer adds running status to all sequences */
0186     snd_midi_event_no_status(mdev->coder, 1);
0187 
0188     /*
0189      * look for en empty slot
0190      */
0191     spin_lock_irqsave(&register_lock, flags);
0192     for (i = 0; i < max_midi_devs; i++) {
0193         if (midi_devs[i] == NULL)
0194             break;
0195     }
0196     if (i >= max_midi_devs) {
0197         if (max_midi_devs >= SNDRV_SEQ_OSS_MAX_MIDI_DEVS) {
0198             spin_unlock_irqrestore(&register_lock, flags);
0199             snd_midi_event_free(mdev->coder);
0200             kfree(mdev);
0201             return -ENOMEM;
0202         }
0203         max_midi_devs++;
0204     }
0205     mdev->seq_device = i;
0206     midi_devs[mdev->seq_device] = mdev;
0207     spin_unlock_irqrestore(&register_lock, flags);
0208 
0209     return 0;
0210 }
0211 
0212 /*
0213  * release the midi device if it was registered
0214  */
0215 int
0216 snd_seq_oss_midi_check_exit_port(int client, int port)
0217 {
0218     struct seq_oss_midi *mdev;
0219     unsigned long flags;
0220     int index;
0221 
0222     mdev = find_slot(client, port);
0223     if (mdev) {
0224         spin_lock_irqsave(&register_lock, flags);
0225         midi_devs[mdev->seq_device] = NULL;
0226         spin_unlock_irqrestore(&register_lock, flags);
0227         snd_use_lock_free(&mdev->use_lock);
0228         snd_use_lock_sync(&mdev->use_lock);
0229         snd_midi_event_free(mdev->coder);
0230         kfree(mdev);
0231     }
0232     spin_lock_irqsave(&register_lock, flags);
0233     for (index = max_midi_devs - 1; index >= 0; index--) {
0234         if (midi_devs[index])
0235             break;
0236     }
0237     max_midi_devs = index + 1;
0238     spin_unlock_irqrestore(&register_lock, flags);
0239     return 0;
0240 }
0241 
0242 
0243 /*
0244  * release the midi device if it was registered
0245  */
0246 void
0247 snd_seq_oss_midi_clear_all(void)
0248 {
0249     int i;
0250     struct seq_oss_midi *mdev;
0251     unsigned long flags;
0252 
0253     spin_lock_irqsave(&register_lock, flags);
0254     for (i = 0; i < max_midi_devs; i++) {
0255         mdev = midi_devs[i];
0256         if (mdev) {
0257             snd_midi_event_free(mdev->coder);
0258             kfree(mdev);
0259             midi_devs[i] = NULL;
0260         }
0261     }
0262     max_midi_devs = 0;
0263     spin_unlock_irqrestore(&register_lock, flags);
0264 }
0265 
0266 
0267 /*
0268  * set up midi tables
0269  */
0270 void
0271 snd_seq_oss_midi_setup(struct seq_oss_devinfo *dp)
0272 {
0273     spin_lock_irq(&register_lock);
0274     dp->max_mididev = max_midi_devs;
0275     spin_unlock_irq(&register_lock);
0276 }
0277 
0278 /*
0279  * clean up midi tables
0280  */
0281 void
0282 snd_seq_oss_midi_cleanup(struct seq_oss_devinfo *dp)
0283 {
0284     int i;
0285     for (i = 0; i < dp->max_mididev; i++)
0286         snd_seq_oss_midi_close(dp, i);
0287     dp->max_mididev = 0;
0288 }
0289 
0290 
0291 /*
0292  * open all midi devices.  ignore errors.
0293  */
0294 void
0295 snd_seq_oss_midi_open_all(struct seq_oss_devinfo *dp, int file_mode)
0296 {
0297     int i;
0298     for (i = 0; i < dp->max_mididev; i++)
0299         snd_seq_oss_midi_open(dp, i, file_mode);
0300 }
0301 
0302 
0303 /*
0304  * get the midi device information
0305  */
0306 static struct seq_oss_midi *
0307 get_mididev(struct seq_oss_devinfo *dp, int dev)
0308 {
0309     if (dev < 0 || dev >= dp->max_mididev)
0310         return NULL;
0311     dev = array_index_nospec(dev, dp->max_mididev);
0312     return get_mdev(dev);
0313 }
0314 
0315 
0316 /*
0317  * open the midi device if not opened yet
0318  */
0319 int
0320 snd_seq_oss_midi_open(struct seq_oss_devinfo *dp, int dev, int fmode)
0321 {
0322     int perm;
0323     struct seq_oss_midi *mdev;
0324     struct snd_seq_port_subscribe subs;
0325 
0326     mdev = get_mididev(dp, dev);
0327     if (!mdev)
0328         return -ENODEV;
0329 
0330     /* already used? */
0331     if (mdev->opened && mdev->devinfo != dp) {
0332         snd_use_lock_free(&mdev->use_lock);
0333         return -EBUSY;
0334     }
0335 
0336     perm = 0;
0337     if (is_write_mode(fmode))
0338         perm |= PERM_WRITE;
0339     if (is_read_mode(fmode))
0340         perm |= PERM_READ;
0341     perm &= mdev->flags;
0342     if (perm == 0) {
0343         snd_use_lock_free(&mdev->use_lock);
0344         return -ENXIO;
0345     }
0346 
0347     /* already opened? */
0348     if ((mdev->opened & perm) == perm) {
0349         snd_use_lock_free(&mdev->use_lock);
0350         return 0;
0351     }
0352 
0353     perm &= ~mdev->opened;
0354 
0355     memset(&subs, 0, sizeof(subs));
0356 
0357     if (perm & PERM_WRITE) {
0358         subs.sender = dp->addr;
0359         subs.dest.client = mdev->client;
0360         subs.dest.port = mdev->port;
0361         if (snd_seq_kernel_client_ctl(dp->cseq, SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, &subs) >= 0)
0362             mdev->opened |= PERM_WRITE;
0363     }
0364     if (perm & PERM_READ) {
0365         subs.sender.client = mdev->client;
0366         subs.sender.port = mdev->port;
0367         subs.dest = dp->addr;
0368         subs.flags = SNDRV_SEQ_PORT_SUBS_TIMESTAMP;
0369         subs.queue = dp->queue;     /* queue for timestamps */
0370         if (snd_seq_kernel_client_ctl(dp->cseq, SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, &subs) >= 0)
0371             mdev->opened |= PERM_READ;
0372     }
0373 
0374     if (! mdev->opened) {
0375         snd_use_lock_free(&mdev->use_lock);
0376         return -ENXIO;
0377     }
0378 
0379     mdev->devinfo = dp;
0380     snd_use_lock_free(&mdev->use_lock);
0381     return 0;
0382 }
0383 
0384 /*
0385  * close the midi device if already opened
0386  */
0387 int
0388 snd_seq_oss_midi_close(struct seq_oss_devinfo *dp, int dev)
0389 {
0390     struct seq_oss_midi *mdev;
0391     struct snd_seq_port_subscribe subs;
0392 
0393     mdev = get_mididev(dp, dev);
0394     if (!mdev)
0395         return -ENODEV;
0396     if (! mdev->opened || mdev->devinfo != dp) {
0397         snd_use_lock_free(&mdev->use_lock);
0398         return 0;
0399     }
0400 
0401     memset(&subs, 0, sizeof(subs));
0402     if (mdev->opened & PERM_WRITE) {
0403         subs.sender = dp->addr;
0404         subs.dest.client = mdev->client;
0405         subs.dest.port = mdev->port;
0406         snd_seq_kernel_client_ctl(dp->cseq, SNDRV_SEQ_IOCTL_UNSUBSCRIBE_PORT, &subs);
0407     }
0408     if (mdev->opened & PERM_READ) {
0409         subs.sender.client = mdev->client;
0410         subs.sender.port = mdev->port;
0411         subs.dest = dp->addr;
0412         snd_seq_kernel_client_ctl(dp->cseq, SNDRV_SEQ_IOCTL_UNSUBSCRIBE_PORT, &subs);
0413     }
0414 
0415     mdev->opened = 0;
0416     mdev->devinfo = NULL;
0417 
0418     snd_use_lock_free(&mdev->use_lock);
0419     return 0;
0420 }
0421 
0422 /*
0423  * change seq capability flags to file mode flags
0424  */
0425 int
0426 snd_seq_oss_midi_filemode(struct seq_oss_devinfo *dp, int dev)
0427 {
0428     struct seq_oss_midi *mdev;
0429     int mode;
0430 
0431     mdev = get_mididev(dp, dev);
0432     if (!mdev)
0433         return 0;
0434 
0435     mode = 0;
0436     if (mdev->opened & PERM_WRITE)
0437         mode |= SNDRV_SEQ_OSS_FILE_WRITE;
0438     if (mdev->opened & PERM_READ)
0439         mode |= SNDRV_SEQ_OSS_FILE_READ;
0440 
0441     snd_use_lock_free(&mdev->use_lock);
0442     return mode;
0443 }
0444 
0445 /*
0446  * reset the midi device and close it:
0447  * so far, only close the device.
0448  */
0449 void
0450 snd_seq_oss_midi_reset(struct seq_oss_devinfo *dp, int dev)
0451 {
0452     struct seq_oss_midi *mdev;
0453 
0454     mdev = get_mididev(dp, dev);
0455     if (!mdev)
0456         return;
0457     if (! mdev->opened) {
0458         snd_use_lock_free(&mdev->use_lock);
0459         return;
0460     }
0461 
0462     if (mdev->opened & PERM_WRITE) {
0463         struct snd_seq_event ev;
0464         int c;
0465 
0466         memset(&ev, 0, sizeof(ev));
0467         ev.dest.client = mdev->client;
0468         ev.dest.port = mdev->port;
0469         ev.queue = dp->queue;
0470         ev.source.port = dp->port;
0471         if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_SYNTH) {
0472             ev.type = SNDRV_SEQ_EVENT_SENSING;
0473             snd_seq_oss_dispatch(dp, &ev, 0, 0);
0474         }
0475         for (c = 0; c < 16; c++) {
0476             ev.type = SNDRV_SEQ_EVENT_CONTROLLER;
0477             ev.data.control.channel = c;
0478             ev.data.control.param = MIDI_CTL_ALL_NOTES_OFF;
0479             snd_seq_oss_dispatch(dp, &ev, 0, 0);
0480             if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC) {
0481                 ev.data.control.param =
0482                     MIDI_CTL_RESET_CONTROLLERS;
0483                 snd_seq_oss_dispatch(dp, &ev, 0, 0);
0484                 ev.type = SNDRV_SEQ_EVENT_PITCHBEND;
0485                 ev.data.control.value = 0;
0486                 snd_seq_oss_dispatch(dp, &ev, 0, 0);
0487             }
0488         }
0489     }
0490     // snd_seq_oss_midi_close(dp, dev);
0491     snd_use_lock_free(&mdev->use_lock);
0492 }
0493 
0494 
0495 /*
0496  * get client/port of the specified MIDI device
0497  */
0498 void
0499 snd_seq_oss_midi_get_addr(struct seq_oss_devinfo *dp, int dev, struct snd_seq_addr *addr)
0500 {
0501     struct seq_oss_midi *mdev;
0502 
0503     mdev = get_mididev(dp, dev);
0504     if (!mdev)
0505         return;
0506     addr->client = mdev->client;
0507     addr->port = mdev->port;
0508     snd_use_lock_free(&mdev->use_lock);
0509 }
0510 
0511 
0512 /*
0513  * input callback - this can be atomic
0514  */
0515 int
0516 snd_seq_oss_midi_input(struct snd_seq_event *ev, int direct, void *private_data)
0517 {
0518     struct seq_oss_devinfo *dp = (struct seq_oss_devinfo *)private_data;
0519     struct seq_oss_midi *mdev;
0520     int rc;
0521 
0522     if (dp->readq == NULL)
0523         return 0;
0524     mdev = find_slot(ev->source.client, ev->source.port);
0525     if (!mdev)
0526         return 0;
0527     if (! (mdev->opened & PERM_READ)) {
0528         snd_use_lock_free(&mdev->use_lock);
0529         return 0;
0530     }
0531 
0532     if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC)
0533         rc = send_synth_event(dp, ev, mdev->seq_device);
0534     else
0535         rc = send_midi_event(dp, ev, mdev);
0536 
0537     snd_use_lock_free(&mdev->use_lock);
0538     return rc;
0539 }
0540 
0541 /*
0542  * convert ALSA sequencer event to OSS synth event
0543  */
0544 static int
0545 send_synth_event(struct seq_oss_devinfo *dp, struct snd_seq_event *ev, int dev)
0546 {
0547     union evrec ossev;
0548 
0549     memset(&ossev, 0, sizeof(ossev));
0550 
0551     switch (ev->type) {
0552     case SNDRV_SEQ_EVENT_NOTEON:
0553         ossev.v.cmd = MIDI_NOTEON; break;
0554     case SNDRV_SEQ_EVENT_NOTEOFF:
0555         ossev.v.cmd = MIDI_NOTEOFF; break;
0556     case SNDRV_SEQ_EVENT_KEYPRESS:
0557         ossev.v.cmd = MIDI_KEY_PRESSURE; break;
0558     case SNDRV_SEQ_EVENT_CONTROLLER:
0559         ossev.l.cmd = MIDI_CTL_CHANGE; break;
0560     case SNDRV_SEQ_EVENT_PGMCHANGE:
0561         ossev.l.cmd = MIDI_PGM_CHANGE; break;
0562     case SNDRV_SEQ_EVENT_CHANPRESS:
0563         ossev.l.cmd = MIDI_CHN_PRESSURE; break;
0564     case SNDRV_SEQ_EVENT_PITCHBEND:
0565         ossev.l.cmd = MIDI_PITCH_BEND; break;
0566     default:
0567         return 0; /* not supported */
0568     }
0569 
0570     ossev.v.dev = dev;
0571 
0572     switch (ev->type) {
0573     case SNDRV_SEQ_EVENT_NOTEON:
0574     case SNDRV_SEQ_EVENT_NOTEOFF:
0575     case SNDRV_SEQ_EVENT_KEYPRESS:
0576         ossev.v.code = EV_CHN_VOICE;
0577         ossev.v.note = ev->data.note.note;
0578         ossev.v.parm = ev->data.note.velocity;
0579         ossev.v.chn = ev->data.note.channel;
0580         break;
0581     case SNDRV_SEQ_EVENT_CONTROLLER:
0582     case SNDRV_SEQ_EVENT_PGMCHANGE:
0583     case SNDRV_SEQ_EVENT_CHANPRESS:
0584         ossev.l.code = EV_CHN_COMMON;
0585         ossev.l.p1 = ev->data.control.param;
0586         ossev.l.val = ev->data.control.value;
0587         ossev.l.chn = ev->data.control.channel;
0588         break;
0589     case SNDRV_SEQ_EVENT_PITCHBEND:
0590         ossev.l.code = EV_CHN_COMMON;
0591         ossev.l.val = ev->data.control.value + 8192;
0592         ossev.l.chn = ev->data.control.channel;
0593         break;
0594     }
0595     
0596     snd_seq_oss_readq_put_timestamp(dp->readq, ev->time.tick, dp->seq_mode);
0597     snd_seq_oss_readq_put_event(dp->readq, &ossev);
0598 
0599     return 0;
0600 }
0601 
0602 /*
0603  * decode event and send MIDI bytes to read queue
0604  */
0605 static int
0606 send_midi_event(struct seq_oss_devinfo *dp, struct snd_seq_event *ev, struct seq_oss_midi *mdev)
0607 {
0608     char msg[32];
0609     int len;
0610     
0611     snd_seq_oss_readq_put_timestamp(dp->readq, ev->time.tick, dp->seq_mode);
0612     if (!dp->timer->running)
0613         len = snd_seq_oss_timer_start(dp->timer);
0614     if (ev->type == SNDRV_SEQ_EVENT_SYSEX) {
0615         snd_seq_oss_readq_sysex(dp->readq, mdev->seq_device, ev);
0616         snd_midi_event_reset_decode(mdev->coder);
0617     } else {
0618         len = snd_midi_event_decode(mdev->coder, msg, sizeof(msg), ev);
0619         if (len > 0)
0620             snd_seq_oss_readq_puts(dp->readq, mdev->seq_device, msg, len);
0621     }
0622 
0623     return 0;
0624 }
0625 
0626 
0627 /*
0628  * dump midi data
0629  * return 0 : enqueued
0630  *        non-zero : invalid - ignored
0631  */
0632 int
0633 snd_seq_oss_midi_putc(struct seq_oss_devinfo *dp, int dev, unsigned char c, struct snd_seq_event *ev)
0634 {
0635     struct seq_oss_midi *mdev;
0636 
0637     mdev = get_mididev(dp, dev);
0638     if (!mdev)
0639         return -ENODEV;
0640     if (snd_midi_event_encode_byte(mdev->coder, c, ev)) {
0641         snd_seq_oss_fill_addr(dp, ev, mdev->client, mdev->port);
0642         snd_use_lock_free(&mdev->use_lock);
0643         return 0;
0644     }
0645     snd_use_lock_free(&mdev->use_lock);
0646     return -EINVAL;
0647 }
0648 
0649 /*
0650  * create OSS compatible midi_info record
0651  */
0652 int
0653 snd_seq_oss_midi_make_info(struct seq_oss_devinfo *dp, int dev, struct midi_info *inf)
0654 {
0655     struct seq_oss_midi *mdev;
0656 
0657     mdev = get_mididev(dp, dev);
0658     if (!mdev)
0659         return -ENXIO;
0660     inf->device = dev;
0661     inf->dev_type = 0; /* FIXME: ?? */
0662     inf->capabilities = 0; /* FIXME: ?? */
0663     strscpy(inf->name, mdev->name, sizeof(inf->name));
0664     snd_use_lock_free(&mdev->use_lock);
0665     return 0;
0666 }
0667 
0668 
0669 #ifdef CONFIG_SND_PROC_FS
0670 /*
0671  * proc interface
0672  */
0673 static char *
0674 capmode_str(int val)
0675 {
0676     val &= PERM_READ|PERM_WRITE;
0677     if (val == (PERM_READ|PERM_WRITE))
0678         return "read/write";
0679     else if (val == PERM_READ)
0680         return "read";
0681     else if (val == PERM_WRITE)
0682         return "write";
0683     else
0684         return "none";
0685 }
0686 
0687 void
0688 snd_seq_oss_midi_info_read(struct snd_info_buffer *buf)
0689 {
0690     int i;
0691     struct seq_oss_midi *mdev;
0692 
0693     snd_iprintf(buf, "\nNumber of MIDI devices: %d\n", max_midi_devs);
0694     for (i = 0; i < max_midi_devs; i++) {
0695         snd_iprintf(buf, "\nmidi %d: ", i);
0696         mdev = get_mdev(i);
0697         if (mdev == NULL) {
0698             snd_iprintf(buf, "*empty*\n");
0699             continue;
0700         }
0701         snd_iprintf(buf, "[%s] ALSA port %d:%d\n", mdev->name,
0702                 mdev->client, mdev->port);
0703         snd_iprintf(buf, "  capability %s / opened %s\n",
0704                 capmode_str(mdev->flags),
0705                 capmode_str(mdev->opened));
0706         snd_use_lock_free(&mdev->use_lock);
0707     }
0708 }
0709 #endif /* CONFIG_SND_PROC_FS */