linux/sound/core/seq/oss/seq_oss.c
<<
>>
Prefs
   1/*
   2 * OSS compatible sequencer driver
   3 *
   4 * registration of device and proc
   5 *
   6 * Copyright (C) 1998,99 Takashi Iwai <tiwai@suse.de>
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License as published by
  10 * the Free Software Foundation; either version 2 of the License, or
  11 * (at your option) any later version.
  12 *
  13 * This program is distributed in the hope that it will be useful,
  14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16 * GNU General Public License for more details.
  17 *
  18 * You should have received a copy of the GNU General Public License
  19 * along with this program; if not, write to the Free Software
  20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  21 */
  22
  23#include <linux/init.h>
  24#include <linux/module.h>
  25#include <linux/mutex.h>
  26#include <sound/core.h>
  27#include <sound/minors.h>
  28#include <sound/initval.h>
  29#include "seq_oss_device.h"
  30#include "seq_oss_synth.h"
  31
  32/*
  33 * module option
  34 */
  35MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
  36MODULE_DESCRIPTION("OSS-compatible sequencer module");
  37MODULE_LICENSE("GPL");
  38/* Takashi says this is really only for sound-service-0-, but this is OK. */
  39MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_SEQUENCER);
  40MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_MUSIC);
  41
  42
  43/*
  44 * prototypes
  45 */
  46static int register_device(void);
  47static void unregister_device(void);
  48#ifdef CONFIG_PROC_FS
  49static int register_proc(void);
  50static void unregister_proc(void);
  51#else
  52static inline int register_proc(void) { return 0; }
  53static inline void unregister_proc(void) {}
  54#endif
  55
  56static int odev_open(struct inode *inode, struct file *file);
  57static int odev_release(struct inode *inode, struct file *file);
  58static ssize_t odev_read(struct file *file, char __user *buf, size_t count, loff_t *offset);
  59static ssize_t odev_write(struct file *file, const char __user *buf, size_t count, loff_t *offset);
  60static long odev_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
  61static unsigned int odev_poll(struct file *file, poll_table * wait);
  62
  63
  64/*
  65 * module interface
  66 */
  67
  68static struct snd_seq_driver seq_oss_synth_driver = {
  69        .driver = {
  70                .name = KBUILD_MODNAME,
  71                .probe = snd_seq_oss_synth_probe,
  72                .remove = snd_seq_oss_synth_remove,
  73        },
  74        .id = SNDRV_SEQ_DEV_ID_OSS,
  75        .argsize = sizeof(struct snd_seq_oss_reg),
  76};
  77
  78static int __init alsa_seq_oss_init(void)
  79{
  80        int rc;
  81
  82        if ((rc = register_device()) < 0)
  83                goto error;
  84        if ((rc = register_proc()) < 0) {
  85                unregister_device();
  86                goto error;
  87        }
  88        if ((rc = snd_seq_oss_create_client()) < 0) {
  89                unregister_proc();
  90                unregister_device();
  91                goto error;
  92        }
  93
  94        rc = snd_seq_driver_register(&seq_oss_synth_driver);
  95        if (rc < 0) {
  96                snd_seq_oss_delete_client();
  97                unregister_proc();
  98                unregister_device();
  99                goto error;
 100        }
 101
 102        /* success */
 103        snd_seq_oss_synth_init();
 104
 105 error:
 106        return rc;
 107}
 108
 109static void __exit alsa_seq_oss_exit(void)
 110{
 111        snd_seq_driver_unregister(&seq_oss_synth_driver);
 112        snd_seq_oss_delete_client();
 113        unregister_proc();
 114        unregister_device();
 115}
 116
 117module_init(alsa_seq_oss_init)
 118module_exit(alsa_seq_oss_exit)
 119
 120/*
 121 * ALSA minor device interface
 122 */
 123
 124static DEFINE_MUTEX(register_mutex);
 125
 126static int
 127odev_open(struct inode *inode, struct file *file)
 128{
 129        int level, rc;
 130
 131        if (iminor(inode) == SNDRV_MINOR_OSS_MUSIC)
 132                level = SNDRV_SEQ_OSS_MODE_MUSIC;
 133        else
 134                level = SNDRV_SEQ_OSS_MODE_SYNTH;
 135
 136        mutex_lock(&register_mutex);
 137        rc = snd_seq_oss_open(file, level);
 138        mutex_unlock(&register_mutex);
 139
 140        return rc;
 141}
 142
 143static int
 144odev_release(struct inode *inode, struct file *file)
 145{
 146        struct seq_oss_devinfo *dp;
 147
 148        if ((dp = file->private_data) == NULL)
 149                return 0;
 150
 151        snd_seq_oss_drain_write(dp);
 152
 153        mutex_lock(&register_mutex);
 154        snd_seq_oss_release(dp);
 155        mutex_unlock(&register_mutex);
 156
 157        return 0;
 158}
 159
 160static ssize_t
 161odev_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
 162{
 163        struct seq_oss_devinfo *dp;
 164        dp = file->private_data;
 165        if (snd_BUG_ON(!dp))
 166                return -ENXIO;
 167        return snd_seq_oss_read(dp, buf, count);
 168}
 169
 170
 171static ssize_t
 172odev_write(struct file *file, const char __user *buf, size_t count, loff_t *offset)
 173{
 174        struct seq_oss_devinfo *dp;
 175        dp = file->private_data;
 176        if (snd_BUG_ON(!dp))
 177                return -ENXIO;
 178        return snd_seq_oss_write(dp, buf, count, file);
 179}
 180
 181static long
 182odev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 183{
 184        struct seq_oss_devinfo *dp;
 185        dp = file->private_data;
 186        if (snd_BUG_ON(!dp))
 187                return -ENXIO;
 188        return snd_seq_oss_ioctl(dp, cmd, arg);
 189}
 190
 191#ifdef CONFIG_COMPAT
 192#define odev_ioctl_compat       odev_ioctl
 193#else
 194#define odev_ioctl_compat       NULL
 195#endif
 196
 197static unsigned int
 198odev_poll(struct file *file, poll_table * wait)
 199{
 200        struct seq_oss_devinfo *dp;
 201        dp = file->private_data;
 202        if (snd_BUG_ON(!dp))
 203                return -ENXIO;
 204        return snd_seq_oss_poll(dp, file, wait);
 205}
 206
 207/*
 208 * registration of sequencer minor device
 209 */
 210
 211static const struct file_operations seq_oss_f_ops =
 212{
 213        .owner =        THIS_MODULE,
 214        .read =         odev_read,
 215        .write =        odev_write,
 216        .open =         odev_open,
 217        .release =      odev_release,
 218        .poll =         odev_poll,
 219        .unlocked_ioctl =       odev_ioctl,
 220        .compat_ioctl = odev_ioctl_compat,
 221        .llseek =       noop_llseek,
 222};
 223
 224static int __init
 225register_device(void)
 226{
 227        int rc;
 228
 229        mutex_lock(&register_mutex);
 230        if ((rc = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_SEQUENCER,
 231                                          NULL, 0,
 232                                          &seq_oss_f_ops, NULL)) < 0) {
 233                pr_err("ALSA: seq_oss: can't register device seq\n");
 234                mutex_unlock(&register_mutex);
 235                return rc;
 236        }
 237        if ((rc = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MUSIC,
 238                                          NULL, 0,
 239                                          &seq_oss_f_ops, NULL)) < 0) {
 240                pr_err("ALSA: seq_oss: can't register device music\n");
 241                snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_SEQUENCER, NULL, 0);
 242                mutex_unlock(&register_mutex);
 243                return rc;
 244        }
 245        mutex_unlock(&register_mutex);
 246        return 0;
 247}
 248
 249static void
 250unregister_device(void)
 251{
 252        mutex_lock(&register_mutex);
 253        if (snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MUSIC, NULL, 0) < 0)                
 254                pr_err("ALSA: seq_oss: error unregister device music\n");
 255        if (snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_SEQUENCER, NULL, 0) < 0)
 256                pr_err("ALSA: seq_oss: error unregister device seq\n");
 257        mutex_unlock(&register_mutex);
 258}
 259
 260/*
 261 * /proc interface
 262 */
 263
 264#ifdef CONFIG_PROC_FS
 265
 266static struct snd_info_entry *info_entry;
 267
 268static void
 269info_read(struct snd_info_entry *entry, struct snd_info_buffer *buf)
 270{
 271        mutex_lock(&register_mutex);
 272        snd_iprintf(buf, "OSS sequencer emulation version %s\n", SNDRV_SEQ_OSS_VERSION_STR);
 273        snd_seq_oss_system_info_read(buf);
 274        snd_seq_oss_synth_info_read(buf);
 275        snd_seq_oss_midi_info_read(buf);
 276        mutex_unlock(&register_mutex);
 277}
 278
 279
 280static int __init
 281register_proc(void)
 282{
 283        struct snd_info_entry *entry;
 284
 285        entry = snd_info_create_module_entry(THIS_MODULE, SNDRV_SEQ_OSS_PROCNAME, snd_seq_root);
 286        if (entry == NULL)
 287                return -ENOMEM;
 288
 289        entry->content = SNDRV_INFO_CONTENT_TEXT;
 290        entry->private_data = NULL;
 291        entry->c.text.read = info_read;
 292        if (snd_info_register(entry) < 0) {
 293                snd_info_free_entry(entry);
 294                return -ENOMEM;
 295        }
 296        info_entry = entry;
 297        return 0;
 298}
 299
 300static void
 301unregister_proc(void)
 302{
 303        snd_info_free_entry(info_entry);
 304        info_entry = NULL;
 305}
 306#endif /* CONFIG_PROC_FS */
 307