天嵌 ARM开发社区

 找回密码
 注册
查看: 2014|回复: 0

[转载]Linux设备驱动程序学习(2)-调试技术

[复制链接]
machoe 发表于 2010-8-12 16:50:59 | 显示全部楼层 |阅读模式
原创文章版权所有!如需转载,请注明出处: tekkman.cublog.cn ,谢谢合作!!!!!

Linux设备驱动程序学习(2)-调试技术

今天进入《Linux设备驱动程序(第3版)》第四章调试技术的学习。

一、内核中的调试支持

在前面已经建议过:学习编写驱动程序要构建安装自己的内核(标准主线内核)。最重要的原因之一是:内核开发者已经建立了多项用于调试的功能。但是由于这些功能会造成额外的输出,并导致能下降,因此发行版厂商通常会禁止发行版内核中的调试功能。
为了实现内核调试,我在内核配置上增加了几项:
  Kernel hacking  --->     
        
  • Magic SysRq key
            
  • Kernel debugging
            
  •    Debug slab memory allocations  
            
  •    Spinlock and rw-lock debugging: basic checks
            
  •    Spinlock debugging: sleep-inside-spinlock checking
            
  •    Compile the kernel with debug info  
            
  • Magic SysRq key
    Device Drivers  --->  
            Generic Driver Options  --->
             
  • Driver Core verbose debug messages
    General setup  --->
          
  • Configure standard kernel features (for small systems)  --->
             
  •    Load all symbols for debugging/ksymoops
    书上介绍的还有其他配置,有的我不需要,或是s3c2440不支持,菜单里看不见。

    二、通过打印调试
    (1)printk
    首先,printk有8个loglevel,定义在<linux/kernel.h>中:
    #define    KERN_EMERG    "<0>"/* system is unusable           */
    #define    KERN_ALERT    "<1>"   /* action must be taken immediately*/
    #define    KERN_CRIT    "<2>"/* critical conditions    */
    #define    KERN_ERR    "<3>"/* error conditions            */
    #define    KERN_WARNING    "<4>"/* warning conditions   */
    #define    KERN_NOTICE    "<5>"/* normal but significant condition */
    #define    KERN_INFO    "<6>"/* informational            */
    #define    KERN_DEBUG    "<7>"/* debug-level messages   */




    未指定优先级的默认级别定义在/kernel/printk.c中:
    #define DEFAULT_MESSAGE_LOGLEVEL 4 /* KERN_WARNING */




    当优先级的值小于console_loglevel这个整数变量的值,信息才能显示出来。而console_loglevel的初始值DEFAULT_CONSOLE_LOGLEVEL也定义在/kernel/printk.c中: #define DEFAULT_CONSOLE_LOGLEVEL 7 /* anything MORE serious than KERN_DEBUG */




    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <errno.h>
    #define __LIBRARY__ /* _syscall3 and friends are only available through this */
    #include <linux/unistd.h>
    /* define the system call, to override the library function */
    _syscall3(int, syslog, int, type, char *, bufp, int, len);

    int main(int argc, char **argv)
    {
    int level;
        if (argc==2) {
        level = atoi(argv[1]); /* the chosen console */
    } else {
    fprintf(stderr, "%s: need a single arg\n",argv[0]); exit(1);
    }
    if (syslog(8,NULL,level) < 0) {
    fprintf(stderr,"%s: syslog(setlevel): %s\n",
                    argv[0],strerror(errno));
    exit(1);
    }
    exit(0);
    }




    最关键的语句我不理解,没有找到相关资料。但是通过在ARM9板上的实验表明:程序是ok的!我用Hello world模块做了实验,现象和书上的一致。
    [Tekkaman2440@SBC2440V4]#cd /tmp/
    [Tekkaman2440@SBC2440V4]#./setlevel 1
    [Tekkaman2440@SBC2440V4]#cd /lib/modules/
    [Tekkaman2440@SBC2440V4]#insmod hello.ko
    [Tekkaman2440@SBC2440V4]#rmmod hello
    [Tekkaman2440@SBC2440V4]#cd /tmp/
    [Tekkaman2440@SBC2440V4]#./setlevel 7
    [Tekkaman2440@SBC2440V4]#cd /lib/modules/
    [Tekkaman2440@SBC2440V4]#insmod hello.ko
    Hello, Tekkaman Ninja !
    [Tekkaman2440@SBC2440V4]#rmmod hello
    Goodbye, Tekkaman Ninja !
    Love Linux !Love ARM ! Love KeKe !
    [Tekkaman2440@SBC2440V4]#




    还有通过对/proc/sys/kernel/printk的访问来改变console_loglevel的值:

    [Tekkaman2440@SBC2440V4]#echo 1 > /proc/sys/kernel/printk


    [Tekkaman2440@SBC2440V4]#cat /proc/sys/kernel/printk
    1 4       1       7

    [Tekkaman2440@SBC2440V4]#insmod hello.ko
    [Tekkaman2440@SBC2440V4]#rmmod hello
    [Tekkaman2440@SBC2440V4]#echo 7 > /proc/sys/kernel/printk
    [Tekkaman2440@SBC2440V4]#cat /proc/sys/kernel/printk
    7       4       1       7

    [Tekkaman2440@SBC2440V4]#insmod hello.ko
    Hello, Tekkaman Ninja !
    [Tekkaman2440@SBC2440V4]#rmmod hello
    Goodbye, Tekkaman Ninja !
    Love Linux !Love ARM ! Love KeKe !



    四个数字的含义:当前的loglevel、默认loglevel、最小允许的loglevel、引导时的默认loglevel。

    /* Macros to help debugging */
    #undef PDEBUG /* undef it, just in case */
    #ifdef SCULL_DEBUG
    # ifdef __KERNEL__
    /* This one if debugging is on, and kernel space */
    # define PDEBUG(fmt, args...) printk( KERN_DEBUG "scull: " fmt, ## args)
    # else/* This one for user space */
    # define PDEBUG(fmt, args...) fprintf(stderr, fmt, ## args)
    # endif
    #else
    # define PDEBUG(fmt, args...) /* not debugging: nothing */
    #endif

    #undef PDEBUGG
    #define PDEBUGG(fmt, args...) /* nothing: it's a placeholder */




    Makefile中要添加的语句:

    # Comment/uncomment the following line to disable/enable debugging
    DEBUG = y


    # Add your debugging flag (or not) to CFLAGS
    ifeq ($(DEBUG),y)
      DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines
    else
      DEBFLAGS = -O2
    endif

    CFLAGS += $(DEBFLAGS)





    为了避免printk重复输出过快而阻塞系统,内核使用以下函数跳过部分输出:

    典型的应用如下:

    if (printk_ratelimit( ))
        printk(KERN_NOTICE "The printer is still on fire\n");




    可以通过修改/proc/sys/kernel/printk_ratelimit(重开信息前应等待的秒数)和/proc/sys/kernel/printk_ratelimit_burst(在速度限制前可接受的信息数)来定制printk_ratelimit的行为。

    int print_dev_t(char *buffer, dev_t dev);
    char *format_dev_t(char *buffer, dev_t dev);




    两个函数的唯一区别是:

    三、通过查询调试
    多数情况中,获取相关信息的最好方法是在需要的时候才去查询系统信息,而不是持续不断地产生数据。
    使用/proc文件系统
    /proc文件系统是一种特殊的、由软件创建的文件系统,内核使用他向外界导出信息。/proc下面的每个文件都绑定于一个内核函数,用户读取其中的文件时,该函数动态的生成文件的内容。如以前用过的:
    [Tekkaman2440@SBC2440V4]#cat /proc/devices
    Character devices:
      1 mem
      2 pty
      3 ttyp
      4 /dev/vc/0
      4 tty
      4 ttyS
      5 /dev/tty
      5 /dev/console
      5 /dev/ptmx
      7 vcs
    10 misc
    13 input
    14 sound
    81 video4linux
    89 i2c
    90 mtd
    116 alsa
    128 ptm
    136 pts
    180 usb
    189 usb_device
    204 s3c2410_serial
    252 scull
    253 usb_endpoint
    254 rtc

    Block devices:
      1 ramdisk
    256 rfd
      7 loop
    31 mtdblock
    93 nftl
    96 inftl
    179 mmc




    使用/proc的模块必须包含<linux/proc_fs.h>,而使用seq_file接口要包含<linux/seq_file.h>。
    具体的应用方法看源程序、做实验更有效果。
    至于其他的调试方法,如gdb、LTT、SysRq等方法,在其他的书籍,如:《嵌入式Linux系统开发技术详解-基于ARM》、《构建嵌入式Linux系统》等,上讲解的更为详细,以后专门花时间研究。
    四、源码实验
    模块程序链接:模块程序
    模块测试程序链接:模块测试程序

    实验现象:

    [Tekkaman2440@SBC2440V4]#cd /lib/modules/
    [Tekkaman2440@SBC2440V4]#insmod scull_debug.ko scull_nr_devs=1 scull_quantum=6 scull_qset=2
    [Tekkaman2440@SBC2440V4]#cd /tmp/
    [Tekkaman2440@SBC2440V4]#./scull_test
    write code=6
    write code=6
    write code=6
    write code=2
    read code=6
    read code=6
    read code=6
    read code=2
    [0]=0 [1]=1 [2]=2 [3]=3 [4]=4
    [5]=5 [6]=6 [7]=7 [8]=8 [9]=9
    [10]=10 [11]=11 [12]=12 [13]=13 [14]=14
    [15]=15 [16]=16 [17]=17 [18]=18 [19]=19

    [Tekkaman2440@SBC2440V4]#cd /proc/
    [Tekkaman2440@SBC2440V4]#ls
    1              751            cmdline        kallsyms       stat
    2              769            cpu            kmsg           swaps
    3              77             cpuinfo        loadavg        sys
    4              778            crypto         locks          sysrq-trigger
    5              779            devices        meminfo        sysvipc
    59             78             diskstats      misc           timer_list
    6              781            driver         modules        tty
    60             783            execdomains    mounts         uptime
    63             785            filesystems    mtd            version
    65             79             fs             net            vmstat
    707            80             ide            partitions     yaffs
    708            819            interrupts     scullmem       zoneinfo
    709            asound         iomem          scullseq
    710            buddyinfo      ioports        self
    742            bus            irq            slabinfo

    [Tekkaman2440@SBC2440V4]#cat scullmem

    Device 0: qset 2, q 6, sz 20
      item at c071ebd4, qset at c071ef7c
      item at c071ef14, qset at c071eee0
           0: c071eeac
           1: c071ee78
    [Tekkaman2440@SBC2440V4]#cat scullseq

    Device 0: qset 2, q 6, sz 20
      item at c071ebd4, qset at c071ef7c
      item at c071ef14, qset at c071eee0
           0: c071eeac
           1: c071ee78
    [Tekkaman2440@SBC2440V4]#rmmod scull_debug
    [Tekkaman2440@SBC2440V4]#ls
    1              742            buddyinfo      iomem          self
    2              751            bus            ioports        slabinfo
    3              769            cmdline        irq            stat
    4              77             cpu            kallsyms       swaps
    5              778            cpuinfo        kmsg           sys
    59             779            crypto         loadavg        sysrq-trigger
    6              78             devices        locks          sysvipc
    60             781            diskstats      meminfo        timer_list
    63             783            driver         misc           tty
    65             785            execdomains    modules        uptime
    707            79             filesystems    mounts         version
    708            80             fs             mtd            vmstat
    709            824            ide            net            yaffs
    710            asound         interrupts     partitions     zoneinfo




    发表于: 2007-10-25,修改于: 2007-10-26 16:10,已浏览4841次,有评论0条 推荐 投诉

    网友评论
    好文章,我是从你的第一章开始看的,今天9号看到你又有新内容,学不少东西,请坚持下去,加油啊  
    很不错啊,我几乎每天都来学习你的经验,感觉收益非浅,加油啊!  
    我觉得最好的方式就是有人交流^_^我很想与你交流,我的QQ32313055  
    我学arm一年多了,可是水平比阁下差远了。看完文章,收获良多,非常感谢!  
    向Tekkaman  Ninja致敬,你的学习态度和学习方式都值得我们借鉴!

    圣诞快乐!
    让我学到了很多东西,  
    很好的文章啊,我正在学习驱动开发,刚刚入门,谢谢啊  


    write error! code=-1
    write ok! code=21
    read ok! code=20
    [0]=0 [1]=0 [2]=1 [3]=2 [4]=3
    [5]=4 [6]=5 [7]=6 [8]=7 [9]=8
    [10]=9 [11]=10 [12]=11 [13]=12 [14]=13
    [15]=14 [16]=15 [17]=16 [18]=17 [19]=18

    我改了一下makefile在pc上运行是这个结果  
    所有的源码都在友善之臂SBC2440V4上反复测试过(内核为2.6.22.2)。所以基本上只要改Makefile就好(除了硬件相关的部分)。如果有问题可以将详细的情况发邮件给我,有空我会回复的。





    写的真的很好
    我们老师就让写一个字符设备驱动程序,我都是通过在你的网页上学会的所有的东西。  
    赞一个,总结的很好

    曾经研究过ldd3,没有认真写下读书笔记,以后还得好好再看下了  
    请问怎么使用drivers/spi/atmel_spi.c提供的驱动呢?在/dev下没有相应的设备节点,怎么才能在用户空间访问设备?如果自己写一个驱动注册一个spi驱动可以使用其中哪些函数接口?诚请帮忙  
    今天看了你的文章很感慨,希望能共同学习。有个问题想问,
    请问当insmod scull.ko scull_quantum=6 scull_qset=2
    数据已经溢出了,为什么20个数据还能写进去。谢谢了  
    这个和scull的数据结构有关,你认真看看《Linux设备驱动程序学习(1)-字符设备驱动程序》,中的图,你可能对scull的数据结构还没有理解透,scull_quantum代表了一个quantum的字节数,scull_qset代表一个qset包含几个quantum,但是还有qset没有限制,也就是说我写20个字节进去,一个scull中有2个qset。




    总结的太好了。
    有一个问题想请教一下。看模块中定义了一个char *whom = "world"
    这是一个字符串常量,如果按照标准C的话,指针指向的是一个常量字符串才对,其中的内容不能修改。比如whom[2]='a';这样会有段错误,为什么在内核中这样操作是合法的呢?   
    我觉得你这样是定义一个字符串变量,所以可以修改。我学硬件的,对c研究还不深,不知见解是否正确?




    lz的经验和态度值得我们学习,向你致敬!  
    很不错,尤其是有源码和测试程序。  
    你好!刚接触linux驱动,看到你这里的设备模型分析,很不错
    帮了我的大忙!
    我有一个问题,对于nand flash,作为一个块设备,应用程序如何去访问它,对它进行擦除、读写等操作?
    因为它不象字符设备那样有可供调用的系统调用


    块设备我暂时还没看,见谅




    我也想知道块设备的一些知识,老是来你这儿看,希望能得到一些帮助,呵呵  
    块设备我还没看啊,苦于没时间和没板做实验




    问一个问题:
    你上文提到的测试程序是不是相当于linux系统的应用程序,实现对驱动的系统调用?
    如果是这样,那么测试程序应该放在什么路径下,用什么编译器进行编译,因为我看到你有写测试程序的makefile,是不是也要用交叉编译器对它进行编译阿,可是这样的话,生成的目标代码是arm格式的,不能在pc上直接执行。
    麻烦你帮我解答一下这个疑问。
    刚刚接触linux,问得问题比较愚蠢,见笑了



    测试程序是应用程序,在板上运行
    要交叉编译




    总结得很好   就像上完课了要复习   
    很好的学习总结,受益匪浅!  
    [root@(none) scullc]# insmod scullc.ko
    Using scullc.ko
    nfs: server 222.31.45.9 not responding, still trying
    nfs: server 222.31.45.9 not responding, still trying
    nfs: server 222.31.45.9 not responding, still trying
    我按照傅大哥写的模块,一装载的时候就出错了........
    里面的网络没问题,就是装载了模块后出问题的........
    傅大哥知道怎么回事吗???????  

    我是刚接触linux的。今天看到你的总接非常高兴,做的太详细了。。。
    我想问一下,是否可以讲解一下container_of是怎么用的。。
    谢谢!  
    关于楼主描述的:
    最关键的“syslog(8,NULL,level)”语句我不理解,没有找到相关资料。但是通过在ARM9板上的实验表明:程序是ok的!我用Hello world模块做了实验,现象和书上的一致。
    我查阅了一下,应该这么理解:
    原型是:int syslog(int type, char *bufp, int len);
    根据type来采取对内核ring buffer的操作,并设置consele_loglevel的值为len。
    type参数有以下几种值:
           /*
            * Commands to sys_syslog:
            *
            *      0 -- Close the log.  Currently a NOP.
            *      1 -- Open the log. Currently a NOP.
            *      2 -- Read from the log.
            *      3 -- Read up to the last 4k of messages in the ring buffer.
            *      4 -- Read and clear last 4k of messages in the ring buffer
            *      5 -- Clear ring buffer.
            *      6 -- Disable printk’s to console
            *      7 -- Enable printk’s to console
            *      8 -- Set level of messages printed to console
            *      9 -- Return number of unread characters in the log buffer
            */
    返回值的描述:
           In case of error, -1 is returned, and errno is set. Otherwise,
           for  type  equal  to 2, 3 or 4, syslog() returns the number of
           bytes read, and otherwise 0.
    不妥之处请指教,谢谢。  
    文章写的很好,刚开始学驱动,有很多地方都不是很懂,很想跟你学习啊,想请教一下学习linux设备驱动的方法。  
    问一个很弱的问题,楼主的源码文件是如何存储在cublog里面的,敬请告知,不胜感激  

    write code=6
    write code=6
    write code=6
    write code=2
    read code=6
    read code=6
    read code=6
    read code=2
    [0]=0 [1]=1 [2]=2 [3]=3 [4]=4
    [5]=5 [6]=6 [7]=7 [8]=8 [9]=9
    [10]=10 [11]=11 [12]=12 [13]=13 [14]=14
    [15]=15 [16]=16 [17]=17 [18]=18 [19]=19

    看你的测试程序中 输出语句 要么是 work error! code=..   或者 work ok! code=..    上面的代码输出 work  code=...   既没有error! 也没有ok! 什么原因啊?
    在字符驱动那张图 scull_device所指的链表中 Scull_qset 这种结构的个数如何确定呢。

    insmod scull_debug.ko scull_nr_devs=1 scull_quantum=6 scull_qset=2后
    我测试的结果是:
    write error! code=6
    write error! code=6
    write error! code=6
    write ok! code=2
    read error! code=6
    read error! code=6
    read error! code=6
    read ok! code=2
    [0]=0 [1]=1 [2]=2 [3]=3 [4]=4
    [5]=5 [6]=6 [7]=7 [8]=8 [9]=9
    [10]=10 [11]=11 [12]=12 [13]=13 [14]=14
    [15]=15 [16]=16 [17]=17 [18]=18 [19]=19
    请问如何解释啊。  

    从楼主这里学到不少东西
    void kobject_del(struct kobject *kobj); /*是 kobject_del 和 kobject_put 的结合*/写错了  
    编译的时候出现
    [root@localhost scull]# make modules
    make -C /home/alu/mywork/systems/linux-2.6.22.6  M=/home/soso/ldd3/scull   modules
    make[1]: Entering directory `/home/alu/mywork/systems/linux-2.6.22.6'
      CC [M]  /home/soso/ldd3/scull/scull_t1.o
    cc1: invalid option `little-endian'
    cc1: invalid option `arm'
    cc1: invalid option `apcs'
    cc1: invalid option `no-sched-prolog'
    cc1: invalid option `apcs-32'
    cc1: invalid option `no-thumb-interwork'
    cc1: invalid option `tune=arm9tdmi'
    cc1: invalid option `alignment-traps'
    cc1: unrecognized option `-Wdeclaration-after-statement'
    make[2]: *** [/home/soso/ldd3/scull/scull_t1.o] 错误 1
    make[1]: *** [_module_/home/soso/ldd3/scull] 错误 2
    make[1]: Leaving directory `/home/alu/mywork/systems/linux-2.6.22.6'
    make: *** [modules] 错误 2


    请教大哥  这个大概可能是什么问题啊  那么多参数无效  

    内核版本2.6.22.6
    arm-linux-gcc -v
    gcc version 3.3.6  
    "include/linux/moduleparam.h文件中有关于module_param_array宏的说明,这里第三个参数的作用是:
    *nump is set to number they actually specified

    所以这里的TNparam_nr并不是限制输入数组参数的数目,而是实际数据的大小。
    可以在上面的示例代码中加一句:
    printk(KERN_ALERT "TNparam_nr=%d\n",TNparam_nr);
    得到的结果会是你实际输入的数组元素个数。

    BTW:笔记写得这么详细,我都懒得写了,直接收藏你的笔记了:-)  
    感谢兄台指点!!!!!!!




    新学驱动开发   跟着ldd3看不懂  来支持下你     
        /* Then follow the list */
        while (n--) {
            if (!qs->next) {
                qs->next = kmalloc(sizeof(struct scull_qset), GFP_KERNEL);
                if (qs->next == NULL)
                    return NULL;  /* Never mind */
                memset(qs->next, 0, sizeof(struct scull_qset));
            }
            qs = qs->next;
            continue;
        }
        return qs;
    }
    continue;有什么作用

    正如注释所说的: 是不断的跟随双向链表到底!




    网友: 本站网友  时间:2009-04-12 09:43:54 IP地址:159.226.139.★


         /* Then follow the list */
        while (n--) {
            if (!qs->next) {
                qs->next = kmalloc(sizeof(struct scull_qset), GFP_KERNEL);
                if (qs->next == NULL)
                    return NULL;  /* Never mind */
                memset(qs->next, 0, sizeof(struct scull_qset));
            }
            qs = qs->next;
            continue;
        }
        return qs;
    }
    continue;有什么作用

    Blog作者的回复:
    正如注释所说的: 是不断的跟随双向链表到底!

    去掉continue;依然可以继续循环,continue是多余的???


    Tekkaman:
                你好,首先向你的工作致敬,我很希望和你一起探讨内核题,
    对于 文中提到“我这个实验除了对参数的改变进行实验外,我的一个重要的目的是测试“ module_param_array(TNparam , int , &TNparam_nr , S_IRUGO);”中&TNparam_nr对输入参数数目的限制作用。经过我的实验,表明&TNparam_nr并没有对输入参数的数目起到限制作用。真正起到限制作用的是“static int TNparam[] = {1,2,3,4};”本身定义的大小,我将程序进行修改:”
      我作了测试,当insmod hello-param.ko howmany=2 whom="KeKe" TNparam=4,3,2,1,5,时,系统报错
    “insmod:error inserting 'paramadd.ko":-1 Invalid parameters
    说明&TNparam_nr有对输入参数的数目起到限制作用,
    我用的是Fedora8  
    博主你是我见过的最好的博主了!永远支持你!  
    man syslog  如下:

    NAME
           syslog,  klogctl  -  read  and/or clear kernel message ring buffer; set
           console_loglevel

    SYNOPSIS
           int syslog(int type, char *bufp, int len);
                           /* No wrapper provided in glibc */

           /* The glibc interface */
           #include <sys/klog.h>

           int klogctl(int type, char *bufp, int len);

    DESCRIPTION
           If you need the libc function syslog()  (which  talks  to  syslogd(8)),
           then look at syslog(3).  The system call of this name is about control‐
           ling the kernel printk()  buffer,  and  the  glibc  version  is  called
           klogctl().

           The type argument determines the action taken by this function.

           Quoting from kernel/printk.c:
           /*
            * Commands to sys_syslog:
            *
            *      0 -- Close the log.  Currently a NOP.
            *      1 -- Open the log. Currently a NOP.
            *      2 -- Read from the log.
            *      3 -- Read all messages remaining in the ring buffer.
            *      4 -- Read and clear all messages remaining in the ring buffer
            *      5 -- Clear ring buffer.
            *      6 -- Disable printk to console
            *      7 -- Enable printk to console
            *      8 -- Set level of messages printed to console
            *      9 -- Return number of unread characters in the log buffer
            *     10 -- Return size of the log buffer
            */

           Only  command types 3 and 10 are allowed to non-root processes.  Type 9
           was added in 2.4.10; type 10 in 2.6.6.

       The kernel log buffer
           The kernel has a cyclic buffer of length LOG_BUF_LEN in which  messages
           given  as arguments to the kernel function printk() are stored (regard‐
           less of their loglevel).  In early kernels, LOG_BUF_LEN had  the  value
           4096;  from  kernel  1.3.54,  it  was  8192; from kernel 2.1.113 it was
           16384; since 2.4.23/2.6 the value is a kernel configuration option.  In
           recent kernels the size can be queried with command type 10.

           The  call  syslog(2,buf,len)  waits  until  this  kernel  log buffer is
           nonempty, and then reads at most len bytes into  the  buffer  buf.   It
           returns  the  number  of bytes read.  Bytes read from the log disappear
           from the log buffer: the information can only be read  once.   This  is
           the  function  executed  by  the  kernel  when  a  user  program  reads
           /proc/kmsg.

           The call syslog(3,buf,len) will read the last len bytes  from  the  log
           buffer  (non-destructively),  but  will  not read more than was written
           into the buffer since the last "clear ring buffer" command (which  does
           not clear the buffer at all).  It returns the number of bytes read.

           The  call  syslog(4,buf,len) does precisely the same, but also executes
           the "clear ring buffer" command.

           The call syslog(5,dummy,dummy) executes just the  "clear  ring  buffer"
           command.  (In each call where buf or len is shown as "dummy", the value
           of the argument is ignored by the call.)

           The call syslog(6,dummy,dummy) sets the console log level  to  minimum,
           so that no messages are printed to the console.

           The  call  syslog(7,dummy,dummy) sets the console log level to default,
           so that messages are printed to the console.

           The call syslog(8,dummy,level) sets the console  log  level  to  level,
           which must be an integer between 1 and 8 (inclusive).  See the loglevel
           section for details.

           The call syslog(9,dummy,dummy) returns the number  of  bytes  currently
           available to be read on the kernel log buffer.

           The  call  syslog(10,dummy,dummy)  returns the total size of the kernel
           log buffer.

       The loglevel
           The kernel routine printk() will only print a message on  the  console,
           if  it  has  a  loglevel  less  than  the  value  of  the variable con‐
           sole_loglevel.  This variable  initially  has  the  value  DEFAULT_CON‐
           SOLE_LOGLEVEL (7), but is set to 10 if the kernel command line contains
           the word "debug", and to 15 in case of a kernel fault (the  10  and  15
           are just silly, and equivalent to 8).  This variable is set (to a value
           in the range 1-8) by the call syslog(8,dummy,value).   The  calls  sys‐
           log(type,dummy,dummy)  with  type  equal to 6 or 7, set it to 1 (kernel
           panics only) or 7 (all except debugging messages), respectively.

           Every text line in a message has  its  own  loglevel.   This  level  is
           DEFAULT_MESSAGE_LOGLEVEL  - 1 (6) unless the line starts with <d> where
           d is a digit in the range 1-7, in which case the level is d.  The  con‐
           ventional  meaning  of  the  loglevel is defined in <linux/kernel.h> as
           follows:

           #define KERN_EMERG    "<0>"  /* system is unusable               */
           #define KERN_ALERT    "<1>"  /* action must be taken immediately */
           #define KERN_CRIT     "<2>"  /* critical conditions              */
           #define KERN_ERR      "<3>"  /* error conditions                 */
           #define KERN_WARNING  "<4>"  /* warning conditions               */
           #define KERN_NOTICE   "<5>"  /* normal but significant condition */
           #define KERN_INFO     "<6>"  /* informational                    */
           #define KERN_DEBUG    "<7>"  /* debug-level messages             */

    RETURN VALUE
           For type equal to 2, 3, or 4, a successful call to syslog() returns the
           number of bytes read.  For type 9, syslog() returns the number of bytes
           currently available to be read on the kernel log buffer.  For type  10,
           syslog() returns the total size  of  the  kernel log buffer.  For other
           values of type, 0 is returned on success.

           In case of error, -1 is returned, and errno  is  set  to  indicate  the
           error.

    ERRORS
           EINVAL Bad  parameters  (e.g., bad type; or for type 2, 3, or 4, buf is
                  NULL, or len is less than zero; or for type 8, the level is out‐
                  side the range 1 to 8).

           EPERM  An attempt was made to change console_loglevel or clear the ker‐
                  nel message ring buffer by a process  without  root  permissions
                  (more precisely: without the CAP_SYS_ADMIN capability).

           ERESTARTSYS
                  System  call  was  interrupted  by  a  signal; nothing was read.
                  (This can be seen only during a trace.)

    CONFORMING TO
           This system call is Linux-specific and should not be used  in  programs
           intended to be portable.

    NOTES
           From  the  very start people noted that it is unfortunate that a system
           call and a library routine of the same name are entirely different ani‐
           mals.   In  libc4  and  libc5  the  number  of this call was defined by
           SYS_klog.  In glibc 2.0 the syscall is baptized klogctl().

    SEE ALSO
           syslog(3)

    COLOPHON
           This page is part of release 2.79 of the Linux  man-pages  project.   A
           description  of  the project, and information about reporting bugs, can
           be found at http://www.kernel.org/doc/man-pages/.


    您好,我是为向您求教才注册的。我现在想以动态分配设备号的方式加载驱动,并建立设备节点。由于是新手,所以好多地方不是很明白。总之,我希望能在驱动加载上就自动建立设备文件节点,方法1:在网上看到好像说是在驱动中用class之类的可以达到这个效果;方法2:希望通过读取/proc/dev得到的消息来建立设备文件节点,但没写过shell脚本,且不知道怎样让它自动运行。希望得到您的提示。谢谢  
    要自动创建节点的话必须实现:
    1、文件系统中mdev或udev
    2、驱动中实现class(或是用偷懒点的办法:直接注册misc类)。




    刚才申请的帐号居然登录不上,所以只能匿名了,郁闷……  
    博主,请问一下你的hello模块没什么没写Kconfig文件,我看有的书上说添加模块必须写kconfig文件啊····?请指教,谢谢!  
    我是在内核外编译模块,不用Kconfig




    请问楼主你的程序哪里来的,书上都不全呀?  
    我的程序是根据《LDD3》的程序修改、增删而成的。  




    请问测试程序read(sculltest , &buffer2[20-i] , i),write(sculltest , &buffer1[20-i] , i)两个函数与驱动是怎么挂钩,是怎么样一个运行机制?谢谢。  
    哎……驱动层与用户层的,代码上的联系是怎么样的?说实话,这个驱动我看完了都不知道它能做什么?更不知道测试程序应该怎么写...惭愧啊  
    所以在学驱动前一定要学一点应用层的东西,写一些应用层的小软件试试,不如驱动是学不下去的。




    请问你当初在应用层是如何学习的?谢谢指点。  
    我看到你也是硬件出身,很期待你对于应用层开发入门的建议。  

    我是初学者,我按照你提供的程序输入make modules 输出提示:missing separator. Stop.  
    不管读,还是写,都休眠,然后就卡在那了,动也动不了,大概是什么原因  
    博主好久没发 新的关于驱动的啦 ,终于来啦 哈哈,激动  
    博主:
          我是初学者,写2440的linux驱动时会用到一些例如s3c2410_gpio_setpin()的函数,这些函数的定义在内核的哪个目录下呢?有没有一些系统的函数用法说明啊?  

    博主:
    请教个问题,你在驱动程序IO_irq.c中的函数为int IO_irq_ioctl(struct inode *inode, struct file *filp,unsigned int cmd, unsigned long arg)
    而你在应用程序IO_irq_test.c中调用的if ((code=ioctl( IO_irqtest , IO_IRQ_1  , NULL ) ) < 0) ,没有参数struct inode *inode,能解释下吗?谢谢  
    哈哈,最近也在学ldd3,每学完一章就来你这儿看一下你的笔记,实在是写得太好了。  
    我刚学习linux驱动,请问以下问题怎么解决呢?
    [root@localhost LinuxDriver]# insmod ./hello.o
    ./hello.o: kernel-module version mismatch
            ./hello.o was compiled for kernel version 2.4.20
            while this kernel is version 2.4.20-8.  
    你编译模块使用的内核版本和运行模块的内核版本不同,建议统一下。
    或者,好像在内核配置上可以关闭这个检查。
  • 您需要登录后才可以回帖 登录 | 注册

    本版积分规则

    关闭

    i.MX8系列ARM cortex A53 M4 工控板上一条 /1 下一条

    Archiver|手机版|小黑屋|天嵌 嵌入式开发社区 ( 粤ICP备11094220号-2 )

    GMT+8, 2024-6-26 11:06 , Processed in 1.062500 second(s), 19 queries .

    Powered by Discuz! X3.4 Licensed

    Copyright © 2001-2020, Tencent Cloud.

    快速回复 返回顶部 返回列表