📄 sb16_csp.c
字号:
if (!(channels & p->acc_channels)) { snd_printd("%s: Invalid number of channels\n", __FUNCTION__); return -EINVAL; } /* Mute PCM volume */ spin_lock_irqsave(&p->chip->mixer_lock, flags); mixL = snd_sbmixer_read(p->chip, SB_DSP4_PCM_DEV); mixR = snd_sbmixer_read(p->chip, SB_DSP4_PCM_DEV + 1); snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV, mixL & 0x7); snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV + 1, mixR & 0x7); spin_lock(&p->chip->reg_lock); set_mode_register(p->chip, 0xc0); /* c0 = STOP */ set_mode_register(p->chip, 0x70); /* 70 = RUN */ s_type = 0x00; if (channels == SNDRV_SB_CSP_MONO) s_type = 0x11; /* 000n 000n (n = 1 if mono) */ if (sample_width == SNDRV_SB_CSP_SAMPLE_8BIT) s_type |= 0x22; /* 00dX 00dX (d = 1 if 8 bit samples) */ if (set_codec_parameter(p->chip, 0x81, s_type)) { snd_printd("%s: Set sample type command failed\n", __FUNCTION__); goto __fail; } if (set_codec_parameter(p->chip, 0x80, 0x00)) { snd_printd("%s: Codec start command failed\n", __FUNCTION__); goto __fail; } p->run_width = sample_width; p->run_channels = channels; p->running |= SNDRV_SB_CSP_ST_RUNNING; if (p->mode & SNDRV_SB_CSP_MODE_QSOUND) { set_codec_parameter(p->chip, 0xe0, 0x01); /* enable QSound decoder */ set_codec_parameter(p->chip, 0x00, 0xff); set_codec_parameter(p->chip, 0x01, 0xff); p->running |= SNDRV_SB_CSP_ST_QSOUND; /* set QSound startup value */ snd_sb_csp_qsound_transfer(p); } result = 0; __fail: spin_unlock(&p->chip->reg_lock); /* restore PCM volume */ snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV, mixL); snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV + 1, mixR); spin_unlock_irqrestore(&p->chip->mixer_lock, flags); return result;}/* * stop CSP */static int snd_sb_csp_stop(snd_sb_csp_t * p){ int result; unsigned char mixL, mixR; unsigned long flags; if (!(p->running & SNDRV_SB_CSP_ST_RUNNING)) return 0; /* Mute PCM volume */ spin_lock_irqsave(&p->chip->mixer_lock, flags); mixL = snd_sbmixer_read(p->chip, SB_DSP4_PCM_DEV); mixR = snd_sbmixer_read(p->chip, SB_DSP4_PCM_DEV + 1); snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV, mixL & 0x7); snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV + 1, mixR & 0x7); spin_lock(&p->chip->reg_lock); if (p->running & SNDRV_SB_CSP_ST_QSOUND) { set_codec_parameter(p->chip, 0xe0, 0x01); /* disable QSound decoder */ set_codec_parameter(p->chip, 0x00, 0x00); set_codec_parameter(p->chip, 0x01, 0x00); p->running &= ~SNDRV_SB_CSP_ST_QSOUND; } result = set_mode_register(p->chip, 0xc0); /* c0 = STOP */ spin_unlock(&p->chip->reg_lock); /* restore PCM volume */ snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV, mixL); snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV + 1, mixR); spin_unlock_irqrestore(&p->chip->mixer_lock, flags); if (!(result)) p->running &= ~(SNDRV_SB_CSP_ST_PAUSED | SNDRV_SB_CSP_ST_RUNNING); return result;}/* * pause CSP codec and hold DMA transfer */static int snd_sb_csp_pause(snd_sb_csp_t * p){ int result; unsigned long flags; if (!(p->running & SNDRV_SB_CSP_ST_RUNNING)) return -EBUSY; spin_lock_irqsave(&p->chip->reg_lock, flags); result = set_codec_parameter(p->chip, 0x80, 0xff); spin_unlock_irqrestore(&p->chip->reg_lock, flags); if (!(result)) p->running |= SNDRV_SB_CSP_ST_PAUSED; return result;}/* * restart CSP codec and resume DMA transfer */static int snd_sb_csp_restart(snd_sb_csp_t * p){ int result; unsigned long flags; if (!(p->running & SNDRV_SB_CSP_ST_PAUSED)) return -EBUSY; spin_lock_irqsave(&p->chip->reg_lock, flags); result = set_codec_parameter(p->chip, 0x80, 0x00); spin_unlock_irqrestore(&p->chip->reg_lock, flags); if (!(result)) p->running &= ~SNDRV_SB_CSP_ST_PAUSED; return result;}/* ------------------------------ *//* * QSound mixer control for PCM */static int snd_sb_qsound_switch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo){ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; uinfo->count = 1; uinfo->value.integer.min = 0; uinfo->value.integer.max = 1; return 0;}static int snd_sb_qsound_switch_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ snd_sb_csp_t *p = snd_kcontrol_chip(kcontrol); ucontrol->value.integer.value[0] = p->q_enabled ? 1 : 0; return 0;}static int snd_sb_qsound_switch_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ snd_sb_csp_t *p = snd_kcontrol_chip(kcontrol); unsigned long flags; int change; unsigned char nval; nval = ucontrol->value.integer.value[0] & 0x01; spin_lock_irqsave(&p->q_lock, flags); change = p->q_enabled != nval; p->q_enabled = nval; spin_unlock_irqrestore(&p->q_lock, flags); return change;}static int snd_sb_qsound_space_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo){ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 2; uinfo->value.integer.min = 0; uinfo->value.integer.max = SNDRV_SB_CSP_QSOUND_MAX_RIGHT; return 0;}static int snd_sb_qsound_space_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ snd_sb_csp_t *p = snd_kcontrol_chip(kcontrol); unsigned long flags; spin_lock_irqsave(&p->q_lock, flags); ucontrol->value.integer.value[0] = p->qpos_left; ucontrol->value.integer.value[1] = p->qpos_right; spin_unlock_irqrestore(&p->q_lock, flags); return 0;}static int snd_sb_qsound_space_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ snd_sb_csp_t *p = snd_kcontrol_chip(kcontrol); unsigned long flags; int change; unsigned char nval1, nval2; nval1 = ucontrol->value.integer.value[0]; if (nval1 > SNDRV_SB_CSP_QSOUND_MAX_RIGHT) nval1 = SNDRV_SB_CSP_QSOUND_MAX_RIGHT; nval2 = ucontrol->value.integer.value[1]; if (nval2 > SNDRV_SB_CSP_QSOUND_MAX_RIGHT) nval2 = SNDRV_SB_CSP_QSOUND_MAX_RIGHT; spin_lock_irqsave(&p->q_lock, flags); change = p->qpos_left != nval1 || p->qpos_right != nval2; p->qpos_left = nval1; p->qpos_right = nval2; p->qpos_changed = change; spin_unlock_irqrestore(&p->q_lock, flags); return change;}static snd_kcontrol_new_t snd_sb_qsound_switch = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "3D Control - Switch", .info = snd_sb_qsound_switch_info, .get = snd_sb_qsound_switch_get, .put = snd_sb_qsound_switch_put};static snd_kcontrol_new_t snd_sb_qsound_space = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "3D Control - Space", .info = snd_sb_qsound_space_info, .get = snd_sb_qsound_space_get, .put = snd_sb_qsound_space_put};static int snd_sb_qsound_build(snd_sb_csp_t * p){ snd_card_t * card; int err; snd_assert(p != NULL, return -EINVAL); card = p->chip->card; p->qpos_left = p->qpos_right = SNDRV_SB_CSP_QSOUND_MAX_RIGHT / 2; p->qpos_changed = 0; spin_lock_init(&p->q_lock); if ((err = snd_ctl_add(card, p->qsound_switch = snd_ctl_new1(&snd_sb_qsound_switch, p))) < 0) goto __error; if ((err = snd_ctl_add(card, p->qsound_space = snd_ctl_new1(&snd_sb_qsound_space, p))) < 0) goto __error; return 0; __error: snd_sb_qsound_destroy(p); return err;}static void snd_sb_qsound_destroy(snd_sb_csp_t * p){ snd_card_t * card; unsigned long flags; snd_assert(p != NULL, return); card = p->chip->card; down_write(&card->controls_rwsem); if (p->qsound_switch) snd_ctl_remove(card, p->qsound_switch); if (p->qsound_space) snd_ctl_remove(card, p->qsound_space); up_write(&card->controls_rwsem); /* cancel pending transfer of QSound parameters */ spin_lock_irqsave (&p->q_lock, flags); p->qpos_changed = 0; spin_unlock_irqrestore (&p->q_lock, flags);}/* * Transfer qsound parameters to CSP, * function should be called from interrupt routine */static int snd_sb_csp_qsound_transfer(snd_sb_csp_t * p){ int err = -ENXIO; spin_lock(&p->q_lock); if (p->running & SNDRV_SB_CSP_ST_QSOUND) { set_codec_parameter(p->chip, 0xe0, 0x01); /* left channel */ set_codec_parameter(p->chip, 0x00, p->qpos_left); set_codec_parameter(p->chip, 0x02, 0x00); /* right channel */ set_codec_parameter(p->chip, 0x00, p->qpos_right); set_codec_parameter(p->chip, 0x03, 0x00); err = 0; } p->qpos_changed = 0; spin_unlock(&p->q_lock); return err;}/* ------------------------------ *//* * proc interface */static int init_proc_entry(snd_sb_csp_t * p, int device){ char name[16]; snd_info_entry_t *entry; sprintf(name, "cspD%d", device); if (! snd_card_proc_new(p->chip->card, name, &entry)) snd_info_set_text_ops(entry, p, 1024, info_read); return 0;}static void info_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer){ snd_sb_csp_t *p = entry->private_data; snd_iprintf(buffer, "Creative Signal Processor [v%d.%d]\n", (p->version >> 4), (p->version & 0x0f)); snd_iprintf(buffer, "State: %cx%c%c%c\n", ((p->running & SNDRV_SB_CSP_ST_QSOUND) ? 'Q' : '-'), ((p->running & SNDRV_SB_CSP_ST_PAUSED) ? 'P' : '-'), ((p->running & SNDRV_SB_CSP_ST_RUNNING) ? 'R' : '-'), ((p->running & SNDRV_SB_CSP_ST_LOADED) ? 'L' : '-')); if (p->running & SNDRV_SB_CSP_ST_LOADED) { snd_iprintf(buffer, "Codec: %s [func #%d]\n", p->codec_name, p->func_nr); snd_iprintf(buffer, "Sample rates: "); if (p->acc_rates == SNDRV_SB_CSP_RATE_ALL) { snd_iprintf(buffer, "All\n"); } else { snd_iprintf(buffer, "%s%s%s%s\n", ((p->acc_rates & SNDRV_SB_CSP_RATE_8000) ? "8000Hz " : ""), ((p->acc_rates & SNDRV_SB_CSP_RATE_11025) ? "11025Hz " : ""), ((p->acc_rates & SNDRV_SB_CSP_RATE_22050) ? "22050Hz " : ""), ((p->acc_rates & SNDRV_SB_CSP_RATE_44100) ? "44100Hz" : "")); } if (p->mode == SNDRV_SB_CSP_MODE_QSOUND) { snd_iprintf(buffer, "QSound decoder %sabled\n", p->q_enabled ? "en" : "dis"); } else { snd_iprintf(buffer, "PCM format ID: 0x%x (%s/%s) [%s/%s] [%s/%s]\n", p->acc_format, ((p->acc_width & SNDRV_SB_CSP_SAMPLE_16BIT) ? "16bit" : "-"), ((p->acc_width & SNDRV_SB_CSP_SAMPLE_8BIT) ? "8bit" : "-"), ((p->acc_channels & SNDRV_SB_CSP_MONO) ? "mono" : "-"), ((p->acc_channels & SNDRV_SB_CSP_STEREO) ? "stereo" : "-"), ((p->mode & SNDRV_SB_CSP_MODE_DSP_WRITE) ? "playback" : "-"), ((p->mode & SNDRV_SB_CSP_MODE_DSP_READ) ? "capture" : "-")); } } if (p->running & SNDRV_SB_CSP_ST_AUTO) { snd_iprintf(buffer, "Autoloaded Mu-Law, A-Law or Ima-ADPCM hardware codec\n"); } if (p->running & SNDRV_SB_CSP_ST_RUNNING) { snd_iprintf(buffer, "Processing %dbit %s PCM samples\n", ((p->run_width & SNDRV_SB_CSP_SAMPLE_16BIT) ? 16 : 8), ((p->run_channels & SNDRV_SB_CSP_MONO) ? "mono" : "stereo")); } if (p->running & SNDRV_SB_CSP_ST_QSOUND) { snd_iprintf(buffer, "Qsound position: left = 0x%x, right = 0x%x\n", p->qpos_left, p->qpos_right); }}/* */EXPORT_SYMBOL(snd_sb_csp_new);/* * INIT part */static int __init alsa_sb_csp_init(void){ return 0;}static void __exit alsa_sb_csp_exit(void){}module_init(alsa_sb_csp_init)module_exit(alsa_sb_csp_exit)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -