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