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; }
static irqreturn_t snd_als300plus_interrupt(int irq, void *dev_id) { u8 general, mpu, dram; struct snd_als300 *chip = dev_id; struct snd_als300_substream_data *data; general = inb(chip->port+ALS300P_IRQ_STATUS); mpu = inb(chip->port+MPU_IRQ_STATUS); dram = inb(chip->port+ALS300P_DRAM_IRQ_STATUS); /* shared IRQ, for different device?? Exit ASAP! */ if ((general == 0) && ((mpu & 0x80) == 0) && ((dram & 0x01) == 0)) return IRQ_NONE; if (general & IRQ_PLAYBACK) { if (chip->pcm && chip->playback_substream) { outb(IRQ_PLAYBACK, chip->port+ALS300P_IRQ_STATUS); data = chip->playback_substream->runtime->private_data; data->period_flipflop ^= 1; snd_pcm_period_elapsed(chip->playback_substream); snd_als300_dbgplay("IRQ_PLAYBACK\n"); } } if (general & IRQ_CAPTURE) { if (chip->pcm && chip->capture_substream) { outb(IRQ_CAPTURE, chip->port+ALS300P_IRQ_STATUS); data = chip->capture_substream->runtime->private_data; data->period_flipflop ^= 1; snd_pcm_period_elapsed(chip->capture_substream); snd_als300_dbgplay("IRQ_CAPTURE\n"); } } /* FIXME: Ack other interrupt types. Not important right now as * those other devices aren't enabled. */ return IRQ_HANDLED; }
static irqreturn_t snd_als300plus_interrupt(int irq, void *dev_id) { u8 general, mpu, dram; struct snd_als300 *chip = dev_id; struct snd_als300_substream_data *data; general = inb(chip->port+ALS300P_IRQ_STATUS); mpu = inb(chip->port+MPU_IRQ_STATUS); dram = inb(chip->port+ALS300P_DRAM_IRQ_STATUS); /* */ if ((general == 0) && ((mpu & 0x80) == 0) && ((dram & 0x01) == 0)) return IRQ_NONE; if (general & IRQ_PLAYBACK) { if (chip->pcm && chip->playback_substream) { outb(IRQ_PLAYBACK, chip->port+ALS300P_IRQ_STATUS); data = chip->playback_substream->runtime->private_data; data->period_flipflop ^= 1; snd_pcm_period_elapsed(chip->playback_substream); snd_als300_dbgplay("IRQ_PLAYBACK\n"); } } if (general & IRQ_CAPTURE) { if (chip->pcm && chip->capture_substream) { outb(IRQ_CAPTURE, chip->port+ALS300P_IRQ_STATUS); data = chip->capture_substream->runtime->private_data; data->period_flipflop ^= 1; snd_pcm_period_elapsed(chip->capture_substream); snd_als300_dbgplay("IRQ_CAPTURE\n"); } } /* */ return IRQ_HANDLED; }