/* * get the current pointer on via686 */ static snd_pcm_uframes_t snd_via686_pcm_pointer(struct snd_pcm_substream *substream) { struct via82xx_modem *chip = snd_pcm_substream_chip(substream); struct viadev *viadev = substream->runtime->private_data; unsigned int idx, ptr, count, res; if (snd_BUG_ON(!viadev->tbl_entries)) return 0; if (!(inb(VIADEV_REG(viadev, OFFSET_STATUS)) & VIA_REG_STAT_ACTIVE)) return 0; spin_lock(&chip->reg_lock); count = inl(VIADEV_REG(viadev, OFFSET_CURR_COUNT)) & 0xffffff; /* The via686a does not have the current index register, * so we need to calculate the index from CURR_PTR. */ ptr = inl(VIADEV_REG(viadev, OFFSET_CURR_PTR)); if (ptr <= (unsigned int)viadev->table.addr) idx = 0; else /* CURR_PTR holds the address + 8 */ idx = ((ptr - (unsigned int)viadev->table.addr) / 8 - 1) % viadev->tbl_entries; res = calc_linear_pos(viadev, idx, count); spin_unlock(&chip->reg_lock); return bytes_to_frames(substream->runtime, res); }
static irqreturn_t snd_via82xx_interrupt(int irq, void *dev_id) { struct via82xx_modem *chip = dev_id; unsigned int status; unsigned int i; status = inl(VIAREG(chip, SGD_SHADOW)); if (! (status & chip->intr_mask)) { return IRQ_NONE; } // _skip_sgd: /* check status for each stream */ spin_lock(&chip->reg_lock); for (i = 0; i < chip->num_devs; i++) { struct viadev *viadev = &chip->devs[i]; unsigned char c_status = inb(VIADEV_REG(viadev, OFFSET_STATUS)); c_status &= (VIA_REG_STAT_EOL|VIA_REG_STAT_FLAG|VIA_REG_STAT_STOPPED); if (! c_status) continue; if (viadev->substream && viadev->running) { spin_unlock(&chip->reg_lock); snd_pcm_period_elapsed(viadev->substream); spin_lock(&chip->reg_lock); } outb(c_status, VIADEV_REG(viadev, OFFSET_STATUS)); /* ack */ } spin_unlock(&chip->reg_lock); return IRQ_HANDLED; }
static void snd_via82xx_channel_reset(struct via82xx_modem *chip, struct viadev *viadev) { outb(VIA_REG_CTRL_PAUSE | VIA_REG_CTRL_TERMINATE | VIA_REG_CTRL_RESET, VIADEV_REG(viadev, OFFSET_CONTROL)); inb(VIADEV_REG(viadev, OFFSET_CONTROL)); udelay(50); /* disable interrupts */ outb(0x00, VIADEV_REG(viadev, OFFSET_CONTROL)); /* clear interrupts */ outb(0x03, VIADEV_REG(viadev, OFFSET_STATUS)); outb(0x00, VIADEV_REG(viadev, OFFSET_TYPE)); /* for via686 */ // outl(0, VIADEV_REG(viadev, OFFSET_CURR_PTR)); viadev->lastpos = 0; }
static void snd_via82xx_channel_reset(struct via82xx_modem *chip, struct viadev *viadev) { outb(VIA_REG_CTRL_PAUSE | VIA_REG_CTRL_TERMINATE | VIA_REG_CTRL_RESET, VIADEV_REG(viadev, OFFSET_CONTROL)); inb(VIADEV_REG(viadev, OFFSET_CONTROL)); udelay(50); /* */ outb(0x00, VIADEV_REG(viadev, OFFSET_CONTROL)); /* */ outb(0x03, VIADEV_REG(viadev, OFFSET_STATUS)); outb(0x00, VIADEV_REG(viadev, OFFSET_TYPE)); /* */ // viadev->lastpos = 0; }
/* * set up the table pointer */ static void snd_via82xx_set_table_ptr(struct via82xx_modem *chip, struct viadev *viadev) { snd_via82xx_codec_ready(chip, chip->ac97_secondary); outl((u32)viadev->table.addr, VIADEV_REG(viadev, OFFSET_TABLE_PTR)); udelay(20); snd_via82xx_codec_ready(chip, chip->ac97_secondary); }
/* * trigger callback */ static int snd_via82xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { struct via82xx_modem *chip = snd_pcm_substream_chip(substream); struct viadev *viadev = substream->runtime->private_data; unsigned char val = 0; switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_SUSPEND: val |= VIA_REG_CTRL_START; viadev->running = 1; break; case SNDRV_PCM_TRIGGER_STOP: val = VIA_REG_CTRL_TERMINATE; viadev->running = 0; break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: val |= VIA_REG_CTRL_PAUSE; viadev->running = 0; break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: viadev->running = 1; break; default: return -EINVAL; } outb(val, VIADEV_REG(viadev, OFFSET_CONTROL)); if (cmd == SNDRV_PCM_TRIGGER_STOP) snd_via82xx_channel_reset(chip, viadev); return 0; }
/* * prepare callback for playback and capture */ static int snd_via82xx_pcm_prepare(struct snd_pcm_substream *substream) { struct via82xx_modem *chip = snd_pcm_substream_chip(substream); struct viadev *viadev = substream->runtime->private_data; snd_via82xx_channel_reset(chip, viadev); /* this must be set after channel_reset */ snd_via82xx_set_table_ptr(chip, viadev); outb(VIA_REG_TYPE_AUTOSTART|VIA_REG_TYPE_INT_EOL|VIA_REG_TYPE_INT_FLAG, VIADEV_REG(viadev, OFFSET_TYPE)); return 0; }