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 15 struct hostaudio_state { 16 int fd; 17 }; 18 19 struct 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 */ 31 static char *dsp = HOSTAUDIO_DEV_DSP; 32 static 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 43 static 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 51 static 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 61 module_param(dsp, charp, 0644); 62 MODULE_PARM_DESC(dsp, DSP_HELP); 63 64 module_param(mixer, charp, 0644); 65 MODULE_PARM_DESC(mixer, MIXER_HELP); 66 67 #endif 68 69 /* /dev/dsp file operations */ 70 71 static 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 93 out: 94 kfree(kbuf); 95 return err; 96 } 97 98 static 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 127 static 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 139 static 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 182 static 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 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(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 226 static 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 238 static 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 270 static 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 286 static 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 298 static 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 306 struct { 307 int dev_audio; 308 int dev_mixer; 309 } module_data; 310 311 MODULE_AUTHOR("Steve Schmidtke"); 312 MODULE_DESCRIPTION("UML Audio Relay"); 313 MODULE_LICENSE("GPL"); 314 315 static 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 337 static 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 343 module_init(hostaudio_init_module); 344 module_exit(hostaudio_cleanup_module); 345