607 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright (c) by Jaroslav Kysela <perex@perex.cz>4 * I/O routines for GF1/InterWave synthesizer chips5 */6 7#include <linux/delay.h>8#include <linux/time.h>9#include <sound/core.h>10#include <sound/gus.h>11 12void snd_gf1_delay(struct snd_gus_card * gus)13{14 int i;15 16 for (i = 0; i < 6; i++) {17 mb();18 inb(GUSP(gus, DRAM));19 }20}21 22/*23 * =======================================================================24 */25 26/*27 * ok.. stop of control registers (wave & ramp) need some special things..28 * big UltraClick (tm) elimination...29 */30 31static inline void __snd_gf1_ctrl_stop(struct snd_gus_card * gus, unsigned char reg)32{33 unsigned char value;34 35 outb(reg | 0x80, gus->gf1.reg_regsel);36 mb();37 value = inb(gus->gf1.reg_data8);38 mb();39 outb(reg, gus->gf1.reg_regsel);40 mb();41 outb((value | 0x03) & ~(0x80 | 0x20), gus->gf1.reg_data8);42 mb();43}44 45static inline void __snd_gf1_write8(struct snd_gus_card * gus,46 unsigned char reg,47 unsigned char data)48{49 outb(reg, gus->gf1.reg_regsel);50 mb();51 outb(data, gus->gf1.reg_data8);52 mb();53}54 55static inline unsigned char __snd_gf1_look8(struct snd_gus_card * gus,56 unsigned char reg)57{58 outb(reg, gus->gf1.reg_regsel);59 mb();60 return inb(gus->gf1.reg_data8);61}62 63static inline void __snd_gf1_write16(struct snd_gus_card * gus,64 unsigned char reg, unsigned int data)65{66 outb(reg, gus->gf1.reg_regsel);67 mb();68 outw((unsigned short) data, gus->gf1.reg_data16);69 mb();70}71 72static inline unsigned short __snd_gf1_look16(struct snd_gus_card * gus,73 unsigned char reg)74{75 outb(reg, gus->gf1.reg_regsel);76 mb();77 return inw(gus->gf1.reg_data16);78}79 80static inline void __snd_gf1_adlib_write(struct snd_gus_card * gus,81 unsigned char reg, unsigned char data)82{83 outb(reg, gus->gf1.reg_timerctrl);84 inb(gus->gf1.reg_timerctrl);85 inb(gus->gf1.reg_timerctrl);86 outb(data, gus->gf1.reg_timerdata);87 inb(gus->gf1.reg_timerctrl);88 inb(gus->gf1.reg_timerctrl);89}90 91static inline void __snd_gf1_write_addr(struct snd_gus_card * gus, unsigned char reg,92 unsigned int addr, int w_16bit)93{94 if (gus->gf1.enh_mode) {95 if (w_16bit)96 addr = ((addr >> 1) & ~0x0000000f) | (addr & 0x0000000f);97 __snd_gf1_write8(gus, SNDRV_GF1_VB_UPPER_ADDRESS, (unsigned char) ((addr >> 26) & 0x03));98 } else if (w_16bit)99 addr = (addr & 0x00c0000f) | ((addr & 0x003ffff0) >> 1);100 __snd_gf1_write16(gus, reg, (unsigned short) (addr >> 11));101 __snd_gf1_write16(gus, reg + 1, (unsigned short) (addr << 5));102}103 104static inline unsigned int __snd_gf1_read_addr(struct snd_gus_card * gus,105 unsigned char reg, short w_16bit)106{107 unsigned int res;108 109 res = ((unsigned int) __snd_gf1_look16(gus, reg | 0x80) << 11) & 0xfff800;110 res |= ((unsigned int) __snd_gf1_look16(gus, (reg + 1) | 0x80) >> 5) & 0x0007ff;111 if (gus->gf1.enh_mode) {112 res |= (unsigned int) __snd_gf1_look8(gus, SNDRV_GF1_VB_UPPER_ADDRESS | 0x80) << 26;113 if (w_16bit)114 res = ((res << 1) & 0xffffffe0) | (res & 0x0000000f);115 } else if (w_16bit)116 res = ((res & 0x001ffff0) << 1) | (res & 0x00c0000f);117 return res;118}119 120 121/*122 * =======================================================================123 */124 125void snd_gf1_ctrl_stop(struct snd_gus_card * gus, unsigned char reg)126{127 __snd_gf1_ctrl_stop(gus, reg);128}129 130void snd_gf1_write8(struct snd_gus_card * gus,131 unsigned char reg,132 unsigned char data)133{134 __snd_gf1_write8(gus, reg, data);135}136 137unsigned char snd_gf1_look8(struct snd_gus_card * gus, unsigned char reg)138{139 return __snd_gf1_look8(gus, reg);140}141 142void snd_gf1_write16(struct snd_gus_card * gus,143 unsigned char reg,144 unsigned int data)145{146 __snd_gf1_write16(gus, reg, data);147}148 149unsigned short snd_gf1_look16(struct snd_gus_card * gus, unsigned char reg)150{151 return __snd_gf1_look16(gus, reg);152}153 154void snd_gf1_adlib_write(struct snd_gus_card * gus,155 unsigned char reg,156 unsigned char data)157{158 __snd_gf1_adlib_write(gus, reg, data);159}160 161void snd_gf1_write_addr(struct snd_gus_card * gus, unsigned char reg,162 unsigned int addr, short w_16bit)163{164 __snd_gf1_write_addr(gus, reg, addr, w_16bit);165}166 167unsigned int snd_gf1_read_addr(struct snd_gus_card * gus,168 unsigned char reg,169 short w_16bit)170{171 return __snd_gf1_read_addr(gus, reg, w_16bit);172}173 174/*175 176 */177 178void snd_gf1_i_ctrl_stop(struct snd_gus_card * gus, unsigned char reg)179{180 unsigned long flags;181 182 spin_lock_irqsave(&gus->reg_lock, flags);183 __snd_gf1_ctrl_stop(gus, reg);184 spin_unlock_irqrestore(&gus->reg_lock, flags);185}186 187void snd_gf1_i_write8(struct snd_gus_card * gus,188 unsigned char reg,189 unsigned char data)190{191 unsigned long flags;192 193 spin_lock_irqsave(&gus->reg_lock, flags);194 __snd_gf1_write8(gus, reg, data);195 spin_unlock_irqrestore(&gus->reg_lock, flags);196}197 198unsigned char snd_gf1_i_look8(struct snd_gus_card * gus, unsigned char reg)199{200 unsigned long flags;201 unsigned char res;202 203 spin_lock_irqsave(&gus->reg_lock, flags);204 res = __snd_gf1_look8(gus, reg);205 spin_unlock_irqrestore(&gus->reg_lock, flags);206 return res;207}208 209void snd_gf1_i_write16(struct snd_gus_card * gus,210 unsigned char reg,211 unsigned int data)212{213 unsigned long flags;214 215 spin_lock_irqsave(&gus->reg_lock, flags);216 __snd_gf1_write16(gus, reg, data);217 spin_unlock_irqrestore(&gus->reg_lock, flags);218}219 220unsigned short snd_gf1_i_look16(struct snd_gus_card * gus, unsigned char reg)221{222 unsigned long flags;223 unsigned short res;224 225 spin_lock_irqsave(&gus->reg_lock, flags);226 res = __snd_gf1_look16(gus, reg);227 spin_unlock_irqrestore(&gus->reg_lock, flags);228 return res;229}230 231#if 0232 233void snd_gf1_i_adlib_write(struct snd_gus_card * gus,234 unsigned char reg,235 unsigned char data)236{237 unsigned long flags;238 239 spin_lock_irqsave(&gus->reg_lock, flags);240 __snd_gf1_adlib_write(gus, reg, data);241 spin_unlock_irqrestore(&gus->reg_lock, flags);242}243 244void snd_gf1_i_write_addr(struct snd_gus_card * gus, unsigned char reg,245 unsigned int addr, short w_16bit)246{247 unsigned long flags;248 249 spin_lock_irqsave(&gus->reg_lock, flags);250 __snd_gf1_write_addr(gus, reg, addr, w_16bit);251 spin_unlock_irqrestore(&gus->reg_lock, flags);252}253 254#endif /* 0 */255 256#ifdef CONFIG_SND_DEBUG257static unsigned int snd_gf1_i_read_addr(struct snd_gus_card * gus,258 unsigned char reg, short w_16bit)259{260 unsigned int res;261 unsigned long flags;262 263 spin_lock_irqsave(&gus->reg_lock, flags);264 res = __snd_gf1_read_addr(gus, reg, w_16bit);265 spin_unlock_irqrestore(&gus->reg_lock, flags);266 return res;267}268#endif269 270/*271 272 */273 274void snd_gf1_dram_addr(struct snd_gus_card * gus, unsigned int addr)275{276 outb(0x43, gus->gf1.reg_regsel);277 mb();278 outw((unsigned short) addr, gus->gf1.reg_data16);279 mb();280 outb(0x44, gus->gf1.reg_regsel);281 mb();282 outb((unsigned char) (addr >> 16), gus->gf1.reg_data8);283 mb();284}285 286void snd_gf1_poke(struct snd_gus_card * gus, unsigned int addr, unsigned char data)287{288 unsigned long flags;289 290 spin_lock_irqsave(&gus->reg_lock, flags);291 outb(SNDRV_GF1_GW_DRAM_IO_LOW, gus->gf1.reg_regsel);292 mb();293 outw((unsigned short) addr, gus->gf1.reg_data16);294 mb();295 outb(SNDRV_GF1_GB_DRAM_IO_HIGH, gus->gf1.reg_regsel);296 mb();297 outb((unsigned char) (addr >> 16), gus->gf1.reg_data8);298 mb();299 outb(data, gus->gf1.reg_dram);300 spin_unlock_irqrestore(&gus->reg_lock, flags);301}302 303unsigned char snd_gf1_peek(struct snd_gus_card * gus, unsigned int addr)304{305 unsigned long flags;306 unsigned char res;307 308 spin_lock_irqsave(&gus->reg_lock, flags);309 outb(SNDRV_GF1_GW_DRAM_IO_LOW, gus->gf1.reg_regsel);310 mb();311 outw((unsigned short) addr, gus->gf1.reg_data16);312 mb();313 outb(SNDRV_GF1_GB_DRAM_IO_HIGH, gus->gf1.reg_regsel);314 mb();315 outb((unsigned char) (addr >> 16), gus->gf1.reg_data8);316 mb();317 res = inb(gus->gf1.reg_dram);318 spin_unlock_irqrestore(&gus->reg_lock, flags);319 return res;320}321 322#if 0323 324void snd_gf1_pokew(struct snd_gus_card * gus, unsigned int addr, unsigned short data)325{326 unsigned long flags;327 328 if (!gus->interwave)329 dev_dbg(gus->card->dev, "%s - GF1!!!\n", __func__);330 spin_lock_irqsave(&gus->reg_lock, flags);331 outb(SNDRV_GF1_GW_DRAM_IO_LOW, gus->gf1.reg_regsel);332 mb();333 outw((unsigned short) addr, gus->gf1.reg_data16);334 mb();335 outb(SNDRV_GF1_GB_DRAM_IO_HIGH, gus->gf1.reg_regsel);336 mb();337 outb((unsigned char) (addr >> 16), gus->gf1.reg_data8);338 mb();339 outb(SNDRV_GF1_GW_DRAM_IO16, gus->gf1.reg_regsel);340 mb();341 outw(data, gus->gf1.reg_data16);342 spin_unlock_irqrestore(&gus->reg_lock, flags);343}344 345unsigned short snd_gf1_peekw(struct snd_gus_card * gus, unsigned int addr)346{347 unsigned long flags;348 unsigned short res;349 350 if (!gus->interwave)351 dev_dbg(gus->card->dev, "%s - GF1!!!\n", __func__);352 spin_lock_irqsave(&gus->reg_lock, flags);353 outb(SNDRV_GF1_GW_DRAM_IO_LOW, gus->gf1.reg_regsel);354 mb();355 outw((unsigned short) addr, gus->gf1.reg_data16);356 mb();357 outb(SNDRV_GF1_GB_DRAM_IO_HIGH, gus->gf1.reg_regsel);358 mb();359 outb((unsigned char) (addr >> 16), gus->gf1.reg_data8);360 mb();361 outb(SNDRV_GF1_GW_DRAM_IO16, gus->gf1.reg_regsel);362 mb();363 res = inw(gus->gf1.reg_data16);364 spin_unlock_irqrestore(&gus->reg_lock, flags);365 return res;366}367 368void snd_gf1_dram_setmem(struct snd_gus_card * gus, unsigned int addr,369 unsigned short value, unsigned int count)370{371 unsigned long port;372 unsigned long flags;373 374 if (!gus->interwave)375 dev_dbg(gus->card->dev, "%s - GF1!!!\n", __func__);376 addr &= ~1;377 count >>= 1;378 port = GUSP(gus, GF1DATALOW);379 spin_lock_irqsave(&gus->reg_lock, flags);380 outb(SNDRV_GF1_GW_DRAM_IO_LOW, gus->gf1.reg_regsel);381 mb();382 outw((unsigned short) addr, gus->gf1.reg_data16);383 mb();384 outb(SNDRV_GF1_GB_DRAM_IO_HIGH, gus->gf1.reg_regsel);385 mb();386 outb((unsigned char) (addr >> 16), gus->gf1.reg_data8);387 mb();388 outb(SNDRV_GF1_GW_DRAM_IO16, gus->gf1.reg_regsel);389 while (count--)390 outw(value, port);391 spin_unlock_irqrestore(&gus->reg_lock, flags);392}393 394#endif /* 0 */395 396void snd_gf1_select_active_voices(struct snd_gus_card * gus)397{398 unsigned short voices;399 400 static const unsigned short voices_tbl[32 - 14 + 1] =401 {402 44100, 41160, 38587, 36317, 34300, 32494, 30870, 29400, 28063, 26843,403 25725, 24696, 23746, 22866, 22050, 21289, 20580, 19916, 19293404 };405 406 voices = gus->gf1.active_voices;407 if (voices > 32)408 voices = 32;409 if (voices < 14)410 voices = 14;411 if (gus->gf1.enh_mode)412 voices = 32;413 gus->gf1.active_voices = voices;414 gus->gf1.playback_freq =415 gus->gf1.enh_mode ? 44100 : voices_tbl[voices - 14];416 if (!gus->gf1.enh_mode) {417 snd_gf1_i_write8(gus, SNDRV_GF1_GB_ACTIVE_VOICES, 0xc0 | (voices - 1));418 udelay(100);419 }420}421 422#ifdef CONFIG_SND_DEBUG423 424void snd_gf1_print_voice_registers(struct snd_gus_card * gus)425{426 unsigned char mode;427 int voice, ctrl;428 429 voice = gus->gf1.active_voice;430 dev_info(gus->card->dev,431 " -%i- GF1 voice ctrl, ramp ctrl = 0x%x, 0x%x\n",432 voice, ctrl = snd_gf1_i_read8(gus, 0), snd_gf1_i_read8(gus, 0x0d));433 dev_info(gus->card->dev,434 " -%i- GF1 frequency = 0x%x\n",435 voice, snd_gf1_i_read16(gus, 1));436 dev_info(gus->card->dev,437 " -%i- GF1 loop start, end = 0x%x (0x%x), 0x%x (0x%x)\n",438 voice, snd_gf1_i_read_addr(gus, 2, ctrl & 4),439 snd_gf1_i_read_addr(gus, 2, (ctrl & 4) ^ 4),440 snd_gf1_i_read_addr(gus, 4, ctrl & 4),441 snd_gf1_i_read_addr(gus, 4, (ctrl & 4) ^ 4));442 dev_info(gus->card->dev,443 " -%i- GF1 ramp start, end, rate = 0x%x, 0x%x, 0x%x\n",444 voice, snd_gf1_i_read8(gus, 7), snd_gf1_i_read8(gus, 8),445 snd_gf1_i_read8(gus, 6));446 dev_info(gus->card->dev,447 " -%i- GF1 volume = 0x%x\n",448 voice, snd_gf1_i_read16(gus, 9));449 dev_info(gus->card->dev,450 " -%i- GF1 position = 0x%x (0x%x)\n",451 voice, snd_gf1_i_read_addr(gus, 0x0a, ctrl & 4),452 snd_gf1_i_read_addr(gus, 0x0a, (ctrl & 4) ^ 4));453 if (gus->interwave && snd_gf1_i_read8(gus, 0x19) & 0x01) { /* enhanced mode */454 mode = snd_gf1_i_read8(gus, 0x15);455 dev_info(gus->card->dev,456 " -%i- GFA1 mode = 0x%x\n",457 voice, mode);458 if (mode & 0x01) { /* Effect processor */459 dev_info(gus->card->dev,460 " -%i- GFA1 effect address = 0x%x\n",461 voice, snd_gf1_i_read_addr(gus, 0x11, ctrl & 4));462 dev_info(gus->card->dev,463 " -%i- GFA1 effect volume = 0x%x\n",464 voice, snd_gf1_i_read16(gus, 0x16));465 dev_info(gus->card->dev,466 " -%i- GFA1 effect volume final = 0x%x\n",467 voice, snd_gf1_i_read16(gus, 0x1d));468 dev_info(gus->card->dev,469 " -%i- GFA1 effect accumulator = 0x%x\n",470 voice, snd_gf1_i_read8(gus, 0x14));471 }472 if (mode & 0x20) {473 dev_info(gus->card->dev,474 " -%i- GFA1 left offset = 0x%x (%i)\n",475 voice, snd_gf1_i_read16(gus, 0x13),476 snd_gf1_i_read16(gus, 0x13) >> 4);477 dev_info(gus->card->dev,478 " -%i- GFA1 left offset final = 0x%x (%i)\n",479 voice, snd_gf1_i_read16(gus, 0x1c),480 snd_gf1_i_read16(gus, 0x1c) >> 4);481 dev_info(gus->card->dev,482 " -%i- GFA1 right offset = 0x%x (%i)\n",483 voice, snd_gf1_i_read16(gus, 0x0c),484 snd_gf1_i_read16(gus, 0x0c) >> 4);485 dev_info(gus->card->dev,486 " -%i- GFA1 right offset final = 0x%x (%i)\n",487 voice, snd_gf1_i_read16(gus, 0x1b),488 snd_gf1_i_read16(gus, 0x1b) >> 4);489 } else490 dev_info(gus->card->dev,491 " -%i- GF1 pan = 0x%x\n",492 voice, snd_gf1_i_read8(gus, 0x0c));493 } else494 dev_info(gus->card->dev,495 " -%i- GF1 pan = 0x%x\n",496 voice, snd_gf1_i_read8(gus, 0x0c));497}498 499#if 0500 501void snd_gf1_print_global_registers(struct snd_gus_card * gus)502{503 unsigned char global_mode = 0x00;504 505 dev_info(gus->card->dev,506 " -G- GF1 active voices = 0x%x\n",507 snd_gf1_i_look8(gus, SNDRV_GF1_GB_ACTIVE_VOICES));508 if (gus->interwave) {509 global_mode = snd_gf1_i_read8(gus, SNDRV_GF1_GB_GLOBAL_MODE);510 dev_info(gus->card->dev,511 " -G- GF1 global mode = 0x%x\n",512 global_mode);513 }514 if (global_mode & 0x02) /* LFO enabled? */515 dev_info(gus->card->dev,516 " -G- GF1 LFO base = 0x%x\n",517 snd_gf1_i_look16(gus, SNDRV_GF1_GW_LFO_BASE));518 dev_info(gus->card->dev,519 " -G- GF1 voices IRQ read = 0x%x\n",520 snd_gf1_i_look8(gus, SNDRV_GF1_GB_VOICES_IRQ_READ));521 dev_info(gus->card->dev,522 " -G- GF1 DRAM DMA control = 0x%x\n",523 snd_gf1_i_look8(gus, SNDRV_GF1_GB_DRAM_DMA_CONTROL));524 dev_info(gus->card->dev,525 " -G- GF1 DRAM DMA high/low = 0x%x/0x%x\n",526 snd_gf1_i_look8(gus, SNDRV_GF1_GB_DRAM_DMA_HIGH),527 snd_gf1_i_read16(gus, SNDRV_GF1_GW_DRAM_DMA_LOW));528 dev_info(gus->card->dev,529 " -G- GF1 DRAM IO high/low = 0x%x/0x%x\n",530 snd_gf1_i_look8(gus, SNDRV_GF1_GB_DRAM_IO_HIGH),531 snd_gf1_i_read16(gus, SNDRV_GF1_GW_DRAM_IO_LOW));532 if (!gus->interwave)533 dev_info(gus->card->dev,534 " -G- GF1 record DMA control = 0x%x\n",535 snd_gf1_i_look8(gus, SNDRV_GF1_GB_REC_DMA_CONTROL));536 dev_info(gus->card->dev,537 " -G- GF1 DRAM IO 16 = 0x%x\n",538 snd_gf1_i_look16(gus, SNDRV_GF1_GW_DRAM_IO16));539 if (gus->gf1.enh_mode) {540 dev_info(gus->card->dev,541 " -G- GFA1 memory config = 0x%x\n",542 snd_gf1_i_look16(gus, SNDRV_GF1_GW_MEMORY_CONFIG));543 dev_info(gus->card->dev,544 " -G- GFA1 memory control = 0x%x\n",545 snd_gf1_i_look8(gus, SNDRV_GF1_GB_MEMORY_CONTROL));546 dev_info(gus->card->dev,547 " -G- GFA1 FIFO record base = 0x%x\n",548 snd_gf1_i_look16(gus, SNDRV_GF1_GW_FIFO_RECORD_BASE_ADDR));549 dev_info(gus->card->dev,550 " -G- GFA1 FIFO playback base = 0x%x\n",551 snd_gf1_i_look16(gus, SNDRV_GF1_GW_FIFO_PLAY_BASE_ADDR));552 dev_info(gus->card->dev,553 " -G- GFA1 interleave control = 0x%x\n",554 snd_gf1_i_look16(gus, SNDRV_GF1_GW_INTERLEAVE));555 }556}557 558void snd_gf1_print_setup_registers(struct snd_gus_card * gus)559{560 dev_info(gus->card->dev,561 " -S- mix control = 0x%x\n",562 inb(GUSP(gus, MIXCNTRLREG)));563 dev_info(gus->card->dev,564 " -S- IRQ status = 0x%x\n",565 inb(GUSP(gus, IRQSTAT)));566 dev_info(gus->card->dev,567 " -S- timer control = 0x%x\n",568 inb(GUSP(gus, TIMERCNTRL)));569 dev_info(gus->card->dev,570 " -S- timer data = 0x%x\n",571 inb(GUSP(gus, TIMERDATA)));572 dev_info(gus->card->dev,573 " -S- status read = 0x%x\n",574 inb(GUSP(gus, REGCNTRLS)));575 dev_info(gus->card->dev,576 " -S- Sound Blaster control = 0x%x\n",577 snd_gf1_i_look8(gus, SNDRV_GF1_GB_SOUND_BLASTER_CONTROL));578 dev_info(gus->card->dev,579 " -S- AdLib timer 1/2 = 0x%x/0x%x\n",580 snd_gf1_i_look8(gus, SNDRV_GF1_GB_ADLIB_TIMER_1),581 snd_gf1_i_look8(gus, SNDRV_GF1_GB_ADLIB_TIMER_2));582 dev_info(gus->card->dev,583 " -S- reset = 0x%x\n",584 snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET));585 if (gus->interwave) {586 dev_info(gus->card->dev,587 " -S- compatibility = 0x%x\n",588 snd_gf1_i_look8(gus, SNDRV_GF1_GB_COMPATIBILITY));589 dev_info(gus->card->dev,590 " -S- decode control = 0x%x\n",591 snd_gf1_i_look8(gus, SNDRV_GF1_GB_DECODE_CONTROL));592 dev_info(gus->card->dev,593 " -S- version number = 0x%x\n",594 snd_gf1_i_look8(gus, SNDRV_GF1_GB_VERSION_NUMBER));595 dev_info(gus->card->dev,596 " -S- MPU-401 emul. control A/B = 0x%x/0x%x\n",597 snd_gf1_i_look8(gus, SNDRV_GF1_GB_MPU401_CONTROL_A),598 snd_gf1_i_look8(gus, SNDRV_GF1_GB_MPU401_CONTROL_B));599 dev_info(gus->card->dev,600 " -S- emulation IRQ = 0x%x\n",601 snd_gf1_i_look8(gus, SNDRV_GF1_GB_EMULATION_IRQ));602 }603}604#endif /* 0 */605 606#endif607