#include <linux/module.h>
#include <linux/version.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <asm/io.h>

MODULE_LICENSE("GPL");

static ssize_t DriverWrite( struct file *File, 
    __user const char *User, size_t count, loff_t *Offs)
{
    u16 tone;
    u8 Save;
    char buffer[6];

    if( count > sizeof(buffer) )
	count = sizeof(buffer);
    copy_from_user( buffer, User, count );
    buffer[sizeof(buffer)-1] = '\0';
    tone = (u16) simple_strtoul( buffer, NULL, 0 );
    if( tone ) {
	tone = CLOCK_TICK_RATE/tone;
	outb( 0xb6, 0x43 ); // Mode 3: Generiere Rechteck
	outb_p(tone & 0xff, 0x42);
	outb((tone>>8) & 0xff, 0x42);
	Save = inb( 0x61 );
	outb( Save | 0x03, 0x61 );
    } else {
	outb(inb_p(0x61) & 0xFC, 0x61);
    }
    return count;
}

static struct file_operations Fops = {
    .owner=THIS_MODULE,
    .write=DriverWrite,
};

static int __init BufInit(void)
{
    if(register_chrdev(240, "PC-Speaker", &Fops) == 0)
	return 0;
    return -EIO;
}

static void __exit BufExit(void)
{
    outb(inb_p(0x61) & 0xFC, 0x61);
    unregister_chrdev(240,"PC-Speaker");
}

module_init( BufInit );
module_exit( BufExit );
