《Linux设备设备驱动程序(第三版)》学习笔记之三: sleepy 设备的使用
By: 吴垠 Date: 2007-07-05 Email: lazy.fox.wu#gmail.com Homepage: http://blog.csdn.net/wooin Copyright: 该文章版权由吴垠所有。可在非商业目的下任意传播和复制。 对于商业目的下对本文的任何行为需经作者同意。 联系方式:lazy.fox.wu#gmail.com
1. 写在前面:
a. 在进行下面的工作之前请先阅读我 的文章 《在 Linux 2.6内核下编译可以加载的内核模块》 ,配 置好可加载内核模块的Linux环境 b. 下载《Linux设备设备驱动程序(第三版)》配套的源代 码,在这里 可 以下载到,如果无法下载的话可以留言 或者给我发邮件索取。 c. 本文的工作环境是Fedora Core 5,用“uname -r”查看内核版本是:2.6.15-1.2054_FC5 d. 本文主要针对的是《Linux设备设备驱动程序(第三 版)》中第六章:高级字符设备驱动程序操作,第151页中举了个例子用来说明简单的休眠,本文记录了我对该例子的实现和运行。 e. 下文的有些操作需要root权限,所以请尽量用root用 户来执行命令。
2. 源代码包解压后进入misc-modules文件夹,其中的文件有:
[wooin@15:05 misc-modules]$ pwd /home/wooin/ldd.3rd.examples/misc-modules [wooin@15:06 misc-modules]$ ll 总计 60K -rw-r--r-- 1 wooin bao 2.1K 2005-02-01 04:31 complete.c -rw-r--r-- 1 wooin bao 2.0K 2005-02-01 04:31 faulty.c -rw-r--r-- 1 wooin bao 463 2005-02-01 04:31 hello.c -rw-r--r-- 1 wooin bao 1.2K 2005-02-01 04:31 hellop.c -rw-r--r-- 1 wooin bao 6.1K 2005-02-01 04:31 jiq.c -rw-r--r-- 1 wooin bao 7.4K 2005-02-01 04:31 jit.c -rw-r--r-- 1 wooin bao 2.3K 2005-02-01 04:31 kdataalign.c -rw-r--r-- 1 wooin bao 1.5K 2005-02-01 04:31 kdatasize.c -rw-r--r-- 1 wooin bao 987 2005-02-01 04:31 Makefile -rw-r--r-- 1 wooin bao 2.0K 2005-02-01 04:31 seq.c -rw-r--r-- 1 wooin bao 6.1K 2005-02-01 04:31 silly.c -rw-r--r-- 1 wooin bao 2.2K 2005-02-01 04:31 sleepy.c
其中sleepy.c就是本文要讲的文件,先打开该文件,将printk()函数中的“KERN_DEBUG1”改为 “KERN_ALERT”,保存退出,这是为了可以在/var/log/messages 文件中 看到调试信息。 3. 编译: 直接在misc-modules目录下运行make命令就可以编译通过,如果编译有问题请看我的这篇文章 《在 Linux 2.6内核下编译可以加载的内核模块 》 编译成功后会生成很多文件,其中有一个sleepy.ko,就是我们要的内核模块,其部分源码在《Linux设备设备驱动程序(第三 版)》中第六章:高级字符设备驱动程序操作,第151页。 4. 将设备添加到内核中去: 运行命令:
将其添加到内核中去,此时内核已经可以认出sleepy设备了,但是我们用户却无法访问,因为目前在用户空间中还没有sleepy这个设备,也就是说在 /dev/中还没有sleepy设备,需要我们手动添加。首先查看 /proc/devices文件找到sleepy设备,并找到其主设备号,比如:
[root@FOX misc-modules]# cat /proc/devices Character devices: 1 mem 4 /dev/vc/0 4 tty 4 ttyS : : 180 usb 189 usb_device 226 drm 253 sleepy # 查到sleepy的主设备号是253 254 pcmcia Block devices: 1 ramdisk 1 ramdisk 3 ide0 7 loop 8 sd : :
再在/dev/目录中创建sleepy设备:
// 其中253是主设备号,你可以根据你的情况自己修改这个值,0是次设备号 # mknod /dev/sleepy c 253 0 // 查看我们新添加的设备 # ls -l /dev/sleepy crw-r--r-- 1 root root 253, 0 08-03 15:34 /dev/sleepy
5. 试试设备: 根据书中介绍,sleepy设备是用来演示简单休眠的:当读该设备的时候进程会进入休眠状态,直到有其他进程写该设备,读进程才会被唤醒,我们来读 sleepy设备:
# dd if=/dev/sleepy of=~/temp
上面命令的意思是从/dev/sleepy设备中读取数据,并写到 ~/temp文件中,当按下回车键后,命令行就被挂起了,想死掉了一样,查看/var/log/messages文件可以看到类似下面的 内 容: “Aug 3 15:58:20 FOX kernel: process 13534 (dd) going to sleep” 这个是sleepy.c中函数sleepy_read()里的调试信息,告诉你进程已经sleep了 此时我们打开另一个终端运行下面的命令来写sleepy设备:
该命令会马上返回,并且在/var/log/messages文件中输出调试信 息: “Aug 3 16:05:22 FOX kernel: process 13583 (ls) awakening the readers...” 这个是sleepy.c中函数sleepy_write()里的调试信息,告诉你当前进程开始唤醒读进程了。 我们再回过头看看刚才挂起的读操作,发现“dd if=/dev/sleepy of=~/temp”命令已经返回了,并且在/var/log/messages文件中输出调试信息: Aug 3 16:05:22 FOX kernel: awoken 13534 (dd) 这个是sleepy.c中函数sleepy_read()里的调试信息,告诉你进程已经被唤醒了 6. 相关代码: 跟踪一下printk打印出来信息的先后顺序,就可以大致了解整个“休眠”和“唤醒”的过程了。
34 ssize_t sleepy_read (struct file *filp, char __user *buf, size_t count, loff_t *pos)35 {36 printk(KERN_ALERT "process %i ( %s ) going to sleep /n " ,37 current->pid, current->comm);38 wait_event_interruptible(wq, flag != 0 );39 flag = 0 ;40 printk(KERN_ALERT "awoken %i ( %s ) /n " , current->pid, current->comm);41 return 0 ; /* EOF */ 42 }43 44 ssize_t sleepy_write (struct file *filp, const char __user *buf, size_t count,45 loff_t *pos)46 {47 printk(KERN_ALERT "process %i ( %s ) awakening the readers... /n " ,48 current->pid, current->comm);49 flag = 1 ;50 wake_up_interruptible(&wq);51 return count; /* succeed, to avoid retrial */ 52
7. 8. 9.