让键盘灯闪烁的驱动程序
#include
#include
#include
#include
#include
#include
#include
MODULE_LICENSE("GPL");
struct timer_list my_timer;
struct tty_driver *my_driver;
struct cdev *char_dev;
unsigned long led_seq = 1;
#define BLINK_DELAY HZ/5
#define LED_FIRST 0x02
#define LED_SECOND 0x04
#define LED_THIRD 0x01
#define LED_ALL 0x07
#define RESTORE_LEDS 0xFF
#define LED_LIGHT 0x01
#define LED_DARK 0x02
static void my_timer_func(unsigned long ptr)
{
if(ptr == 1){
(my_driver->ioctl)(vc_cons[fg_console].d->vc_tty,NULL,KDSETLED,RESTORE_LEDS);
(my_driver->ioctl)(vc_cons[fg_console].d->vc_tty,NULL,KDSETLED,LED_FIRST);
led_seq = 2;
my_timer.data = led_seq;
my_timer.expires = jiffies + BLINK_DELAY;
add_timer(&my_timer);
}
if(ptr == 2){
(my_driver->ioctl)(vc_cons[fg_console].d->vc_tty,NULL,KDSETLED,RESTORE_LEDS);
(my_driver->ioctl)(vc_cons[fg_console].d->vc_tty,NULL,KDSETLED,LED_SECOND);
led_seq = 3;
my_timer.data = led_seq;
my_timer.expires = jiffies + BLINK_DELAY;
add_timer(&my_timer);
}
if(ptr == 3)
{
(my_driver->ioctl)(vc_cons[fg_console].d->vc_tty,NULL,KDSETLED,RESTORE_LEDS);
(my_driver->ioctl)(vc_cons[fg_console].d->vc_tty,NULL,KDSETLED,LED_SECOND);
led_seq = 1;
my_timer.data = led_seq;
my_timer.expires = jiffies + BLINK_DELAY;
add_timer(&my_timer);
}
}
static int device_open(struct inode *inode,struct file *file)
{
int i;
for(i=0; i if(!vc_cons[i].d)
break;
}
my_driver = vc_cons[fg_console].d->vc_tty->driver;
init_timer(&my_timer);
my_timer.fucction = my_timer_func;
my_timer.data = led_seq;
my_timer.expires = jiffies + BLINK_DELAY;
add_timer(&my_timer);
return 0;
}
static int device_release(struct inode *inode,struct file *file)
{
del_timer(&my_timer);
return 0;
}
static ssize_t device_read(struct file *file,char * buf,size_t count,loff_t *ppos)
{
return 0;
}
static ssize_t device_write(struct file *file,char * buf,size_t count,loff_t *ppos)
{
return 0;
}
static int device_ioctl(struct inode *inode,struct file *file,unsigned int cmd,unsigned long arg)
{
switch(cmd){
case LED_LIGHT:
(my_driver->ioctl)(vc_cons[fg_console].d->vc_tty,NULL,KDSETLED,LED_ALL);
break;
case LED_DARK:
(my_driver->ioctl)(vc_cons[fg_console].d->vc_tty,NULL,KDSETLED,RESTORE_LEDS);
break;
default:break;
}
return 0;
}
struct file_operations device_ops = {
.owner = THIS_MODULE,
.llseek = NULL,
.read = device_read,
.write = device_write,
.readdir = NULL,
.poll = NULL,
.ioctl = device_ioctl,
.mmap = NULL,
.open = device_open,
.flush = NULL,
.release = device_release,
.fsync = NULL,
.fasync = NULL,
.lock = NULL,
.readv = NULL,
.writev = NULL,
}
static int __init kbleds_init(void)
{
int i,ret;
int chardev_major;
dev_t dev = 0;
ret = alloc_chrdev_region(&dev,0,1,"char_dev");
chardev_major = MAJOR(dev);
if(ret < 0)
printk(KERN_WARNING "alloction device number failed./n");
printk("char_dev major number:%d/n",chardev_major);
char_dev = cdev_alloc();
cdev_init(char_dev,&device_ops);
cdev_add(char_dev,dev,1);
for(i=0; i if(!vc_cons[i].d)
break;
}
my_driver = vc_cons[fg_console].d->vc_tty->driver;
return 0;
}
static void __exit kbleds_cleanup(void)
{
cdev_del(char_dev);
unregister_chardev_region(dev,1);
(my_driver->ioctl)(vc_cons[fg_console].d->vc_tty,NULL,KDSETLED,RESTORE_LEDS);
}
module_init(kbleds_init);
module_exit(kbleds_cleanup);