/* * amu_module.c is based on procfs_example.c by Erik Mouw. * For more information, please see The Linux Kernel Procfs Guide, * http://kernelnewbies.org/documents/kdoc/procfs-guide/lkprocfsguide.html * * J.J. Boor, AimSys bv * http://www.aimsys.nl * jjboor@aimsys.nl */ /* ${CROSS_COMPILE}gcc -O2 -D__KERNEL__ -DMODULE amu_timer.c -o amu_timer.o */ #include #include #include #include #include #include #define TICK_MAJOR 241 #define MODULE_VERSION "0.1" #define MODULE_NAME "timer" static struct proc_dir_entry *timer_file; static struct timer_list timer; static unsigned long tick_count = 0; static int timer_delay = 1; DECLARE_WAIT_QUEUE_HEAD(timer_queue); int timer_open(struct inode* inode, struct file* filp); ssize_t timer_read (struct file *filp, char *buf, size_t count, loff_t *f_pos); int timer_release(struct inode* inode, struct file* filp); static struct file_operations timer_fops = { open: timer_open, read: timer_read, release: timer_release }; static int proc_read_timer(char *page, char **start, off_t off, int count, int *eof, void *data) { int len; len = sprintf(page, "nr of timer ticks: %lu\n", tick_count); return len; } static int proc_write_timer(struct file *file, const char *buffer, unsigned long count, void *data) { return 0; } void timerEvent(unsigned long arg) { tick_count++; wake_up_interruptible(&timer_queue); timer.expires= jiffies + timer_delay; add_timer(&timer); } int __init init_timer_module(void) { /* Create the proc entry and make it readable and writeable by all - 0666 */ timer_file = create_proc_entry("timer", 0666, NULL); if (timer_file == NULL) { return -ENOMEM; } /* Set timer_file fields */ timer_file->read_proc = &proc_read_timer; timer_file->write_proc = &proc_write_timer; timer_file->owner = THIS_MODULE; SET_MODULE_OWNER(&timer_fops); /* register /dev/tick */ register_chrdev(TICK_MAJOR, "tick", &timer_fops); init_timer(&timer); timer.expires= jiffies + timer_delay; timer.function=timerEvent; timer.data=42; add_timer(&timer); /* everything initialized */ printk(KERN_INFO "%s %s initialized\n", MODULE_NAME, MODULE_VERSION); return 0; } static void __exit cleanup_timer_module(void) { del_timer(&timer); remove_proc_entry("timer", NULL); unregister_chrdev(TICK_MAJOR, "tick"); printk(KERN_INFO "%s %s removed\n", MODULE_NAME, MODULE_VERSION); } int timer_open(struct inode* inode, struct file* filp) { return 0; } int timer_release(struct inode* inode, struct file* filp) { return 0; } ssize_t timer_read (struct file *filp, char *buf, size_t count, loff_t *f_pos) { /* dummy read to wait on kernel timer */ while (1) { interruptible_sleep_on(&timer_queue); if (signal_pending (current)) /* a signal arrived */ return -ERESTARTSYS; /* tell the fs layer to handle it */ else break; } return 0; } #ifdef MODULE /* here are the compiler macros for module operation */ module_init(init_timer_module); module_exit(cleanup_timer_module); #endif MODULE_AUTHOR("J.J. Boor, AimSys bv"); MODULE_DESCRIPTION("timer module"); MODULE_LICENSE("GPL"); EXPORT_NO_SYMBOLS;