轉變思維做個當家人
不知道你對花錢,有沒有這樣的感覺?做孩子的時候,經常伸手要錢;但等到你泡到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函數操作時對此指針賦值 unsigned int f_flags;//文件標識,用于對阻塞或非阻塞檢查 loff_t f_pos; //當前讀寫位置,loff_t為64位數 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結構被釋放掉時,會調用這個方法 .read = sn9c102_read, //讀函數,ssize_t表示當前平臺上固有的整數類型 .mmap = sn9c102_mmap, //請求將設備內存映射到進程地址空間,一般用于塊設備 .llseek = no_llseek, //標識當前文件的操作位置 }; |
static struct usb_driver sn9c102_usb_driver = { .name = "sn9c102",//驅動名,通常和驅動模塊的名稱一樣,即/dev/sn9c102 .id_table = sn9c102_id_table, // ID設備表,包含了一列該驅動程序可以支持的USB設備 }; |
其中對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 "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
所以其實,寫個驅動并不是很難,相反他并沒有太多新玩兒,如果你打算寫個應用往往要想大把大把的算法去解決實際問題,寫驅動則沒有太多花樣,花樣多了反而易出問題。這透露我們一個信息,女朋友和老婆,泡妞和過日子完全是兩碼事。最后,祝你過得愉快,因為你愉快,我愉快!
這篇文章,了解寫一個驅動的大體結構,這很重要,下一個文我們再練練手
地震讓大伙知道:居安思危,才是生存之道。
