LINUX驱动程序初体验

原创 2007年10月01日 22:21:00
 严格来说已经不算第一次了 大三的时候刚开始学嵌入式LINUX  就写过驱动 不过过了这么久没弄 基本忘光了 从头开始. 这篇文章不讲驱动的框架,而是记录我在编写第一个驱动中遇到的问题.

问题一: 到底哪个先执行

    这是一个来自运算符优先级的诡异的问题.是在编写用户空间代码时遇到的.还是先上问题代码:

这段代码的意图在于打开我编写的设备,并开启设备的异步通知机制; 不过在执行write系统调用的时候,用于测试的字符串"s"被打印在了控制台上. ..... 这真是个让人困惑的问题. 这个自符串(虽然只有一个字符的长度)本来是写向设备的.是如何阴差阳错到了控制台上呢...  检查文件描述符fd的值,发现居然是0 .0 代表了控制台设备 是每个进程默认打开的设备 难怪乎了. 可明明设备打开是成功,fd为什么变成了0呢.  问题就出在 if(fd = open("/dev/mod",O_RDWR) < 0) 上面.  原以为赋值运算符的优先级高于<运算 一查才发现原来是倒过来的 所以<运算先被执行了 结果为假 也就是0  这个值又被赋给了 fd......  真相大白...

这个错误虽然是因为错误的估计了运算符的优先级而引起的 却也暴露了用C这种介于高级与低级之间的语言进行编程时给程序员带来的问题--- 数据结构类型太少.  在JAVA之下,标识文件的数据结构类型与标识真假的boolean类型代表两个完全不同的类型 相互赋值时会发生错误 因此象这类错误会在编译器就被发现而不至于引起更让人困惑现象.C语言里, 文件句柄,BOOL值都是用整型值来表示 相互赋值在语法上没有任何问题 于是上面的问题就出现了...

问题二:返回值太重要 重要的可以决定程序是否崩溃

    相对与前一个 这个问题隐藏得更深(至少对初学者来说是这样)  问题代码在这里:

static int mobile_open(struct inode * inode,struct file * filp)
...{
    MOD_INC_USE_COUNT;
    
    
return 1;
}

    看看吧 多么简单的代码 就两句;作为一个驱动的 open 方法的实现,这个函数仅仅增加引用计数值,然后返回.可就是两句代码. 引得其后在用户空间里的代码在调用fcntl系统调用设置设备文件属主的时候出现了segmentation fault .

 按照LINUX对驱动程序方法的定义,方法的返回值有重大的意味. 他标志着这次方法的调用是否成功.而我在写这个方法的时候,想当然的以为1代表打开成功. 就给返回了. 而事实恰恰是LINUX规定OPEN方法返回0才代表万事OK.于是,一方面内核认为这是一次失败的设备打开操作,而另一方面却返回给用户空间的OPEN系统调用一个合法的文件描述符... 所以在FCNTL系统调用作用与这个文件描述符的时候,将访问一个没有为其分配空间的数据结构,产生非法访问的错误...

    将return 1改为return 0.OK.

问题三: 她和她,WHICH IS YOUR RIGHT ONE?

    LINUX最为迷惑开发者之一的地方在与起头文件. 你可以在很多地方看到有include字样的目录. 而GCC会有一个默认的寻找头文件的目录 .在本例中,为了编译出内核一部分的MODULE,必须使用内核代码中的头文件目录.这很简单,我用-I选项就能轻松搞定. 不过,别忘了 ,GCC默认的头文件搜索目录始终默默的存在着, 当我们自己指定的目录出现问题时,这个我们并不注意到的目录里的文件会是我们的恶梦...

    本例中,当使用ARM-LINUX-GCC 交叉编译器为手机编译MODULE时,出现类似下面这样的错误:

In file included   from  ...................................................... xxx.h

   from.........................................................yyy.h

  from...........................................................zzz.h

Symbol  ABC redefined....

仔细观察这些问题头文件所在的路径,你会惊讶的发现他们存在于我们指定编译器搜索的路径之外.这就是默认的路径------两套不同的头文件体系交叉被编译器默不作声的交叉使用了. 试想我们想要INCLUDE的是在A目录下的文件A.H.而在B目录下存在一个同名的A.H 并被错误的INCLUDE近来...这会是什么后果...乱套了... 

    可为什么会发生这种状况呢. 我们用-I/usr/src/arm-linux-src/include选项作为头文件的目录,可头文件还会包含其他头文件,举个例子,这个目录下的ptracr.h会有这样一行 #include <asm/ptrace.h>意思是:编译器,你给我把//usr/src/arm-linux-src/include/asm下的ptrace.H给我包含进来 编译器一找,发现没有asm这个目录,这个时候他并不报错,而是在默认的目录里继续寻找是否有个asm目录,他下面是否有个 ptrace.h  一找,哟 还真有 就是他了...本来一个是给用户程序用的 ,另一个是给内核程序用的 就这么混用到了一起 ....

      那那个惹出问题的ptrace.h 文件到底该在哪呢 其实asm是一个包含具体体系结构代码的目录,他在/usr/src/arm-linux-src/include以这种形式存在:

   asm-arm , asm-x86, asm-mips......

    为了编译出给ARM体系结构的代码,asm必须指向的是 asm-arm目录.这个好解决:ln -s ./asm-arm asm 这步昨晚后,所有编译器出错信息全部消失...

 

 

linux驱动程序调试常用方法

驱动程序开发的一个重大难点就是不易调试。本文目的就是介绍驱动开发中常用的几种直接和间接的调试手段,它们是: 利用printk查看OOP消息利用strace利用内核内置的hacking选项利用io...

linux驱动程序调试常用方法

驱动程序开发的一个重大难点就是不易调试。本文目的就是介绍驱动开发中常用的几种直接和间接的调试手段,它们是: 利用printk 查看OOP消息 利用strace 利用内核内置的hacking选项 ...

Linux驱动程序中的file,inode,file_operations三大结构体

file_operations:     该结构是将 系统调用 和驱动程序 连接起来,这个结构的每一成员都对应着一个系统调用。当用户进程利用系统调用对设备进行读写操作的时候,这些系统调用通过设备节点...

linux驱动程序之定时器防按键抖动

前提:按键按下通过中断方式进行处理。本博文基于上一个博文改写:上一篇博文 目的: 使用定时器防止按键抖动产生中断。 方法: 每次发生按键中断后,推迟10ms进行处理,最终将会只执行一次定时器中断处理...

解释一下linux驱动程序结构框架及工作原理

一、Linux device driver 的概念   系统调用是操作系统内核和应用程序之间的接口,设备驱动程序是操作系统内核和机器硬件之间的接口。设备驱动程序为应用程序屏蔽了硬件的细节,这样在应用...

linux驱动程序开发 1

linux驱动程序分成三类:字符设备,块设备,网络设备。 字符设备:能像字节流一样访问的设备,通过/dev下的字符设备文件来访问。 块设备:按照块为单位来访问数据,比如一块为512KB,是通过/d...

Linux驱动程序开发 005- 内核同步技术

序言 就像我们在操作系统里学习的那样,如果多个程序(进程或线程)同时访问临界区数据就会发生竞争。存在竞争条件的程序会产生不可预料的结果。消除竞争的方法一般就是同步的访问临界区数据(原子访问)。Lin...

Linux驱动程序开发005 - 内核同步技术

序言 就像我们在操作系统里学习的那样,如果多个程序(进程或线程)同时访问临界区数据就会发生竞争。存在竞争条件的程序会产生不可预料的结果。消除竞争的方法一般就是同步的访问临界区数据(原子访问)。Lin...

嵌入式Linux驱动程序开发

作者:ce123 来自:http://blog.csdn.net/ce123/article/details/6581260 1.设备驱动程序的概念... 2 2.处理器与设备间...
  • whw8007
  • whw8007
  • 2013年03月25日 23:55
  • 399

Linux驱动程序之阻塞和非阻塞IO

所谓阻塞方式block,顾名思义,就是进程或是线程执行到这些函数时必须等待某个事件的发生,如果事件没有发生,进程或线程就被阻塞,函数不能立即返回。也就是说在执行设备操作时,若不能获得资源,则挂起进程直...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:LINUX驱动程序初体验
举报原因:
原因补充:

(最多只允许输入30个字)