static void snd_als300_init(struct snd_als300 *chip) { unsigned long flags; u32 tmp; snd_als300_dbgcallenter(); spin_lock_irqsave(&chip->reg_lock, flags); chip->revision = (snd_als300_gcr_read(chip->port, MISC_CONTROL) >> 16) & 0x0000000F; /* */ tmp = snd_als300_gcr_read(chip->port, DRAM_WRITE_CONTROL); snd_als300_gcr_write(chip->port, DRAM_WRITE_CONTROL, (tmp | DRAM_MODE_2) & ~WRITE_TRANS_START); /* */ snd_als300_set_irq_flag(chip, IRQ_ENABLE); /* */ tmp = snd_als300_gcr_read(chip->port, MISC_CONTROL); snd_als300_gcr_write(chip->port, MISC_CONTROL, tmp | VMUTE_NORMAL | MMUTE_NORMAL); /* */ snd_als300_gcr_write(chip->port, MUS_VOC_VOL, 0); /* */ tmp = snd_als300_gcr_read(chip->port, PLAYBACK_CONTROL); snd_als300_gcr_write(chip->port, PLAYBACK_CONTROL, tmp & ~TRANSFER_START); spin_unlock_irqrestore(&chip->reg_lock, flags); snd_als300_dbgcallleave(); }
static void snd_als300_init(struct snd_als300 *chip) { unsigned long flags; u32 tmp; spin_lock_irqsave(&chip->reg_lock, flags); chip->revision = (snd_als300_gcr_read(chip->port, MISC_CONTROL) >> 16) & 0x0000000F; /* Setup DRAM */ tmp = snd_als300_gcr_read(chip->port, DRAM_WRITE_CONTROL); snd_als300_gcr_write(chip->port, DRAM_WRITE_CONTROL, (tmp | DRAM_MODE_2) & ~WRITE_TRANS_START); /* Enable IRQ output */ snd_als300_set_irq_flag(chip, IRQ_ENABLE); /* Unmute hardware devices so their outputs get routed to * the onboard mixer */ tmp = snd_als300_gcr_read(chip->port, MISC_CONTROL); snd_als300_gcr_write(chip->port, MISC_CONTROL, tmp | VMUTE_NORMAL | MMUTE_NORMAL); /* Reset volumes */ snd_als300_gcr_write(chip->port, MUS_VOC_VOL, 0); /* Make sure playback transfer is stopped */ tmp = snd_als300_gcr_read(chip->port, PLAYBACK_CONTROL); snd_als300_gcr_write(chip->port, PLAYBACK_CONTROL, tmp & ~TRANSFER_START); spin_unlock_irqrestore(&chip->reg_lock, flags); }
static int snd_als300_capture_prepare(struct snd_pcm_substream *substream) { u32 tmp; struct snd_als300 *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; unsigned short period_bytes = snd_pcm_lib_period_bytes(substream); unsigned short buffer_bytes = snd_pcm_lib_buffer_bytes(substream); spin_lock_irq(&chip->reg_lock); tmp = snd_als300_gcr_read(chip->port, RECORD_CONTROL); tmp &= ~TRANSFER_START; snd_als300_dbgplay("Period bytes: %d Buffer bytes %d\n", period_bytes, buffer_bytes); /* set block size */ tmp &= 0xffff0000; tmp |= period_bytes - 1; /* set dma area */ snd_als300_gcr_write(chip->port, RECORD_CONTROL, tmp); snd_als300_gcr_write(chip->port, RECORD_START, runtime->dma_addr); snd_als300_gcr_write(chip->port, RECORD_END, runtime->dma_addr + buffer_bytes - 1); spin_unlock_irq(&chip->reg_lock); return 0; }
static snd_pcm_uframes_t snd_als300_pointer(struct snd_pcm_substream *substream) { u16 current_ptr; struct snd_als300 *chip = snd_pcm_substream_chip(substream); struct snd_als300_substream_data *data; unsigned short period_bytes; data = substream->runtime->private_data; period_bytes = snd_pcm_lib_period_bytes(substream); snd_als300_dbgcallenter(); spin_lock(&chip->reg_lock); current_ptr = (u16) snd_als300_gcr_read(chip->port, data->block_counter_register) + 4; spin_unlock(&chip->reg_lock); if (current_ptr > period_bytes) current_ptr = 0; else current_ptr = period_bytes - current_ptr; if (data->period_flipflop == 0) current_ptr += period_bytes; snd_als300_dbgplay("Pointer (bytes): %d\n", current_ptr); snd_als300_dbgcallleave(); return bytes_to_frames(substream->runtime, current_ptr); }
static int snd_als300_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_als300 *chip = snd_pcm_substream_chip(substream); u32 tmp; struct snd_als300_substream_data *data; unsigned short reg; int ret = 0; data = substream->runtime->private_data; reg = data->control_register; snd_als300_dbgcallenter(); spin_lock(&chip->reg_lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: tmp = snd_als300_gcr_read(chip->port, reg); data->period_flipflop = 1; snd_als300_gcr_write(chip->port, reg, tmp | TRANSFER_START); snd_als300_dbgplay("TRIGGER START\n"); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: tmp = snd_als300_gcr_read(chip->port, reg); snd_als300_gcr_write(chip->port, reg, tmp & ~TRANSFER_START); snd_als300_dbgplay("TRIGGER STOP\n"); break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: tmp = snd_als300_gcr_read(chip->port, reg); snd_als300_gcr_write(chip->port, reg, tmp | FIFO_PAUSE); snd_als300_dbgplay("TRIGGER PAUSE\n"); break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: tmp = snd_als300_gcr_read(chip->port, reg); snd_als300_gcr_write(chip->port, reg, tmp & ~FIFO_PAUSE); snd_als300_dbgplay("TRIGGER RELEASE\n"); break; default: snd_als300_dbgplay("TRIGGER INVALID\n"); ret = -EINVAL; } spin_unlock(&chip->reg_lock); snd_als300_dbgcallleave(); return ret; }
/* Enable/Disable Interrupts */ static void snd_als300_set_irq_flag(struct snd_als300 *chip, int cmd) { u32 tmp = snd_als300_gcr_read(chip->port, MISC_CONTROL); /* boolean XOR check, since old vs. new hardware have directly reversed bit setting for ENABLE and DISABLE. ALS300+ acts like newer versions of ALS300 */ if (((chip->revision > 5 || chip->chip_type == DEVICE_ALS300_PLUS) ^ (cmd == IRQ_ENABLE)) == 0) tmp |= IRQ_SET_BIT; else tmp &= ~IRQ_SET_BIT; snd_als300_gcr_write(chip->port, MISC_CONTROL, tmp); }
static void snd_als300_set_irq_flag(struct snd_als300 *chip, int cmd) { u32 tmp = snd_als300_gcr_read(chip->port, MISC_CONTROL); snd_als300_dbgcallenter(); /* */ if (((chip->revision > 5 || chip->chip_type == DEVICE_ALS300_PLUS) ^ (cmd == IRQ_ENABLE)) == 0) tmp |= IRQ_SET_BIT; else tmp &= ~IRQ_SET_BIT; snd_als300_gcr_write(chip->port, MISC_CONTROL, tmp); snd_als300_dbgcallleave(); }