📄 intel8x0m.c
字号:
step += ICH_REG_LVI_MASK + 1; // if (step != 1) // snd_printd("step = %d, %d -> %d\n", step, ichdev->civ, civ); ichdev->civ = civ; } ichdev->position += step * ichdev->fragsize1; ichdev->position %= ichdev->size; ichdev->lvi += step; ichdev->lvi &= ICH_REG_LVI_MASK; iputbyte(chip, port + ICH_REG_OFF_LVI, ichdev->lvi); for (i = 0; i < step; i++) { ichdev->lvi_frag++; ichdev->lvi_frag %= ichdev->frags; ichdev->bdbar[ichdev->lvi * 2] = cpu_to_le32(ichdev->physbuf + ichdev->lvi_frag * ichdev->fragsize1);#if 0 printk("new: bdbar[%i] = 0x%x [0x%x], prefetch = %i, all = 0x%x, 0x%x\n", ichdev->lvi * 2, ichdev->bdbar[ichdev->lvi * 2], ichdev->bdbar[ichdev->lvi * 2 + 1], inb(ICH_REG_OFF_PIV + port), inl(port + 4), inb(port + ICH_REG_OFF_CR));#endif if (--ichdev->ack == 0) { ichdev->ack = ichdev->ack_reload; ack = 1; } } if (ack && ichdev->substream) { spin_unlock(&chip->reg_lock); snd_pcm_period_elapsed(ichdev->substream); spin_lock(&chip->reg_lock); } iputbyte(chip, port + ichdev->roff_sr, ICH_FIFOE | ICH_BCIS | ICH_LVBCI);}static irqreturn_t snd_intel8x0_interrupt(int irq, void *dev_id){ struct intel8x0m *chip = dev_id; struct ichdev *ichdev; unsigned int status; unsigned int i; spin_lock(&chip->reg_lock); status = igetdword(chip, chip->int_sta_reg); if (status == 0xffffffff) { /* we are not yet resumed */ spin_unlock(&chip->reg_lock); return IRQ_NONE; } if ((status & chip->int_sta_mask) == 0) { if (status) iputdword(chip, chip->int_sta_reg, status); spin_unlock(&chip->reg_lock); return IRQ_NONE; } for (i = 0; i < chip->bdbars_count; i++) { ichdev = &chip->ichd[i]; if (status & ichdev->int_sta_mask) snd_intel8x0_update(chip, ichdev); } /* ack them */ iputdword(chip, chip->int_sta_reg, status & chip->int_sta_mask); spin_unlock(&chip->reg_lock); return IRQ_HANDLED;}/* * PCM part */static int snd_intel8x0_pcm_trigger(struct snd_pcm_substream *substream, int cmd){ struct intel8x0m *chip = snd_pcm_substream_chip(substream); struct ichdev *ichdev = get_ichdev(substream); unsigned char val = 0; unsigned long port = ichdev->reg_offset; switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: val = ICH_IOCE | ICH_STARTBM; break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: val = 0; break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: val = ICH_IOCE; break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: val = ICH_IOCE | ICH_STARTBM; break; default: return -EINVAL; } iputbyte(chip, port + ICH_REG_OFF_CR, val); if (cmd == SNDRV_PCM_TRIGGER_STOP) { /* wait until DMA stopped */ while (!(igetbyte(chip, port + ichdev->roff_sr) & ICH_DCH)) ; /* reset whole DMA things */ iputbyte(chip, port + ICH_REG_OFF_CR, ICH_RESETREGS); } return 0;}static int snd_intel8x0_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params){ return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));}static int snd_intel8x0_hw_free(struct snd_pcm_substream *substream){ return snd_pcm_lib_free_pages(substream);}static snd_pcm_uframes_t snd_intel8x0_pcm_pointer(struct snd_pcm_substream *substream){ struct intel8x0m *chip = snd_pcm_substream_chip(substream); struct ichdev *ichdev = get_ichdev(substream); size_t ptr1, ptr; ptr1 = igetword(chip, ichdev->reg_offset + ichdev->roff_picb) << chip->pcm_pos_shift; if (ptr1 != 0) ptr = ichdev->fragsize1 - ptr1; else ptr = 0; ptr += ichdev->position; if (ptr >= ichdev->size) return 0; return bytes_to_frames(substream->runtime, ptr);}static int snd_intel8x0m_pcm_prepare(struct snd_pcm_substream *substream){ struct intel8x0m *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct ichdev *ichdev = get_ichdev(substream); ichdev->physbuf = runtime->dma_addr; ichdev->size = snd_pcm_lib_buffer_bytes(substream); ichdev->fragsize = snd_pcm_lib_period_bytes(substream); snd_ac97_write(ichdev->ac97, AC97_LINE1_RATE, runtime->rate); snd_ac97_write(ichdev->ac97, AC97_LINE1_LEVEL, 0); snd_intel8x0_setup_periods(chip, ichdev); return 0;}static struct snd_pcm_hardware snd_intel8x0m_stream ={ .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME), .formats = SNDRV_PCM_FMTBIT_S16_LE, .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_KNOT, .rate_min = 8000, .rate_max = 16000, .channels_min = 1, .channels_max = 1, .buffer_bytes_max = 64 * 1024, .period_bytes_min = 32, .period_bytes_max = 64 * 1024, .periods_min = 1, .periods_max = 1024, .fifo_size = 0,};static int snd_intel8x0m_pcm_open(struct snd_pcm_substream *substream, struct ichdev *ichdev){ static unsigned int rates[] = { 8000, 9600, 12000, 16000 }; static struct snd_pcm_hw_constraint_list hw_constraints_rates = { .count = ARRAY_SIZE(rates), .list = rates, .mask = 0, }; struct snd_pcm_runtime *runtime = substream->runtime; int err; ichdev->substream = substream; runtime->hw = snd_intel8x0m_stream; err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates); if ( err < 0 ) return err; runtime->private_data = ichdev; return 0;}static int snd_intel8x0m_playback_open(struct snd_pcm_substream *substream){ struct intel8x0m *chip = snd_pcm_substream_chip(substream); return snd_intel8x0m_pcm_open(substream, &chip->ichd[ICHD_MDMOUT]);}static int snd_intel8x0m_playback_close(struct snd_pcm_substream *substream){ struct intel8x0m *chip = snd_pcm_substream_chip(substream); chip->ichd[ICHD_MDMOUT].substream = NULL; return 0;}static int snd_intel8x0m_capture_open(struct snd_pcm_substream *substream){ struct intel8x0m *chip = snd_pcm_substream_chip(substream); return snd_intel8x0m_pcm_open(substream, &chip->ichd[ICHD_MDMIN]);}static int snd_intel8x0m_capture_close(struct snd_pcm_substream *substream){ struct intel8x0m *chip = snd_pcm_substream_chip(substream); chip->ichd[ICHD_MDMIN].substream = NULL; return 0;}static struct snd_pcm_ops snd_intel8x0m_playback_ops = { .open = snd_intel8x0m_playback_open, .close = snd_intel8x0m_playback_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_intel8x0_hw_params, .hw_free = snd_intel8x0_hw_free, .prepare = snd_intel8x0m_pcm_prepare, .trigger = snd_intel8x0_pcm_trigger, .pointer = snd_intel8x0_pcm_pointer,};static struct snd_pcm_ops snd_intel8x0m_capture_ops = { .open = snd_intel8x0m_capture_open, .close = snd_intel8x0m_capture_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_intel8x0_hw_params, .hw_free = snd_intel8x0_hw_free, .prepare = snd_intel8x0m_pcm_prepare, .trigger = snd_intel8x0_pcm_trigger, .pointer = snd_intel8x0_pcm_pointer,};struct ich_pcm_table { char *suffix; struct snd_pcm_ops *playback_ops; struct snd_pcm_ops *capture_ops; size_t prealloc_size; size_t prealloc_max_size; int ac97_idx;};static int __devinit snd_intel8x0_pcm1(struct intel8x0m *chip, int device, struct ich_pcm_table *rec){ struct snd_pcm *pcm; int err; char name[32]; if (rec->suffix) sprintf(name, "Intel ICH - %s", rec->suffix); else strcpy(name, "Intel ICH"); err = snd_pcm_new(chip->card, name, device, rec->playback_ops ? 1 : 0, rec->capture_ops ? 1 : 0, &pcm); if (err < 0) return err; if (rec->playback_ops) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, rec->playback_ops); if (rec->capture_ops) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, rec->capture_ops); pcm->private_data = chip; pcm->info_flags = 0; pcm->dev_class = SNDRV_PCM_CLASS_MODEM; if (rec->suffix) sprintf(pcm->name, "%s - %s", chip->card->shortname, rec->suffix); else strcpy(pcm->name, chip->card->shortname); chip->pcm[device] = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), rec->prealloc_size, rec->prealloc_max_size); return 0;}static struct ich_pcm_table intel_pcms[] __devinitdata = { { .suffix = "Modem", .playback_ops = &snd_intel8x0m_playback_ops, .capture_ops = &snd_intel8x0m_capture_ops, .prealloc_size = 32 * 1024, .prealloc_max_size = 64 * 1024, },};static int __devinit snd_intel8x0_pcm(struct intel8x0m *chip){ int i, tblsize, device, err; struct ich_pcm_table *tbl, *rec;#if 1 tbl = intel_pcms; tblsize = 1;#else switch (chip->device_type) { case DEVICE_NFORCE: tbl = nforce_pcms; tblsize = ARRAY_SIZE(nforce_pcms); break; case DEVICE_ALI: tbl = ali_pcms; tblsize = ARRAY_SIZE(ali_pcms); break; default: tbl = intel_pcms; tblsize = 2; break; }#endif device = 0; for (i = 0; i < tblsize; i++) { rec = tbl + i; if (i > 0 && rec->ac97_idx) { /* activate PCM only when associated AC'97 codec */ if (! chip->ichd[rec->ac97_idx].ac97) continue; } err = snd_intel8x0_pcm1(chip, device, rec); if (err < 0) return err; device++; } chip->pcm_devs = device; return 0;} /* * Mixer part */static void snd_intel8x0_mixer_free_ac97_bus(struct snd_ac97_bus *bus){ struct intel8x0m *chip = bus->private_data; chip->ac97_bus = NULL;}static void snd_intel8x0_mixer_free_ac97(struct snd_ac97 *ac97){ struct intel8x0m *chip = ac97->private_data; chip->ac97 = NULL;}static int __devinit snd_intel8x0_mixer(struct intel8x0m *chip, int ac97_clock){ struct snd_ac97_bus *pbus; struct snd_ac97_template ac97; struct snd_ac97 *x97; int err; unsigned int glob_sta = 0; static struct snd_ac97_bus_ops ops = { .write = snd_intel8x0_codec_write, .read = snd_intel8x0_codec_read, }; chip->in_ac97_init = 1; memset(&ac97, 0, sizeof(ac97)); ac97.private_data = chip; ac97.private_free = snd_intel8x0_mixer_free_ac97; ac97.scaps = AC97_SCAP_SKIP_AUDIO | AC97_SCAP_POWER_SAVE; glob_sta = igetdword(chip, ICHREG(GLOB_STA)); if ((err = snd_ac97_bus(chip->card, 0, &ops, chip, &pbus)) < 0) goto __err; pbus->private_free = snd_intel8x0_mixer_free_ac97_bus; if (ac97_clock >= 8000 && ac97_clock <= 48000) pbus->clock = ac97_clock; chip->ac97_bus = pbus; ac97.pci = chip->pci; ac97.num = glob_sta & ICH_SCR ? 1 : 0; if ((err = snd_ac97_mixer(pbus, &ac97, &x97)) < 0) { snd_printk(KERN_ERR "Unable to initialize codec #%d\n", ac97.num); if (ac97.num == 0) goto __err; return err; } chip->ac97 = x97; if(ac97_is_modem(x97) && !chip->ichd[ICHD_MDMIN].ac97) { chip->ichd[ICHD_MDMIN].ac97 = x97; chip->ichd[ICHD_MDMOUT].ac97 = x97; } chip->in_ac97_init = 0; return 0; __err: /* clear the cold-reset bit for the next chance */ if (chip->device_type != DEVICE_ALI) iputdword(chip, ICHREG(GLOB_CNT), igetdword(chip, ICHREG(GLOB_CNT)) & ~ICH_AC97COLD); return err;}/* * */static int snd_intel8x0m_ich_chip_init(struct intel8x0m *chip, int probing){ unsigned long end_time; unsigned int cnt, status, nstatus; /* put logic to right state */ /* first clear status bits */ status = ICH_RCS | ICH_MIINT | ICH_MOINT; cnt = igetdword(chip, ICHREG(GLOB_STA)); iputdword(chip, ICHREG(GLOB_STA), cnt & status); /* ACLink on, 2 channels */ cnt = igetdword(chip, ICHREG(GLOB_CNT)); cnt &= ~(ICH_ACLINK); /* finish cold or do warm reset */ cnt |= (cnt & ICH_AC97COLD) == 0 ? ICH_AC97COLD : ICH_AC97WARM; iputdword(chip, ICHREG(GLOB_CNT), cnt); end_time = (jiffies + (HZ / 4)) + 1; do { if ((igetdword(chip, ICHREG(GLOB_CNT)) & ICH_AC97WARM) == 0) goto __ok; schedule_timeout_uninterruptible(1); } while (time_after_eq(end_time, jiffies)); snd_printk(KERN_ERR "AC'97 warm reset still in progress? [0x%x]\n", igetdword(chip, ICHREG(GLOB_CNT)));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -