📄 sb_ess.c
字号:
ess_exec_commands (devc, ess_out_cmds); ess_change (devc, 0xb1, 0xf0, 0x50); /* Enable DMA */ ess_change (devc, 0xb2, 0xf0, 0x50); /* Enable IRQ */ sb_dsp_command(devc, DSP_CMD_SPKON); /* There be sound! */ devc->trigger_bits = 0; return 0;}static int ess_audio_prepare_for_output_audio2 (int dev, int bsize, int bcount){ sb_devc *devc = audio_devs[dev]->devc; unsigned char bits;/* FKS: qqq sb_dsp_reset(devc);*/ /* * Auto-Initialize: * DMA mode + demand mode (8 bytes/request, yes I want it all!) * But leave 16-bit DMA bit untouched! */ ess_chgmixer (devc, 0x78, 0xd0, 0xd0); ess_speed(devc, 2); /* bits 4:3 on ES1887 represent recording source. Keep them! */ bits = ess_getmixer (devc, 0x7a) & 0x18; /* Set stereo/mono */ if (devc->channels != 1) bits |= 0x02; /* Init DACs; UNSIGNED mode for 8 bit; SIGNED mode for 16 bit */ if (devc->bits != AFMT_U8) bits |= 0x05; /* 16 bit */ /* Enable DMA, IRQ will be shared (hopefully)*/ bits |= 0x60; ess_setmixer (devc, 0x7a, bits); ess_mixer_reload (devc, SOUND_MIXER_PCM); /* There be sound! */ devc->trigger_bits = 0; return 0;}static int ess_audio_prepare_for_output(int dev, int bsize, int bcount){ sb_devc *devc = audio_devs[dev]->devc;#ifdef FKS_REG_LOGGINGprintk(KERN_INFO "ess_audio_prepare_for_output: dma_out=%d,dma_in=%d\n", audio_devs[dev]->dmap_out->dma, audio_devs[dev]->dmap_in->dma);#endif if (devc->duplex) { return ess_audio_prepare_for_output_audio2 (dev, bsize, bcount); } else { return ess_audio_prepare_for_output_audio1 (dev, bsize, bcount); }}static void ess_audio_halt_xfer(int dev){ unsigned long flags; sb_devc *devc = audio_devs[dev]->devc; save_flags(flags); cli(); sb_dsp_reset(devc); restore_flags(flags); /* * Audio 2 may still be operational! Creates awful sounds! */ if (devc->duplex) ess_chgmixer(devc, 0x78, 0x03, 0x00);}static void ess_audio_start_input (int dev, unsigned long buf, int nr_bytes, int intrflag){ int count = nr_bytes; sb_devc *devc = audio_devs[dev]->devc; short c = -nr_bytes; /* * Start a DMA input to the buffer pointed by dmaqtail */ if (audio_devs[dev]->dmap_in->dma > 3) count >>= 1; count--; devc->irq_mode = IMODE_INPUT; ess_write (devc, 0xa4, (unsigned char) ((unsigned short) c & 0xff)); ess_write (devc, 0xa5, (unsigned char) (((unsigned short) c >> 8) & 0xff)); ess_change (devc, 0xb8, 0x0f, 0x0f); /* Go */ devc->intr_active = 1;}static void ess_audio_output_block_audio1 (int dev, unsigned long buf, int nr_bytes, int intrflag){ int count = nr_bytes; sb_devc *devc = audio_devs[dev]->devc; short c = -nr_bytes; if (audio_devs[dev]->dmap_out->dma > 3) count >>= 1; count--; devc->irq_mode = IMODE_OUTPUT; ess_write (devc, 0xa4, (unsigned char) ((unsigned short) c & 0xff)); ess_write (devc, 0xa5, (unsigned char) (((unsigned short) c >> 8) & 0xff)); ess_change (devc, 0xb8, 0x05, 0x05); /* Go */ devc->intr_active = 1;}static void ess_audio_output_block_audio2 (int dev, unsigned long buf, int nr_bytes, int intrflag){ int count = nr_bytes; sb_devc *devc = audio_devs[dev]->devc; short c = -nr_bytes; if (audio_devs[dev]->dmap_out->dma > 3) count >>= 1; count--; ess_setmixer (devc, 0x74, (unsigned char) ((unsigned short) c & 0xff)); ess_setmixer (devc, 0x76, (unsigned char) (((unsigned short) c >> 8) & 0xff)); ess_chgmixer (devc, 0x78, 0x03, 0x03); /* Go */ devc->irq_mode_16 = IMODE_OUTPUT; devc->intr_active_16 = 1;}static void ess_audio_output_block (int dev, unsigned long buf, int nr_bytes, int intrflag){ sb_devc *devc = audio_devs[dev]->devc; if (devc->duplex) { ess_audio_output_block_audio2 (dev, buf, nr_bytes, intrflag); } else { ess_audio_output_block_audio1 (dev, buf, nr_bytes, intrflag); }}/* * FKS: the if-statements for both bits and bits_16 are quite alike. * Combine this... */static void ess_audio_trigger(int dev, int bits){ sb_devc *devc = audio_devs[dev]->devc; int bits_16 = bits & devc->irq_mode_16; bits &= devc->irq_mode; if (!bits && !bits_16) { /* FKS oh oh.... wrong?? for dma 16? */ sb_dsp_command(devc, 0xd0); /* Halt DMA */ } if (bits) { switch (devc->irq_mode) { case IMODE_INPUT: ess_audio_start_input(dev, devc->trg_buf, devc->trg_bytes, devc->trg_intrflag); break; case IMODE_OUTPUT: ess_audio_output_block(dev, devc->trg_buf, devc->trg_bytes, devc->trg_intrflag); break; } } if (bits_16) { switch (devc->irq_mode_16) { case IMODE_INPUT: ess_audio_start_input(dev, devc->trg_buf_16, devc->trg_bytes_16, devc->trg_intrflag_16); break; case IMODE_OUTPUT: ess_audio_output_block(dev, devc->trg_buf_16, devc->trg_bytes_16, devc->trg_intrflag_16); break; } } devc->trigger_bits = bits | bits_16;}static int ess_audio_set_speed(int dev, int speed){ sb_devc *devc = audio_devs[dev]->devc; int minspeed, maxspeed, dummydiv; if (speed > 0) { minspeed = (devc->duplex ? 6215 : 5000 ); maxspeed = (devc->duplex ? 44100 : 48000); if (speed < minspeed) speed = minspeed; if (speed > maxspeed) speed = maxspeed; ess_common_speed (devc, &speed, &dummydiv); devc->speed = speed; } return devc->speed;}/* * FKS: This is a one-on-one copy of sb1_audio_set_bits */static unsigned int ess_audio_set_bits(int dev, unsigned int bits){ sb_devc *devc = audio_devs[dev]->devc; if (bits != 0) { if (bits == AFMT_U8 || bits == AFMT_S16_LE) { devc->bits = bits; } else { devc->bits = AFMT_U8; } } return devc->bits;}/* * FKS: This is a one-on-one copy of sbpro_audio_set_channels * (*) Modified it!! */static short ess_audio_set_channels(int dev, short channels){ sb_devc *devc = audio_devs[dev]->devc; if (channels == 1 || channels == 2) devc->channels = channels; return devc->channels;}static struct audio_driver ess_audio_driver = /* ESS ES688/1688 */{ sb_audio_open, sb_audio_close, ess_set_output_parms, ess_set_input_parms, NULL, ess_audio_prepare_for_input, ess_audio_prepare_for_output, ess_audio_halt_xfer, NULL, /* local_qlen */ NULL, /* copy_from_user */ NULL, NULL, ess_audio_trigger, ess_audio_set_speed, ess_audio_set_bits, ess_audio_set_channels};/* * ess_audio_init must be called from sb_audio_init */struct audio_driver *ess_audio_init (sb_devc *devc, int *audio_flags, int *format_mask){ *audio_flags = DMA_AUTOMODE; *format_mask |= AFMT_S16_LE; if (devc->duplex) { int tmp_dma; /* * sb_audio_init thinks dma8 is for playback and * dma16 is for record. Not now! So swap them. */ tmp_dma = devc->dma16; devc->dma16 = devc->dma8; devc->dma8 = tmp_dma; *audio_flags |= DMA_DUPLEX; } return &ess_audio_driver;}/**************************************************************************** * * * ESS common * * * ****************************************************************************/static void ess_handle_channel (char *channel, int dev, int intr_active, unsigned char flag, int irq_mode){ if (!intr_active || !flag) return;#ifdef FKS_REG_LOGGINGprintk(KERN_INFO "FKS: ess_handle_channel %s irq_mode=%d\n", channel, irq_mode);#endif switch (irq_mode) { case IMODE_OUTPUT: DMAbuf_outputintr (dev, 1); break; case IMODE_INPUT: DMAbuf_inputintr (dev); break; case IMODE_INIT: break; default: /* printk(KERN_WARN "ESS: Unexpected interrupt\n"); */ }}/* * FKS: TODO!!! Finish this! * * I think midi stuff uses uart401, without interrupts. * So IMODE_MIDI isn't a value for devc->irq_mode. */void ess_intr (sb_devc *devc){ int status; unsigned char src; if (devc->submodel == SUBMDL_ES1887) { src = ess_getmixer (devc, 0x7f) >> 4; } else { src = 0xff; }#ifdef FKS_REG_LOGGINGprintk(KERN_INFO "FKS: sbintr src=%x\n",(int)src);#endif ess_handle_channel ( "Audio 1" , devc->dev, devc->intr_active , src & 0x01, devc->irq_mode ); ess_handle_channel ( "Audio 2" , devc->dev, devc->intr_active_16, src & 0x02, devc->irq_mode_16); /* * Acknowledge interrupts */ if (devc->submodel == SUBMDL_ES1887 && (src & 0x02)) { ess_chgmixer (devc, 0x7a, 0x80, 0x00); } if (src & 0x01) { status = inb(DSP_DATA_AVAIL); }}static void ess_extended (sb_devc * devc){ /* Enable extended mode */ sb_dsp_command(devc, 0xc6);}static int ess_write (sb_devc * devc, unsigned char reg, unsigned char data){#ifdef FKS_REG_LOGGINGprintk(KERN_INFO "FKS: write reg %x: %x\n", reg, data);#endif /* Write a byte to an extended mode register of ES1688 */ if (!sb_dsp_command(devc, reg)) return 0; return sb_dsp_command(devc, data);}static int ess_read (sb_devc * devc, unsigned char reg){ /* Read a byte from an extended mode register of ES1688 */ /* Read register command */ if (!sb_dsp_command(devc, 0xc0)) return -1; if (!sb_dsp_command(devc, reg )) return -1; return sb_dsp_get_byte(devc);}int ess_dsp_reset(sb_devc * devc){ int loopc;#ifdef FKS_REG_LOGGINGprintk(KERN_INFO "FKS: ess_dsp_reset 1\n");ess_show_mixerregs (devc);#endif DEB(printk("Entered ess_dsp_reset()\n")); outb(3, DSP_RESET); /* Reset FIFO too */ udelay(10); outb(0, DSP_RESET); udelay(30); for (loopc = 0; loopc < 1000 && !(inb(DSP_DATA_AVAIL) & 0x80); loopc++); if (inb(DSP_READ) != 0xAA) { DDB(printk("sb: No response to RESET\n")); return 0; /* Sorry */ } ess_extended (devc); DEB(printk("sb_dsp_reset() OK\n"));#ifdef FKS_LOGGINGprintk(KERN_INFO "FKS: dsp_reset 2\n");ess_show_mixerregs (devc);#endif return 1;}static int ess_irq_bits (int irq){ switch (irq) { case 2: case 9: return 0; case 5: return 1; case 7: return 2; case 10: return 3; default: printk(KERN_ERR "ESS1688: Invalid IRQ %d\n", irq); return -1; }}/* * Set IRQ configuration register for all ESS models
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -