2 * Copyright (C) 2002 Steve Schmidtke
3 * Licensed under the GPL
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"
15 struct hostaudio_state
{
19 struct hostmixer_state
{
23 #define HOSTAUDIO_DEV_DSP "/dev/sound/dsp"
24 #define HOSTAUDIO_DEV_MIXER "/dev/sound/mixer"
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.
31 static char *dsp
= HOSTAUDIO_DEV_DSP
;
32 static char *mixer
= HOSTAUDIO_DEV_MIXER
;
35 " This is used to specify the host dsp device to the hostaudio driver.\n" \
36 " The default is \"" HOSTAUDIO_DEV_DSP "\".\n\n"
39 " This is used to specify the host mixer device to the hostaudio driver.\n"\
40 " The default is \"" HOSTAUDIO_DEV_MIXER "\".\n\n"
43 static int set_dsp(char *name
, int *add
)
49 __uml_setup("dsp=", set_dsp
, "dsp=<dsp device>\n" DSP_HELP
);
51 static int set_mixer(char *name
, int *add
)
57 __uml_setup("mixer=", set_mixer
, "mixer=<mixer device>\n" MIXER_HELP
);
61 module_param(dsp
, charp
, 0644);
62 MODULE_PARM_DESC(dsp
, DSP_HELP
);
64 module_param(mixer
, charp
, 0644);
65 MODULE_PARM_DESC(mixer
, MIXER_HELP
);
69 /* /dev/dsp file operations */
71 static ssize_t
hostaudio_read(struct file
*file
, char __user
*buffer
,
72 size_t count
, loff_t
*ppos
)
74 struct hostaudio_state
*state
= file
->private_data
;
79 printk(KERN_DEBUG
"hostaudio: read called, count = %d\n", count
);
82 kbuf
= kmalloc(count
, GFP_KERNEL
);
86 err
= os_read_file(state
->fd
, kbuf
, count
);
90 if (copy_to_user(buffer
, kbuf
, err
))
98 static ssize_t
hostaudio_write(struct file
*file
, const char __user
*buffer
,
99 size_t count
, loff_t
*ppos
)
101 struct hostaudio_state
*state
= file
->private_data
;
106 printk(KERN_DEBUG
"hostaudio: write called, count = %d\n", count
);
109 kbuf
= kmalloc(count
, GFP_KERNEL
);
114 if (copy_from_user(kbuf
, buffer
, count
))
117 err
= os_write_file(state
->fd
, kbuf
, count
);
127 static unsigned int hostaudio_poll(struct file
*file
,
128 struct poll_table_struct
*wait
)
130 unsigned int mask
= 0;
133 printk(KERN_DEBUG
"hostaudio: poll called (unimplemented)\n");
139 static int hostaudio_ioctl(struct inode
*inode
, struct file
*file
,
140 unsigned int cmd
, unsigned long arg
)
142 struct hostaudio_state
*state
= file
->private_data
;
143 unsigned long data
= 0;
147 printk(KERN_DEBUG
"hostaudio: ioctl called, cmd = %u\n", 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
))
163 err
= os_ioctl_generic(state
->fd
, cmd
, (unsigned long) &data
);
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
))
182 static int hostaudio_open(struct inode
*inode
, struct file
*file
)
184 struct hostaudio_state
*state
;
189 printk(KERN_DEBUG
"hostaudio: open called (host: %s)\n", dsp
);
192 state
= kmalloc(sizeof(struct hostaudio_state
), GFP_KERNEL
);
196 if (file
->f_mode
& FMODE_READ
)
198 if (file
->f_mode
& FMODE_WRITE
)
201 ret
= os_open_file(dsp
, of_set_rw(OPENFLAGS(), r
, w
), 0);
207 file
->private_data
= state
;
211 static int hostaudio_release(struct inode
*inode
, struct file
*file
)
213 struct hostaudio_state
*state
= file
->private_data
;
216 printk(KERN_DEBUG
"hostaudio: release called\n");
218 os_close_file(state
->fd
);
224 /* /dev/mixer file operations */
226 static int hostmixer_ioctl_mixdev(struct inode
*inode
, struct file
*file
,
227 unsigned int cmd
, unsigned long arg
)
229 struct hostmixer_state
*state
= file
->private_data
;
232 printk(KERN_DEBUG
"hostmixer: ioctl called\n");
235 return os_ioctl_generic(state
->fd
, cmd
, arg
);
238 static int hostmixer_open_mixdev(struct inode
*inode
, struct file
*file
)
240 struct hostmixer_state
*state
;
245 printk(KERN_DEBUG
"hostmixer: open called (host: %s)\n", mixer
);
248 state
= kmalloc(sizeof(struct hostmixer_state
), GFP_KERNEL
);
252 if (file
->f_mode
& FMODE_READ
)
254 if (file
->f_mode
& FMODE_WRITE
)
257 ret
= os_open_file(mixer
, of_set_rw(OPENFLAGS(), r
, w
), 0);
260 printk(KERN_ERR
"hostaudio_open_mixdev failed to open '%s', "
261 "err = %d\n", dsp
, -ret
);
266 file
->private_data
= state
;
270 static int hostmixer_release(struct inode
*inode
, struct file
*file
)
272 struct hostmixer_state
*state
= file
->private_data
;
275 printk(KERN_DEBUG
"hostmixer: release called\n");
278 os_close_file(state
->fd
);
284 /* kernel module operations */
286 static const struct file_operations hostaudio_fops
= {
287 .owner
= THIS_MODULE
,
289 .read
= hostaudio_read
,
290 .write
= hostaudio_write
,
291 .poll
= hostaudio_poll
,
292 .ioctl
= hostaudio_ioctl
,
294 .open
= hostaudio_open
,
295 .release
= hostaudio_release
,
298 static const struct file_operations hostmixer_fops
= {
299 .owner
= THIS_MODULE
,
301 .ioctl
= hostmixer_ioctl_mixdev
,
302 .open
= hostmixer_open_mixdev
,
303 .release
= hostmixer_release
,
311 MODULE_AUTHOR("Steve Schmidtke");
312 MODULE_DESCRIPTION("UML Audio Relay");
313 MODULE_LICENSE("GPL");
315 static int __init
hostaudio_init_module(void)
317 printk(KERN_INFO
"UML Audio Relay (host dsp = %s, host mixer = %s)\n",
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");
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 "
330 unregister_sound_dsp(module_data
.dev_audio
);
337 static void __exit
hostaudio_cleanup_module (void)
339 unregister_sound_mixer(module_data
.dev_mixer
);
340 unregister_sound_dsp(module_data
.dev_audio
);
343 module_init(hostaudio_init_module
);
344 module_exit(hostaudio_cleanup_module
);