kbleds.c for linux kernel version 3.7.5

The example of blinking led given at “http://www.tldp.org/LDP/lkmpg/2.6/html/lkmpg.html#AEN1201 ” works fine for kernel versions before 2.6.36, but for version above that it fails to compile due the changes in the structure vc_data and ioctl call of tty_driver.

Here is the modified code tested and working on 3.7.5.

The changes are

1. change the the vc_tty pointer to port.tty

vc_cons[fg_console].d->vc_tty to vc_cons[fg_console].d->port.tty

2. Remove the argument “NULL” being passed to the ioctl call of tty driver.

(my_driver->ops->ioctl) (vc_cons[fg_console].d->port.tty, NULL, KDSETLED,*pstatus); to (my_driver->ops->ioctl) (vc_cons[fg_console].d->port.tty, KDSETLED, *pstatus);

Full code:

/* * kbleds.c − Blink keyboard leds until the module is unloaded.(modified for 3.7.5) */ #include #include #include #include /* For fg_console, MAX_NR_CONSOLES */ #include /* For KDSETLED */ #include #include /* For vc_cons */ #include MODULE_DESCRIPTION(“Example module illustrating the use of Keyboard LEDs.”); MODULE_LICENSE(“GPL”); struct timer_list my_timer; struct tty_driver *my_driver; char kbledstatus = 0; #define BLINK_DELAY HZ/5 #define ALL_LEDS_ON 0x07 #define RESTORE_LEDS 0xFF /* * Function my_timer_func blinks the keyboard LEDs periodically by invoking * command KDSETLED of ioctl() on the keyboard driver. To learn more on virtual * terminal ioctl operations, please see file: * /usr/src/linux/drivers/char/vt_ioctl.c, function vt_ioctl(). * * The argument to KDSETLED is alternatively set to 7 (thus causing the led * mode to be set to LED_SHOW_IOCTL, and all the leds are lit) and to 0xFF * (any value above 7 switches back the led mode to LED_SHOW_FLAGS, thus * the LEDs reflect the actual keyboard status). To learn more on this, * please see file: * /usr/src/linux/drivers/char/keyboard.c, function setledstate(). * */ static void my_timer_func(unsigned long ptr) { int *pstatus = (int *)ptr; if (*pstatus == ALL_LEDS_ON) *pstatus = RESTORE_LEDS; else *pstatus = ALL_LEDS_ON; (my_driver->ops->ioctl) (vc_cons[fg_console].d->port.tty, KDSETLED, *pstatus); my_timer.expires = jiffies + BLINK_DELAY; add_timer(&my_timer); } static int __init kbleds_init(void) { int i; printk(KERN_INFO “kbleds: loading\n”); printk(KERN_INFO “kbleds: fgconsole is %x\n”, fg_console); for (i = 0; i < MAX_NR_CONSOLES; i++) { if (!vc_cons[i].d) break; printk(KERN_INFO "poet_atkm: console[%i/%i] #%i, tty %lx\n", i, MAX_NR_CONSOLES, vc_cons[i].d->vc_num, (unsigned long)vc_cons[i].d->port.tty); } printk(KERN_INFO “kbleds: finished scanning consoles\n”); my_driver = vc_cons[fg_console].d->port.tty->driver; printk(KERN_INFO “kbleds: tty driver magic %x\n”, my_driver->magic); /* * Set up the LED blink timer the first time */ init_timer(&my_timer); my_timer.function = my_timer_func; my_timer.data = (unsigned long)&kbledstatus; my_timer.expires = jiffies + BLINK_DELAY; add_timer(&my_timer); return 0; } static void __exit kbleds_cleanup(void) { printk(KERN_INFO “kbleds: unloading…\n”); del_timer(&my_timer); (my_driver->ops->ioctl) (vc_cons[fg_console].d->port.tty, KDSETLED, RESTORE_LEDS); } module_init(kbleds_init); module_exit(kbleds_cleanup);

Now save the file as kbleds.c

Compile it using the makefile

obj-m += kbleds.o all: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules clean: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

Insert it into the kernel using insmod

$ insmod kbleds.ko

The key board leds should start to blink as soon as the module is inserted and will continue to blink as long as we do not remove the module using rmmmod

$ rmmmod kbleds

or reboot the system.

Tags: ,
Copyright 2017. All rights reserved.

Posted February 13, 2013 by Tux Think in category "Linux