#include <linux/module.h>
int lpv_busy = LPV_FREE;
struct wait_queue *lpv_wait_q;
// Interrupt Handler
// Just wake up the read...
}
static int lpv_open(struct inode * inode, struct file * file)
if (minor != 0)
lpv_busy = LPV_BUSY;
// Register irq7
// Port 0x21 -> interrupt mask (write 0 to bit 7 to
// Tell the PC the irq has been processed
// Set LPV_0 to 1 (to get Vcc for the irq7)
sti();
printk("lpv: open concluded.\n");
return 0;
static int lpv_read(struct inode * inode, struct file * file,
if (count != 1) return -EINVAL;
// Sleep until interrupt wakes it up
return 0;
static int lpv_write(struct inode * inode, struct file * file,
temp=buf;
while(count>0){
return temp-buf;
}
static int lpv_ioctl(struct inode * inode, struct file * file,
static void lpv_release(struct inode * inode, struct file * file)
// Port 0x21 -> interrupt mask (write 1 to bit 7 to
free_irq(irq7,NULL);
sti();
lpv_busy = LPV_FREE;
printk("lpv: device released.\n");
}
static struct file_operations lpv_fops = {
int init_module( void)
// Initialize the chip
// Register the device driver with the system
return 0;
void cleanup_module( void)
}
//
// lpv.c
//
// Create the device with:
// mknod /dev/lpv c 32 0
//
#include <linux/mm.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/sched.h>
#include <linux/malloc.h>
#include <linux/ioport.h>
#include <linux/fcntl.h>
#include <linux/delay.h>
#include <time.h>
#include <asm/io.h>
#include <asm/segment.h>
#include <asm/system.h>
#include <sys/ioctl.h>
#include "lpv.h"
int irq7 = 7;
int irq7_flag = 0;
void lpv_irq7(int irq7) {
wake_up(&lpv_wait_q);
{
unsigned int minor = MINOR(inode->i_rdev);
int ret_code;
return -ENODEV;
if (lpv_busy == LPV_BUSY)
return -EBUSY;
cli();
ret_code = request_irq(irq7,(void *)lpv_irq7,
SA_INTERRUPT,"lpv",NULL);
if(ret_code) {
printk("lpv: unable to use irq7.\n");
} else {
printk("lpv: irq7 registered.\n");
}
// enable irq7 - Do not modify the others!!)
outb(inb(0x21)&(~0x80),0x21);
outb(0x20,0x20);
outb(inb(LPV)|0x01,LPV);
}
char * buf, int count)
{
interruptible_sleep_on(&lpv_wait_q);
}
const char * buf, int count)
{
char c;
const char *temp;
c=get_user(temp); /* Get next char */
outb(c|0x01,LPV); /* Send it to the LPV */
count--;
temp++;
}
unsigned int cmd, unsigned long arg)
{
switch(cmd) {
case LPV_IRQ:
// Toggle bit 4 of Control Port
// 1: irq enabled, 0: disabled
if(arg==LPV_ENABLE) {
outb(inb(LPVC)|0x10,LPVC);
printk("lpv: irq7 enabled.\n");
return 0;
}
else if(arg==LPV_DISABLE) {
outb(inb(LPVC)&(~0x10),LPVC);
printk("lpv: irq7 disabled.\n");
return 0;
}
else {
return -EINVAL;
}
break;
default:
return -EINVAL;
}
}
{
cli();
// disable irq7 - Do not modify the others!!)
outb(inb(0x21)|(0x80),0x21);
NULL, /* seek */
lpv_read, /* read */
lpv_write, /* write */
NULL, /* readdir */
NULL, /* select */
lpv_ioctl, /* control */
NULL, /* mmap */
lpv_open, /* open */
lpv_release /* release */
};
{
// Debug
printk("lpv: init_module called.\n");
outb(0, LPV);
if (register_chrdev(LPV_MAJOR, "lpv", &lpv_fops)) {
printk(KERN_ERR "lpv: register_chrdev failed.\n");
return -EIO;
}
else
// Debug
printk("lpv: driver registered.\n");
}
{
if (lpv_busy)
// Debug
printk("lpv: device busy, remove delayed.\n");
if (unregister_chrdev(LPV_MAJOR, "lpv") != 0) {
// Debug
printk("lpv: cleanup_module failed.\n");
}
else
// Debug
printk("lpv: cleanup_module succeeded.\n");