📄 dosgus.c
字号:
__gus_outregb(GF1R_DRAM_HIGH, address >> 16); if (flags & GUS_WAVE_INVERT) if (flags & GUS_WAVE_16BIT) while (size64k-- && size64k--) { __gus_outregw(GF1R_DRAM_LOW, address++); outportb(GF1_DRAM, *source++); __gus_outregw(GF1R_DRAM_LOW, address++); outportb(GF1_DRAM, (*source++) ^ 0x80); } else while (size64k--) { __gus_outregw(GF1R_DRAM_LOW, address++); outportb(GF1_DRAM, (*source++) ^ 0x80); } else while (size64k--) { __gus_outregw(GF1R_DRAM_LOW, address++); outportb(GF1_DRAM, *source++); } }}/* Wait for DMA transfer to finish between 8-9 1/18sec timer ticks */static int __gus_wait_dma(){ unsigned long timer; _farsetsel(_dos_ds); timer = _farnspeekl(0x46c); while (gus.dma_active) if (_farnspeekl(0x46c) - timer > 8) { /* Force DMA abort since something went wrong */ __gus_reset(0); return -1; } return 0;}/* Transfer a block of data into GUS DRAM through DMA controller */static void __gus_transfer_dma(unsigned long address, unsigned char *source, unsigned long size, int flags){ unsigned char dma_control; unsigned long bytes_left; unsigned long cur_size; unsigned long dest_addr; if ((gus.dma[0] > 3) || (flags & GUS_WAVE_16BIT)) size = (size + 1) & ~1; bytes_left = size; while (bytes_left) { __gus_wait_dma(); cur_size = gus.dma_buff->size; if (cur_size > bytes_left) cur_size = bytes_left; bytes_left -= cur_size; dest_addr = address; if (gus.dma_buff->linear != source) memmove(gus.dma_buff->linear, source, cur_size); source += cur_size; address += cur_size; /* Disable GUS -> DMA tie */ __gus_outregb(GF1R_DMA_CONTROL, 0); __gus_delay(); /* Set up the DMA */ dma_start(gus.dma_buff, cur_size, DMA_MODE_WRITE); gus.dma_active = 1; /* Reset the DMA IRQ pending bit if set */ __gus_inregb(GF1R_DMA_CONTROL); /* The 16-bit DMA channels needs a slightly different approach */ dma_control = GF1M_DMAR_ENABLE | GF1M_DMAR_IRQ_ENABLE | gus.dma_rate; if (gus.dma[0] > 3) { dest_addr = __gus_convert_addr16(dest_addr); dma_control |= GF1M_DMAR_CHAN16; } __gus_outregw(GF1R_DMA_ADDRESS, dest_addr >> 4); if (flags & GUS_WAVE_16BIT) dma_control |= GF1M_DMAR_DATA16; if (flags & GUS_WAVE_INVERT) dma_control |= GF1M_DMAR_TOGGLE_SIGN; /* Tell GUS to start transfer */ __gus_outregb(GF1R_DMA_CONTROL, dma_control); }}static void __gus_detect_version(){ unsigned char tmp; switch (gus.version = inportb(GF1_REVISION)) { case 5: gus.version = GUS_CARD_VERSION_CLASSIC_ICS; gus.ics = 1; gus.ics_flipped = 1; break; case 6: case 7: case 8: case 9: gus.version = GUS_CARD_VERSION_CLASSIC_ICS; gus.ics = 1; break; case 10: gus.version = GUS_CARD_VERSION_MAX; gus.codec = 1; break; case 11: gus.version = GUS_CARD_VERSION_MAX1; gus.codec = 1; break; case 0x30: gus.version = GUS_CARD_VERSION_ACE; break; case 0x50: gus.version = GUS_CARD_VERSION_EXTREME; break; case 0xff: /* Pre-3.7 board */ outportb(GF1_REG_CTRL, 0x20); tmp = inportb(GF1_REG_CTRL); if ((tmp != 0xff) && (tmp & 0x06)) gus.version = GUS_CARD_VERSION_CLASSIC1; else gus.version = GUS_CARD_VERSION_CLASSIC; break; default: /* Hmm... unknown revision. Assume a safe Classic model */#ifdef MIKMOD_DEBUG fprintf(stderr, "libgus: Unknown board revision (%02x)\n", gus.version);#endif gus.version = GUS_CARD_VERSION_CLASSIC; break; }}static void __gus_detect_transfer(){ unsigned char *outbuff, *inbuff; unsigned int i, j, seed = 0x13243546; __gus_transfer_func func;#define TRANSFER_SIZE 0x4000 outbuff = malloc(TRANSFER_SIZE); inbuff = malloc(TRANSFER_SIZE); /* Suppose we have an malfunctioning GUS */ gus.transfer = NULL; for (i = (gus.dma_buff ? 0 : 4); i <= 4; i++) { switch (i) { case 0: gus.dma_rate = GF1M_DMAR_RATE0; func = __gus_transfer_dma; break; case 1: gus.dma_rate = GF1M_DMAR_RATE1; func = __gus_transfer_dma; break; case 2: gus.dma_rate = GF1M_DMAR_RATE2; func = __gus_transfer_dma; break; case 3: gus.dma_rate = GF1M_DMAR_RATE3; func = __gus_transfer_dma; break; case 4: func = __gus_transfer_io; break; } /* Fill data array each time with pseudo-random values */ for (j = 0; j < TRANSFER_SIZE; j++) outbuff[j] = seed, seed = ((seed + 358979323) ^ (seed >> 16)) * 314159265; /* Transfer the random array to GUS */ /* Poke a security fence around dest block */ __gus_poke(0x100 - 1, 0xAA); __gus_poke(0x100 - 2, 0x55); __gus_poke(0x100 + TRANSFER_SIZE + 0, 0xAA); __gus_poke(0x100 + TRANSFER_SIZE + 1, 0x55); func(0x100, outbuff, TRANSFER_SIZE, 0); if (__gus_wait_dma() == 0) { /* Check if the security fence was not damaged */ if ((__gus_peek(0x100 - 1) != 0xAA) || (__gus_peek(0x100 - 2) != 0x55) || (__gus_peek(0x100 + TRANSFER_SIZE + 0) != 0xAA) || (__gus_peek(0x100 + TRANSFER_SIZE + 1) != 0x55)) continue; /* Now check if GUS DRAM really data that we expects to be transferred */ __gus_transfer_io_in(0x100, inbuff, TRANSFER_SIZE); if (memcmp(outbuff, inbuff, TRANSFER_SIZE) == 0) { gus.transfer = func; break; } } }#undef TRANSFER_SIZE free(inbuff); free(outbuff);}static void __gus_detect_memory(){ unsigned int size; for (size = 0; size < 1024; size += 256) { __gus_poke(size * 1024, 0xaa); if (__gus_peek(size * 1024) != 0xaa) break; __gus_poke(size * 1024, 0x55); if (__gus_peek(size * 1024) != 0x55) break; } gus.ram = size;}static void __gus_init(){ char *gusenv = getenv("ULTRASND"); memset((void *)&gus, 0, sizeof(gus)); gus.cmd_voice = -1; if (!gusenv) return; sscanf(gusenv, "%x,%d,%d,%d,%d", &gus.port, &gus.dma[0], &gus.dma[1], &gus.irq[0], &gus.irq[1]); /* A relaxed sanity check */ if ((gus.port < 0x100) || (gus.port > 0x1000) || (gus.irq[0] < 2) || (gus.irq[0] > 15) || (gus.irq[1] < 2) || (gus.irq[1] > 15) || (gus.dma[0] < 0) || (gus.dma[0] > 7) || (gus.dma[1] < 0) || (gus.dma[1] > 7)) return; gus.voices = 32; gus.timer_ctl = GF1M_MASK_TIMER1 | GF1M_MASK_TIMER2; /* Detect if the card is really there */ if (__gus_detect() == 0) return; /* Detect the version of Gravis Ultrasound */ __gus_detect_version(); /* Reset the card */ __gus_reset(1); /* Detect the amount of on-board memory */ __gus_detect_memory(); gus.ok = 1;}static void __gus_kick(gus_wave_t * wave, unsigned int wave_offset){ unsigned char vc; vc = GF1VC_IRQ; if (wave->format & GUS_WAVE_16BIT) vc |= GF1VC_DATA16; if (wave->format & GUS_WAVE_BACKWARD) vc |= GF1VC_BACKWARD; if (wave->format & GUS_WAVE_LOOP) { vc |= GF1VC_LOOP_ENABLE; if (wave->format & GUS_WAVE_BIDIR) vc |= GF1VC_BI_LOOP; } __gus_set_loop_start(vc, (wave->begin.memory << 4) + wave->loop_start); if (wave->format & GUS_WAVE_LOOP) __gus_set_loop_end(vc, (wave->begin.memory << 4) + wave->loop_end); else __gus_set_loop_end(vc, (wave->begin.memory + wave->size) << 4); __gus_set_current(vc, (wave->begin.memory << 4) + wave_offset + 100); __gus_outregb_slow(GF1R_VOICE_CONTROL, vc);}/* Timer 1 callback function (updates voices) */static void __gus_timer_update(){ gus_wave_t *wave; unsigned long wave_offset; unsigned char *src, *top; unsigned int vmask = (1 << gus.cur_voice); if (!gus.cmd_pool_ready) return; __gus_select_voice(gus.cur_voice); wave_offset = 0; src = gus.cmd_pool; top = gus.cmd_pool + gus.cmd_pool_top;#define GET_B *src#define GET_W *((unsigned short *)src)#define GET_L *((unsigned long *)src) while (src < top) { __gus_delay(); switch (GET_B++) { case PCMD_VOICE: __gus_select_voice(gus.cur_voice = GET_B++); vmask = (1 << gus.cur_voice); break; case PCMD_FREQ: __gus_outregw(GF1R_FREQUENCY, GET_W++); break; case PCMD_PAN: __gus_outregb(GF1R_BALANCE, GET_B++); break; case PCMD_VOLUME: __gus_volume_ramp_to(gus.cur_vol[gus.cur_voice] = GET_W++, GUS_VOLCHANGE_RAMP, GF1VL_IRQ); break; case PCMD_VOLUME_PREPARE: gus.cur_vol[gus.cur_voice] = GET_W++; break; case PCMD_OFFSET: wave_offset = GET_L++; break; case PCMD_START: wave = (gus_wave_t *) GET_L++; gus.cur_wave[gus.cur_voice] = wave; gus.kick_offs[gus.cur_voice] = wave_offset; if (__gus_volume_ramp_to(0, GUS_VOLCHANGE_RAMP, GF1VL_IRQ)) { __gus_kick(wave, wave_offset); __gus_volume_ramp_to(gus.cur_vol[gus.cur_voice], GUS_VOLCHANGE_RAMP, GF1VL_IRQ); } else gus.voice_kick[gus.cur_voice] = 1; wave_offset = 0; gus.eow_ignore |= vmask; break; case PCMD_STOP: /* If volume is close to nothing, abort immediately instead of ramping */ gus.cur_vol[gus.cur_voice] = 0; gus.cur_wave[gus.cur_voice] = NULL; if (__gus_volume_ramp_to(0, GUS_VOLCHANGE_RAMP, GF1VL_IRQ)) __gus_stop_voice(); break; case PCMD_STOP_LOOP: __gus_outregb_slow(GF1R_VOICE_CONTROL, (__gus_inregb(GF1R_VOICE_CONTROL) | GF1VC_IRQ) & ~GF1VC_LOOP_ENABLE); __gus_outregb_slow(GF1R_VOLUME_CONTROL, __gus_inregb(GF1R_VOLUME_CONTROL) & ~GF1VL_ROLLOVER); break; default: /* Alarm! Break out immediately */ src = top; break; } }#undef GET_B#undef GET_W#undef GET_L gus.cmd_pool_ready = 0; gus.cmd_pool_top = 0;}static void __gus_wavetable_update(unsigned int voice, unsigned int voice_ctl, unsigned int volume_ctl){ gus_wave_t *wave = gus.cur_wave[voice]; if (!wave || !(wave->format & GUS_WAVE_LOOP)) { __gus_stop_voice(); gus.cur_wave[voice] = NULL; gus.cur_vol[voice] = 0; if (__gus_volume_ramp_to(0, GUS_VOLCHANGE_RAMP, GF1VL_IRQ)) __gus_stop_voice(); }}static void __gus_volume_update(unsigned int voice, unsigned int voice_ctl, unsigned int volume_ctl){ __gus_volume_ramp_to(gus.cur_vol[voice], GUS_VOLCHANGE_RAMP, GF1VL_IRQ); if (!gus.cur_wave[voice]) __gus_stop_voice(); else if (gus.voice_kick[voice]) __gus_kick(gus.cur_wave[voice], gus.kick_offs[voice]); gus.voice_kick[voice] = 0;}/***************************************************** GUS memory manager *****//* Mark all GUS memory as available */static void __gus_mem_clear(){ __gus_mcb *cur = gus.mcb; while (cur) { __gus_mcb *next = cur->next; if (cur != gus.mcb) free(cur); cur = next; } if (!gus.mcb) gus.mcb = malloc(sizeof(__gus_mcb)); gus.mcb->next = gus.mcb->prev = NULL; gus.mcb->addr = 0; gus.mcb->size = gus.ram * 1024; gus.mcb->free = 1;}/* Return amount of free memory */static unsigned int __gus_mem_get_free(){ __gus_mcb *cur = gus.mcb; unsigned int size = 0; if (!gus.open) return gus.ram * 1024; while (cur) { if (cur->free) size += cur->size; cur = cur->next; } return size;}/* Return largest size for a 8-bit sample */static unsigned int __gus_mem_get_free_8(){ __gus_mcb *cur = gus.mcb; unsigned int size = 0; if (!gus.open) return 0; while (cur) { if (cur->free && (cur->size > size)) size = cur->size; cur = cur->next; } return size;}/* Return largest size for a 16-bit sample */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -