linux/arch/um/drivers/hostaudio_kern.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2002 Steve Schmidtke
   3 * Licensed under the GPL
   4 */
   5
   6#include "linux/fs.h"
   7#include "linux/module.h"
   8#include "linux/slab.h"
   9#include "linux/sound.h"
  10#include "linux/soundcard.h"
  11#include "asm/uaccess.h"
  12#include "init.h"
  13#include "os.h"
  14
  15struct hostaudio_state {
  16        int fd;
  17};
  18
  19struct hostmixer_state {
  20        int fd;
  21};
  22
  23#define HOSTAUDIO_DEV_DSP "/dev/sound/dsp"
  24#define HOSTAUDIO_DEV_MIXER "/dev/sound/mixer"
  25
  26/*
  27 * Changed either at boot time or module load time.  At boot, this is
  28 * single-threaded; at module load, multiple modules would each have
  29 * their own copy of these variables.
  30 */
  31static char *dsp = HOSTAUDIO_DEV_DSP;
  32static char *mixer = HOSTAUDIO_DEV_MIXER;
  33
  34#define DSP_HELP \
  35"    This is used to specify the host dsp device to the hostaudio driver.\n" \
  36"    The default is \"" HOSTAUDIO_DEV_DSP "\".\n\n"
  37
  38#define MIXER_HELP \
  39"    This is used to specify the host mixer device to the hostaudio driver.\n"\
  40"    The default is \"" HOSTAUDIO_DEV_MIXER "\".\n\n"
  41
  42#ifndef MODULE
  43static int set_dsp(char *name, int *add)
  44{
  45        dsp = name;
  46        return 0;
  47}
  48
  49__uml_setup("dsp=", set_dsp, "dsp=<dsp device>\n" DSP_HELP);
  50
  51static int set_mixer(char *name, int *add)
  52{
  53        mixer = name;
  54        return 0;
  55}
  56
  57__uml_setup("mixer=", set_mixer, "mixer=<mixer device>\n" MIXER_HELP);
  58
  59#else /*MODULE*/
  60
  61module_param(dsp, charp, 0644);
  62MODULE_PARM_DESC(dsp, DSP_HELP);
  63
  64module_param(mixer, charp, 0644);
  65MODULE_PARM_DESC(mixer, MIXER_HELP);
  66
  67#endif
  68
  69/* /dev/dsp file operations */
  70
  71static ssize_t hostaudio_read(struct file *file, char __user *buffer,
  72                              size_t count, loff_t *ppos)
  73{
  74        struct hostaudio_state *state = file->private_data;
  75        void *kbuf;
  76        int err;
  77
  78#ifdef DEBUG
  79        printk(KERN_DEBUG "hostaudio: read called, count = %d\n", count);
  80#endif
  81
  82        kbuf = kmalloc(count, GFP_KERNEL);
  83        if (kbuf == NULL)
  84                return -ENOMEM;
  85
  86        err = os_read_file(state->fd, kbuf, count);
  87        if (err < 0)
  88                goto out;
  89
  90        if (copy_to_user(buffer, kbuf, err))
  91                err = -EFAULT;
  92
  93out:
  94        kfree(kbuf);
  95        return err;
  96}
  97
  98static ssize_t hostaudio_write(struct file *file, const char __user *buffer,
  99                               size_t count, loff_t *ppos)
 100{
 101        struct hostaudio_state *state = file->private_data;
 102        void *kbuf;
 103        int err;
 104
 105#ifdef DEBUG
 106        printk(KERN_DEBUG "hostaudio: write called, count = %d\n", count);
 107#endif
 108
 109        kbuf = kmalloc(count, GFP_KERNEL);
 110        if (kbuf == NULL)
 111                return -ENOMEM;
 112
 113        err = -EFAULT;
 114        if (copy_from_user(kbuf, buffer, count))
 115                goto out;
 116
 117        err = os_write_file(state->fd, kbuf, count);
 118        if (err < 0)
 119                goto out;
 120        *ppos += err;
 121
 122 out:
 123        kfree(kbuf);
 124        return err;
 125}
 126
 127static unsigned int hostaudio_poll(struct file *file,
 128                                   struct poll_table_struct *wait)
 129{
 130        unsigned int mask = 0;
 131
 132#ifdef DEBUG
 133        printk(KERN_DEBUG "hostaudio: poll called (unimplemented)\n");
 134#endif
 135
 136        return mask;
 137}
 138
 139static int hostaudio_ioctl(struct inode *inode, struct file *file,
 140                           unsigned int cmd, unsigned long arg)
 141{
 142        struct hostaudio_state *state = file->private_data;
 143        unsigned long data = 0;
 144        int err;
 145
 146#ifdef DEBUG
 147        printk(KERN_DEBUG "hostaudio: ioctl called, cmd = %u\n", cmd);
 148#endif
 149        switch(cmd){
 150        case SNDCTL_DSP_SPEED:
 151        case SNDCTL_DSP_STEREO:
 152        case SNDCTL_DSP_GETBLKSIZE:
 153        case SNDCTL_DSP_CHANNELS:
 154        case SNDCTL_DSP_SUBDIVIDE:
 155        case SNDCTL_DSP_SETFRAGMENT:
 156                if (get_user(data, (int __user *) arg))
 157                        return -EFAULT;
 158                break;
 159        default:
 160                break;
 161        }
 162
 163        err = os_ioctl_generic(state->fd, cmd, (unsigned long) &data);
 164
 165        switch(cmd){
 166        case SNDCTL_DSP_SPEED:
 167        case SNDCTL_DSP_STEREO:
 168        case SNDCTL_DSP_GETBLKSIZE:
 169        case SNDCTL_DSP_CHANNELS:
 170        case SNDCTL_DSP_SUBDIVIDE:
 171        case SNDCTL_DSP_SETFRAGMENT:
 172                if (put_user(data, (int __user *) arg))
 173                        return -EFAULT;
 174                break;
 175        default:
 176                break;
 177        }
 178
 179        return err;
 180}
 181
 182static int hostaudio_open(struct inode *inode, struct file *file)
 183{
 184        struct hostaudio_state *state;
 185        int r = 0, w = 0;
 186        int ret;
 187
 188#ifdef DEBUG
 189        printk(KERN_DEBUG "hostaudio: open called (host: %s)\n", dsp);
 190#endif
 191
 192        state = kmalloc(sizeof(struct hostaudio_state), GFP_KERNEL);
 193        if (state == NULL)
 194                return -ENOMEM;
 195
 196        if (file->f_mode & FMODE_READ)
 197                r = 1;
 198        if (file->f_mode & FMODE_WRITE)
 199                w = 1;
 200
 201        ret = os_open_file(dsp, of_set_rw(OPENFLAGS(), r, w), 0);
 202        if (ret < 0) {
 203                kfree(state);
 204                return ret;
 205        }
 206        state->fd = ret;
 207        file->private_data = state;
 208        return 0;
 209}
 210
 211static int hostaudio_release(struct inode *inode, struct file *file)
 212{
 213        struct hostaudio_state *state = file->private_data;
 214
 215#ifdef DEBUG
 216        printk(KERN_DEBUG "hostaudio: release called\n");
 217#endif
 218        os_close_file(state->fd);
 219        kfree(state);
 220
 221        return 0;
 222}
 223
 224/* /dev/mixer file operations */
 225
 226static int hostmixer_ioctl_mixdev(struct inode *inode, struct file *file,
 227                                  unsigned int cmd, unsigned long arg)
 228{
 229        struct hostmixer_state *state = file->private_data;
 230
 231#ifdef DEBUG
 232        printk(KERN_DEBUG "hostmixer: ioctl called\n");
 233#endif
 234
 235        return os_ioctl_generic(state->fd, cmd, arg);
 236}
 237
 238static int hostmixer_open_mixdev(struct inode *inode, struct file *file)
 239{
 240        struct hostmixer_state *state;
 241        int r = 0, w = 0;
 242        int ret;
 243
 244#ifdef DEBUG
 245        printk(KERN_DEBUG "hostmixer: open called (host: %s)\n", mixer);
 246#endif
 247
 248        state = kmalloc(sizeof(struct hostmixer_state), GFP_KERNEL);
 249        if (state == NULL)
 250                return -ENOMEM;
 251
 252        if (file->f_mode & FMODE_READ)
 253                r = 1;
 254        if (file->f_mode & FMODE_WRITE)
 255                w = 1;
 256
 257        ret = os_open_file(mixer, of_set_rw(OPENFLAGS(), r, w), 0);
 258
 259        if (ret < 0) {
 260                printk(KERN_ERR "hostaudio_open_mixdev failed to open '%s', "
 261                       "err = %d\n", dsp, -ret);
 262                kfree(state);
 263                return ret;
 264        }
 265
 266        file->private_data = state;
 267        return 0;
 268}
 269
 270static int hostmixer_release(struct inode *inode, struct file *file)
 271{
 272        struct hostmixer_state *state = file->private_data;
 273
 274#ifdef DEBUG
 275        printk(KERN_DEBUG "hostmixer: release called\n");
 276#endif
 277
 278        os_close_file(state->fd);
 279        kfree(state);
 280
 281        return 0;
 282}
 283
 284/* kernel module operations */
 285
 286static const struct file_operations hostaudio_fops = {
 287        .owner          = THIS_MODULE,
 288        .llseek         = no_llseek,
 289        .read           = hostaudio_read,
 290        .write          = hostaudio_write,
 291        .poll           = hostaudio_poll,
 292        .ioctl          = hostaudio_ioctl,
 293        .mmap           = NULL,
 294        .open           = hostaudio_open,
 295        .release        = hostaudio_release,
 296};
 297
 298static const struct file_operations hostmixer_fops = {
 299        .owner          = THIS_MODULE,
 300        .llseek         = no_llseek,
 301        .ioctl          = hostmixer_ioctl_mixdev,
 302        .open           = hostmixer_open_mixdev,
 303        .release        = hostmixer_release,
 304};
 305
 306struct {
 307        int dev_audio;
 308        int dev_mixer;
 309} module_data;
 310
 311MODULE_AUTHOR("Steve Schmidtke");
 312MODULE_DESCRIPTION("UML Audio Relay");
 313MODULE_LICENSE("GPL");
 314
 315static int __init hostaudio_init_module(void)
 316{
 317        printk(KERN_INFO "UML Audio Relay (host dsp = %s, host mixer = %s)\n",
 318               dsp, mixer);
 319
 320        module_data.dev_audio = register_sound_dsp(&hostaudio_fops, -1);
 321        if (module_data.dev_audio < 0) {
 322                printk(KERN_ERR "hostaudio: couldn't register DSP device!\n");
 323                return -ENODEV;
 324        }
 325
 326        module_data.dev_mixer = register_sound_mixer(&hostmixer_fops, -1);
 327        if (module_data.dev_mixer < 0) {
 328                printk(KERN_ERR "hostmixer: couldn't register mixer "
 329                       "device!\n");
 330                unregister_sound_dsp(module_data.dev_audio);
 331                return -ENODEV;
 332        }
 333
 334        return 0;
 335}
 336
 337static void __exit hostaudio_cleanup_module (void)
 338{
 339        unregister_sound_mixer(module_data.dev_mixer);
 340        unregister_sound_dsp(module_data.dev_audio);
 341}
 342
 343module_init(hostaudio_init_module);
 344module_exit(hostaudio_cleanup_module);
 345
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.