//------------------------------------------------------------------- // timedfoo.c // // This is an enhancement of our 'foo.c' device-driver. It // uses a kernel timer to curtail the frequency of calls to // its 'read()' function, by putting any task to sleep that // tries to reread from the device-file without waiting for // at least one-tenth of a second (as 'watchfoo.cpp' does). // // programmer: ALLAN CRUSE // written on: 20 MAR 2005 //------------------------------------------------------------------- #include // for init_module() #include // for register_chrdev() #include // for copy_to_user() #include // for init_timer() char modname[] = "foo"; int mymajor = 96; struct timer_list mytimer; struct foo_data { int ready; wait_queue_head_t wq; } mydata; void mytimeraction( unsigned long data ) { struct foo_data *datap = (struct foo_data*)data; datap->ready = 1; wake_up_interruptible( &datap->wq ); } ssize_t myread( struct file *file, char *buf, size_t count, loff_t *pos ) { void *from = (void*)&jiffies_64; while ( !mydata.ready ) { //printk( "going to sleep... (ready=%d) \n", mydata.ready ); if ( wait_event_interruptible( mydata.wq, mydata.ready ) ) return -ERESTARTSYS; //printk( "awoke! (ready=%d) \n", mydata.ready ); } mydata.ready = 0; if ( count > 8 ) count = 8; if ( copy_to_user( buf, from, count ) ) return -EFAULT; mod_timer( &mytimer, jiffies + HZ / 10 ); return count; } struct file_operations myfops = { owner: THIS_MODULE, read: myread, }; int init_module( void ) { printk( "<1>\nInstalling \'%s\' module ", modname ); printk( "(major=%d) \n", mymajor ); // initialize our timer-function's data-structure mydata.ready = 1; init_waitqueue_head( &mydata.wq ); // initialize our kernel-timer init_timer( &mytimer ); mytimer.function = mytimeraction; mytimer.data = (unsigned long)&mydata; mytimer.expires = jiffies + HZ * 2; // add our timer to the kernel's list of timers add_timer( &mytimer ); // register our device-driver with the kernel return register_chrdev( mymajor, modname, &myfops ); } void cleanup_module( void ) { printk( "<1>Removing \'%s\' module\n", modname ); // unregister our device-driver unregister_chrdev( mymajor, modname ); // remove our timer from the kernel's list del_timer_sync( &mytimer ); } MODULE_LICENSE("GPL");