隨筆 - 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 小尋 閱讀(2398) 評論(1)  編輯  收藏 所屬分類: kernel

          FeedBack:
          # re: [原創]如何編寫Linux 驅動程序(三) 2010-05-14 18:57 dengnice
          很好很強大,呼呼,學習下!  回復  更多評論
            
          主站蜘蛛池模板: 家居| 安龙县| 广元市| 溆浦县| 泸州市| 宁津县| 门头沟区| 施甸县| 西城区| 宿松县| 民乐县| 南丹县| 新宾| 农安县| 阜宁县| 雅江县| 丹寨县| 南丹县| 慈利县| 日照市| 沁源县| 鄂尔多斯市| 津南区| 永兴县| 手机| 德格县| 怀安县| 绥阳县| 余姚市| 布尔津县| 中山市| 依安县| 曲松县| 太仓市| 宜宾县| 酒泉市| 五台县| 靖江市| 连城县| 上虞市| 南平市|