📄 dmasound_core.c
字号:
}static int sq_fsync(struct file *filp, struct dentry *dentry){ int rc = 0; write_sq.syncing = 1; sq_play(); /* there may be an incomplete frame waiting */ while (write_sq.active) { SLEEP(write_sq.sync_queue); if (signal_pending(current)) { /* While waiting for audio output to drain, an * interrupt occurred. Stop audio output immediately * and clear the queue. */ sq_reset(); rc = -EINTR; break; } } write_sq.syncing = 0; return rc;}static int sq_release(struct inode *inode, struct file *file){ int rc = 0; lock_kernel(); if (write_sq.busy) rc = sq_fsync(file, file->f_dentry); dmasound.soft = dmasound.dsp; dmasound.hard = dmasound.dsp; sound_silence(); write_sq_release_buffers(); read_sq_release_buffers(); dmasound.mach.release(); /* There is probably a DOS atack here. They change the mode flag. */ /* XXX add check here */ read_sq_wake_up(file); write_sq_wake_up(file); /* Wake up a process waiting for the queue being released. * Note: There may be several processes waiting for a call * to open() returning. */ unlock_kernel(); return rc;}static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg){ int val; u_long fmt; int data; int size, nbufs; audio_buf_info info; switch (cmd) { case SNDCTL_DSP_RESET: sq_reset(); return 0; case SNDCTL_DSP_POST: case SNDCTL_DSP_SYNC: return sq_fsync(file, file->f_dentry); /* ++TeSche: before changing any of these it's * probably wise to wait until sound playing has * settled down. */ case SNDCTL_DSP_SPEED: sq_fsync(file, file->f_dentry); IOCTL_IN(arg, data); return IOCTL_OUT(arg, sound_set_speed(data)); case SNDCTL_DSP_STEREO: sq_fsync(file, file->f_dentry); IOCTL_IN(arg, data); return IOCTL_OUT(arg, sound_set_stereo(data)); case SOUND_PCM_WRITE_CHANNELS: sq_fsync(file, file->f_dentry); IOCTL_IN(arg, data); return IOCTL_OUT(arg, sound_set_stereo(data-1)+1); case SNDCTL_DSP_SETFMT: sq_fsync(file, file->f_dentry); IOCTL_IN(arg, data); return IOCTL_OUT(arg, sound_set_format(data)); case SNDCTL_DSP_GETFMTS: fmt = 0; if (dmasound.trans_write) { if (dmasound.trans_write->ct_ulaw) fmt |= AFMT_MU_LAW; if (dmasound.trans_write->ct_alaw) fmt |= AFMT_A_LAW; if (dmasound.trans_write->ct_s8) fmt |= AFMT_S8; if (dmasound.trans_write->ct_u8) fmt |= AFMT_U8; if (dmasound.trans_write->ct_s16be) fmt |= AFMT_S16_BE; if (dmasound.trans_write->ct_u16be) fmt |= AFMT_U16_BE; if (dmasound.trans_write->ct_s16le) fmt |= AFMT_S16_LE; if (dmasound.trans_write->ct_u16le) fmt |= AFMT_U16_LE; } return IOCTL_OUT(arg, fmt); case SNDCTL_DSP_GETBLKSIZE: size = write_sq.block_size * dmasound.soft.size * (dmasound.soft.stereo + 1) / (dmasound.hard.size * (dmasound.hard.stereo + 1)); return IOCTL_OUT(arg, size); case SNDCTL_DSP_SUBDIVIDE: break; case SNDCTL_DSP_SETFRAGMENT: if (write_sq.count || write_sq.active || write_sq.syncing) return -EINVAL; IOCTL_IN(arg, size); nbufs = size >> 16; if (nbufs < 2 || nbufs > write_sq.numBufs) nbufs = write_sq.numBufs; size &= 0xffff; if (size >= 8 && size <= 29) { size = 1 << size; size *= dmasound.hard.size * (dmasound.hard.stereo + 1); size /= dmasound.soft.size * (dmasound.soft.stereo + 1); if (size > write_sq.bufSize) size = write_sq.bufSize; } else size = write_sq.bufSize; sq_setup(&write_sq, write_sq.numBufs, nbufs, size); return IOCTL_OUT(arg,write_sq.bufSize | write_sq.numBufs << 16); case SNDCTL_DSP_GETOSPACE: info.fragments = write_sq.max_active - write_sq.count; info.fragstotal = write_sq.max_active; info.fragsize = write_sq.block_size; info.bytes = info.fragments * info.fragsize; if (copy_to_user((void *)arg, &info, sizeof(info))) return -EFAULT; return 0; case SNDCTL_DSP_GETCAPS: val = 1; /* Revision level of this ioctl() */ return IOCTL_OUT(arg,val); default: return mixer_ioctl(inode, file, cmd, arg); } return -EINVAL;}static struct file_operations sq_fops ={ owner: THIS_MODULE, llseek: sound_lseek, write: sq_write, ioctl: sq_ioctl, open: sq_open, release: sq_release,#ifdef HAS_RECORD read: sq_read,#endif};static void __init sq_init(void){#ifndef MODULE int sq_unit;#endif sq_unit = register_sound_dsp(&sq_fops, -1); if (sq_unit < 0) return; write_sq_init_waitqueue(); read_sq_init_waitqueue(); /* whatever you like as startup mode for /dev/dsp, * (/dev/audio hasn't got a startup mode). note that * once changed a new open() will *not* restore these! */ dmasound.dsp.format = AFMT_U8; dmasound.dsp.stereo = 0; dmasound.dsp.size = 8; /* set minimum rate possible without expanding */ dmasound.dsp.speed = dmasound.mach.min_dsp_speed; /* before the first open to /dev/dsp this wouldn't be set */ dmasound.soft = dmasound.dsp; dmasound.hard = dmasound.dsp; sound_silence();} /* * /dev/sndstat */static struct { int busy; char buf[512]; /* state.buf should not overflow! */ int len, ptr;} state;static int state_open(struct inode *inode, struct file *file){ char *buffer = state.buf; int len = 0; if (state.busy) return -EBUSY; dmasound.mach.open(); state.ptr = 0; state.busy = 1; len += sprintf(buffer+len, "%sDMA sound driver:\n", dmasound.mach.name); len += sprintf(buffer+len, "\tsound.format = 0x%x", dmasound.soft.format); switch (dmasound.soft.format) { case AFMT_MU_LAW: len += sprintf(buffer+len, " (mu-law)"); break; case AFMT_A_LAW: len += sprintf(buffer+len, " (A-law)"); break; case AFMT_U8: len += sprintf(buffer+len, " (unsigned 8 bit)"); break; case AFMT_S8: len += sprintf(buffer+len, " (signed 8 bit)"); break; case AFMT_S16_BE: len += sprintf(buffer+len, " (signed 16 bit big)"); break; case AFMT_U16_BE: len += sprintf(buffer+len, " (unsigned 16 bit big)"); break; case AFMT_S16_LE: len += sprintf(buffer+len, " (signed 16 bit little)"); break; case AFMT_U16_LE: len += sprintf(buffer+len, " (unsigned 16 bit little)"); break; } len += sprintf(buffer+len, "\n"); len += sprintf(buffer+len, "\tsound.speed = %dHz (phys. %dHz)\n", dmasound.soft.speed, dmasound.hard.speed); len += sprintf(buffer+len, "\tsound.stereo = 0x%x (%s)\n", dmasound.soft.stereo, dmasound.soft.stereo ? "stereo" : "mono"); if (dmasound.mach.state_info) len += dmasound.mach.state_info(buffer); len += sprintf(buffer+len, "\tsq.block_size = %d sq.max_count = %d" " sq.max_active = %d\n", write_sq.block_size, write_sq.max_count, write_sq.max_active); len += sprintf(buffer+len, "\tsq.count = %d sq.rear_size = %d\n", write_sq.count, write_sq.rear_size); len += sprintf(buffer+len, "\tsq.active = %d sq.syncing = %d\n", write_sq.active, write_sq.syncing); state.len = len; return 0;}static int state_release(struct inode *inode, struct file *file){ lock_kernel(); state.busy = 0; dmasound.mach.release(); unlock_kernel(); return 0;}static ssize_t state_read(struct file *file, char *buf, size_t count, loff_t *ppos){ int n = state.len - state.ptr; if (n > count) n = count; if (n <= 0) return 0; if (copy_to_user(buf, &state.buf[state.ptr], n)) return -EFAULT; state.ptr += n; return n;}static struct file_operations state_fops = { owner: THIS_MODULE, llseek: sound_lseek, read: state_read, open: state_open, release: state_release,};static void __init state_init(void){#ifndef MODULE int state_unit;#endif state_unit = register_sound_special(&state_fops, SND_DEV_STATUS); if (state_unit < 0) return; state.busy = 0;} /* * Config & Setup * * This function is called by _one_ chipset-specific driver */int __init dmasound_init(void){#ifdef MODULE if (irq_installed) return -EBUSY;#endif /* Set up sound queue, /dev/audio and /dev/dsp. */ /* Set default settings. */ sq_init(); /* Set up /dev/sndstat. */ state_init(); /* Set up /dev/mixer. */ mixer_init(); if (!dmasound.mach.irqinit()) { printk(KERN_ERR "DMA sound driver: Interrupt initialization failed\n"); return -ENODEV; }#ifdef MODULE irq_installed = 1;#endif printk(KERN_INFO "DMA sound driver installed, using %d buffers of %dk.\n", numWriteBufs, writeBufSize); return 0;}#ifdef MODULEvoid dmasound_deinit(void){ if (irq_installed) { sound_silence(); dmasound.mach.irqcleanup(); } write_sq_release_buffers(); read_sq_release_buffers(); if (mixer_unit >= 0) unregister_sound_mixer(mixer_unit); if (state_unit >= 0) unregister_sound_special(state_unit); if (sq_unit >= 0) unregister_sound_dsp(sq_unit);}#else /* !MODULE */static int __init dmasound_setup(char *str){ int ints[6]; str = get_options(str, ARRAY_SIZE(ints), ints); /* check the bootstrap parameter for "dmasound=" */ switch (ints[0]) { case 3: if ((ints[3] < 0) || (ints[3] > MAX_CATCH_RADIUS)) printk("dmasound_setup: illegal catch radius, using default = %d\n", catchRadius); else catchRadius = ints[3]; /* fall through */ case 2: if (ints[1] < MIN_BUFFERS) printk("dmasound_setup: illegal number of buffers, using default = %d\n", numWriteBufs); else numWriteBufs = ints[1]; if (ints[2] < MIN_BUFSIZE || ints[2] > MAX_BUFSIZE) printk("dmasound_setup: illegal buffer size, using default = %dK\n", writeBufSize); else writeBufSize = ints[2]; break; case 0: break; default: printk("dmasound_setup: illegal number of arguments\n"); return 0; } return 1;}__setup("dmasound=", dmasound_setup);#endif /* !MODULE */ /* * Visible symbols for modules */EXPORT_SYMBOL(dmasound);EXPORT_SYMBOL(dmasound_init);#ifdef MODULEEXPORT_SYMBOL(dmasound_deinit);#endifEXPORT_SYMBOL(dmasound_write_sq);#ifdef HAS_RECORDEXPORT_SYMBOL(dmasound_read_sq);#endifEXPORT_SYMBOL(dmasound_catchRadius);#ifdef HAS_8BIT_TABLESEXPORT_SYMBOL(dmasound_ulaw2dma8);EXPORT_SYMBOL(dmasound_alaw2dma8);#endif#ifdef HAS_16BIT_TABLESEXPORT_SYMBOL(dmasound_ulaw2dma16);EXPORT_SYMBOL(dmasound_alaw2dma16);#endif#ifdef HAS_14BIT_TABLESEXPORT_SYMBOL(dmasound_ulaw2dma14l);EXPORT_SYMBOL(dmasound_ulaw2dma14h);EXPORT_SYMBOL(dmasound_alaw2dma14l);EXPORT_SYMBOL(dmasound_alaw2dma14h);#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -