⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 linux设备驱动程序笔记.txt

📁 Linux设备驱动程序笔记
💻 TXT
📖 第 1 页 / 共 5 页
字号:
unsigned long copy_to_user(void __user *to,
                           const void *from,
                           unsigned long count);
unsigned long copy_from_user(void *to,
                             const void __user *from,
                             unsigned long count);
 

而值得一提的是以上两个函数和

#define __copy_from_user(to,from,n) (memcpy(to, (void __force *)from, n), 0)
#define __copy_to_user(to,from,n) (memcpy((void __force *)to, from, n), 0)
 

之间的关系:通过源码可知,前者调用后者,但前者在调用前对用户空间指针进行了检查。

至于read和write 的具体函数比较简单,就在实验中验证好了。


--------------------------------------------------------------------------------
2.7 模块实验
这次模块实验的使用是友善之臂SBC2440V4,使用Linux2.6.22.2内核。

模块程序链接:scull模块源程序
模块测试程序链接:模块测试程序

测试结果:

量子大小为6:

[Tekkaman2440@SBC2440V4]#cd /lib/modules/ [Tekkaman2440@SBC2440V4]#insmod scull.ko scull_quantum=6

[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
[Tekkaman2440@SBC2440V4]#mknod -m 666 scull0 c  252 0
[Tekkaman2440@SBC2440V4]#mknod -m 666 scull1 c  252 1
[Tekkaman2440@SBC2440V4]#mknod -m 666 scull2 c  252 2
[Tekkaman2440@SBC2440V4]#mknod -m 666 scull3 c  252 3


启动测试程序

[Tekkaman2440@SBC2440V4]#./scull_test 

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


改变量子大小为默认值4000:
[Tekkaman2440@SBC2440V4]#cd /lib/modules/
[Tekkaman2440@SBC2440V4]#rmmod scull
[Tekkaman2440@SBC2440V4]#insmod scull.ko


启动测试程序
[Tekkaman2440@SBC2440V4]#./scull_test
write ok! code=20
read ok! code=20
[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]#    


改变量子大小为6,量子集大小为2:
[Tekkaman2440@SBC2440V4]#cd /lib/modules/
[Tekkaman2440@SBC2440V4]#rmmod scull
[Tekkaman2440@SBC2440V4]#insmod scull.ko scull_quantum=6 scull_qset=2


启动测试程序
[Tekkaman2440@SBC2440V4]#./scull_test
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              
 

实验不仅测试了模块的读写能力,还测试了量子读写是否有效。

 
Linux设备驱动程序(3)-调试技术
进入《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不支持,菜单里看不见。


--------------------------------------------------------------------------------
3.2 通过打印调试
(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 */
 


而在运行是改变console_loglevel的程序(《Linux设备驱动程序(第3版)》提供)如下: 

#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);
}
 

最关键的“syslog(8,NULL,level)”语句不理解,没有找到相关资料。但是通过在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。 


 

 为了方便的打开和关闭调试信息,《Linux设备驱动程序(第3版)》提供以下源码:

/* 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重复输出过快而阻塞系统,内核使用以下函数跳过部分输出:

int printk_ratelimit(void);
 

典型的应用如下:

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的行为。 
 Linux还提供了打印设备编号的宏(在<linux/kdev_t.h>中定义):

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

两个函数的唯一区别是:print_dev_t返回打印字符数,format_dev_t返回缓冲区指针。注意缓冲区char *buffer的大小应至少有20B。


通过查询调试
多数情况中,获取相关信息的最好方法是在需要的时候才去查询系统信息,而不是持续不断地产生数据。
使用/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

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -