当前位置:嗨网首页>书籍在线阅读

13-实例_秒字符设备

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

10.5.3 实例:秒字符设备

下面我们编写一个字符设备“second”(即“秒”)的驱动,它在被打开的时候初始化一个定时器并将其添加到内核定时器链表,每秒输出一次当前的jiffies(为此,定时器处理函数中每次都要修改新的expires),整个程序如代码清单10.11所示。

代码清单10.12 使用内核定时器的second字符设备驱动

1 #include <linux/module.h>

2 #include <linux/types.h>

3 #include <linux/fs.h>

4 #include <linux/errno.h>

5 #include <linux/mm.h>

6 #include <linux/sched.h>

7 #include <linux/init.h>

8 #include <linux/cdev.h>

9 #include <asm/io.h>

10 #include <asm/system.h>

11 #include <asm/uaccess.h>

12

13 #define SECOND_MAJOR 248 /预设的second的主设备号/

14

15 static int second_major = SECOND_MAJOR;

16

17 /second设备结构体/

18 struct second_dev {

19 struct cdev cdev; /cdev结构体/

20 atomic_t counter;/ 一共经历了多少秒?/

21 struct timer_list s_timer; /设备要使用的定时器/

22 };

23

24 struct second_dev second_devp; /设备结构体指针*/

25

26 /定时器处理函数/

27 static void second_timer_handle(unsigned long arg)

28 {

29 mod_timer(&second_devp->s_timer,jiffies + Hz);

30 atomic_inc(&second_devp->counter);

31

32 printk(KERN_NOTICE "current jiffies is %ld\n", jiffies);

33 }

34

35 /文件打开函数/

36 int second_open(struct inode inode, struct file filp)

37 {

38 /初始化定时器/

39 init_timer(&second_devp->s_timer);

40 second_devp->s_timer.function = &second_timer_handle;

41 second_devp->s_timer.expires = jiffies + Hz;

42

43 add_timer(&second_devp->s_timer); /添加(注册)定时器/

44

45 atomic_set(&second_devp->counter,0); //计数清0

46

47 return 0;

48 }

49 /文件释放函数/

50 int second_release(struct inode inode, struct file filp)

51 {

52 del_timer(&second_devp->s_timer);

53

54 return 0;

55 }

56

57 /读函数/

58 static ssize_t second_read(struct file filp, char - -user buf, size_t count,

59 loff_t *ppos)

60 {

61 int counter;

62

63 counter = atomic_read(&second_devp->counter);

64 if(put_user(counter, (int*)buf))

65 return - EFAULT;

66 else

67 return sizeof(unsigned int);

68 }

69

70 /文件操作结构体/

71 static const struct file_operations second_fops = {

72 .owner = THIS_MODULE,

73 .open = second_open,

74 .release = second_release,

75 .read = second_read,

76 };

77

78 /初始化并注册cdev/

79 static void second_setup_cdev(struct second_dev *dev, int index)

80 {

81 int err, devno = MKDEV(second_major, index);

82

83 cdev_init(&dev->cdev, &second_fops);

84 dev->cdev.owner = THIS_MODULE;

85 err = cdev_add(&dev->cdev, devno, 1);

86 if (err)

87 printk(KERN_NOTICE "Error %d adding LED%d", err, index);

88 }

89

90 /设备驱动模块加载函数/

91 int second_init(void)

92 {

93 int ret;

94 dev_t devno = MKDEV(second_major, 0);

95

96 / 申请设备号/

97 if (second_major)

98 ret = register_chrdev_region(devno, 1, "second");

99 else { / 动态申请设备号 /

100 ret = alloc_chrdev_region(&devno, 0, 1, "second");

101 second_major = MAJOR(devno);

102 }

103 if (ret < 0)

104 return ret;

105 / 动态申请设备结构体的内存/

106 second_devp = kmalloc(sizeof(struct second_dev), GFP_KERNEL);

107 if (!second_devp) { /申请失败/

108 ret = - ENOMEM;

109 goto fail_malloc;

110 }

111

112 memset(second_devp, 0, sizeof(struct second_dev));

113

114 second_setup_cdev(second_devp, 0);

115

116 return 0;

117

118 fail_malloc:

119 unregister_chrdev_region(devno, 1);

120 return ret;

121 }

122

123 /模块卸载函数/

124 void second_exit(void)

125 {

126 cdev_del(&second_devp->cdev); /注销cdev/

127 kfree(second_devp); /释放设备结构体内存/

128 unregister_chrdev_region(MKDEV(second_major, 0), 1); /释放设备号/

129 }

130

131 MODULE_AUTHOR("Barry Song [email protected]");

132 MODULE_LICENSE("Dual BSD/GPL");

133

134 module_param(second_major, int, S_IRUGO);

135

136 module_init(second_init);

137 module_exit(second_exit);

在second的open()函数中,将启动定时器,此后每1s会再次运行定时器处理函数,在second 的release()函数中,定时器被删除。

second_dev结构体中的原子变量counter用于秒计数,每次在定时器处理函数中将被atomic_inc()调用原子的增1,second的read()函数会将这个值返回给用户空间。

/home/lihacker/develop/svn/ldd6410-read-only/training/kernel/drivers/second包含了second设备驱动以及second_test.c用户空间测试程序,运行make命令编译得到second.ko和second_test,加载second.ko内核模块并创建“/dev/second”设备文件结点:

root@lihacker-laptop:/home/lihacker/develop/svn/ldd6410-read-only/training/kernel/d

rivers/second# mknod /dev/second c 248 0

代码清单10.13给出了second_test.c这个应用程序,它打开“/dev/second”,其后不断地读取自打开“/dev/second”设备文件以来经历的秒数。

代码清单10.13 second设备用户空间测试程序

1 #include ...

2

3 main()

4 {

5 int fd;

6 int counter = 0;

7 int old_counter = 0;

8

9 /打开/dev/second设备文件/

10 fd = open("/dev/second", O_RDONLY);

11 if (fd != - 1) {

13 while (1) {

15 read(fd,&counter, sizeof(unsigned int));/ 读目前经历的秒数 /

16 if(counter!=old_counter) {

18 printf("seconds after open /dev/second :%d\n",counter);

19 old_counter = counter;

20 }

21 }

22 } else {

25 printf("Device open failure\n");

26 }

27 }

运行second_test后,内核将不断地输出目前的jiffies值:

[44335.554313] current jiffies is 11008888

[44336.553166] current jiffies is 11009138

[44337.553175] current jiffies is 11009388

[44338.552383] current jiffies is 11009638

[44339.552321] current jiffies is 11009888

...

而应用程序将不断输出自打开/dec/second以来经历的秒数:

root@lihacker-laptop:/home/lihacker/develop/svn/ldd6410-read-only/training/kernel/d

rivers/second# ./second_test

seconds after open /dev/second :1

seconds after open /dev/second :2

seconds after open /dev/second :3

seconds after open /dev/second :4

seconds after open /dev/second :5

...