随笔 - 303  文章 - 883  trackbacks - 0
<2008年5月>
27282930123
45678910
11121314151617
18192021222324
25262728293031
1234567

欢迎光临! 
闲聊 QQ:1074961813

随笔分类(357)

我管理的群

公共blog

  • n维空间
  • Email : java3d@126.com 群 : 12999758

参与管理的论坛

好友的blog

我的其他blog

朋友的网站

搜索

  •  

最新评论

 

转变思维做个当家人

不知道你对花钱,有没有这样的感觉?做孩子的时候,经常伸手要钱;但等到你泡到MM成家之后一切就不同了,这个时候的我们花钱还要不断努力赚钱,同时lp会不断向你伸手,我们成了一个提款机,难怪MM们找对象的时候把金钱排在第一位了。做孩子的时候我们写的是应用程序,调用人家的API做一些自己想做的事情;成家后,我们成了男人,在调用系统API的时候,还要懂得给别人提供API,搞驱动了这时。于是,你领悟到写驱动之前必须先转变自己的思维,懂得承担责任,不然就永远是个小屁孩。唉,人生也许就是这样,阶段不同思想不同。

有句话说:“有付出就会有收获。”讲得一点也没错,成家之后,我们变得很重要了,处事自然小心谨慎起来了,要知道驱动可以是在内核空间运行的,稍不注意,就会对整个系统造成毁灭性的破坏。换个说法:为避免离婚,结婚之后,我们要更爱自己的另一半,观头顾尾,前后上下左右。做一个好的男人(好的驱动),据过来人(高手)说,并不是一件很容易的事情,我们的目标之一就是让我们的LP过得更好(内核稳定、高效地运行),这需要成熟的心态(技术)。爱情可以说是世界上最美好的一种感情,两人若是可以相携人生路,一同生活到老死,是怎样美好的事情。网上找个图说明下先,很喜欢用图,事实说明这样很省口水:



做男人该做的事情

要做一个当家人,有那么几件事情一定要知道怎么做;写一个驱动,有三个结构体也是一定要懂的,可以说整个驱动都在绕着它们三转。

Linux/include/fs.h里有两个:

struct file {

    union {

       struct list_head  fu_list;

       struct rcu_head   fu_rcuhead;

    } f_u;

    struct dentry     *f_dentry;

    struct vfsmount         *f_vfsmnt;

    struct file_operations   *f_op;//文件操作的结构指针,内核在做file_operations中的open函数操作时对此指针赋值
    atomic_t      f_count;

    unsigned int      f_flags;//文件标识,用于对阻塞或非阻塞检查
    mode_t        f_mode;//标识文件的读写权限

    loff_t        f_pos; //当前读写位置,loff_t64位数

    struct fown_struct   f_owner;

    unsigned int      f_uid, f_gid;

    struct file_ra_state f_ra;

 

    unsigned long     f_version;

    void          *f_security;

 

    /* needed for tty driver, and maybe others */

    void          *private_data;

 

#ifdef CONFIG_EPOLL

    /* Used by fs/eventpoll.c to link all the hooks to this file */

    struct list_head  f_ep_links;

    spinlock_t    f_ep_lock;

#endif /* #ifdef CONFIG_EPOLL */

    struct address_space *f_mapping;

};

/*

 * NOTE:

 * read, write, poll, fsync, readv, writev, unlocked_ioctl and compat_ioctl

 * can be called without the big kernel lock held in all filesystems.

 */

struct file_operations {

    struct module *owner;

    loff_t (*llseek) (struct file *, loff_t, int);

    ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);

    ssize_t (*aio_read) (struct kiocb *, char __user *, size_t, loff_t);

    ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);

    ssize_t (*aio_write) (struct kiocb *, const char __user *, size_t, loff_t);

    int (*readdir) (struct file *, void *, filldir_t);

    unsigned int (*poll) (struct file *, struct poll_table_struct *);

    int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);

    long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);

    long (*compat_ioctl) (struct file *, unsigned int, unsigned long);

    int (*mmap) (struct file *, struct vm_area_struct *);

    int (*open) (struct inode *, struct file *);

    int (*flush) (struct file *);

    int (*release) (struct inode *, struct file *);

    int (*fsync) (struct file *, struct dentry *, int datasync);

    int (*aio_fsync) (struct kiocb *, int datasync);

    int (*fasync) (int, struct file *, int);

    int (*lock) (struct file *, int, struct file_lock *);

    ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);

    ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *);

    ssize_t (*sendfile) (struct file *, loff_t *, size_t, read_actor_t, void *);

    ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);

    unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);

    int (*check_flags)(int);

    int (*dir_notify)(struct file *filp, unsigned long arg);

    int (*flock) (struct file *, int, struct file_lock *);

};

Linux/usb.h(注意这个结构根据实际使用的不同而不同,这是USB设备)

struct usb_driver {

    const char *name;

    int (*probe) (struct usb_interface *intf,

             const struct usb_device_id *id);

    void (*disconnect) (struct usb_interface *intf);

    int (*ioctl) (struct usb_interface *intf, unsigned int code,

           void *buf);

    int (*suspend) (struct usb_interface *intf, pm_message_t message);

    int (*resume) (struct usb_interface *intf);

    const struct usb_device_id *id_table;

 

    struct usb_dynids dynids;

    struct device_driver driver;

