📄 es1371.c
字号:
struct proc_dir_entry *ps;#endif /* ES1371_DEBUG */ struct ac97_codec codec; /* wave stuff */ unsigned ctrl; unsigned sctrl; unsigned dac1rate, dac2rate, adcrate; spinlock_t lock; struct semaphore open_sem; mode_t open_mode; wait_queue_head_t open_wait; struct dmabuf { void *rawbuf; dma_addr_t dmaaddr; unsigned buforder; unsigned numfrag; unsigned fragshift; unsigned hwptr, swptr; unsigned total_bytes; int count; unsigned error; /* over/underrun */ wait_queue_head_t wait; /* redundant, but makes calculations easier */ unsigned fragsize; unsigned dmasize; unsigned fragsamples; /* OSS stuff */ unsigned mapped:1; unsigned ready:1; unsigned endcleared:1; unsigned enabled:1; unsigned ossfragshift; int ossmaxfrags; unsigned subdivision; } dma_dac1, dma_dac2, dma_adc; /* midi stuff */ struct { unsigned ird, iwr, icnt; unsigned ord, owr, ocnt; wait_queue_head_t iwait; wait_queue_head_t owait; unsigned char ibuf[MIDIINBUF]; unsigned char obuf[MIDIOUTBUF]; } midi; struct gameport gameport; struct semaphore sem;};/* --------------------------------------------------------------------- */static LIST_HEAD(devs);/* --------------------------------------------------------------------- */static inline unsigned ld2(unsigned int x){ unsigned r = 0; if (x >= 0x10000) { x >>= 16; r += 16; } if (x >= 0x100) { x >>= 8; r += 8; } if (x >= 0x10) { x >>= 4; r += 4; } if (x >= 4) { x >>= 2; r += 2; } if (x >= 2) r++; return r;}/* --------------------------------------------------------------------- */static unsigned wait_src_ready(struct es1371_state *s){ unsigned int t, r; for (t = 0; t < POLL_COUNT; t++) { if (!((r = inl(s->io + ES1371_REG_SRCONV)) & SRC_BUSY)) return r; udelay(1); } printk(KERN_DEBUG PFX "sample rate converter timeout r = 0x%08x\n", r); return r;}static unsigned src_read(struct es1371_state *s, unsigned reg){ unsigned int temp,i,orig; /* wait for ready */ temp = wait_src_ready (s); /* we can only access the SRC at certain times, make sure we're allowed to before we read */ orig = temp; /* expose the SRC state bits */ outl ( (temp & SRC_CTLMASK) | (reg << SRC_RAMADDR_SHIFT) | 0x10000UL, s->io + ES1371_REG_SRCONV); /* now, wait for busy and the correct time to read */ temp = wait_src_ready (s); if ( (temp & 0x00870000UL ) != ( SRC_OKSTATE << 16 )){ /* wait for the right state */ for (i=0; i<POLL_COUNT; i++){ temp = inl (s->io + ES1371_REG_SRCONV); if ( (temp & 0x00870000UL ) == ( SRC_OKSTATE << 16 )) break; } } /* hide the state bits */ outl ((orig & SRC_CTLMASK) | (reg << SRC_RAMADDR_SHIFT), s->io + ES1371_REG_SRCONV); return temp; }static void src_write(struct es1371_state *s, unsigned reg, unsigned data){ unsigned int r; r = wait_src_ready(s) & (SRC_DIS | SRC_DDAC1 | SRC_DDAC2 | SRC_DADC); r |= (reg << SRC_RAMADDR_SHIFT) & SRC_RAMADDR_MASK; r |= (data << SRC_RAMDATA_SHIFT) & SRC_RAMDATA_MASK; outl(r | SRC_WE, s->io + ES1371_REG_SRCONV);}/* --------------------------------------------------------------------- *//* most of the following here is black magic */static void set_adc_rate(struct es1371_state *s, unsigned rate){ unsigned long flags; unsigned int n, truncm, freq; if (rate > 48000) rate = 48000; if (rate < 4000) rate = 4000; n = rate / 3000; if ((1 << n) & ((1 << 15) | (1 << 13) | (1 << 11) | (1 << 9))) n--; truncm = (21 * n - 1) | 1; freq = ((48000UL << 15) / rate) * n; s->adcrate = (48000UL << 15) / (freq / n); spin_lock_irqsave(&s->lock, flags); if (rate >= 24000) { if (truncm > 239) truncm = 239; src_write(s, SRCREG_ADC+SRCREG_TRUNC_N, (((239 - truncm) >> 1) << 9) | (n << 4)); } else { if (truncm > 119) truncm = 119; src_write(s, SRCREG_ADC+SRCREG_TRUNC_N, 0x8000 | (((119 - truncm) >> 1) << 9) | (n << 4)); } src_write(s, SRCREG_ADC+SRCREG_INT_REGS, (src_read(s, SRCREG_ADC+SRCREG_INT_REGS) & 0x00ff) | ((freq >> 5) & 0xfc00)); src_write(s, SRCREG_ADC+SRCREG_VFREQ_FRAC, freq & 0x7fff); src_write(s, SRCREG_VOL_ADC, n << 8); src_write(s, SRCREG_VOL_ADC+1, n << 8); spin_unlock_irqrestore(&s->lock, flags);}static void set_dac1_rate(struct es1371_state *s, unsigned rate){ unsigned long flags; unsigned int freq, r; if (rate > 48000) rate = 48000; if (rate < 4000) rate = 4000; freq = ((rate << 15) + 1500) / 3000; s->dac1rate = (freq * 3000 + 16384) >> 15; spin_lock_irqsave(&s->lock, flags); r = (wait_src_ready(s) & (SRC_DIS | SRC_DDAC2 | SRC_DADC)) | SRC_DDAC1; outl(r, s->io + ES1371_REG_SRCONV); src_write(s, SRCREG_DAC1+SRCREG_INT_REGS, (src_read(s, SRCREG_DAC1+SRCREG_INT_REGS) & 0x00ff) | ((freq >> 5) & 0xfc00)); src_write(s, SRCREG_DAC1+SRCREG_VFREQ_FRAC, freq & 0x7fff); r = (wait_src_ready(s) & (SRC_DIS | SRC_DDAC2 | SRC_DADC)); outl(r, s->io + ES1371_REG_SRCONV); spin_unlock_irqrestore(&s->lock, flags);}static void set_dac2_rate(struct es1371_state *s, unsigned rate){ unsigned long flags; unsigned int freq, r; if (rate > 48000) rate = 48000; if (rate < 4000) rate = 4000; freq = ((rate << 15) + 1500) / 3000; s->dac2rate = (freq * 3000 + 16384) >> 15; spin_lock_irqsave(&s->lock, flags); r = (wait_src_ready(s) & (SRC_DIS | SRC_DDAC1 | SRC_DADC)) | SRC_DDAC2; outl(r, s->io + ES1371_REG_SRCONV); src_write(s, SRCREG_DAC2+SRCREG_INT_REGS, (src_read(s, SRCREG_DAC2+SRCREG_INT_REGS) & 0x00ff) | ((freq >> 5) & 0xfc00)); src_write(s, SRCREG_DAC2+SRCREG_VFREQ_FRAC, freq & 0x7fff); r = (wait_src_ready(s) & (SRC_DIS | SRC_DDAC1 | SRC_DADC)); outl(r, s->io + ES1371_REG_SRCONV); spin_unlock_irqrestore(&s->lock, flags);}/* --------------------------------------------------------------------- */static void __init src_init(struct es1371_state *s){ unsigned int i; /* before we enable or disable the SRC we need to wait for it to become ready */ wait_src_ready(s); outl(SRC_DIS, s->io + ES1371_REG_SRCONV); for (i = 0; i < 0x80; i++) src_write(s, i, 0); src_write(s, SRCREG_DAC1+SRCREG_TRUNC_N, 16 << 4); src_write(s, SRCREG_DAC1+SRCREG_INT_REGS, 16 << 10); src_write(s, SRCREG_DAC2+SRCREG_TRUNC_N, 16 << 4); src_write(s, SRCREG_DAC2+SRCREG_INT_REGS, 16 << 10); src_write(s, SRCREG_VOL_ADC, 1 << 12); src_write(s, SRCREG_VOL_ADC+1, 1 << 12); src_write(s, SRCREG_VOL_DAC1, 1 << 12); src_write(s, SRCREG_VOL_DAC1+1, 1 << 12); src_write(s, SRCREG_VOL_DAC2, 1 << 12); src_write(s, SRCREG_VOL_DAC2+1, 1 << 12); set_adc_rate(s, 22050); set_dac1_rate(s, 22050); set_dac2_rate(s, 22050); /* WARNING: * enabling the sample rate converter without properly programming * its parameters causes the chip to lock up (the SRC busy bit will * be stuck high, and I've found no way to rectify this other than * power cycle) */ wait_src_ready(s); outl(0, s->io+ES1371_REG_SRCONV);}/* --------------------------------------------------------------------- */static void wrcodec(struct ac97_codec *codec, u8 addr, u16 data){ struct es1371_state *s = (struct es1371_state *)codec->private_data; unsigned long flags; unsigned t, x; for (t = 0; t < POLL_COUNT; t++) if (!(inl(s->io+ES1371_REG_CODEC) & CODEC_WIP)) break; spin_lock_irqsave(&s->lock, flags); /* save the current state for later */ x = wait_src_ready(s); /* enable SRC state data in SRC mux */ outl((x & (SRC_DIS | SRC_DDAC1 | SRC_DDAC2 | SRC_DADC)) | 0x00010000, s->io+ES1371_REG_SRCONV); /* wait for not busy (state 0) first to avoid transition states */ for (t=0; t<POLL_COUNT; t++){ if((inl(s->io+ES1371_REG_SRCONV) & 0x00870000) ==0 ) break; udelay(1); } /* wait for a SAFE time to write addr/data and then do it, dammit */ for (t=0; t<POLL_COUNT; t++){ if((inl(s->io+ES1371_REG_SRCONV) & 0x00870000) ==0x00010000) break; udelay(1); } outl(((addr << CODEC_POADD_SHIFT) & CODEC_POADD_MASK) | ((data << CODEC_PODAT_SHIFT) & CODEC_PODAT_MASK), s->io+ES1371_REG_CODEC); /* restore SRC reg */ wait_src_ready(s); outl(x, s->io+ES1371_REG_SRCONV); spin_unlock_irqrestore(&s->lock, flags);}static u16 rdcodec(struct ac97_codec *codec, u8 addr){ struct es1371_state *s = (struct es1371_state *)codec->private_data; unsigned long flags; unsigned t, x; /* wait for WIP to go away */ for (t = 0; t < 0x1000; t++) if (!(inl(s->io+ES1371_REG_CODEC) & CODEC_WIP)) break; spin_lock_irqsave(&s->lock, flags); /* save the current state for later */ x = (wait_src_ready(s) & (SRC_DIS | SRC_DDAC1 | SRC_DDAC2 | SRC_DADC)); /* enable SRC state data in SRC mux */ outl( x | 0x00010000, s->io+ES1371_REG_SRCONV); /* wait for not busy (state 0) first to avoid transition states */ for (t=0; t<POLL_COUNT; t++){ if((inl(s->io+ES1371_REG_SRCONV) & 0x00870000) ==0 ) break; udelay(1); } /* wait for a SAFE time to write addr/data and then do it, dammit */ for (t=0; t<POLL_COUNT; t++){ if((inl(s->io+ES1371_REG_SRCONV) & 0x00870000) ==0x00010000) break; udelay(1); } outl(((addr << CODEC_POADD_SHIFT) & CODEC_POADD_MASK) | CODEC_PORD, s->io+ES1371_REG_CODEC); /* restore SRC reg */ wait_src_ready(s); outl(x, s->io+ES1371_REG_SRCONV); spin_unlock_irqrestore(&s->lock, flags); /* wait for WIP again */ for (t = 0; t < 0x1000; t++) if (!(inl(s->io+ES1371_REG_CODEC) & CODEC_WIP)) break; /* now wait for the stinkin' data (RDY) */ for (t = 0; t < POLL_COUNT; t++) if ((x = inl(s->io+ES1371_REG_CODEC)) & CODEC_RDY) break; return ((x & CODEC_PIDAT_MASK) >> CODEC_PIDAT_SHIFT);}/* --------------------------------------------------------------------- */static inline void stop_adc(struct es1371_state *s){ unsigned long flags; spin_lock_irqsave(&s->lock, flags); s->ctrl &= ~CTRL_ADC_EN; outl(s->ctrl, s->io+ES1371_REG_CONTROL); spin_unlock_irqrestore(&s->lock, flags);} static inline void stop_dac1(struct es1371_state *s){ unsigned long flags; spin_lock_irqsave(&s->lock, flags); s->ctrl &= ~CTRL_DAC1_EN; outl(s->ctrl, s->io+ES1371_REG_CONTROL); spin_unlock_irqrestore(&s->lock, flags);} static inline void stop_dac2(struct es1371_state *s){ unsigned long flags; spin_lock_irqsave(&s->lock, flags); s->ctrl &= ~CTRL_DAC2_EN; outl(s->ctrl, s->io+ES1371_REG_CONTROL); spin_unlock_irqrestore(&s->lock, flags);} static void start_dac1(struct es1371_state *s){ unsigned long flags; unsigned fragremain, fshift; spin_lock_irqsave(&s->lock, flags); if (!(s->ctrl & CTRL_DAC1_EN) && (s->dma_dac1.mapped || s->dma_dac1.count > 0) && s->dma_dac1.ready) { s->ctrl |= CTRL_DAC1_EN; s->sctrl = (s->sctrl & ~(SCTRL_P1LOOPSEL | SCTRL_P1PAUSE | SCTRL_P1SCTRLD)) | SCTRL_P1INTEN;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -