📄 riptide.c
字号:
goto errout; } err = 0; for (j = 0, time = 0; time < CMDIF_TIMEOUT; j++, time += 2) { cmdport = &(hwport->port[j % 2]); if (IS_DATF(cmdport)) { /* free pending data */ READ_PORT_ULONG(cmdport->data1); READ_PORT_ULONG(cmdport->data2); } if (IS_CMDE(cmdport)) { if (flags & PARM) /* put data */ WRITE_PORT_ULONG(cmdport->data2, parm); WRITE_PORT_ULONG(cmdport->data1, cmd); /* write cmd */ if ((flags & RESP) && ret) { while (!IS_DATF(cmdport) && time++ < CMDIF_TIMEOUT) udelay(10); if (time < CMDIF_TIMEOUT) { /* read response */ ret->retlongs[0] = READ_PORT_ULONG(cmdport->data1); ret->retlongs[1] = READ_PORT_ULONG(cmdport->data2); } else { err = -ENOSYS; goto errout; } } break; } udelay(20); } if (time == CMDIF_TIMEOUT) { err = -ENODATA; goto errout; } spin_unlock_irqrestore(&cif->lock, irqflags); cif->cmdcnt++; /* update command statistics */ cif->cmdtime += time; if (time > cif->cmdtimemax) cif->cmdtimemax = time; if (time < cif->cmdtimemin) cif->cmdtimemin = time; if ((cif->cmdcnt) % 1000 == 0) snd_printdd ("send cmd %d time: %d mintime: %d maxtime %d err: %d\n", cif->cmdcnt, cif->cmdtime, cif->cmdtimemin, cif->cmdtimemax, cif->errcnt); return 0; errout: cif->errcnt++; spin_unlock_irqrestore(&cif->lock, irqflags); snd_printdd ("send cmd %d hw: 0x%x flag: 0x%x cmd: 0x%x parm: 0x%x ret: 0x%x 0x%x CMDE: %d DATF: %d failed %d\n", cif->cmdcnt, (int)((void *)&(cmdport->stat) - (void *)hwport), flags, cmd, parm, ret ? ret->retlongs[0] : 0, ret ? ret->retlongs[1] : 0, IS_CMDE(cmdport), IS_DATF(cmdport), err); return err;}static intsetmixer(struct cmdif *cif, short num, unsigned short rval, unsigned short lval){ union cmdret rptr = CMDRET_ZERO; int i = 0; snd_printdd("sent mixer %d: 0x%d 0x%d\n", num, rval, lval); do { SEND_SDGV(cif, num, num, rval, lval); SEND_RDGV(cif, num, num, &rptr); if (rptr.retwords[0] == lval && rptr.retwords[1] == rval) return 0; } while (i++ < MAX_WRITE_RETRY); snd_printdd("sent mixer failed\n"); return -EIO;}static int getpaths(struct cmdif *cif, unsigned char *o){ unsigned char src[E2SINK_MAX]; unsigned char sink[E2SINK_MAX]; int i, j = 0; for (i = 0; i < E2SINK_MAX; i++) { getsourcesink(cif, i, i, &src[i], &sink[i]); if (sink[i] < E2SINK_MAX) { o[j++] = sink[i]; o[j++] = i; } } return j;}static intgetsourcesink(struct cmdif *cif, unsigned char source, unsigned char sink, unsigned char *a, unsigned char *b){ union cmdret rptr = CMDRET_ZERO; if (SEND_RSSV(cif, source, sink, &rptr) && SEND_RSSV(cif, source, sink, &rptr)) return -EIO; *a = rptr.retbytes[0]; *b = rptr.retbytes[1]; snd_printdd("getsourcesink 0x%x 0x%x\n", *a, *b); return 0;}static intgetsamplerate(struct cmdif *cif, unsigned char *intdec, unsigned int *rate){ unsigned char *s; unsigned int p[2] = { 0, 0 }; int i; union cmdret rptr = CMDRET_ZERO; s = intdec; for (i = 0; i < 2; i++) { if (*s != 0xff) { if (SEND_RSRC(cif, *s, &rptr) && SEND_RSRC(cif, *s, &rptr)) return -EIO; p[i] += rptr.retwords[1]; p[i] *= rptr.retwords[2]; p[i] += rptr.retwords[3]; p[i] /= 65536; } s++; } if (p[0]) { if (p[1] != p[0]) snd_printdd("rates differ %d %d\n", p[0], p[1]); *rate = (unsigned int)p[0]; } else *rate = (unsigned int)p[1]; snd_printdd("getsampleformat %d %d %d\n", intdec[0], intdec[1], *rate); return 0;}static intsetsampleformat(struct cmdif *cif, unsigned char mixer, unsigned char id, unsigned char channels, unsigned char format){ unsigned char w, ch, sig, order; snd_printdd ("setsampleformat mixer: %d id: %d channels: %d format: %d\n", mixer, id, channels, format); ch = channels == 1; w = snd_pcm_format_width(format) == 8; sig = snd_pcm_format_unsigned(format) != 0; order = snd_pcm_format_big_endian(format) != 0; if (SEND_SETF(cif, mixer, w, ch, order, sig, id) && SEND_SETF(cif, mixer, w, ch, order, sig, id)) { snd_printdd("setsampleformat failed\n"); return -EIO; } return 0;}static intsetsamplerate(struct cmdif *cif, unsigned char *intdec, unsigned int rate){ u32 D, M, N; union cmdret rptr = CMDRET_ZERO; int i; snd_printdd("setsamplerate intdec: %d,%d rate: %d\n", intdec[0], intdec[1], rate); D = 48000; M = ((rate == 48000) ? 47999 : rate) * 65536; N = M % D; M /= D; for (i = 0; i < 2; i++) { if (*intdec != 0xff) { do { SEND_SSRC(cif, *intdec, D, M, N); SEND_RSRC(cif, *intdec, &rptr); } while (rptr.retwords[1] != D && rptr.retwords[2] != M && rptr.retwords[3] != N && i++ < MAX_WRITE_RETRY); if (i == MAX_WRITE_RETRY) { snd_printdd("sent samplerate %d: %d failed\n", *intdec, rate); return -EIO; } } intdec++; } return 0;}static intgetmixer(struct cmdif *cif, short num, unsigned short *rval, unsigned short *lval){ union cmdret rptr = CMDRET_ZERO; if (SEND_RDGV(cif, num, num, &rptr) && SEND_RDGV(cif, num, num, &rptr)) return -EIO; *rval = rptr.retwords[0]; *lval = rptr.retwords[1]; snd_printdd("got mixer %d: 0x%d 0x%d\n", num, *rval, *lval); return 0;}static void riptide_handleirq(unsigned long dev_id){ struct snd_riptide *chip = (void *)dev_id; struct cmdif *cif = chip->cif; struct snd_pcm_substream *substream[PLAYBACK_SUBSTREAMS + 1]; struct snd_pcm_runtime *runtime; struct pcmhw *data = NULL; unsigned int pos, period_bytes; struct sgd *c; int i, j; unsigned int flag; if (!cif) return; for (i = 0; i < PLAYBACK_SUBSTREAMS; i++) substream[i] = chip->playback_substream[i]; substream[i] = chip->capture_substream; for (i = 0; i < PLAYBACK_SUBSTREAMS + 1; i++) { if (substream[i] && (runtime = substream[i]->runtime) && (data = runtime->private_data) && data->state != ST_STOP) { pos = 0; for (j = 0; j < data->pages; j++) { c = &data->sgdbuf[j]; flag = le32_to_cpu(c->dwStat_Ctl); if (flag & EOB_STATUS) pos += le32_to_cpu(c->dwSegLen); if (flag & EOC_STATUS) pos += le32_to_cpu(c->dwSegLen); if ((flag & EOS_STATUS) && (data->state == ST_PLAY)) { data->state = ST_STOP; snd_printk(KERN_ERR "Riptide: DMA stopped unexpectedly\n"); } c->dwStat_Ctl = cpu_to_le32(flag & ~(EOS_STATUS | EOB_STATUS | EOC_STATUS)); } data->pointer += pos; pos += data->oldpos; if (data->state != ST_STOP) { period_bytes = frames_to_bytes(runtime, runtime->period_size); snd_printdd ("interrupt 0x%x after 0x%lx of 0x%lx frames in period\n", READ_AUDIO_STATUS(cif->hwport), bytes_to_frames(runtime, pos), runtime->period_size); j = 0; if (pos >= period_bytes) { j++; while (pos >= period_bytes) pos -= period_bytes; } data->oldpos = pos; if (j > 0) snd_pcm_period_elapsed(substream[i]); } } }}#ifdef CONFIG_PMstatic int riptide_suspend(struct pci_dev *pci, pm_message_t state){ struct snd_card *card = pci_get_drvdata(pci); struct snd_riptide *chip = card->private_data; chip->in_suspend = 1; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); snd_pcm_suspend_all(chip->pcm); snd_ac97_suspend(chip->ac97); pci_set_power_state(pci, PCI_D3hot); pci_disable_device(pci); pci_save_state(pci); return 0;}static int riptide_resume(struct pci_dev *pci){ struct snd_card *card = pci_get_drvdata(pci); struct snd_riptide *chip = card->private_data; pci_restore_state(pci); pci_enable_device(pci); pci_set_power_state(pci, PCI_D0); pci_set_master(pci); snd_riptide_initialize(chip); snd_ac97_resume(chip->ac97); snd_power_change_state(card, SNDRV_CTL_POWER_D0); chip->in_suspend = 0; return 0;}#endifstatic int riptide_reset(struct cmdif *cif, struct snd_riptide *chip){ int timeout, tries; union cmdret rptr = CMDRET_ZERO; union firmware_version firmware; int i, j, err, has_firmware; if (!cif) return -EINVAL; cif->cmdcnt = 0; cif->cmdtime = 0; cif->cmdtimemax = 0; cif->cmdtimemin = 0xffffffff; cif->errcnt = 0; cif->is_reset = 0; tries = RESET_TRIES; has_firmware = 0; while (has_firmware == 0 && tries-- > 0) { for (i = 0; i < 2; i++) { WRITE_PORT_ULONG(cif->hwport->port[i].data1, 0); WRITE_PORT_ULONG(cif->hwport->port[i].data2, 0); } SET_GRESET(cif->hwport); udelay(100); UNSET_GRESET(cif->hwport); udelay(100); for (timeout = 100000; --timeout; udelay(10)) { if (IS_READY(cif->hwport) && !IS_GERR(cif->hwport)) break; } if (timeout == 0) { snd_printk(KERN_ERR "Riptide: device not ready, audio status: 0x%x ready: %d gerr: %d\n", READ_AUDIO_STATUS(cif->hwport), IS_READY(cif->hwport), IS_GERR(cif->hwport)); return -EIO; } else { snd_printdd ("Riptide: audio status: 0x%x ready: %d gerr: %d\n", READ_AUDIO_STATUS(cif->hwport), IS_READY(cif->hwport), IS_GERR(cif->hwport)); } SEND_GETV(cif, &rptr); for (i = 0; i < 4; i++) firmware.ret.retwords[i] = rptr.retwords[i]; snd_printdd ("Firmware version: ASIC: %d CODEC %d AUXDSP %d PROG %d\n", firmware.firmware.ASIC, firmware.firmware.CODEC, firmware.firmware.AUXDSP, firmware.firmware.PROG); for (j = 0; j < FIRMWARE_VERSIONS; j++) { has_firmware = 1; for (i = 0; i < 4; i++) { if (firmware_versions[j].ret.retwords[i] != firmware.ret.retwords[i]) has_firmware = 0; } if (has_firmware) break; } if (chip != NULL && has_firmware == 0) { snd_printdd("Writing Firmware\n"); if (!chip->fw_entry) { if ((err = request_firmware(&chip->fw_entry, "riptide.hex", &chip->pci->dev)) != 0) { snd_printk(KERN_ERR "Riptide: Firmware not available %d\n", err); return -EIO; } } err = loadfirmware(cif, chip->fw_entry->data, chip->fw_entry->size); if (err) snd_printk(KERN_ERR "Riptide: Could not load firmware %d\n", err); } } SEND_SACR(cif, 0, AC97_RESET); SEND_RACR(cif, AC97_RESET, &rptr); snd_printdd("AC97: 0x%x 0x%x\n", rptr.retlongs[0], rptr.retlongs[1]); SEND_PLST(cif, 0); SEND_SLST(cif, 0); SEND_DLST(cif, 0); SEND_ALST(cif, 0); SEND_KDMA(cif); writearm(cif, 0x301F8, 1, 1); writearm(cif, 0x301F4, 1, 1); SEND_LSEL(cif, MODEM_CMD, 0, 0, MODEM_INTDEC, MODEM_MERGER, MODEM_SPLITTER, MODEM_MIXER); setmixer(cif, MODEM_MIXER, 0x7fff, 0x7fff); alloclbuspath(cif, ARM2LBUS_FIFO13, lbus_play_modem, NULL, NULL); SEND_LSEL(cif, FM_CMD, 0, 0, FM_INTDEC, FM_MERGER, FM_SPLITTER, FM_MIXER); setmixer(cif, FM_MIXER, 0x7fff, 0x7fff); writearm(cif, 0x30648 + FM_MIXER * 4, 0x01, 0x00000005); writearm(cif, 0x301A8, 0x02, 0x00000002); writearm(cif, 0x30264, 0x08, 0xffffffff); alloclbuspath(cif, OPL3_SAMPLE, lbus_play_opl3, NULL, NULL); SEND_SSRC(cif, I2S_INTDEC, 48000, ((u32) I2S_RATE * 65536) / 48000, ((u32) I2S_RATE * 65536) % 48000); SEND_LSEL(cif, I2S_CMD0, 0, 0, I2S_INTDEC, I2S_MERGER, I2S_SPLITTER, I2S_MIXER); SEND_SI2S(cif, 1); alloclbuspath(cif, ARM2LBUS_FIFO0, lbus_play_i2s, NULL, NULL); alloclbuspath(cif, DIGITAL_MIXER_OUT0, lbus_play_out, NULL, NULL); alloclbuspath(cif, DIGITAL_MIXER_OUT0, lbus_play_outhp, NULL, NULL); SET_AIACK(cif->hwport); SET_AIE(cif->hwport); SET_AIACK(cif->hwport); cif->is_reset = 1; if (chip) { for (i = 0; i < 4; i++) chip->firmware.ret.retwords[i] = firmware.ret.retwords[i]; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -