/* Drive the PC Speaker and timer directly to do a 1 second beep. */
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <sys/io.h>

/* Standard Ports */
#define Timer_Control 0x43
#define Timer_Data 0x42
#define Speaker_Gate 0x61
#define CLOCK_TICK_RATE 1193182

void
speaker_on(int hertz)
{
	int count = CLOCK_TICK_RATE/hertz;

	/* Enable the counter, and attach to the speaker */
	outb_p(inb_p(Speaker_Gate) | 3, Speaker_Gate);

	/* Set up 2-byte write to timer 2 */
	outb_p(0xB6, Timer_Control);

	/* And initialise the timer */
	outb_p(count & 0xff, Timer_Data);
	outb(count >> 8, Timer_Data);
}

void
speaker_off(void)
{
	/* Disconnect timer 2 from the speaker, and disable the timer */
	outb(inb(Speaker_Gate) & ~3, Speaker_Gate);
}

int
main(void)
{
	/*
	 * {out,in}[bw]_p are implemented as the actual in or 
	 * out instruction followed by an access to port 0x80.
	 * So ask for ports 0x42, 0x43, 0x61 and 0x80 to be made
	 * available to this program.
	 */
	if (ioperm(0x61, 1, 1) == -1 || ioperm(0x42, 2, 1) == -1 || ioperm(0x80, 1, 1)) {
		fprintf(stderr, "Cannot gain access to PC speaker IO ports: %s\n", strerror(errno));
		return EXIT_FAILURE;
	}

	speaker_on(440);
	sleep(1);
	speaker_off();
	return 0;
}
