Chinaunix首页 | 论坛 | 博客
  • 博客访问: 5699938
  • 博文数量: 675
  • 博客积分: 20301
  • 博客等级: 上将
  • 技术积分: 7671
  • 用 户 组: 普通用户
  • 注册时间: 2005-12-31 16:15
文章分类

全部博文(675)

文章存档

2012年(1)

2011年(20)

2010年(14)

2009年(63)

2008年(118)

2007年(141)

2006年(318)

分类: LINUX

2008-08-14 18:21:58

已经有好几个人问过我这个问题了,之前的时候,LKMP中有一个例子来使用定时器在内核态来使得键盘灯闪烁,今天分析了一下那个module代码,发现其使用了ioctl,也就意味着在用户态使用ioctl将会调用驱动中的ioctl,具有一样的效果。

分析一下那个驱动:
/* 
* kbleds.c - Blink keyboard leds until the module is unloaded.
*/

#include
#include
#include
#include /* For fg_console, MAX_NR_CONSOLES */
#include /* For KDSETLED */
#include /* For vc_cons */

MODULE_DESCRIPTION("Example module illustrating the use of Keyboard LEDs.");
MODULE_AUTHOR("Daniele Paolo Scarpazza");
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->ioctl) (vc_cons[fg_console].d->vc_tty, NULL, 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->vc_tty);
}
printk(KERN_INFO "kbleds: finished scanning consoles\n");

my_driver = vc_cons[fg_console].d->vc_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->ioctl) (vc_cons[fg_console].d->vc_tty, NULL, KDSETLED,
RESTORE_LEDS);
}

module_init(kbleds_init);
module_exit(kbleds_cleanup);

这种方法是通过调用虚拟终端驱动中的ioctl函数,我们完全可以在用户空间open一个虚拟终端,然后对得到的fd进行ioctl。
查找ioctl相关资料,发现ioctl对于虚拟终端fd,支持一个KDSETLED命令字,这样用这个命令字就可以设置三个键盘灯的状态了。
#include
#include
#include
#include
#include
#include
#include
#include

#define ERROR -1

int fd; /* File descriptor for console (/dev/tty/) */

void sighandler(int signum);

void main()
{
int i;

/* To be used as the fd in ioctl(). */
if ((fd = open("/dev/console", O_NOCTTY)) == ERROR) {
perror("open");
exit(ERROR);
}

signal(SIGINT, sighandler);
signal(SIGTERM, sighandler);
signal(SIGQUIT, sighandler);
signal(SIGTSTP, sighandler);

printf("w00w00!\n\n");
printf("To exit hit Control-C.\n");

while (1) {
for (i = 0x01; i <= 0x04; i++) {
/* We do this because there is no LED for 0x03. */
if (i == 0x03) continue;

usleep(50000);

if ((ioctl(fd, KDSETLED, i)) == ERROR) {
perror("ioctl");
close(fd);
exit(ERROR);
}
}
}

close(fd);
}

void sighandler(int signum)
{
/* Turn off all leds. No LED == 0x0. */
if ((ioctl(fd, KDSETLED, 0x0)) == ERROR) {
perror("ioctl");
close(fd);
exit(ERROR);
}

printf("\nw00w00!\n");
close(fd);
exit(0);
}

参考:
http://www.net-security.org/article.php?id=83&p=1




阅读(1810) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~