    unsigned int no_dynamic_id:1;

};

我们这里没可能对每个函数的作用做具体介绍,这些内容您完全可以从我一个文里的介绍的书中找到。

对我们需要的函数做填充,可以对去做如下填充:(这两个来自/drivers/usb/media/sn9c102_core.c

static struct file_operations sn9c102_fops = {

    .owner = THIS_MODULE,//标识模块的拥有者

    .open =    sn9c102_open,//打开设备文件,它往往是设备文件执行的第一操作

    .release = sn9c102_release, //file结构被释放掉时,会调用这个方法
    .ioctl =   sn9c102_ioctl,//ioctl是一个系统调用,提供了一种执行设备特定命令的方法

    .read =    sn9c102_read, //读函数,ssize_t表示当前平台上固有的整数类型
    .poll =    sn9c102_poll, //这个方法用于查询设备是否可读,可写或处于某种状态。当设备是不可读写时,它们可以被阻塞直至设备变为可读或可写。如果驱动程序中没有定义这个方法则它驱动的设备就会被人认为是可读写的。

    .mmap =    sn9c102_mmap, //请求将设备内存映射到进程地址空间,一般用于块设备

    .llseek =  no_llseek, //标识当前文件的操作位置

};

 

static struct usb_driver sn9c102_usb_driver = {

    .name =       "sn9c102",//驱动名,通常和驱动模块的名称一样,即/dev/sn9c102

    .id_table =   sn9c102_id_table, // ID设备表,包含了一列该驱动程序可以支持的USB设备
    .probe =      sn9c102_usb_probe,//探测函数
    .disconnect = sn9c102_usb_disconnect,//断开函数

};

其中对file* filp的操作通常出现在file_operations里面的各种函数中:

struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));

同时,代码常通过引用file的某些参数来决定是不是要做某些事情:

if (filp->f_flags & O_NONBLOCK) {

           up(&cam->fileop_sem);

           return -EAGAIN;

       }

具体函数实现可以参看linux2.6.16.20内核,这里就没必要给出了吧!在我们写驱动的时候,是有套路的,先include 一些下面要用到的头文件,提供一些必要函数

#include <linux/module.h> //想搞成模块不能没有这个吧
#include <linux/kernel.h> //prinfk()之类重要的函数
#include <linux/fs.h> //下面的三个结构体两个来自这里,Linux下一切设备都是文件

 

#include "sn9c102.h" //用户自定义通常放最后,””

做一些必要的仪式性质的工作

/**************************************************/

 

#define SN9C102_MODULE_NAME "V4L2 driver for SN9C10x PC Camera Controllers"

#define SN9C102_MODULE_AUTHOR  "(C) 2004-2006 Luca Risolia"

#define SN9C102_AUTHOR_EMAIL  "<luca.risolia@studio.unibo.it>"

#define SN9C102_MODULE_LICENSE  "GPL"

#define SN9C102_MODULE_VERSION  "1:1.26"

#define SN9C102_MODULE_VERSION_CODE  KERNEL_VERSION(1, 0, 26)

 

/************************************************/

 

MODULE_DEVICE_TABLE(usb, sn9c102_id_table);

 

MODULE_AUTHOR(SN9C102_MODULE_AUTHOR " " SN9C102_AUTHOR_EMAIL);

MODULE_DESCRIPTION(SN9C102_MODULE_NAME);

MODULE_VERSION(SN9C102_MODULE_VERSION);

MODULE_LICENSE(SN9C102_MODULE_LICENSE);

再填充file_operations然后填充usb_driver,最后写两个重要的模块函数,用宏定义注册下啊

static int __init sn9c102_module_init(void)

{

    int err = 0;

    KDBG(2, SN9C102_MODULE_NAME " v" SN9C102_MODULE_VERSION);

    KDBG(3, SN9C102_MODULE_AUTHOR);

 

    if ((err = usb_register(&sn9c102_usb_driver)))//设备注册,以获取硬件资源

       KDBG(1, "usb_register() failed");

 

    return err;

}

 

static void __exit sn9c102_module_exit(void)

{

    usb_deregister(&sn9c102_usb_driver); //注销设备,释放硬件资源
}

 

module_init(sn9c102_module_init);//模块初始化时候被用到

module_exit(sn9c102_module_exit); //卸载模块时候被用到

总的来说就是这样的(具体参看/drivers/usb/media/sn9c102_core.c)

包含必要的头文件

填充file_operations

填充usb_driver

usb_register\usb_deregister

module_init\ module_exit


    所以其实,写个驱动并不是很难,相反他并没有太多新玩儿,如果你打算写个应用往往要想大把大把的算法去解决实际问题,写驱动则没有太多花样,花样多了反而易出问题。这透露我们一个信息,女朋友和老婆,泡妞和过日子完全是两码事。最后,祝你过得愉快,因为你愉快,我愉快!

这篇文章,了解写一个驱动的大体结构,这很重要,下一个文我们再练练手



地震让大伙知道:居安思危,才是生存之道。
posted on 2008-05-02 18:01 小寻 阅读(2376) 评论(1)  编辑  收藏 所属分类: kernel

FeedBack:
# re: [原创]如何编写Linux 驱动程序(三) 2010-05-14 18:57 dengnice
很好很强大,呼呼,学习下!  回复  更多评论
  

只有注册用户登录后才能发表评论。


网站导航: