// Tap module, just for fun, Version 0.9 // // Usage, // Compile using // gcc -c tap.c -o tap.o -I/lib/modules/`uname -r`/build/include // // Use: // // insmod ./tap.o // mknod /dev/water c 200 1 // cat /dev/water // // Removal // // rm /dev/water // rmmod tap // // Beau Kuiper Copyright (C) 2001 // Parts derived from devices/mm/mem.c from linux kernel // Licensed under GPL 2.0 #define MODULE #define __KERNEL__ #include #include #include #include #include #include #include #include #include #include #include #include #include #include devfs_handle_t waterdev; int water_pos; #define WATER_MAJ 200 #define WATER_MIN 1 static loff_t water_lseek(struct file * file, loff_t offset, int orig) { return file->f_pos = 0; } static size_t water_read(struct file * file, char * buf, size_t count, loff_t *ppos) { unsigned long left, pos; if (!access_ok(VERIFY_WRITE, buf, count)) return -EFAULT; left = count; pos = 0; while(pos < count) { strncpy(buf + pos, "WaterWater" + water_pos, min(left, (unsigned long)5)); pos += min(left, (unsigned long)5); left -= 5; } water_pos += pos % 5; water_pos = water_pos % 5; return count; } static size_t water_write(struct file * file, char * buf, size_t count, loff_t *ppos) { return -EINVAL; } static struct file_operations water_fops = { llseek: water_lseek, read: water_read, write: water_write, }; static int water_open(struct inode * inode, struct file * filp) { switch (MINOR(inode->i_rdev)) { case WATER_MIN: filp->f_op = &water_fops; break; default: return -ENXIO; } return(0); } static struct file_operations water_meta_fops = { open: water_open, }; int init_module(void) { if (devfs_register_chrdev(WATER_MAJ ,"tap",&water_meta_fops)) { printk("unable to get major %d for memory devs\n", WATER_MAJ); return -1; } waterdev = devfs_register(NULL, "water", DEVFS_FL_NONE, WATER_MAJ, WATER_MIN, S_IRUGO | S_IWUGO | S_IFCHR, &water_fops, NULL); water_pos = 0; return 0; } void cleanup_module(void) { devfs_unregister_chrdev(WATER_MAJ, "tap"); devfs_unregister(waterdev); }