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