873 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright (c) by Jaroslav Kysela <perex@perex.cz>4 * Routines for control of GF1 chip (PCM things)5 *6 * InterWave chips supports interleaved DMA, but this feature isn't used in7 * this code.8 * 9 * This code emulates autoinit DMA transfer for playback, recording by GF110 * chip doesn't support autoinit DMA.11 */12 13#include <asm/dma.h>14#include <linux/slab.h>15#include <linux/sched/signal.h>16 17#include <sound/core.h>18#include <sound/control.h>19#include <sound/gus.h>20#include <sound/pcm_params.h>21#include "gus_tables.h"22 23/* maximum rate */24 25#define SNDRV_GF1_PCM_RATE 4800026 27#define SNDRV_GF1_PCM_PFLG_NONE 028#define SNDRV_GF1_PCM_PFLG_ACTIVE (1<<0)29#define SNDRV_GF1_PCM_PFLG_NEUTRAL (2<<0)30 31struct gus_pcm_private {32 struct snd_gus_card * gus;33 struct snd_pcm_substream *substream;34 spinlock_t lock;35 unsigned int voices;36 struct snd_gus_voice *pvoices[2];37 unsigned int memory;38 unsigned short flags;39 unsigned char voice_ctrl, ramp_ctrl;40 unsigned int bpos;41 unsigned int blocks;42 unsigned int block_size;43 unsigned int dma_size;44 wait_queue_head_t sleep;45 atomic_t dma_count;46 int final_volume;47};48 49static void snd_gf1_pcm_block_change_ack(struct snd_gus_card * gus, void *private_data)50{51 struct gus_pcm_private *pcmp = private_data;52 53 if (pcmp) {54 atomic_dec(&pcmp->dma_count);55 wake_up(&pcmp->sleep);56 }57}58 59static int snd_gf1_pcm_block_change(struct snd_pcm_substream *substream,60 unsigned int offset,61 unsigned int addr,62 unsigned int count)63{64 struct snd_gf1_dma_block block;65 struct snd_pcm_runtime *runtime = substream->runtime;66 struct gus_pcm_private *pcmp = runtime->private_data;67 68 count += offset & 31;69 offset &= ~31;70 memset(&block, 0, sizeof(block));71 block.cmd = SNDRV_GF1_DMA_IRQ;72 if (snd_pcm_format_unsigned(runtime->format))73 block.cmd |= SNDRV_GF1_DMA_UNSIGNED;74 if (snd_pcm_format_width(runtime->format) == 16)75 block.cmd |= SNDRV_GF1_DMA_16BIT;76 block.addr = addr & ~31;77 block.buffer = runtime->dma_area + offset;78 block.buf_addr = runtime->dma_addr + offset;79 block.count = count;80 block.private_data = pcmp;81 block.ack = snd_gf1_pcm_block_change_ack;82 if (!snd_gf1_dma_transfer_block(pcmp->gus, &block, 0, 0))83 atomic_inc(&pcmp->dma_count);84 return 0;85}86 87static void snd_gf1_pcm_trigger_up(struct snd_pcm_substream *substream)88{89 struct snd_pcm_runtime *runtime = substream->runtime;90 struct gus_pcm_private *pcmp = runtime->private_data;91 struct snd_gus_card * gus = pcmp->gus;92 unsigned long flags;93 unsigned char voice_ctrl, ramp_ctrl;94 unsigned short rate;95 unsigned int curr, begin, end;96 unsigned short vol;97 unsigned char pan;98 unsigned int voice;99 100 spin_lock_irqsave(&pcmp->lock, flags);101 if (pcmp->flags & SNDRV_GF1_PCM_PFLG_ACTIVE) {102 spin_unlock_irqrestore(&pcmp->lock, flags);103 return;104 }105 pcmp->flags |= SNDRV_GF1_PCM_PFLG_ACTIVE;106 pcmp->final_volume = 0;107 spin_unlock_irqrestore(&pcmp->lock, flags);108 rate = snd_gf1_translate_freq(gus, runtime->rate << 4);109 /* enable WAVE IRQ */110 voice_ctrl = snd_pcm_format_width(runtime->format) == 16 ? 0x24 : 0x20;111 /* enable RAMP IRQ + rollover */112 ramp_ctrl = 0x24;113 if (pcmp->blocks == 1) {114 voice_ctrl |= 0x08; /* loop enable */115 ramp_ctrl &= ~0x04; /* disable rollover */116 }117 for (voice = 0; voice < pcmp->voices; voice++) {118 begin = pcmp->memory + voice * (pcmp->dma_size / runtime->channels);119 curr = begin + (pcmp->bpos * pcmp->block_size) / runtime->channels;120 end = curr + (pcmp->block_size / runtime->channels);121 end -= snd_pcm_format_width(runtime->format) == 16 ? 2 : 1;122 pan = runtime->channels == 2 ? (!voice ? 1 : 14) : 8;123 vol = !voice ? gus->gf1.pcm_volume_level_left : gus->gf1.pcm_volume_level_right;124 spin_lock_irqsave(&gus->reg_lock, flags);125 snd_gf1_select_voice(gus, pcmp->pvoices[voice]->number);126 snd_gf1_write8(gus, SNDRV_GF1_VB_PAN, pan);127 snd_gf1_write16(gus, SNDRV_GF1_VW_FREQUENCY, rate);128 snd_gf1_write_addr(gus, SNDRV_GF1_VA_START, begin << 4, voice_ctrl & 4);129 snd_gf1_write_addr(gus, SNDRV_GF1_VA_END, end << 4, voice_ctrl & 4);130 snd_gf1_write_addr(gus, SNDRV_GF1_VA_CURRENT, curr << 4, voice_ctrl & 4);131 snd_gf1_write16(gus, SNDRV_GF1_VW_VOLUME, SNDRV_GF1_MIN_VOLUME << 4);132 snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_RATE, 0x2f);133 snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_START, SNDRV_GF1_MIN_OFFSET);134 snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_END, vol >> 8);135 snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_CONTROL, ramp_ctrl);136 if (!gus->gf1.enh_mode) {137 snd_gf1_delay(gus);138 snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_CONTROL, ramp_ctrl);139 }140 spin_unlock_irqrestore(&gus->reg_lock, flags);141 }142 spin_lock_irqsave(&gus->reg_lock, flags);143 for (voice = 0; voice < pcmp->voices; voice++) {144 snd_gf1_select_voice(gus, pcmp->pvoices[voice]->number);145 if (gus->gf1.enh_mode)146 snd_gf1_write8(gus, SNDRV_GF1_VB_MODE, 0x00); /* deactivate voice */147 snd_gf1_write8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL, voice_ctrl);148 voice_ctrl &= ~0x20;149 }150 voice_ctrl |= 0x20;151 if (!gus->gf1.enh_mode) {152 snd_gf1_delay(gus);153 for (voice = 0; voice < pcmp->voices; voice++) {154 snd_gf1_select_voice(gus, pcmp->pvoices[voice]->number);155 snd_gf1_write8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL, voice_ctrl);156 voice_ctrl &= ~0x20; /* disable IRQ for next voice */157 }158 }159 spin_unlock_irqrestore(&gus->reg_lock, flags);160}161 162static void snd_gf1_pcm_interrupt_wave(struct snd_gus_card * gus,163 struct snd_gus_voice *pvoice)164{165 struct gus_pcm_private * pcmp;166 struct snd_pcm_runtime *runtime;167 unsigned char voice_ctrl, ramp_ctrl;168 unsigned int idx;169 unsigned int end, step;170 171 if (!pvoice->private_data) {172 dev_dbg(gus->card->dev, "%s: unknown wave irq?\n", __func__);173 snd_gf1_smart_stop_voice(gus, pvoice->number);174 return;175 }176 pcmp = pvoice->private_data;177 if (pcmp == NULL) {178 dev_dbg(gus->card->dev, "%s: unknown wave irq?\n", __func__);179 snd_gf1_smart_stop_voice(gus, pvoice->number);180 return;181 } 182 gus = pcmp->gus;183 runtime = pcmp->substream->runtime;184 185 spin_lock(&gus->reg_lock);186 snd_gf1_select_voice(gus, pvoice->number);187 voice_ctrl = snd_gf1_read8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL) & ~0x8b;188 ramp_ctrl = (snd_gf1_read8(gus, SNDRV_GF1_VB_VOLUME_CONTROL) & ~0xa4) | 0x03;189#if 0190 snd_gf1_select_voice(gus, pvoice->number);191 dev_dbg(gus->card->dev, "position = 0x%x\n",192 (snd_gf1_read_addr(gus, SNDRV_GF1_VA_CURRENT, voice_ctrl & 4) >> 4));193 snd_gf1_select_voice(gus, pcmp->pvoices[1]->number);194 dev_dbg(gus->card->dev, "position = 0x%x\n",195 (snd_gf1_read_addr(gus, SNDRV_GF1_VA_CURRENT, voice_ctrl & 4) >> 4));196 snd_gf1_select_voice(gus, pvoice->number);197#endif198 pcmp->bpos++;199 pcmp->bpos %= pcmp->blocks;200 if (pcmp->bpos + 1 >= pcmp->blocks) { /* last block? */201 voice_ctrl |= 0x08; /* enable loop */202 } else {203 ramp_ctrl |= 0x04; /* enable rollover */204 }205 end = pcmp->memory + (((pcmp->bpos + 1) * pcmp->block_size) / runtime->channels);206 end -= voice_ctrl & 4 ? 2 : 1;207 step = pcmp->dma_size / runtime->channels;208 voice_ctrl |= 0x20;209 if (!pcmp->final_volume) {210 ramp_ctrl |= 0x20;211 ramp_ctrl &= ~0x03;212 }213 for (idx = 0; idx < pcmp->voices; idx++, end += step) {214 snd_gf1_select_voice(gus, pcmp->pvoices[idx]->number);215 snd_gf1_write_addr(gus, SNDRV_GF1_VA_END, end << 4, voice_ctrl & 4);216 snd_gf1_write8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL, voice_ctrl);217 snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_CONTROL, ramp_ctrl);218 voice_ctrl &= ~0x20;219 }220 if (!gus->gf1.enh_mode) {221 snd_gf1_delay(gus);222 voice_ctrl |= 0x20;223 for (idx = 0; idx < pcmp->voices; idx++) {224 snd_gf1_select_voice(gus, pcmp->pvoices[idx]->number);225 snd_gf1_write8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL, voice_ctrl);226 snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_CONTROL, ramp_ctrl);227 voice_ctrl &= ~0x20;228 }229 }230 spin_unlock(&gus->reg_lock);231 232 snd_pcm_period_elapsed(pcmp->substream);233#if 0234 if ((runtime->flags & SNDRV_PCM_FLG_MMAP) &&235 *runtime->state == SNDRV_PCM_STATE_RUNNING) {236 end = pcmp->bpos * pcmp->block_size;237 if (runtime->channels > 1) {238 snd_gf1_pcm_block_change(pcmp->substream, end, pcmp->memory + (end / 2), pcmp->block_size / 2);239 snd_gf1_pcm_block_change(pcmp->substream, end + (pcmp->block_size / 2), pcmp->memory + (pcmp->dma_size / 2) + (end / 2), pcmp->block_size / 2);240 } else {241 snd_gf1_pcm_block_change(pcmp->substream, end, pcmp->memory + end, pcmp->block_size);242 }243 }244#endif245}246 247static void snd_gf1_pcm_interrupt_volume(struct snd_gus_card * gus,248 struct snd_gus_voice * pvoice)249{250 unsigned short vol;251 int cvoice;252 struct gus_pcm_private *pcmp = pvoice->private_data;253 254 /* stop ramp, but leave rollover bit untouched */255 spin_lock(&gus->reg_lock);256 snd_gf1_select_voice(gus, pvoice->number);257 snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL);258 spin_unlock(&gus->reg_lock);259 if (pcmp == NULL)260 return;261 /* are we active? */262 if (!(pcmp->flags & SNDRV_GF1_PCM_PFLG_ACTIVE))263 return;264 /* load real volume - better precision */265 cvoice = pcmp->pvoices[0] == pvoice ? 0 : 1;266 if (pcmp->substream == NULL)267 return;268 vol = !cvoice ? gus->gf1.pcm_volume_level_left : gus->gf1.pcm_volume_level_right;269 spin_lock(&gus->reg_lock);270 snd_gf1_select_voice(gus, pvoice->number);271 snd_gf1_write16(gus, SNDRV_GF1_VW_VOLUME, vol);272 pcmp->final_volume = 1;273 spin_unlock(&gus->reg_lock);274}275 276static void snd_gf1_pcm_volume_change(struct snd_gus_card * gus)277{278}279 280static int snd_gf1_pcm_poke_block(struct snd_gus_card *gus, unsigned char *buf,281 unsigned int pos, unsigned int count,282 int w16, int invert)283{284 unsigned int len;285 unsigned long flags;286 287 while (count > 0) {288 len = count;289 if (len > 512) /* limit, to allow IRQ */290 len = 512;291 count -= len;292 if (gus->interwave) {293 spin_lock_irqsave(&gus->reg_lock, flags);294 snd_gf1_write8(gus, SNDRV_GF1_GB_MEMORY_CONTROL, 0x01 | (invert ? 0x08 : 0x00));295 snd_gf1_dram_addr(gus, pos);296 if (w16) {297 outb(SNDRV_GF1_GW_DRAM_IO16, GUSP(gus, GF1REGSEL));298 outsw(GUSP(gus, GF1DATALOW), buf, len >> 1);299 } else {300 outsb(GUSP(gus, DRAM), buf, len);301 }302 spin_unlock_irqrestore(&gus->reg_lock, flags);303 buf += 512;304 pos += 512;305 } else {306 invert = invert ? 0x80 : 0x00;307 if (w16) {308 len >>= 1;309 while (len--) {310 snd_gf1_poke(gus, pos++, *buf++);311 snd_gf1_poke(gus, pos++, *buf++ ^ invert);312 }313 } else {314 while (len--)315 snd_gf1_poke(gus, pos++, *buf++ ^ invert);316 }317 }318 if (count > 0 && !in_interrupt()) {319 schedule_timeout_interruptible(1);320 if (signal_pending(current))321 return -EAGAIN;322 }323 }324 return 0;325}326 327static int get_bpos(struct gus_pcm_private *pcmp, int voice, unsigned int pos,328 unsigned int len)329{330 unsigned int bpos = pos + (voice * (pcmp->dma_size / 2));331 if (snd_BUG_ON(bpos > pcmp->dma_size))332 return -EIO;333 if (snd_BUG_ON(bpos + len > pcmp->dma_size))334 return -EIO;335 return bpos;336}337 338static int playback_copy_ack(struct snd_pcm_substream *substream,339 unsigned int bpos, unsigned int len)340{341 struct snd_pcm_runtime *runtime = substream->runtime;342 struct gus_pcm_private *pcmp = runtime->private_data;343 struct snd_gus_card *gus = pcmp->gus;344 int w16, invert;345 346 if (len > 32)347 return snd_gf1_pcm_block_change(substream, bpos,348 pcmp->memory + bpos, len);349 350 w16 = (snd_pcm_format_width(runtime->format) == 16);351 invert = snd_pcm_format_unsigned(runtime->format);352 return snd_gf1_pcm_poke_block(gus, runtime->dma_area + bpos,353 pcmp->memory + bpos, len, w16, invert);354}355 356static int snd_gf1_pcm_playback_copy(struct snd_pcm_substream *substream,357 int voice, unsigned long pos,358 struct iov_iter *src, unsigned long count)359{360 struct snd_pcm_runtime *runtime = substream->runtime;361 struct gus_pcm_private *pcmp = runtime->private_data;362 unsigned int len = count;363 int bpos;364 365 bpos = get_bpos(pcmp, voice, pos, len);366 if (bpos < 0)367 return bpos;368 if (copy_from_iter(runtime->dma_area + bpos, len, src) != len)369 return -EFAULT;370 return playback_copy_ack(substream, bpos, len);371}372 373static int snd_gf1_pcm_playback_silence(struct snd_pcm_substream *substream,374 int voice, unsigned long pos,375 unsigned long count)376{377 struct snd_pcm_runtime *runtime = substream->runtime;378 struct gus_pcm_private *pcmp = runtime->private_data;379 unsigned int len = count;380 int bpos;381 382 bpos = get_bpos(pcmp, voice, pos, len);383 if (bpos < 0)384 return bpos;385 snd_pcm_format_set_silence(runtime->format, runtime->dma_area + bpos,386 bytes_to_samples(runtime, count));387 return playback_copy_ack(substream, bpos, len);388}389 390static int snd_gf1_pcm_playback_hw_params(struct snd_pcm_substream *substream,391 struct snd_pcm_hw_params *hw_params)392{393 struct snd_gus_card *gus = snd_pcm_substream_chip(substream);394 struct snd_pcm_runtime *runtime = substream->runtime;395 struct gus_pcm_private *pcmp = runtime->private_data;396 397 if (runtime->buffer_changed) {398 struct snd_gf1_mem_block *block;399 if (pcmp->memory > 0) {400 snd_gf1_mem_free(&gus->gf1.mem_alloc, pcmp->memory);401 pcmp->memory = 0;402 }403 block = snd_gf1_mem_alloc(&gus->gf1.mem_alloc,404 SNDRV_GF1_MEM_OWNER_DRIVER,405 "GF1 PCM",406 runtime->dma_bytes, 1, 32,407 NULL);408 if (!block)409 return -ENOMEM;410 pcmp->memory = block->ptr;411 }412 pcmp->voices = params_channels(hw_params);413 if (pcmp->pvoices[0] == NULL) {414 pcmp->pvoices[0] = snd_gf1_alloc_voice(pcmp->gus, SNDRV_GF1_VOICE_TYPE_PCM, 0, 0);415 if (!pcmp->pvoices[0])416 return -ENOMEM;417 pcmp->pvoices[0]->handler_wave = snd_gf1_pcm_interrupt_wave;418 pcmp->pvoices[0]->handler_volume = snd_gf1_pcm_interrupt_volume;419 pcmp->pvoices[0]->volume_change = snd_gf1_pcm_volume_change;420 pcmp->pvoices[0]->private_data = pcmp;421 }422 if (pcmp->voices > 1 && pcmp->pvoices[1] == NULL) {423 pcmp->pvoices[1] = snd_gf1_alloc_voice(pcmp->gus, SNDRV_GF1_VOICE_TYPE_PCM, 0, 0);424 if (!pcmp->pvoices[1])425 return -ENOMEM;426 pcmp->pvoices[1]->handler_wave = snd_gf1_pcm_interrupt_wave;427 pcmp->pvoices[1]->handler_volume = snd_gf1_pcm_interrupt_volume;428 pcmp->pvoices[1]->volume_change = snd_gf1_pcm_volume_change;429 pcmp->pvoices[1]->private_data = pcmp;430 } else if (pcmp->voices == 1) {431 if (pcmp->pvoices[1]) {432 snd_gf1_free_voice(pcmp->gus, pcmp->pvoices[1]);433 pcmp->pvoices[1] = NULL;434 }435 }436 return 0;437}438 439static int snd_gf1_pcm_playback_hw_free(struct snd_pcm_substream *substream)440{441 struct snd_pcm_runtime *runtime = substream->runtime;442 struct gus_pcm_private *pcmp = runtime->private_data;443 444 if (pcmp->pvoices[0]) {445 snd_gf1_free_voice(pcmp->gus, pcmp->pvoices[0]);446 pcmp->pvoices[0] = NULL;447 }448 if (pcmp->pvoices[1]) {449 snd_gf1_free_voice(pcmp->gus, pcmp->pvoices[1]);450 pcmp->pvoices[1] = NULL;451 }452 if (pcmp->memory > 0) {453 snd_gf1_mem_free(&pcmp->gus->gf1.mem_alloc, pcmp->memory);454 pcmp->memory = 0;455 }456 return 0;457}458 459static int snd_gf1_pcm_playback_prepare(struct snd_pcm_substream *substream)460{461 struct snd_pcm_runtime *runtime = substream->runtime;462 struct gus_pcm_private *pcmp = runtime->private_data;463 464 pcmp->bpos = 0;465 pcmp->dma_size = snd_pcm_lib_buffer_bytes(substream);466 pcmp->block_size = snd_pcm_lib_period_bytes(substream);467 pcmp->blocks = pcmp->dma_size / pcmp->block_size;468 return 0;469}470 471static int snd_gf1_pcm_playback_trigger(struct snd_pcm_substream *substream,472 int cmd)473{474 struct snd_gus_card *gus = snd_pcm_substream_chip(substream);475 struct snd_pcm_runtime *runtime = substream->runtime;476 struct gus_pcm_private *pcmp = runtime->private_data;477 int voice;478 479 if (cmd == SNDRV_PCM_TRIGGER_START) {480 snd_gf1_pcm_trigger_up(substream);481 } else if (cmd == SNDRV_PCM_TRIGGER_STOP) {482 spin_lock(&pcmp->lock);483 pcmp->flags &= ~SNDRV_GF1_PCM_PFLG_ACTIVE;484 spin_unlock(&pcmp->lock);485 voice = pcmp->pvoices[0]->number;486 snd_gf1_stop_voices(gus, voice, voice);487 if (pcmp->pvoices[1]) {488 voice = pcmp->pvoices[1]->number;489 snd_gf1_stop_voices(gus, voice, voice);490 }491 } else {492 return -EINVAL;493 }494 return 0;495}496 497static snd_pcm_uframes_t snd_gf1_pcm_playback_pointer(struct snd_pcm_substream *substream)498{499 struct snd_gus_card *gus = snd_pcm_substream_chip(substream);500 struct snd_pcm_runtime *runtime = substream->runtime;501 struct gus_pcm_private *pcmp = runtime->private_data;502 unsigned int pos;503 unsigned char voice_ctrl;504 505 pos = 0;506 spin_lock(&gus->reg_lock);507 if (pcmp->flags & SNDRV_GF1_PCM_PFLG_ACTIVE) {508 snd_gf1_select_voice(gus, pcmp->pvoices[0]->number);509 voice_ctrl = snd_gf1_read8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL);510 pos = (snd_gf1_read_addr(gus, SNDRV_GF1_VA_CURRENT, voice_ctrl & 4) >> 4) - pcmp->memory;511 if (substream->runtime->channels > 1)512 pos <<= 1;513 pos = bytes_to_frames(runtime, pos);514 }515 spin_unlock(&gus->reg_lock);516 return pos;517}518 519static const struct snd_ratnum clock = {520 .num = 9878400/16,521 .den_min = 2,522 .den_max = 257,523 .den_step = 1,524};525 526static const struct snd_pcm_hw_constraint_ratnums hw_constraints_clocks = {527 .nrats = 1,528 .rats = &clock,529};530 531static int snd_gf1_pcm_capture_hw_params(struct snd_pcm_substream *substream,532 struct snd_pcm_hw_params *hw_params)533{534 struct snd_gus_card *gus = snd_pcm_substream_chip(substream);535 536 gus->c_dma_size = params_buffer_bytes(hw_params);537 gus->c_period_size = params_period_bytes(hw_params);538 gus->c_pos = 0;539 gus->gf1.pcm_rcntrl_reg = 0x21; /* IRQ at end, enable & start */540 if (params_channels(hw_params) > 1)541 gus->gf1.pcm_rcntrl_reg |= 2;542 if (gus->gf1.dma2 > 3)543 gus->gf1.pcm_rcntrl_reg |= 4;544 if (snd_pcm_format_unsigned(params_format(hw_params)))545 gus->gf1.pcm_rcntrl_reg |= 0x80;546 return 0;547}548 549static int snd_gf1_pcm_capture_prepare(struct snd_pcm_substream *substream)550{551 struct snd_gus_card *gus = snd_pcm_substream_chip(substream);552 struct snd_pcm_runtime *runtime = substream->runtime;553 554 snd_gf1_i_write8(gus, SNDRV_GF1_GB_RECORD_RATE, runtime->rate_den - 2);555 snd_gf1_i_write8(gus, SNDRV_GF1_GB_REC_DMA_CONTROL, 0); /* disable sampling */556 snd_gf1_i_look8(gus, SNDRV_GF1_GB_REC_DMA_CONTROL); /* Sampling Control Register */557 snd_dma_program(gus->gf1.dma2, runtime->dma_addr, gus->c_period_size, DMA_MODE_READ);558 return 0;559}560 561static int snd_gf1_pcm_capture_trigger(struct snd_pcm_substream *substream,562 int cmd)563{564 struct snd_gus_card *gus = snd_pcm_substream_chip(substream);565 int val;566 567 if (cmd == SNDRV_PCM_TRIGGER_START) {568 val = gus->gf1.pcm_rcntrl_reg;569 } else if (cmd == SNDRV_PCM_TRIGGER_STOP) {570 val = 0;571 } else {572 return -EINVAL;573 }574 575 spin_lock(&gus->reg_lock);576 snd_gf1_write8(gus, SNDRV_GF1_GB_REC_DMA_CONTROL, val);577 snd_gf1_look8(gus, SNDRV_GF1_GB_REC_DMA_CONTROL);578 spin_unlock(&gus->reg_lock);579 return 0;580}581 582static snd_pcm_uframes_t snd_gf1_pcm_capture_pointer(struct snd_pcm_substream *substream)583{584 struct snd_gus_card *gus = snd_pcm_substream_chip(substream);585 int pos = snd_dma_pointer(gus->gf1.dma2, gus->c_period_size);586 pos = bytes_to_frames(substream->runtime, (gus->c_pos + pos) % gus->c_dma_size);587 return pos;588}589 590static void snd_gf1_pcm_interrupt_dma_read(struct snd_gus_card * gus)591{592 snd_gf1_i_write8(gus, SNDRV_GF1_GB_REC_DMA_CONTROL, 0); /* disable sampling */593 snd_gf1_i_look8(gus, SNDRV_GF1_GB_REC_DMA_CONTROL); /* Sampling Control Register */594 if (gus->pcm_cap_substream != NULL) {595 snd_gf1_pcm_capture_prepare(gus->pcm_cap_substream); 596 snd_gf1_pcm_capture_trigger(gus->pcm_cap_substream, SNDRV_PCM_TRIGGER_START);597 gus->c_pos += gus->c_period_size;598 snd_pcm_period_elapsed(gus->pcm_cap_substream);599 }600}601 602static const struct snd_pcm_hardware snd_gf1_pcm_playback =603{604 .info = SNDRV_PCM_INFO_NONINTERLEAVED,605 .formats = (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 |606 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE),607 .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,608 .rate_min = 5510,609 .rate_max = 48000,610 .channels_min = 1,611 .channels_max = 2,612 .buffer_bytes_max = (128*1024),613 .period_bytes_min = 64,614 .period_bytes_max = (128*1024),615 .periods_min = 1,616 .periods_max = 1024,617 .fifo_size = 0,618};619 620static const struct snd_pcm_hardware snd_gf1_pcm_capture =621{622 .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |623 SNDRV_PCM_INFO_MMAP_VALID),624 .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8,625 .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_44100,626 .rate_min = 5510,627 .rate_max = 44100,628 .channels_min = 1,629 .channels_max = 2,630 .buffer_bytes_max = (128*1024),631 .period_bytes_min = 64,632 .period_bytes_max = (128*1024),633 .periods_min = 1,634 .periods_max = 1024,635 .fifo_size = 0,636};637 638static void snd_gf1_pcm_playback_free(struct snd_pcm_runtime *runtime)639{640 kfree(runtime->private_data);641}642 643static int snd_gf1_pcm_playback_open(struct snd_pcm_substream *substream)644{645 struct gus_pcm_private *pcmp;646 struct snd_gus_card *gus = snd_pcm_substream_chip(substream);647 struct snd_pcm_runtime *runtime = substream->runtime;648 int err;649 650 pcmp = kzalloc(sizeof(*pcmp), GFP_KERNEL);651 if (pcmp == NULL)652 return -ENOMEM;653 pcmp->gus = gus;654 spin_lock_init(&pcmp->lock);655 init_waitqueue_head(&pcmp->sleep);656 atomic_set(&pcmp->dma_count, 0);657 658 runtime->private_data = pcmp;659 runtime->private_free = snd_gf1_pcm_playback_free;660 661#if 0662 dev_dbg(gus->card->dev,663 "playback.buffer = 0x%lx, gf1.pcm_buffer = 0x%lx\n",664 (long) pcm->playback.buffer, (long) gus->gf1.pcm_buffer);665#endif666 err = snd_gf1_dma_init(gus);667 if (err < 0)668 return err;669 pcmp->flags = SNDRV_GF1_PCM_PFLG_NONE;670 pcmp->substream = substream;671 runtime->hw = snd_gf1_pcm_playback;672 snd_pcm_limit_isa_dma_size(gus->gf1.dma1, &runtime->hw.buffer_bytes_max);673 snd_pcm_limit_isa_dma_size(gus->gf1.dma1, &runtime->hw.period_bytes_max);674 snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 64);675 return 0;676}677 678static int snd_gf1_pcm_playback_close(struct snd_pcm_substream *substream)679{680 struct snd_gus_card *gus = snd_pcm_substream_chip(substream);681 struct snd_pcm_runtime *runtime = substream->runtime;682 struct gus_pcm_private *pcmp = runtime->private_data;683 684 if (!wait_event_timeout(pcmp->sleep, (atomic_read(&pcmp->dma_count) <= 0), 2*HZ))685 dev_err(gus->card->dev, "gf1 pcm - serious DMA problem\n");686 687 snd_gf1_dma_done(gus); 688 return 0;689}690 691static int snd_gf1_pcm_capture_open(struct snd_pcm_substream *substream)692{693 struct snd_pcm_runtime *runtime = substream->runtime;694 struct snd_gus_card *gus = snd_pcm_substream_chip(substream);695 696 gus->gf1.interrupt_handler_dma_read = snd_gf1_pcm_interrupt_dma_read;697 gus->pcm_cap_substream = substream;698 substream->runtime->hw = snd_gf1_pcm_capture;699 snd_pcm_limit_isa_dma_size(gus->gf1.dma2, &runtime->hw.buffer_bytes_max);700 snd_pcm_limit_isa_dma_size(gus->gf1.dma2, &runtime->hw.period_bytes_max);701 snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,702 &hw_constraints_clocks);703 return 0;704}705 706static int snd_gf1_pcm_capture_close(struct snd_pcm_substream *substream)707{708 struct snd_gus_card *gus = snd_pcm_substream_chip(substream);709 710 gus->pcm_cap_substream = NULL;711 snd_gf1_set_default_handlers(gus, SNDRV_GF1_HANDLER_DMA_READ);712 return 0;713}714 715static int snd_gf1_pcm_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)716{717 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;718 uinfo->count = 2;719 uinfo->value.integer.min = 0;720 uinfo->value.integer.max = 127;721 return 0;722}723 724static int snd_gf1_pcm_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)725{726 struct snd_gus_card *gus = snd_kcontrol_chip(kcontrol);727 unsigned long flags;728 729 spin_lock_irqsave(&gus->pcm_volume_level_lock, flags);730 ucontrol->value.integer.value[0] = gus->gf1.pcm_volume_level_left1;731 ucontrol->value.integer.value[1] = gus->gf1.pcm_volume_level_right1;732 spin_unlock_irqrestore(&gus->pcm_volume_level_lock, flags);733 return 0;734}735 736static int snd_gf1_pcm_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)737{738 struct snd_gus_card *gus = snd_kcontrol_chip(kcontrol);739 unsigned long flags;740 int change;741 unsigned int idx;742 unsigned short val1, val2, vol;743 struct gus_pcm_private *pcmp;744 struct snd_gus_voice *pvoice;745 746 val1 = ucontrol->value.integer.value[0] & 127;747 val2 = ucontrol->value.integer.value[1] & 127;748 spin_lock_irqsave(&gus->pcm_volume_level_lock, flags);749 change = val1 != gus->gf1.pcm_volume_level_left1 ||750 val2 != gus->gf1.pcm_volume_level_right1;751 gus->gf1.pcm_volume_level_left1 = val1;752 gus->gf1.pcm_volume_level_right1 = val2;753 gus->gf1.pcm_volume_level_left = snd_gf1_lvol_to_gvol_raw(val1 << 9) << 4;754 gus->gf1.pcm_volume_level_right = snd_gf1_lvol_to_gvol_raw(val2 << 9) << 4;755 spin_unlock_irqrestore(&gus->pcm_volume_level_lock, flags);756 /* are we active? */757 spin_lock_irqsave(&gus->voice_alloc, flags);758 for (idx = 0; idx < 32; idx++) {759 pvoice = &gus->gf1.voices[idx];760 if (!pvoice->pcm)761 continue;762 pcmp = pvoice->private_data;763 if (!(pcmp->flags & SNDRV_GF1_PCM_PFLG_ACTIVE))764 continue;765 /* load real volume - better precision */766 spin_lock(&gus->reg_lock);767 snd_gf1_select_voice(gus, pvoice->number);768 snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL);769 vol = pvoice == pcmp->pvoices[0] ? gus->gf1.pcm_volume_level_left : gus->gf1.pcm_volume_level_right;770 snd_gf1_write16(gus, SNDRV_GF1_VW_VOLUME, vol);771 pcmp->final_volume = 1;772 spin_unlock(&gus->reg_lock);773 }774 spin_unlock_irqrestore(&gus->voice_alloc, flags);775 return change;776}777 778static const struct snd_kcontrol_new snd_gf1_pcm_volume_control =779{780 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,781 .name = "PCM Playback Volume",782 .info = snd_gf1_pcm_volume_info,783 .get = snd_gf1_pcm_volume_get,784 .put = snd_gf1_pcm_volume_put785};786 787static const struct snd_kcontrol_new snd_gf1_pcm_volume_control1 =788{789 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,790 .name = "GPCM Playback Volume",791 .info = snd_gf1_pcm_volume_info,792 .get = snd_gf1_pcm_volume_get,793 .put = snd_gf1_pcm_volume_put794};795 796static const struct snd_pcm_ops snd_gf1_pcm_playback_ops = {797 .open = snd_gf1_pcm_playback_open,798 .close = snd_gf1_pcm_playback_close,799 .hw_params = snd_gf1_pcm_playback_hw_params,800 .hw_free = snd_gf1_pcm_playback_hw_free,801 .prepare = snd_gf1_pcm_playback_prepare,802 .trigger = snd_gf1_pcm_playback_trigger,803 .pointer = snd_gf1_pcm_playback_pointer,804 .copy = snd_gf1_pcm_playback_copy,805 .fill_silence = snd_gf1_pcm_playback_silence,806};807 808static const struct snd_pcm_ops snd_gf1_pcm_capture_ops = {809 .open = snd_gf1_pcm_capture_open,810 .close = snd_gf1_pcm_capture_close,811 .hw_params = snd_gf1_pcm_capture_hw_params,812 .prepare = snd_gf1_pcm_capture_prepare,813 .trigger = snd_gf1_pcm_capture_trigger,814 .pointer = snd_gf1_pcm_capture_pointer,815};816 817int snd_gf1_pcm_new(struct snd_gus_card *gus, int pcm_dev, int control_index)818{819 struct snd_card *card;820 struct snd_kcontrol *kctl;821 struct snd_pcm *pcm;822 struct snd_pcm_substream *substream;823 int capture, err;824 825 card = gus->card;826 capture = !gus->interwave && !gus->ess_flag && !gus->ace_flag ? 1 : 0;827 err = snd_pcm_new(card,828 gus->interwave ? "AMD InterWave" : "GF1",829 pcm_dev,830 gus->gf1.pcm_channels / 2,831 capture,832 &pcm);833 if (err < 0)834 return err;835 pcm->private_data = gus;836 /* playback setup */837 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_gf1_pcm_playback_ops);838 839 for (substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; substream = substream->next)840 snd_pcm_set_managed_buffer(substream, SNDRV_DMA_TYPE_DEV,841 card->dev,842 64*1024, gus->gf1.dma1 > 3 ? 128*1024 : 64*1024);843 844 pcm->info_flags = 0;845 pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX;846 if (capture) {847 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_gf1_pcm_capture_ops);848 if (gus->gf1.dma2 == gus->gf1.dma1)849 pcm->info_flags |= SNDRV_PCM_INFO_HALF_DUPLEX;850 snd_pcm_set_managed_buffer(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream,851 SNDRV_DMA_TYPE_DEV, card->dev,852 64*1024, gus->gf1.dma2 > 3 ? 128*1024 : 64*1024);853 }854 strcpy(pcm->name, pcm->id);855 if (gus->interwave) {856 sprintf(pcm->name + strlen(pcm->name), " rev %c", gus->revision + 'A');857 }858 strcat(pcm->name, " (synth)");859 gus->pcm = pcm;860 861 if (gus->codec_flag)862 kctl = snd_ctl_new1(&snd_gf1_pcm_volume_control1, gus);863 else864 kctl = snd_ctl_new1(&snd_gf1_pcm_volume_control, gus);865 kctl->id.index = control_index;866 err = snd_ctl_add(card, kctl);867 if (err < 0)868 return err;869 870 return 0;871}872 873