Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * OSS compatible sequencer driver
0004  *
0005  * registration of device and proc
0006  *
0007  * Copyright (C) 1998,99 Takashi Iwai <tiwai@suse.de>
0008  */
0009 
0010 #include <linux/init.h>
0011 #include <linux/module.h>
0012 #include <linux/mutex.h>
0013 #include <linux/compat.h>
0014 #include <sound/core.h>
0015 #include <sound/minors.h>
0016 #include <sound/initval.h>
0017 #include "seq_oss_device.h"
0018 #include "seq_oss_synth.h"
0019 
0020 /*
0021  * module option
0022  */
0023 MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
0024 MODULE_DESCRIPTION("OSS-compatible sequencer module");
0025 MODULE_LICENSE("GPL");
0026 /* Takashi says this is really only for sound-service-0-, but this is OK. */
0027 MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_SEQUENCER);
0028 MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_MUSIC);
0029 
0030 
0031 /*
0032  * prototypes
0033  */
0034 static int register_device(void);
0035 static void unregister_device(void);
0036 #ifdef CONFIG_SND_PROC_FS
0037 static int register_proc(void);
0038 static void unregister_proc(void);
0039 #else
0040 static inline int register_proc(void) { return 0; }
0041 static inline void unregister_proc(void) {}
0042 #endif
0043 
0044 static int odev_open(struct inode *inode, struct file *file);
0045 static int odev_release(struct inode *inode, struct file *file);
0046 static ssize_t odev_read(struct file *file, char __user *buf, size_t count, loff_t *offset);
0047 static ssize_t odev_write(struct file *file, const char __user *buf, size_t count, loff_t *offset);
0048 static long odev_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
0049 static __poll_t odev_poll(struct file *file, poll_table * wait);
0050 
0051 
0052 /*
0053  * module interface
0054  */
0055 
0056 static struct snd_seq_driver seq_oss_synth_driver = {
0057     .driver = {
0058         .name = KBUILD_MODNAME,
0059         .probe = snd_seq_oss_synth_probe,
0060         .remove = snd_seq_oss_synth_remove,
0061     },
0062     .id = SNDRV_SEQ_DEV_ID_OSS,
0063     .argsize = sizeof(struct snd_seq_oss_reg),
0064 };
0065 
0066 static int __init alsa_seq_oss_init(void)
0067 {
0068     int rc;
0069 
0070     rc = register_device();
0071     if (rc < 0)
0072         goto error;
0073     rc = register_proc();
0074     if (rc < 0) {
0075         unregister_device();
0076         goto error;
0077     }
0078     rc = snd_seq_oss_create_client();
0079     if (rc < 0) {
0080         unregister_proc();
0081         unregister_device();
0082         goto error;
0083     }
0084 
0085     rc = snd_seq_driver_register(&seq_oss_synth_driver);
0086     if (rc < 0) {
0087         snd_seq_oss_delete_client();
0088         unregister_proc();
0089         unregister_device();
0090         goto error;
0091     }
0092 
0093     /* success */
0094     snd_seq_oss_synth_init();
0095 
0096  error:
0097     return rc;
0098 }
0099 
0100 static void __exit alsa_seq_oss_exit(void)
0101 {
0102     snd_seq_driver_unregister(&seq_oss_synth_driver);
0103     snd_seq_oss_delete_client();
0104     unregister_proc();
0105     unregister_device();
0106 }
0107 
0108 module_init(alsa_seq_oss_init)
0109 module_exit(alsa_seq_oss_exit)
0110 
0111 /*
0112  * ALSA minor device interface
0113  */
0114 
0115 static DEFINE_MUTEX(register_mutex);
0116 
0117 static int
0118 odev_open(struct inode *inode, struct file *file)
0119 {
0120     int level, rc;
0121 
0122     if (iminor(inode) == SNDRV_MINOR_OSS_MUSIC)
0123         level = SNDRV_SEQ_OSS_MODE_MUSIC;
0124     else
0125         level = SNDRV_SEQ_OSS_MODE_SYNTH;
0126 
0127     mutex_lock(&register_mutex);
0128     rc = snd_seq_oss_open(file, level);
0129     mutex_unlock(&register_mutex);
0130 
0131     return rc;
0132 }
0133 
0134 static int
0135 odev_release(struct inode *inode, struct file *file)
0136 {
0137     struct seq_oss_devinfo *dp;
0138 
0139     dp = file->private_data;
0140     if (!dp)
0141         return 0;
0142 
0143     mutex_lock(&register_mutex);
0144     snd_seq_oss_release(dp);
0145     mutex_unlock(&register_mutex);
0146 
0147     return 0;
0148 }
0149 
0150 static ssize_t
0151 odev_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
0152 {
0153     struct seq_oss_devinfo *dp;
0154     dp = file->private_data;
0155     if (snd_BUG_ON(!dp))
0156         return -ENXIO;
0157     return snd_seq_oss_read(dp, buf, count);
0158 }
0159 
0160 
0161 static ssize_t
0162 odev_write(struct file *file, const char __user *buf, size_t count, loff_t *offset)
0163 {
0164     struct seq_oss_devinfo *dp;
0165     dp = file->private_data;
0166     if (snd_BUG_ON(!dp))
0167         return -ENXIO;
0168     return snd_seq_oss_write(dp, buf, count, file);
0169 }
0170 
0171 static long
0172 odev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
0173 {
0174     struct seq_oss_devinfo *dp;
0175     long rc;
0176 
0177     dp = file->private_data;
0178     if (snd_BUG_ON(!dp))
0179         return -ENXIO;
0180 
0181     if (cmd != SNDCTL_SEQ_SYNC &&
0182         mutex_lock_interruptible(&register_mutex))
0183         return -ERESTARTSYS;
0184     rc = snd_seq_oss_ioctl(dp, cmd, arg);
0185     if (cmd != SNDCTL_SEQ_SYNC)
0186         mutex_unlock(&register_mutex);
0187     return rc;
0188 }
0189 
0190 #ifdef CONFIG_COMPAT
0191 static long odev_ioctl_compat(struct file *file, unsigned int cmd,
0192                   unsigned long arg)
0193 {
0194     return odev_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
0195 }
0196 #else
0197 #define odev_ioctl_compat   NULL
0198 #endif
0199 
0200 static __poll_t
0201 odev_poll(struct file *file, poll_table * wait)
0202 {
0203     struct seq_oss_devinfo *dp;
0204     dp = file->private_data;
0205     if (snd_BUG_ON(!dp))
0206         return EPOLLERR;
0207     return snd_seq_oss_poll(dp, file, wait);
0208 }
0209 
0210 /*
0211  * registration of sequencer minor device
0212  */
0213 
0214 static const struct file_operations seq_oss_f_ops =
0215 {
0216     .owner =    THIS_MODULE,
0217     .read =     odev_read,
0218     .write =    odev_write,
0219     .open =     odev_open,
0220     .release =  odev_release,
0221     .poll =     odev_poll,
0222     .unlocked_ioctl =   odev_ioctl,
0223     .compat_ioctl = odev_ioctl_compat,
0224     .llseek =   noop_llseek,
0225 };
0226 
0227 static int __init
0228 register_device(void)
0229 {
0230     int rc;
0231 
0232     mutex_lock(&register_mutex);
0233     rc = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_SEQUENCER,
0234                      NULL, 0,
0235                      &seq_oss_f_ops, NULL);
0236     if (rc < 0) {
0237         pr_err("ALSA: seq_oss: can't register device seq\n");
0238         mutex_unlock(&register_mutex);
0239         return rc;
0240     }
0241     rc = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MUSIC,
0242                      NULL, 0,
0243                      &seq_oss_f_ops, NULL);
0244     if (rc < 0) {
0245         pr_err("ALSA: seq_oss: can't register device music\n");
0246         snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_SEQUENCER, NULL, 0);
0247         mutex_unlock(&register_mutex);
0248         return rc;
0249     }
0250     mutex_unlock(&register_mutex);
0251     return 0;
0252 }
0253 
0254 static void
0255 unregister_device(void)
0256 {
0257     mutex_lock(&register_mutex);
0258     if (snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MUSIC, NULL, 0) < 0)        
0259         pr_err("ALSA: seq_oss: error unregister device music\n");
0260     if (snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_SEQUENCER, NULL, 0) < 0)
0261         pr_err("ALSA: seq_oss: error unregister device seq\n");
0262     mutex_unlock(&register_mutex);
0263 }
0264 
0265 /*
0266  * /proc interface
0267  */
0268 
0269 #ifdef CONFIG_SND_PROC_FS
0270 
0271 static struct snd_info_entry *info_entry;
0272 
0273 static void
0274 info_read(struct snd_info_entry *entry, struct snd_info_buffer *buf)
0275 {
0276     mutex_lock(&register_mutex);
0277     snd_iprintf(buf, "OSS sequencer emulation version %s\n", SNDRV_SEQ_OSS_VERSION_STR);
0278     snd_seq_oss_system_info_read(buf);
0279     snd_seq_oss_synth_info_read(buf);
0280     snd_seq_oss_midi_info_read(buf);
0281     mutex_unlock(&register_mutex);
0282 }
0283 
0284 
0285 static int __init
0286 register_proc(void)
0287 {
0288     struct snd_info_entry *entry;
0289 
0290     entry = snd_info_create_module_entry(THIS_MODULE, SNDRV_SEQ_OSS_PROCNAME, snd_seq_root);
0291     if (entry == NULL)
0292         return -ENOMEM;
0293 
0294     entry->content = SNDRV_INFO_CONTENT_TEXT;
0295     entry->private_data = NULL;
0296     entry->c.text.read = info_read;
0297     if (snd_info_register(entry) < 0) {
0298         snd_info_free_entry(entry);
0299         return -ENOMEM;
0300     }
0301     info_entry = entry;
0302     return 0;
0303 }
0304 
0305 static void
0306 unregister_proc(void)
0307 {
0308     snd_info_free_entry(info_entry);
0309     info_entry = NULL;
0310 }
0311 #endif /* CONFIG_SND_PROC_FS */