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