#include <stdio.h>
#include <fcntl.h>
#include <termios.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include <linux/mm.h>

#ifndef DELAY
#define DELAY 20
#endif

/* this sets the *default* volume. */
/* use the -v command-line option to adjust it for individual plays */
#ifndef VOLUME
#define VOLUME 50
#endif

static void inline port_out(char value, unsigned short port)
{
__asm__ volatile ("outb %0,%1"
		::"a" ((char) value),"d" ((unsigned short) port));
}
static unsigned char inline port_in(unsigned short port)
{
	unsigned char _v;
__asm__ volatile ("inb %1,%0"
		:"=a" (_v):"d" ((unsigned short) port));
	return _v;
}

extern int ulaw2linear();	/* from ulaw.c */
extern void usage_exit();	/* from usage.c */

void main()
{
unsigned char a,b,e,i;
unsigned short j, ulaw[256];
short l;
int c;

/* Check permissions */
if (ioperm(0x61,1,1)||ioperm(0x42,1,1)||ioperm(0x43,1,1)) {
    printf("can't get I/O permissions for internal speaker\n");
    exit(-1);
}

/* *Real* U-LAW this time, but still no volume control */
for(l=0;l<256;l++) {
    ulaw[l]=(unsigned short)(ulaw2linear(l)/256);
}

b=0x33;	/* 33? 0x33? Why? I dunno. I suppose it has to be SOMETHING. */
e=port_in(0x61)|0x03;
port_out(0x92,0x43);
port_out(b,0x42);
while(l!=EOF) {
    a=b;
    l=getchar();
    b=ulaw[l&0xff];
    for(j=1;j<DELAY;j++);
    port_out(e,0x61);
    port_out(e-1,0x61);
    port_out((a+b)>>1,0x42);
    for(j=1;j<DELAY;j++);
    port_out(e,0x61);
    port_out(e-1,0x61);
    port_out(b,0x42);

} /* while not EOF */

} /* main */
