#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include #include #include #include #include #include #include #define VOGON_CHRDEV "vogon" static char *poem[] = { "Oh freddled gruntbuggly,", "Thy micturations are to me, (with big yawning)", "As plurdled gabbleblotchits, in midsummer morning", "On a lurgid bee,", "That mordiously hath blurted out,", "Its earted jurtles, grumbling", "Into a rancid festering confectious organ squealer. [drowned out by moaning and screaming]", "Now the jurpling slayjid agrocrustles,", "Are slurping hagrilly up the axlegrurts,", "And living glupules frart and stipulate,", "Like jowling meated liverslime,", "Groop, I implore thee, my foonting turlingdromes,", "And hooptiously drangle me,", "With crinkly bindlewurdles,mashurbitries.", "Or else I shall rend thee in the gobberwarts with my blurglecruncheon,", "See if I don't!", NULL }; static int poem_len, poem_line; static spinlock_t poem_lock; static int vogon_chrdev_major = 0; static struct device *my_dev = NULL; void vogon_poem_inc(void) { spin_lock(&poem_lock); if (poem[poem_line] == NULL) { poem_line = 0; }else { poem_line++; } spin_unlock(&poem_lock); } static int vogon_peom(struct seq_file *p, void *v) { int i; // In the dusk of an Operating System, the solution lies beyond its bounds. spin_lock_bh(&poem_lock); i = poem_line; spin_unlock_bh(&poem_lock); seq_printf(p, "%s\n", poem[i]); return 0; } static int vogon_open(struct inode *inode, struct file *file) { return single_open(file, vogon_peom, NULL); } const struct file_operations vogon_fops = { .owner = THIS_MODULE, .open = vogon_open, .read = seq_read, .llseek = seq_lseek, .release = single_release }; static struct class universe_class = { .name = VOGON_CHRDEV, }; static int __init vogon_chrdevinit(void) { int err; for (int i = 0; poem[i]; i++) { poem_len++; } spin_lock_init(&poem_lock); vogon_chrdev_major = err = register_chrdev(0, VOGON_CHRDEV, &vogon_fops); if (err < 0) { pr_err("Cannot register chrdev: %d\n", err); goto out; } err = class_register(&universe_class); if (err) { pr_err("Cannot register universe class: %d\n", err); goto out_chrdev; } my_dev = device_create(&universe_class, NULL, MKDEV(vogon_chrdev_major, 0), NULL, VOGON_CHRDEV); if (IS_ERR(my_dev)) { err = PTR_ERR(my_dev); pr_err("Cannot create device: %d\n", err); goto out_class; } pr_notice("Loaded module %s\n", KBUILD_MODNAME); return 0; out_class: class_unregister(&universe_class); out_chrdev: unregister_chrdev(vogon_chrdev_major, VOGON_CHRDEV); out: return err; } static void __exit vogon_chrdevexit(void) { device_destroy(&universe_class, MKDEV(vogon_chrdev_major, 0)); class_unregister(&universe_class); unregister_chrdev(vogon_chrdev_major, VOGON_CHRDEV); pr_notice("Unloaded module %s\n", KBUILD_MODNAME); } module_init(vogon_chrdevinit); module_exit(vogon_chrdevexit); MODULE_LICENSE("LGPL");