/* Compile and load the GFN driver module by using the commands, cc -Wall -O1 -c -DMODULE -D__KERNEL__ gfn3.c rmmod gfn - to remove the existing one insmod gfn.o */ #include #include #include #include #define GFN_MAJOR 60 #define BASE 0x378 #define DATAPORT (BASE) #define STATPORT (BASE+1) #define CONPORT (BASE+2) #define IRQENBIT 0x10 #define IRQBIT 0x40 static DECLARE_WAIT_QUEUE_HEAD(my_wait_queue); static ssize_t gfn_write(struct file *file, const char *buf, size_t count, loff_t *ppos) { u8 data; printk("WRITE: Waking up the process Put to sleep by READ\n"); wake_up_interruptible(&my_wait_queue); if (copy_from_user(&data, buf, sizeof(data))) return -EFAULT; printk("Data from user %x hex\n", data); outb(data, CONPORT); return 0; } static ssize_t gfn_read(struct file *file, char *buffer, size_t count, loff_t *ppos) { u8 data; data = inb(STATPORT); // read the printer status port printk("Process put to Sleep in READ\n"); // for debugging only interruptible_sleep_on(&my_wait_queue); printk("Woken up. data = %x hex\n", data); // for debugging only // transfer data from kernel address space to user address space if(copy_to_user( buffer, &data, sizeof(u8))) return -EFAULT; return 0; } static int gfn_open(struct inode * inode, struct file * file) { printk("GFN open: Usage = %d\n", MOD_IN_USE); MOD_INC_USE_COUNT; return 0; } static int gfn_release(struct inode * inode, struct file * file) { MOD_DEC_USE_COUNT; printk("GFN release: Usage = %d\n", MOD_IN_USE); return 0; } struct file_operations gfn_fops = { owner: THIS_MODULE, open: gfn_open, release: gfn_release, write: gfn_write, read: gfn_read }; int init_module(void) { if (register_chrdev(GFN_MAJOR,"gfn",&gfn_fops)) { printk("gfn: Failed to get major %d\n", GFN_MAJOR); return -EIO; } printk("Registered device gfn: major %d\n",GFN_MAJOR); return 0; } void cleanup_module(void) { printk("Freed resources: MOD_IN_USE = %d\n", MOD_IN_USE); unregister_chrdev(GFN_MAJOR,"gfn"); printk("Unregistered device gfn: major %d\n",GFN_MAJOR); }