linux字符设备驱动程序学习实验记录

  • 这是自己平常学习中曾经困惑的问题
    Linux系统下的字符型设备和块设备的区分?
    这里指的区分不是说如何从定义上进行区分,从实用的角度来看。打个比方就是,如果你自己写了个设备的驱动,或者从网上下载了一个驱动。安装好驱动之后,你没有相应的设备节点,要用到这样一条命令。mknod /dev/yourdevice  type Major Slave,这里就牵扯到类型是字符型的还是块设备型的。如何从驱动里看出来呢。传统驱动程序注册/注销字符型设备时用到register_chrdev/unregiter_chrdev,而对于块设备则是:register_blkdev/unregiter_blkdev, 而基于devfs的驱动程序也可以看出来,命令分别对应为:字符型devfs_register()和devfs_unregister,块设备devfs_blkregister和devfs_blkunregister。
    注释:在MagicArm上,上次帮同学看那个CAN总线驱动的时候要创建一个设备节点,我看了半天驱动程序也没有看出来是字符设备。后来只能试了。主要是不了解devfs_resgiter就是字符型设备的驱动。顺便说明下:平常的小型嵌入式实验中用到的块驱动是比较少的。
    上次虚拟机开机发现光盘打不开了,发现在/dev目录下找不到cdrom了,这种问题还是有时候会碰见的,虽然不是很常见。方法就是创建一个cdrom节点就可以了,当然设备号这些东西要去文档目录下看:/usr/src/linux-2.4/Documenttation/Devices.txt.
  • 关于printk
    printk(KERN_DEBUG “driver test”);
    在头文件中定义了8种可用的日志级字符串。
    KERN_EMERG 用于紧急事件,像系统崩溃等严重信息
    KERN_ALERT用于警告信息
    KERN_CRIT临界状态
    KERN_ERR用于错误信息
    KERN_WARNING警告信息
    KERN_NOTICE提醒
    KERN_INFO提示性信息
    KERN_DEBUG调试信息
    日志级别范围0-7,没有指定几倍的使用DEFAULT_MESSAGE_LOGLEVEL,内核可以把消息打印到控制台,可以指定控制台为字符模式的终端或者打印机。当日志界杯小于console_loglevel时,消息才能显示出来。如果运行了klogd和syslogd,则不论console_loglevel为什么值,内河消息都追加到/var/log/messages中。如果klogd没有运行,消息不会传递到用户空间,只能查看/proc/kmsg.
    变量console_loglevel的初始值为DEFAULT_CONSOLE_LOGLEVEL,可以通过sys_syslog系统调用进行修改,调用klogd时可以同过-c选项来修改这个变量。如果要修改其当前值,需要kill klog,然后-c选项重起。
    如果要查看调试信息,应当提高日志级别。
    通过读写/proc/sys/kernel/printk可以读取和修改控制台的日志级别。
    # cat /proc/sys/kernel/printk查看级别 显示如: 6 4 1 7,6是当前级别4为默认
    # echo 8 > /proc/sys/kernel/printk  修改6为8。
  • 无设备相关的hello驱动程序 hello.c
    这部分主要参考:
    http://dev.yesky.com/154/2621154.shtml深入浅出Linux设备驱动编程之内核模块
    2006-10-17 15:36 作者: 宋宝华 出处: 天极开发 责任编辑:>方舟
    #include
    #include
    #include
    MODULE_LICENSE("GPL");
    static int __init hello_init ()
    {
     printk(KERN_DEBUG"Hello module init DEBUG/n");
     printk(KERN_WARNING"Hello module initWARN/n");
     printk(KERN_EMERG"Hello module initEMERG/n");
     printk("Hello module init/n");
     return 0;
    }
    static void __exit hello_exit ()
    {
     printk("Hello module exit/n");
    }
    module_init(hello_init);
    module_exit(hello_exit);

   编译上述文件:命令如下: 

gcc -D__KERNEL__ -DMODULE -DLINUX -I /usr/local/src/linux2.4/include -c -o hello.o hello.c

测试:

a> 测试环境为虚拟机下面的Redhat9.0,内河2.4.20-8,
b> 终端执行命令如下: telinit 3 登陆字符模式,这里因为想看一下驱动程序的输出,应当使用登陆终端,在X桌面下的终端一般是看不到这些输出的。
c> 测试步骤:# cd /root/hello
# insmod hellodriver.o
# rmmod hellodriver.o
OK,这样,就可以轻松测试驱动程序了。记录一下,以示鼓励。

 

  •  设备相关的hello驱动程序

            源代码hellod.c,编译后驱动为hellod.o
            编译方法同上:
                gcc -D__KERNEL__ -DMODULE -DLINUX -I /usr/local/src/linux2.4/include -c -o hello.o hello.c  虚拟字符设备/dev/hello,驱动就利用上面的驱动程序。稍作修改。这部分主要参考周立功 MagicArm实验指导书
程序如下:

#include
#include
#include
MODULE_LICENSE("GPL");
static int hello_open(struct inode* inode,struct file *filp)
{
return 0;
}
static struct file_operations hello_fops=
{       owner: THIS_MODULE,
        open: hello_open,
};
static int __init hello_init ()
{
  register_chrdev(236,"hell",&hello_fops); //注册主设备号码
 printk("Hello module init/n");
 return 0;
}
static void __exit hello_exit ()
{
unregister_chrdev(236,"hell");
 printk("Hello module exit/n");
  }
  module_init(hello_init);
  module_exit(hello_exit);
这部分多加了一个fops结构体,主要是因为我们想通过open 打开我们的虚拟设备而准备的,好歹要加个open操作,要不然说不过去,而且我们的这个结构体和成员函数都很简单。只是作为测试而已。
好了,下面开始测试:
测试程序:test.c  编译方法: gcc test.c –o test
#include
#include
void main()
{
int ret=open("/dev/hello",0);
        if (ret<0)
        printf("cmknod /dev/hello c 236 0 annot oepn/n");
        else
        printf("ocmknod /dev/helll c 236 0 1pen ok/n");                                                                                              
}我们的测试程序也很简单,编译就是平常的编译应用程序的命令就可以了。接下来就可以执行了。还有几个工作要做:
首先:

:# mknod /dev/hello c 236 0        //这里创建设备节点hello
:  #insmod hello.o                //安装设备驱动
:   # ./test            //测试,可以看到打开设备成功。你还可以进行比较,创建另一个没有驱动的设备号节点进行测试,例如237 0 ,然后修改测试程序并运行,发现打开失败,从而可以验证我们的驱动是可以应用的。


  • devfs设备驱动方法
    上面应用的为传统的设备驱动方法,而没有使用devfs驱动方法。在周立功实验书上是用的devfs的方法。不知道什么原因,用devfs方法,我创建的节点没有用,更别提自动创建设备节点了。。。。。。。

你可能感兴趣的:(linux)