The Linux device model
/sys和 /dev的疑問
1、/dev 下放的是設備文件,是由應用層mknod創建的文件。假設底層驅動對mknod的設備號有相應的驅動,如open等函數。那么應用層open “/dev/**”時,就會調用究竟層的驅動。說白了,/dev下放的是內核和應用層交互的文件,讓應用層去open,write,poll等。
2、/sys 是個文件系統,你寫內核代碼時,假設有調用kobj_init等函數,就會在/sys下的相應文件夾生成相應文件。 它的作用是將內核注冊的設備、驅動、BUS連成一個樹形結構。
另外,應用層也能夠通過讀寫/sys下的文件和內核進行交互(ktype)。 說白了/sys就是一個樹形結構。讓你明確內核都有哪些驅動和設備已經bus。方便電源管理。
3、http://blog.csdn.net/eliot_shao/article/details/13019389
在篇博客里《圖解linux設備模型》中,對udev和sysfs的關系做了更具體的說明。
sysfs底層操作
1、kobject結構
一提到kobject非常多人就不想看了。千篇一律。可是使用這個結構,我們能夠建立設備驅動模型,所以必須明確。開發驅動程序對我來說,也就是建幾個文件夾,創幾個屬性文件。內核的設備驅動架構已經打好了,調幾個函數來用就能夠了。在sysfs文件系統里,kobject相應文件夾。屬性(attribute)相應文件。
kobject內容包括文件夾的名字。parent上層文件夾,假設parent=NULL就在/sys以下創建文件夾。ktype可理解為這個文件夾的屬性。
struct kobj_type {void (*release)(struct kobject *);struct sysfs_ops * sysfs_ops;struct attribute ** default_attrs; }; struct sysfs_ops {ssize_t (*show)(struct kobject *, struct attribute *,char *);//讀方法ssize_t (*store)(struct kobject *,struct attribute *,const char *, size_t);//寫方法 }; struct attribute {const char * name;struct module * owner;mode_t mode; };//屬性文件的名字。模式,僅僅讀設為S_IRUGO,可寫設為S_IWUSR2、方法(operations)
想一想在文件系統上能干什么呢?無非是創建文件夾(kobject),創建文件(屬性)。
掛接該kobject對象到kset的list鏈中,添加父文件夾各級kobject的引// 用計數,在其parent指向的文件夾下創建文件節點,并啟動該類型內核對象的hotplug函數
int kobject_add(struct kobject * kobj); // kobject注冊函數,調用kobject init()初始化kobj,再調用kobject_add()完畢該內核對象的注冊 int kobject_register(struct kobject * kobj); // 從Linux設備層次(hierarchy)中刪除kobj對象 void kobject_del(struct kobject * kobj); // kobject注銷函數. 與kobject register()相反。它首先調用kobject del從設備層次中刪除該對象。再調// 用kobject put()降低該對象的引用計數,假設引用計數降為,則釋放kobject對象 void kobject_unregister(struct kobject * kobj);設備模型上層容器
這里說的上層容器指的是總線類型(bus_type)、設備(device)和驅動(device_driver)。LDD3里面舉過一個例如。把kobject當成一個基類,總線類型、設備、驅動和kobject都是繼承關系。這些上層的容器自然具備了sysfs的操作方法!
總線類型一般不須要我們創建了。內核支持大多數總線類型(pci。usb,iic…),還包括了虛擬總線類型(platform_bus),所以這里就不涉及怎樣創建總線,怎樣建立總線的屬性文件云云。
1. 設備 device
設備的操作可簡單理解為1、注冊設備;2、創建設備屬性文件。
通常的注冊和注銷函數:
int device_register(struct device *dev);
void device_unregister(struct device *dev);
設備的注冊和注銷包括了對底層的sysfs的操作。諸如kobject_init。kobject_add…
創建屬性
這些屬性結構可在編譯時建立, 使用這些宏:
DEVICE_ATTR(name, mode, show, store);
結果結構通過前綴 dev_attr_ 到給定名子上來命名. 屬性文件的實際管理使用通常的函數對來處理:
int device_create_file(struct device *device, struct device_attribute *entry);
void device_remove_file(struct device *dev, struct device_attribute *attr);
2. 驅動 driver
驅動的操作可簡單理解為1、注冊驅動;2、創建驅動屬性文件。
通常的注冊和注銷函數:
int driver_register(struct device_driver *drv);
void driver_unregister(struct device_driver *drv);
設備的注冊和注銷包括了對底層的sysfs的操作,諸如kobject_init,kobject_add…
創建屬性
DRIVER_ATTR(name, mode, show, store);
int driver_create_file(struct device_driver *drv, struct driver_attribute *attr);
void driver_remove_file(struct device_driver *drv, struct driver_attribute *attr);
摘一段驅動代碼來講講
#include <linux/fs.h> #include <asm/uaccess.h> #include <linux/pci.h> #include <linux/input.h> #include <linux/platform_device.h>struct input_dev *vms_input_dev; /* Representation of an input device */ static struct platform_device *vms_dev; /* Device structure *//* Sysfs method to input simulatedcoordinates to the virtualmouse driver */ static ssize_t write_vms(struct device *dev,struct device_attribute *attr,const char *buffer, size_t count) {int x,y;sscanf(buffer, "%d%d", &x, &y);/* Report relative coordinates via theevent interface */input_report_rel(vms_input_dev, REL_X, x);input_report_rel(vms_input_dev, REL_Y, y);input_sync(vms_input_dev);return count; } /* Attach the sysfs write method */ DEVICE_ATTR(coordinates, 0644, NULL, write_vms); /* Attribute Descriptor */ static struct attribute *vms_attrs[] = {&dev_attr_coordinates.attr,NULL }; /* Attribute group */ static struct attribute_group vms_attr_group = {.attrs = vms_attrs, }; /* Driver Initialization */ int __init vms_init(void) {/* Register a platform device */vms_dev = platform_device_register_simple("vms", -1, NULL, 0);if (IS_ERR(vms_dev)) {PTR_ERR(vms_dev);printk("vms_init: error\n");}/* Create a sysfs node to read simulated coordinates */sysfs_create_group(&vms_dev->dev.kobj, &vms_attr_group);/* Allocate an input device data structure */vms_input_dev = input_allocate_device();if (!vms_input_dev) {printk("Bad input_alloc_device()\n");}/* Announce that the virtual mouse will generaterelative coordinates */set_bit(EV_REL, vms_input_dev->evbit);set_bit(REL_X, vms_input_dev->relbit);set_bit(REL_Y, vms_input_dev->relbit);/* Register with the input subsystem */input_register_device(vms_input_dev);printk("Virtual Mouse Driver Initialized.\n");return 0; } /* Driver Exit */ void vms_cleanup(void) {/* Unregister from the input subsystem */input_unregister_device(vms_input_dev);/* Cleanup sysfs node */sysfs_remove_group(&vms_dev->dev.kobj, &vms_attr_group);/* Unregister driver */platform_device_unregister(vms_dev);return; }module_init(vms_init); module_exit(vms_cleanup);這是從《Essential Linux Device Drivers》第七章輸入設備摘的代碼,實現從虛擬鼠標讀取數據坐標上報的功能。
這里使用了總線platform_bus。
vms_dev = platform_device_register_simple(“vms”, -1, NULL, 0);注冊設備到總線;
sysfs_create_group(&vms_dev->dev.kobj, &vms_attr_group);創建屬性文件。在linux/sysfs.h中引用,相似于sysfs_create_file。
input_register_device(vms_input_dev);注冊設備文件到input子系統,具體細節參考源代碼;
總的來說,就是干了兩件事,創建文件夾對象和創建屬性,然后加到設備模型中。建立一個資源管理樹!
文章僅僅是片面的。宏觀的略談驅動模型。經驗不足,僅作參考!
參考資料
http://bbs.csdn.net/topics/380166008
http://blog.csdn.net/xiahouzuoxin/article/details/8943863
轉載于:https://www.cnblogs.com/blfshiye/p/5136307.html
總結
以上是生活随笔為你收集整理的The Linux device model的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MetadataType的使用
- 下一篇: Linux内核总结