unsigned long long dosamp_FAR dosamp_time_source_8254_poll(dosamp_time_source_t inst) { if (inst->open_flags == 0) return 0UL; if (ts_8254_pper == t8254_counter[T8254_TIMER_INTERRUPT_TICK]) { uint16_t ncnt = read_8254(T8254_TIMER_INTERRUPT_TICK); uint16_t delta; /* NTS: remember the timer chip counts DOWN to zero. * so normally, ncnt < ts_8254_pcnt unless 16-bit rollover happened. */ if (ncnt <= ts_8254_pcnt) delta = ts_8254_pcnt - ncnt; else delta = ts_8254_pcnt + (uint16_t)ts_8254_pper - ncnt; /* count */ inst->counter += (unsigned long long)delta; /* store the prev counter */ ts_8254_pcnt = ncnt; } else { ts_8254_pcnt = read_8254(T8254_TIMER_INTERRUPT_TICK); ts_8254_pper = t8254_counter[T8254_TIMER_INTERRUPT_TICK]; } return inst->counter; }
int dosamp_FAR dosamp_time_source_8254_open(dosamp_time_source_t inst) { inst->open_flags = (unsigned int)(-1); inst->clock_rate = T8254_REF_CLOCK_HZ; ts_8254_pcnt = read_8254(T8254_TIMER_INTERRUPT_TICK); ts_8254_pper = t8254_counter[T8254_TIMER_INTERRUPT_TICK]; #if defined(TARGET_PC98) assert(inst->clock_rate != 0ul); // blow up here if someone forgot to probe the 8254 #endif return 0; }
void play_sfx(const pcspkt_ent_list *pl) { struct pcspk_ent *p; t8254_time_t pc,cc; t8254_time_t delta; int32_t tim = 0; p = *(pl++); cc = read_8254(0); while (p != NULL) { while (p->delay != 0) { if (p->freq != 0) { #ifdef TARGET_PC98 /* Double the counter to convert IBM PC timer delay (1193182Hz) to PC-98 timer delay (2457600Hz) */ write_8254_pc_speaker(p->freq << 9u); #else write_8254_pc_speaker(p->freq << 8u); #endif t8254_pc_speaker_set_gate(PC_SPEAKER_GATE_ON); } else { t8254_pc_speaker_set_gate(PC_SPEAKER_GATE_OFF); } #ifdef TARGET_PC98 /* Double the delay to convert IBM PC timer delay (1193182Hz) to PC-98 timer delay (2457600Hz) */ tim += (int32_t)((unsigned long)p->delay << 9u); #else tim += (int32_t)((unsigned int)p->delay << 8u); #endif while (tim >= 0l) { pc = cc; cc = read_8254(0); delta = (pc - cc) & 0xFFFFul; /* counts DOWN */ tim -= delta; } p++; } p = *(pl++); } t8254_pc_speaker_set_gate(PC_SPEAKER_GATE_OFF); }
void t8254_wait(unsigned long ticks) { t8254_time_t pr,cr; uint16_t dec; if (ticks <= 1) return; ticks--; cr = read_8254(0); do { /* NTS: remember the 8254 counts downward, not upward */ pr = cr; cr = read_8254(0); if (cr > pr) /* when counter reaches zero it resets to the original counter value and begins counting again */ dec = (pr + (uint16_t)t8254_counter[0] - cr); else dec = (pr - cr); ticks -= dec; } while ((signed long)ticks >= 0L); }
void direct_dac_test(void) { unsigned long time,bytes; unsigned char FAR *ptr; unsigned int i,count; unsigned int pc,c; doubleprintf("Direct DAC playback test.\n"); /* FIXME: Why is the final rate SLOWER in DOSBox-X in 386 protected mode? */ sndsb_reset_dsp(sb_card); sndsb_write_dsp(sb_card,0xD1); /* speaker on */ _cli(); time = 0; bytes = 0; c = read_8254(T8254_TIMER_INTERRUPT_TICK); for (count=0;count < 3;count++) { ptr = sb_dma->lin; for (i=0;i < sb_dma->length;i++) { sndsb_write_dsp(sb_card,SNDSB_DSPCMD_DIRECT_DAC_OUT); /* 0x10 */ sndsb_write_dsp(sb_card,*ptr++); pc = c; c = read_8254(T8254_TIMER_INTERRUPT_TICK); time += (unsigned long)((pc - c) & 0xFFFFU); /* remember: it counts DOWN. assumes full 16-bit count */ } bytes += sb_dma->length; } _sti(); if (time == 0UL) time = 1; { double t = (double)time / T8254_REF_CLOCK_HZ; double rate = (double)bytes / t; doubleprintf(" - %lu bytes played in %.3f seconds\n",(unsigned long)bytes,t); doubleprintf(" - Sample rate is %.3fHz\n",rate); } }
void sb1_sc_play_adpcm2_test(void) { unsigned long time,bytes,expect,tlen,timeout; unsigned int count; unsigned int pc,c; unsigned long d; uint32_t irqc; doubleprintf("SB 1.x ADPCM 2-bit single cycle DSP playback test.\n"); timeout = T8254_REF_CLOCK_HZ * 4UL; for (count=0;count < 256;count++) { expect = 1000000UL / (unsigned long)(256 - count); _cli(); if (sb_card->irq >= 8) { p8259_OCW2(8,P8259_OCW2_SPECIFIC_EOI | (sb_card->irq & 7)); p8259_OCW2(0,P8259_OCW2_SPECIFIC_EOI | 2); } else if (sb_card->irq >= 0) { p8259_OCW2(0,P8259_OCW2_SPECIFIC_EOI | sb_card->irq); } _sti(); tlen = (expect / 4UL) + 1; // 1 sec if (tlen > sb_card->buffer_size) tlen = sb_card->buffer_size; sb_card->buffer_dma_started_length = tlen; sb_card->buffer_dma_started = 0; sndsb_reset_dsp(sb_card); sndsb_write_dsp(sb_card,0xD1); /* speaker on */ sndsb_setup_dma(sb_card); irqc = sb_card->irq_counter; sndsb_write_dsp_timeconst(sb_card,count); _cli(); c = read_8254(T8254_TIMER_INTERRUPT_TICK); bytes = tlen; time = 0; _sti(); { unsigned int lv = (unsigned int)(tlen - 1UL); sndsb_write_dsp(sb_card,SNDSB_DSPCMD_DMA_DAC_OUT_ADPCM_2BIT_REF); /* 0x17 */ sndsb_write_dsp(sb_card,lv); sndsb_write_dsp(sb_card,lv >> 8); } while (1) { if (irqc != sb_card->irq_counter) break; _cli(); pc = c; c = read_8254(T8254_TIMER_INTERRUPT_TICK); time += (unsigned long)((pc - c) & 0xFFFFU); /* remember: it counts DOWN. assumes full 16-bit count */ _sti(); if (time >= timeout) goto x_timeout; } x_complete: if (time == 0UL) time = 1; { double t = (double)time / T8254_REF_CLOCK_HZ; double rate = (double)(((bytes - 1UL) * 4UL) + 1UL) / t; /* 4 samples/byte + 1 reference */ doubleprintf(" - TC 0x%02X: expecting %luHz, %lub/%.3fs @ %.3fHz\n",count,expect,(unsigned long)bytes,t,rate); } if (kbhit()) { if (getch() == 27) break; } continue; x_timeout: d = d8237_read_count(sb_card->dma8); /* counts DOWNWARD */ if (d > tlen) d = 0; /* terminal count */ d = tlen - d; if (irqc == sb_card->irq_counter && d == 0) bytes = 0; /* nothing happened if no IRQ and counter never changed */ else if (bytes > d) bytes = d; goto x_complete; } _cli(); if (sb_card->irq >= 8) { p8259_OCW2(8,P8259_OCW2_SPECIFIC_EOI | (sb_card->irq & 7)); p8259_OCW2(0,P8259_OCW2_SPECIFIC_EOI | 2); } else if (sb_card->irq >= 0) { p8259_OCW2(0,P8259_OCW2_SPECIFIC_EOI | sb_card->irq); } _sti(); sndsb_write_dsp_timeconst(sb_card,0x83); /* 8000Hz */ sndsb_reset_dsp(sb_card); }
void sb16_sc_play_test(void) { unsigned char bytespersample = wav_16bit ? 2 : 1; unsigned long time,bytes,expect,tlen,timeout; unsigned long count; unsigned int pc,c; unsigned long d; uint32_t irqc; int dma; if (wav_16bit && sb_card->dma16 >= 4) dma = sb_card->dma16; else dma = sb_card->dma8; if (sb_card->dsp_vmaj >= 4) /* Sound Blaster 16 */ { } else if (sb_card->is_gallant_sc6600) /* Reveal SC-4000 / Gallant SC-6600 */ { } else return; doubleprintf("SB16 4.x single cycle DSP playback test (%u bit).\n",wav_16bit?16:8); timeout = T8254_REF_CLOCK_HZ * 2UL; count = 0; do { expect = count; _cli(); if (sb_card->irq >= 8) { p8259_OCW2(8,P8259_OCW2_SPECIFIC_EOI | (sb_card->irq & 7)); p8259_OCW2(0,P8259_OCW2_SPECIFIC_EOI | 2); } else if (sb_card->irq >= 0) { p8259_OCW2(0,P8259_OCW2_SPECIFIC_EOI | sb_card->irq); } _sti(); tlen = expect; // 1 sec if (tlen < 4000UL) tlen = 4000UL; if (tlen > (sb_card->buffer_size / (unsigned long)bytespersample)) tlen = sb_card->buffer_size / (unsigned long)bytespersample; sb_card->buffer_dma_started_length = tlen * (unsigned long)bytespersample; sb_card->buffer_dma_started = 0; sndsb_reset_dsp(sb_card); sndsb_write_dsp(sb_card,0xD1); /* speaker on */ sndsb_setup_dma(sb_card); irqc = sb_card->irq_counter; sndsb_write_dsp_outrate(sb_card,count); _cli(); c = read_8254(T8254_TIMER_INTERRUPT_TICK); bytes = tlen; time = 0; _sti(); { unsigned int lv = (unsigned int)(tlen - 1UL); /* NTS: Reveal SC-4000 (Gallant 6600) cards DO support SB16 but only specific commands. * Command 0xC0 is not recognized, but command 0xC6 works. */ if (wav_16bit) { if (sb_card->is_gallant_sc6600) sndsb_write_dsp(sb_card,SNDSB_DSPCMD_SB16_AUTOINIT_DMA_DAC_OUT_16BIT); /* 0xB6 */ else sndsb_write_dsp(sb_card,SNDSB_DSPCMD_SB16_DMA_DAC_OUT_16BIT); /* 0xB0 */ sndsb_write_dsp(sb_card,0x10); /* mode (16-bit signed PCM) */ } else { if (sb_card->is_gallant_sc6600) sndsb_write_dsp(sb_card,SNDSB_DSPCMD_SB16_AUTOINIT_DMA_DAC_OUT_8BIT); /* 0xC6 */ else sndsb_write_dsp(sb_card,SNDSB_DSPCMD_SB16_DMA_DAC_OUT_8BIT); /* 0xC0 */ sndsb_write_dsp(sb_card,0x00); /* mode (8-bit unsigned PCM) */ } sndsb_write_dsp(sb_card,lv); sndsb_write_dsp(sb_card,lv >> 8); } while (1) { if (irqc != sb_card->irq_counter) break; _cli(); pc = c; c = read_8254(T8254_TIMER_INTERRUPT_TICK); time += (unsigned long)((pc - c) & 0xFFFFU); /* remember: it counts DOWN. assumes full 16-bit count */ _sti(); if (time >= timeout) goto x_timeout; } x_complete: if (time == 0UL) time = 1; { double t = (double)time / T8254_REF_CLOCK_HZ; double rate = (double)bytes / t; doubleprintf(" - Rate 0x%04lX: expecting %luHz, %lu%c/%.3fs @ %.3fHz\n",count,expect,(unsigned long)bytes,wav_16bit?'w':'b',t,rate); } if (kbhit()) { if (getch() == 27) break; } count += 0x80; /* count by 128 because enumerating all would take too long */ if (count > 0xFFFFUL) break; continue; x_timeout: d = d8237_read_count(dma) / (unsigned long)bytespersample; /* counts DOWNWARD */ if (d > tlen) d = 0; /* terminal count */ d = tlen - d; if (irqc == sb_card->irq_counter && d == 0) bytes = 0; /* nothing happened if no IRQ and counter never changed */ else if (bytes > d) bytes = d; goto x_complete; } while (1); _cli(); if (sb_card->irq >= 8) { p8259_OCW2(8,P8259_OCW2_SPECIFIC_EOI | (sb_card->irq & 7)); p8259_OCW2(0,P8259_OCW2_SPECIFIC_EOI | 2); } else if (sb_card->irq >= 0) { p8259_OCW2(0,P8259_OCW2_SPECIFIC_EOI | sb_card->irq); } _sti(); sndsb_reset_dsp(sb_card); sndsb_write_dsp_outrate(sb_card,8000U); }
void ess_sc_play_test(void) { unsigned char bytespersample = wav_16bit ? 2 : 1; unsigned long time,bytes,expect,tlen,timeout; unsigned long count; unsigned int pc,c; unsigned long d; uint32_t irqc; if (!sb_card->ess_extensions || sb_card->ess_chipset == 0) return; doubleprintf("ESS688 single cycle DSP playback test (%u bit).\n",wav_16bit?16:8); timeout = T8254_REF_CLOCK_HZ * 2UL; for (count=0;count < 256;count++) { if (count >= 128) expect = 795500UL / (256 - count); else expect = 397700UL / (128 - count); _cli(); if (sb_card->irq >= 8) { p8259_OCW2(8,P8259_OCW2_SPECIFIC_EOI | (sb_card->irq & 7)); p8259_OCW2(0,P8259_OCW2_SPECIFIC_EOI | 2); } else if (sb_card->irq >= 0) { p8259_OCW2(0,P8259_OCW2_SPECIFIC_EOI | sb_card->irq); } _sti(); tlen = expect; // 1 sec if (tlen > (sb_card->buffer_size / (unsigned long)bytespersample)) tlen = sb_card->buffer_size / (unsigned long)bytespersample; /* NTS: We ask the card to use demand ISA, 4 bytes at a time. * Behavior observed on real hardware, is that if you set up * DMA this way and then set up a non-auto-init DMA transfer * that isn't a multiple of 4, the DMA will stop short of * the full transfer and the IRQ will never fire. Therefore * the transfer length must be a multiple of 4! */ tlen -= tlen & 3; if (tlen == 0) tlen = 4; sb_card->buffer_dma_started_length = tlen * (unsigned long)bytespersample; sb_card->buffer_dma_started = 0; sndsb_reset_dsp(sb_card); sndsb_write_dsp(sb_card,0xD1); /* speaker on */ sndsb_ess_set_extended_mode(sb_card,1/*enable*/); sndsb_setup_dma(sb_card); irqc = sb_card->irq_counter; { /* ESS 688/1869 chipset specific DSP playback. using this mode bypasses a lot of the Sound Blaster Pro emulation and restrictions and allows us to run up to 48KHz 16-bit stereo */ unsigned short t16; int b; _cli(); /* clear IRQ */ sndsb_interrupt_ack(sb_card,3); b = 0x00; /* DMA disable */ b |= 0x00; /* no auto-init */ b |= 0x00; /* [3]=DMA converter in ADC mode [1]=DMA read for ADC playback mode */ sndsb_ess_write_controller(sb_card,0xB8,b); b = sndsb_ess_read_controller(sb_card,0xA8); b &= ~0xB; /* clear mono/stereo and record monitor (bits 3, 1, and 0) */ b |= 2; /* mono 10=mono 01=stereo */ sndsb_ess_write_controller(sb_card,0xA8,b); /* NTS: The meaning of bits 1:0 in register 0xB9 * * 00 single DMA transfer mode * 01 demand DMA transfer mode, 2 bytes/request * 10 demand DMA transfer mode, 4 bytes/request * 11 reserved * * NOTES on what happens if you set bits 1:0 (DMA transfer type) to the "reserved" 11 value: * * ESS 688 (Sharp laptop) Nothing, apparently. Treated the same as 4 bytes/request * * ESS 1887 (Compaq Presario) Triggers a hardware bug where the chip appears to fetch * 3 bytes per demand transfer but then only handle 1 byte, * which translates to audio playing at 3x the sample rate * it should be. NOT because the DAC is running any faster, * but because the chip is only playing back every 3rd sample! * This play only 3rds behavior is consistent across 8/16-bit * PCM and mono/stereo. */ b = 2; /* demand transfer DMA 4 bytes per request */ sndsb_ess_write_controller(sb_card,0xB9,b); sndsb_ess_write_controller(sb_card,0xA1,count); /* effectively disable the lowpass filter (NTS: 0xFF mutes the audio, apparently) */ sndsb_ess_write_controller(sb_card,0xA2,0xFE); t16 = -(tlen * (uint16_t)bytespersample); /* DMA transfer count reload register value is 2's complement of length */ sndsb_ess_write_controller(sb_card,0xA4,t16); /* DMA transfer count low */ sndsb_ess_write_controller(sb_card,0xA5,t16>>8); /* DMA transfer count high */ b = sndsb_ess_read_controller(sb_card,0xB1); b &= ~0xA0; /* clear compat game IRQ, fifo half-empty IRQs */ b |= 0x50; /* set overflow IRQ, and "no function" */ sndsb_ess_write_controller(sb_card,0xB1,b); b = sndsb_ess_read_controller(sb_card,0xB2); b &= ~0xA0; /* clear compat */ b |= 0x50; /* set DRQ/DACKB inputs for DMA */ sndsb_ess_write_controller(sb_card,0xB2,b); b = 0x51; /* enable FIFO+DMA, reserved, load signal */ b |= wav_16bit ? 0x20 : 0x00; /* signed complement mode or not */ sndsb_ess_write_controller(sb_card,0xB7,b); b = 0x90; /* enable FIFO+DMA, reserved, load signal */ b |= wav_16bit ? 0x20 : 0x00; /* signed complement mode or not */ b |= 0x40; /* [3]=stereo [6]=!stereo */ b |= wav_16bit ? 0x04 : 0x00; /* [2]=16bit */ sndsb_ess_write_controller(sb_card,0xB7,b); b = sndsb_ess_read_controller(sb_card,0xB8); sndsb_ess_write_controller(sb_card,0xB8,b | 1); } _cli(); c = read_8254(T8254_TIMER_INTERRUPT_TICK); bytes = tlen; time = 0; _sti(); while (1) { if (irqc != sb_card->irq_counter) break; _cli(); pc = c; c = read_8254(T8254_TIMER_INTERRUPT_TICK); time += (unsigned long)((pc - c) & 0xFFFFU); /* remember: it counts DOWN. assumes full 16-bit count */ _sti(); if (time >= timeout) goto x_timeout; } x_complete: if (time == 0UL) time = 1; { int b; b = sndsb_ess_read_controller(sb_card,0xB8); if (b != -1) { b &= ~0x01; /* stop DMA */ sndsb_ess_write_controller(sb_card,0xB8,b); } } { double t = (double)time / T8254_REF_CLOCK_HZ; double rate = (double)bytes / t; doubleprintf(" - TC 0x%02lX: expecting %luHz, %lu%c/%.3fs @ %.3fHz\n",count,expect,(unsigned long)bytes,wav_16bit?'w':'b',t,rate); } if (kbhit()) { if (getch() == 27) break; } continue; x_timeout: d = d8237_read_count(sb_card->dma8) / (unsigned long)bytespersample; /* counts DOWNWARD */ if (d > tlen) d = 0; /* terminal count */ d = tlen - d; if (irqc == sb_card->irq_counter && d == 0) bytes = 0; /* nothing happened if no IRQ and counter never changed */ else if (bytes > d) bytes = d; goto x_complete; } _cli(); if (sb_card->irq >= 8) { p8259_OCW2(8,P8259_OCW2_SPECIFIC_EOI | (sb_card->irq & 7)); p8259_OCW2(0,P8259_OCW2_SPECIFIC_EOI | 2); } else if (sb_card->irq >= 0) { p8259_OCW2(0,P8259_OCW2_SPECIFIC_EOI | sb_card->irq); } _sti(); sndsb_reset_dsp(sb_card); }
int main() { struct t8254_readback_t readback; t8254_time_t tick[3]; unsigned int i; printf("8254 library test program\n"); if (!probe_8254()) { printf("Chip not present. Your computer might be 2010-era hardware that dropped support for it.\n"); return 1; } if (!probe_8259()) { printf("8259 interrupt controller not present. Your computer might be 2010-era hardware that dropped support for it.\n"); return 1; } printf("8254 base clock: %luHz\n",T8254_REF_CLOCK_HZ); speaker_rate = T8254_REF_CLOCK_HZ / 400UL; /* 400Hz */ prev_irq0 = _dos_getvect(T8254_IRQ+0x08); _dos_setvect(T8254_IRQ+0x8,irq0); _cli(); write_8254_pc_speaker(speaker_rate); write_8254_system_timer(max); _sti(); #ifdef TARGET_PC98 /* PC-98 does not have IRQ0 running by default */ p8259_unmask(T8254_IRQ); #endif while (1) { if (kbhit()) { int c = getch(); if (c == 27) break; else if (c == '-') { max -= 80; if (max > (0xFFFF-80)) max = 0xFFFF; _cli(); write_8254_system_timer(max); _sti(); } else if (c == '=') { max += 110; if (max < 110 || max > (0xFFFF-110)) max = 0xFFFF; _cli(); write_8254_system_timer(max); _sti(); } /* play with timer 2 and the PC speaker gate */ else if (c == 'p') { unsigned char on = (t8254_pc_speaker_read_gate() != 0) ? 1 : 0; if (on) t8254_pc_speaker_set_gate(0); else t8254_pc_speaker_set_gate(3); } else if (c == '1') { #ifndef TARGET_PC98 unsigned char v = t8254_pc_speaker_read_gate(); t8254_pc_speaker_set_gate(v ^ PC_SPEAKER_OUTPUT_TTL_AND_GATE); #endif } else if (c == '2') { #ifndef TARGET_PC98 unsigned char v = t8254_pc_speaker_read_gate(); t8254_pc_speaker_set_gate(v ^ PC_SPEAKER_COUNTER_2_GATE); #endif } else if (c == '[') { speaker_rate += 110; if (speaker_rate > (0xFFFF-110) || speaker_rate < 110) speaker_rate = 0xFFFF; write_8254_pc_speaker(speaker_rate); } else if (c == ']') { speaker_rate -= 110; if (speaker_rate > (0xFFFF-110)) speaker_rate = 0; write_8254_pc_speaker(speaker_rate); } else if (c == 'w') { printf("\n"); pulse_width_test(); _cli(); write_8254_system_timer(max); _sti(); printf("\n"); } else if (c == 'z') { /* sleep-wait loop test */ unsigned long delay_ticks; unsigned long z; unsigned int c,cmax; printf("\nDelay interval in us? "); z = 1000000; scanf("%lu",&z); delay_ticks = t8254_us2ticks(z); printf(" %lu = %lu ticks\n",z,delay_ticks); if (delay_ticks == 0UL) cmax = (unsigned int)(T8254_REF_CLOCK_HZ / 20UL); else cmax = (unsigned int)(T8254_REF_CLOCK_HZ / 20UL / (unsigned long)delay_ticks); if (cmax == 0) cmax = 1; write_8254_pc_speaker(T8254_REF_CLOCK_HZ / 400UL); /* tick as fast as possible */ while (1) { if (kbhit()) { if (getch() == 27) break; } for (c=0;c < cmax;c++) { t8254_pc_speaker_set_gate(3); t8254_wait(delay_ticks); t8254_pc_speaker_set_gate(0); t8254_wait(delay_ticks); } } } else if (c == 'd') { printf("\n \nDetail mode, hit 'd' again to exit: [WARNING: 8254 only]\n"); while (1) { if (kbhit()) { int c = getch(); if (c == 'd') { break; } } _cli(); readback_8254(T8254_READBACK_ALL,&readback); _sti(); printf("\x0D"); for (i=0;i <= 2;i++) { printf("[%u] stat=%02x count=%04x ",i, readback.timer[i].status, readback.timer[i].count); } fflush(stdout); } printf("\n"); } } for (i=0;i <= 2;i++) tick[i] = read_8254(i); /* BUG: DOSBox/DOSBox-X appear to have a bug where the PC speaker readback toggles * regardless of the GATE input to Counter 2. Bring GATE low (setting bit 1 * of port 61h to 0) is supposed to cause Counter 2 to stop. The AND gate * after the output (bit 0 of port 61h) is not supposed to affect the readback. */ printf("\x0D %04x %04x %04x max=%04x count=%04x SPKR=%u",tick[0],tick[1],tick[2], max,counter,read_8254_pc_speaker_output()!=0?1:0); fflush(stdout); } printf("\n"); #ifdef TARGET_PC98 /* PC-98 does not have IRQ0 running by default */ p8259_mask(T8254_IRQ); #endif _cli(); write_8254_pc_speaker(0); t8254_pc_speaker_set_gate(0); _dos_setvect(T8254_IRQ+0x8,prev_irq0); _sti(); write_8254_system_timer(0xFFFF); /* restore normal function to prevent BIOS from going crazy */ return 0; }