📄 maestro3.c
字号:
AFMT_S16_LE : AFMT_U8, (int *)arg); case SNDCTL_DSP_POST: return 0; case SNDCTL_DSP_GETTRIGGER: val = 0; if ((file->f_mode & FMODE_READ) && (s->enable & ADC_RUNNING)) val |= PCM_ENABLE_INPUT; if ((file->f_mode & FMODE_WRITE) && (s->enable & DAC_RUNNING)) val |= PCM_ENABLE_OUTPUT; return put_user(val, (int *)arg); case SNDCTL_DSP_SETTRIGGER: get_user_ret(val, (int *)arg, -EFAULT); if (file->f_mode & FMODE_READ) { if (val & PCM_ENABLE_INPUT) { if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1))) return ret; start_adc(s); } else stop_adc(s); } if (file->f_mode & FMODE_WRITE) { if (val & PCM_ENABLE_OUTPUT) { if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0))) return ret; start_dac(s); } else stop_dac(s); } return 0; case SNDCTL_DSP_GETOSPACE: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; if (!(s->enable & DAC_RUNNING) && (val = prog_dmabuf(s, 0)) != 0) return val; spin_lock_irqsave(&s->lock, flags); m3_update_ptr(s); abinfo.fragsize = s->dma_dac.fragsize; abinfo.bytes = s->dma_dac.dmasize - s->dma_dac.count; abinfo.fragstotal = s->dma_dac.numfrag; abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift; spin_unlock_irqrestore(&s->lock, flags); return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; case SNDCTL_DSP_GETISPACE: if (!(file->f_mode & FMODE_READ)) return -EINVAL; if (!(s->enable & ADC_RUNNING) && (val = prog_dmabuf(s, 1)) != 0) return val; spin_lock_irqsave(&s->lock, flags); m3_update_ptr(s); abinfo.fragsize = s->dma_adc.fragsize; abinfo.bytes = s->dma_adc.count; abinfo.fragstotal = s->dma_adc.numfrag; abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift; spin_unlock_irqrestore(&s->lock, flags); return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; case SNDCTL_DSP_NONBLOCK: file->f_flags |= O_NONBLOCK; return 0; case SNDCTL_DSP_GETODELAY: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; spin_lock_irqsave(&s->lock, flags); m3_update_ptr(s); val = s->dma_dac.count; spin_unlock_irqrestore(&s->lock, flags); return put_user(val, (int *)arg); case SNDCTL_DSP_GETIPTR: if (!(file->f_mode & FMODE_READ)) return -EINVAL; spin_lock_irqsave(&s->lock, flags); m3_update_ptr(s); cinfo.bytes = s->dma_adc.total_bytes; cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift; cinfo.ptr = s->dma_adc.hwptr; if (s->dma_adc.mapped) s->dma_adc.count &= s->dma_adc.fragsize-1; spin_unlock_irqrestore(&s->lock, flags); return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); case SNDCTL_DSP_GETOPTR: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; spin_lock_irqsave(&s->lock, flags); m3_update_ptr(s); cinfo.bytes = s->dma_dac.total_bytes; cinfo.blocks = s->dma_dac.count >> s->dma_dac.fragshift; cinfo.ptr = s->dma_dac.hwptr; if (s->dma_dac.mapped) s->dma_dac.count &= s->dma_dac.fragsize-1; spin_unlock_irqrestore(&s->lock, flags); return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); case SNDCTL_DSP_GETBLKSIZE: if (file->f_mode & FMODE_WRITE) { if ((val = prog_dmabuf(s, 0))) return val; return put_user(s->dma_dac.fragsize, (int *)arg); } if ((val = prog_dmabuf(s, 1))) return val; return put_user(s->dma_adc.fragsize, (int *)arg); case SNDCTL_DSP_SETFRAGMENT: get_user_ret(val, (int *)arg, -EFAULT); spin_lock_irqsave(&s->lock, flags); if (file->f_mode & FMODE_READ) { s->dma_adc.ossfragshift = val & 0xffff; s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff; if (s->dma_adc.ossfragshift < 4) s->dma_adc.ossfragshift = 4; if (s->dma_adc.ossfragshift > 15) s->dma_adc.ossfragshift = 15; if (s->dma_adc.ossmaxfrags < 4) s->dma_adc.ossmaxfrags = 4; } if (file->f_mode & FMODE_WRITE) { s->dma_dac.ossfragshift = val & 0xffff; s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff; if (s->dma_dac.ossfragshift < 4) s->dma_dac.ossfragshift = 4; if (s->dma_dac.ossfragshift > 15) s->dma_dac.ossfragshift = 15; if (s->dma_dac.ossmaxfrags < 4) s->dma_dac.ossmaxfrags = 4; } spin_unlock_irqrestore(&s->lock, flags); return 0; case SNDCTL_DSP_SUBDIVIDE: if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) || (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision)) return -EINVAL; get_user_ret(val, (int *)arg, -EFAULT); if (val != 1 && val != 2 && val != 4) return -EINVAL; if (file->f_mode & FMODE_READ) s->dma_adc.subdivision = val; if (file->f_mode & FMODE_WRITE) s->dma_dac.subdivision = val; return 0; case SOUND_PCM_READ_RATE: return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, (int *)arg); case SOUND_PCM_READ_CHANNELS: return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_FMT_STEREO << ESS_ADC_SHIFT) : (ESS_FMT_STEREO << ESS_DAC_SHIFT))) ? 2 : 1, (int *)arg); case SOUND_PCM_READ_BITS: return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_FMT_16BIT << ESS_ADC_SHIFT) : (ESS_FMT_16BIT << ESS_DAC_SHIFT))) ? 16 : 8, (int *)arg); case SOUND_PCM_WRITE_FILTER: case SNDCTL_DSP_SETSYNCRO: case SOUND_PCM_READ_FILTER: return -EINVAL; } return -EINVAL;}static intallocate_dmabuf(struct pci_dev *pci_dev, struct dmabuf *db){ int order; DPRINTK(DPSTR,"allocating for dmabuf %p\n", db); /* * alloc as big a chunk as we can, start with * 64k 'cause we're insane. based on order cause * the amazingly complicated prog_dmabuf wants it. * * pci_alloc_sonsistent guarantees that it won't cross a natural * boundry; the m3 hardware can't have dma cross a 64k bus * address boundry. */ for (order = 16-PAGE_SHIFT; order >= 1; order--) { db->rawbuf = pci_alloc_consistent(pci_dev, PAGE_SIZE << order, &(db->handle)); if(db->rawbuf) break; } if (!db->rawbuf) return 1; DPRINTK(DPSTR,"allocated %ld (%d) bytes at %p\n", PAGE_SIZE<<order, order, db->rawbuf); { struct page *page, *pend; pend = virt_to_page(db->rawbuf + (PAGE_SIZE << order) - 1); for (page = virt_to_page(db->rawbuf); page <= pend; page++) mem_map_reserve(page); } db->buforder = order; db->ready = 0; db->mapped = 0; return 0;}static voidnuke_lists(struct m3_card *card, struct dmabuf *db){ m3_remove_list(card, &(card->dma_list), db->dma_index); m3_remove_list(card, &(card->msrc_list), db->msrc_index); db->in_lists = 0;}static voidfree_dmabuf(struct pci_dev *pci_dev, struct dmabuf *db){ if(db->rawbuf == NULL) return; DPRINTK(DPSTR,"freeing %p from dmabuf %p\n",db->rawbuf, db); { struct page *page, *pend; pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1); for (page = virt_to_page(db->rawbuf); page <= pend; page++) mem_map_unreserve(page); } pci_free_consistent(pci_dev, PAGE_SIZE << db->buforder, db->rawbuf, db->handle); db->rawbuf = NULL; db->buforder = 0; db->mapped = 0; db->ready = 0;}static int m3_open(struct inode *inode, struct file *file){ int minor = MINOR(inode->i_rdev); struct m3_card *c; struct m3_state *s = NULL; int i; unsigned char fmtm = ~0, fmts = 0; unsigned long flags; /* * Scan the cards and find the channel. We only * do this at open time so it is ok */ for(c = devs ; c != NULL ; c = c->next) { for(i=0;i<NR_DSPS;i++) { if(c->channels[i].dev_audio < 0) continue; if((c->channels[i].dev_audio ^ minor) & ~0xf) continue; s = &c->channels[i]; break; } } if (!s) return -ENODEV; VALIDATE_STATE(s); file->private_data = s; /* wait for device to become free */ down(&s->open_sem); while (s->open_mode & file->f_mode) { if (file->f_flags & O_NONBLOCK) { up(&s->open_sem); return -EWOULDBLOCK; } up(&s->open_sem); interruptible_sleep_on(&s->open_wait); if (signal_pending(current)) return -ERESTARTSYS; down(&s->open_sem); } spin_lock_irqsave(&s->lock, flags); if (file->f_mode & FMODE_READ) { fmtm &= ~((ESS_FMT_STEREO | ESS_FMT_16BIT) << ESS_ADC_SHIFT); if ((minor & 0xf) == SND_DEV_DSP16) fmts |= ESS_FMT_16BIT << ESS_ADC_SHIFT; s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0; set_adc_rate(s, 8000); } if (file->f_mode & FMODE_WRITE) { fmtm &= ~((ESS_FMT_STEREO | ESS_FMT_16BIT) << ESS_DAC_SHIFT); if ((minor & 0xf) == SND_DEV_DSP16) fmts |= ESS_FMT_16BIT << ESS_DAC_SHIFT; s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0; set_dac_rate(s, 8000); } set_fmt(s, fmtm, fmts); s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); MOD_INC_USE_COUNT; up(&s->open_sem); spin_unlock_irqrestore(&s->lock, flags); return 0;}static int m3_release(struct inode *inode, struct file *file){ struct m3_state *s = (struct m3_state *)file->private_data; unsigned long flags; VALIDATE_STATE(s); if (file->f_mode & FMODE_WRITE) drain_dac(s, file->f_flags & O_NONBLOCK); down(&s->open_sem); spin_lock_irqsave(&s->lock, flags); if (file->f_mode & FMODE_WRITE) { stop_dac(s); if(s->dma_dac.in_lists) { m3_remove_list(s->card, &(s->card->mixer_list), s->dma_dac.mixer_index); nuke_lists(s->card, &(s->dma_dac)); } } if (file->f_mode & FMODE_READ) { stop_adc(s); if(s->dma_adc.in_lists) { m3_remove_list(s->card, &(s->card->adc1_list), s->dma_adc.adc1_index); nuke_lists(s->card, &(s->dma_adc)); } } s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE); spin_unlock_irqrestore(&s->lock, flags); up(&s->open_sem); wake_up(&s->open_wait); MOD_DEC_USE_COUNT; return 0;}/* * Wait for the ac97 serial bus to be free. * return nonzero if the bus is still busy. */static int m3_ac97_wait(struct m3_card *card){ int i = 10000; while( (m3_inb(card, 0x30) & 1) && i--) ; return i == 0;}u16 m3_ac97_read(struct ac97_codec *codec, u8 reg){ u16 ret = 0; struct m3_card *card = codec->private_data; spin_lock(&card->ac97_lock); if(m3_ac97_wait(card)) { printk(KERN_ERR PFX "serial bus busy reading reg 0x%x\n",reg); goto out; } m3_outb(card, 0x80 | (reg & 0x7f), 0x30); if(m3_ac97_wait(card)) { printk(KERN_ERR PFX "serial bus busy finishing read reg 0x%x\n",reg); goto out; } ret = m3_inw(card, 0x32); DPRINTK(DPCRAP,"reading 0x%04x from 0x%02x\n",ret, reg);out: spin_unlock(&card->ac97_lock); return ret;}void m3_ac97_write(struct ac97_codec *codec, u8 reg, u16 val){ struct m3_card *card = codec->private_data; spin_lock(&card->ac97_lock); if(m3_ac97_wait(card)) { printk(KERN_ERR PFX "serial bus busy writing 0x%x to 0x%x\n",val, reg); goto out; } DPRINTK(DPCRAP,"writing 0x%04x to 0x%02x\n", val, reg); m3_outw(card, val, 0x32); m3_outb(card, reg & 0x7f, 0x30);out: spin_unlock(&card->ac97_lock);}/* OSS /dev/mixer file operation methods */static int m3_open_mixdev(struct inode *inode, struct file *file){ int minor = MINOR(inode->i_rdev); struct m3_card *card = devs; MOD_INC_USE_COUNT; for (card = devs; card != NULL; card = card->next
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -