DEVICE_ATTR
說道sysfs接口,就不得不提到函數(shù)宏?DEVICE_ATTR,原型是
#define DEVICE_ATTR(_name, _mode, _show, _store) \
struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)
函數(shù)宏DEVICE_ATTR內(nèi)封裝的是__ATTR(_name,_mode,_show,_stroe)方法
_show:表示的是讀方法,
_stroe表示的是寫方法。
?
當(dāng)然_ATTR不是獨(dú)生子女,他還有一系列的姊妹__ATTR_RO宏只有讀方法,__ATTR_NULL等等
如對設(shè)備的使用????? ??DEVICE_ATTR???
對驅(qū)動使用??????? ???????DRIVER_ATTR
對總線使用??????? ?? ????BUS_ATTR?
對類別?(class)?使用??CLASS_ATTR
這四個高級的宏來自于<include/linux/device.h>?
DEVICE_ATTR??宏聲明有四個參數(shù),分別是名稱、權(quán)限位、讀函數(shù)、寫函數(shù)。其中讀函數(shù)和寫函數(shù)是讀寫功能函數(shù)的函數(shù)名。
如果你完成了DEVICE_ATTR函數(shù)宏的填充,下面就需要創(chuàng)建接口了
例如:
? ??static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,?show_polling, set_polling);
? ? static struct attribute *dev_attrs[] = {
? ? ? ? ? ??&dev_attr_polling.attr,
? ? ? ? ? ? NULL,
? ? };
當(dāng)你想要實(shí)現(xiàn)的接口名字是polling的時候,需要實(shí)現(xiàn)結(jié)構(gòu)體struct attribute?*dev_attrs[]
其中成員變量的名字必須是&dev_attr_polling.attr
然后再封裝
? ??static struct attribute_group dev_attr_grp = {
? ? ? ? ? ? .attrs = dev_attrs,
? ? };
?????? 通過以上簡單的三個步驟,就可以在adb?shell?終端查看到接口了。當(dāng)我們將數(shù)據(jù)?echo?到接口中時,在上層實(shí)際上完成了一次?write?操作,對應(yīng)到?kernel?,調(diào)用了驅(qū)動中的?“store”。同理,當(dāng)我們cat?一個?接口時則會調(diào)用?“show”?。到這里,只是簡單的建立了?android?層到?kernel?的橋梁,真正實(shí)現(xiàn)對硬件操作的,還是在?"show"?和?"store"?中完成的。
###############################################################
sysfs文件系統(tǒng)學(xué)習(xí)
為了更好地了解kobject的層次關(guān)系,有必要了解一下這種層次關(guān)系的表現(xiàn)機(jī)制:sysfs。本文簡單地學(xué)習(xí)了一下sysfs,大部分內(nèi)容來自內(nèi)核文檔sysfs.txt。好了,開始我們的學(xué)習(xí)之旅,呵呵。
?
何為sysfs
??? sysfs是一種基于ram的文件系統(tǒng),它提供了一種用于向用戶空間展現(xiàn)內(nèi)核空間里的對象、屬性和鏈接。sysfs與kobject層次緊密相連,它將kobject層次關(guān)系表現(xiàn)出來,使得用戶空間可以看見這些層次關(guān)系。
??? 在控制臺輸入命令“mount -t sysfs sysfs /sys”,就可以在/sys目錄下看到這些層次關(guān)系了。
?
目錄的創(chuàng)建
??? 對于每個注冊到系統(tǒng)的kobject,在sysfs中都有一個目錄來展現(xiàn)它,這個目錄(AA)會作為某個目錄(A)的子目錄而被創(chuàng)建,我們知道目錄AA代表kobject,那么目錄A則代表kobject->parent,顯示這種目錄層次關(guān)系可以很好地向用戶展現(xiàn)kobject層次結(jié)構(gòu)。在sysfs中位于頂層的那些目錄,分別代表著不同的子系統(tǒng),每個新加入的kobject都應(yīng)該歸屬于某一個子系統(tǒng)。
????sysfs會把目錄所代表的kobject存儲在目錄的dentry結(jié)構(gòu)的d_fsdata字段,這樣當(dāng)文件打開和關(guān)閉的時候,sysfs可以直接對kobject做引用計數(shù)。
?
屬性
??? 在sysfs中,kobject的屬性表現(xiàn)為一個普通的文件。sysfs將文件的I/O操作重定向到那些為該屬性定義的方法,提供了一種讀寫屬性的機(jī)制。
?????屬性應(yīng)該表現(xiàn)為ASCII文本文件,并且最好每個文件只包含一個值。當(dāng)然,每個文件僅包含一個值可能會有害于效率,所以如果一個文件包含某種類型的數(shù)據(jù)的數(shù)組也是被接受的。不建議在一個文件中包含不同數(shù)據(jù)類型的數(shù)據(jù)和多行數(shù)據(jù)。
??? 屬性的定義如下:
??? struct attribute {
??????? char??????????????????? * name;
??????? struct module??*owner;
??????? mode_t????????????????? mode;
??? };
??? int sysfs_create_file(struct kobject * kobj, const struct attribute * attr);
??????? 在kobj所在目錄下創(chuàng)建一個屬性文件,文件名為attr->name
??? void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr);
??????? 將屬性文件attr->name從kobj所在目錄下移除
?
??? 為了使對屬性的讀寫變得有意義,一般將attribute結(jié)構(gòu)嵌入到其他數(shù)據(jù)結(jié)構(gòu)中。子系統(tǒng)通常都會定義自己的屬性結(jié)構(gòu),并且提供添加和刪除屬性文件的包裹函數(shù)。
??? 例如,設(shè)備驅(qū)動模型為device子系統(tǒng)定義了相應(yīng)的屬性結(jié)構(gòu)device_attribute:
??? struct device_attribute {
???????? struct attribute?attr;
???????? ssize_t (*show)(struct device *dev, struct device_attribute *attr,char *buf);
???????? ssize_t (*store)(struct device *dev, struct device_attribute *attr,const char *buf, size_t count);
??? };
?
??? int device_create_file(struct device *, struct device_attribute *);
??????? 在/sys/devices/xxx/目錄下創(chuàng)建device屬性文件
??? void device_remove_file(struct device *, struct device_attribute *);
??????? 移除/sys/devices/xxx/目錄下的device屬性文件
?
??? 系統(tǒng)提供了一個宏方便定義device屬性:
??? #define DEVICE_ATTR(_name, _mode, _show, _store) /
??????? struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)
??
? ? 其中,__ATTR定義如下:
??? #define __ATTR(_name,_mode,_show,_store) { /
???? .attr = {.name = __stringify(_name), .mode = _mode },?/
???? .show?= _show,?????/
???? .store?= _store,?????/
??? }
???
??? 例如,定義一個device屬性,名為foo,讀寫該文件的方法分別為show_foo和store_foo:
??? static DEVICE_ATTR(foo, S_IWUSR | S_IRUGO, show_foo, store_foo);
??? 將宏展開為:???
??? static struct device_attribute dev_attr_foo = {
??????? ??? .attr?= {
????????????????????????? .name = "foo",
????????????????????????? .mode = S_IWUSR | S_IRUGO,
???????????? ????????? },
??????????? .show = show_foo,
??????????? .store = store_foo,
????};
?
子系統(tǒng)特定的回調(diào)函數(shù)
??? 當(dāng)子系統(tǒng)定義一個新的屬性類型時,必須實(shí)現(xiàn)一組sysfs操作,從而將文件的讀寫調(diào)用(read/write調(diào)用)重定向到屬性擁有者的show和store方法。
?
??? struct sysfs_ops {
??????? ssize_t (*show)(struct kobject *, struct attribute *, char *);
??????? ssize_t (*store)(struct kobject *, struct attribute *, const char *);
??? };
?
??? 當(dāng)讀寫一個文件時,sysfs將為此類型調(diào)用合適的方法,這些方法會將kobject結(jié)構(gòu)和attribute結(jié)構(gòu)轉(zhuǎn)換為合適的指針類型,然后調(diào)用與之關(guān)聯(lián)的相關(guān)的方法。注意,子系統(tǒng)必須已經(jīng)為此類型定義好了kobj_type作為此類型的描述符,因?yàn)閟ysfs_ops指針存儲在kobj_type中。
??? 舉個例子:??
??? #define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr)
??? #define to_dev(d) container_of(d, struct device, kobj)
??? static ssize_t dev_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
??? {
??????? struct device_attribute * dev_attr = to_dev_attr(attr);
??????? struct device * dev = to_dev(kobj);
??????? ssize_t ret = 0;
??????? if (dev_attr->show)
??????????????? ret = dev_attr->show(dev, buf);
??????? return ret;
??? }
?
屬性的讀寫
??? 為了讀寫屬性,當(dāng)定義屬性時,必須指定show和/或者store方法:
ssize_t (*show)(struct device * dev, struct device_attribute * attr, char * buf);
ssize_t (*store)(struct device * dev, struct device_attribute * attr, const char * buf);
?
sysfs allocates a buffer of size (PAGE_SIZE) and passes it to the
method. Sysfs will call the method exactly once for each read or
write. This forces the following behavior on the method
implementations:
?
- On read(2), the show() method should fill the entire buffer.?
? Recall that an attribute should only be exporting one value, or an
? array of similar values, so this shouldn't be that expensive.
? This allows userspace to do partial reads and forward seeks
? arbitrarily over the entire file at will. If userspace seeks back to
? zero or does a pread(2) with an offset of '0' the show() method will
? be called again, rearmed, to fill the buffer.
- On write(2), sysfs expects the entire buffer to be passed during the
? first write. Sysfs then passes the entire buffer to the store()
? method.?
??
??? 當(dāng)寫一個sysfs文件時,用戶空間的進(jìn)程應(yīng)該先讀取整個文件,然后修改希望改變的值,最后將整個緩沖區(qū)回寫到文件中。
??? Attribute method implementations should operate on an identical buffer when reading and writing values.
???
??? 其他注意事項(xiàng):
- Writing causes the show() method to be rearmed regardless of current file position.(???)
- 緩沖區(qū)的大小應(yīng)總是為PAGE_SIZE個字節(jié)。在i386上,PAGE_SIZE=4096
- show方法應(yīng)該返回放入緩沖區(qū)的字節(jié)數(shù),即snprintf的返回值
- show方法應(yīng)該總是使用snprintf
- store方法應(yīng)該返回實(shí)際使用的字節(jié)數(shù),可以使用strlen來得到
- show和/或者store方法可能會出錯,所以當(dāng)失敗時,記得返回錯誤值
- The object passed to the methods will be pinned in memory via sysfs
? referencing counting its embedded object. However, the physical?
? entity (e.g. device) the object represents may not be present. Be?
? sure to have a way to check this, if necessary.?(???)
??? 下面的代碼展示了device屬性的一個簡單的實(shí)現(xiàn):
??? static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf)
??? {
???????? return snprintf(buf, PAGE_SIZE, "%s/n", dev->name);
??? }
??? static ssize_t store_name(struct device * dev, const char * buf)
??? {
???????? sscanf(buf, "%20s", dev->name);
???????? return strnlen(buf, PAGE_SIZE);
????}
??? static DEVICE_ATTR(name, S_IRUGO, show_name, store_name);
??? 注意,實(shí)際應(yīng)用時,并不允許從用戶空間設(shè)置設(shè)備的名字,這里僅舉個例子。
?
sysfs頂層目錄結(jié)構(gòu)
??? sysfs目錄結(jié)構(gòu)展現(xiàn)了內(nèi)核數(shù)據(jù)結(jié)構(gòu)之間的關(guān)系,頂層目錄結(jié)構(gòu)如下:
?
block/
bus/
class/
dev/
devices/
firmware/
net/
fs/
?
??? 下面撿幾個重要的目錄進(jìn)行說明:
??? devices目錄展現(xiàn)了系統(tǒng)中的設(shè)備樹,它直接對應(yīng)于內(nèi)核中的設(shè)備樹,即device的層次結(jié)構(gòu)?;
??? bus目錄下包含了若干目錄,每個目錄表示系統(tǒng)中的一個總線,且每個目錄下又包含兩個子目錄:devices、drivers。其中devices子目錄下包含系統(tǒng)中發(fā)現(xiàn)的device的符號鏈接,這些符號鏈接分別指向/sys/devices/xxx目錄下對應(yīng)的目錄;drivers子目錄下包含特定總線上的那些用于驅(qū)動每個設(shè)備的驅(qū)動程序的目錄(可見,一個驅(qū)動程序只會出現(xiàn)在某一個特定的總線上);
???
當(dāng)前接口
??? 目前sysfs中存在以下接口:
- devices (include/linux/device.h)
??? device屬性:
??? struct device_attribute {
? ?? struct attribute?attr;
? ?? ssize_t (*show)(struct device *dev, struct device_attribute *attr,?char *buf);
? ?? ssize_t (*store)(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
??? };
?
??? 屬性的聲明:
??? DEVICE_ATTR(_name, _mode, _show, _store);
??? 屬性的創(chuàng)建和移除:
??? int device_create_file(struct device *device, struct device_attribute * attr);
??? void device_remove_file(struct device * dev, struct device_attribute * attr);
- bus drivers (include/linux/device.h)
??? bus屬性:
??? struct bus_attribute {
??????? struct attribute??????? attr;
??????? ssize_t (*show)(struct bus_type *, char * buf);
??????? ssize_t (*store)(struct bus_type *, const char * buf);
??? };
??? 屬性的聲明:
??? BUS_ATTR(_name, _mode, _show, _store)
??? 屬性的創(chuàng)建和移除:
??? int bus_create_file(struct bus_type *, struct bus_attribute *);
??? void bus_remove_file(struct bus_type *, struct bus_attribute *);
- device drivers (include/linux/device.h)
??? driver屬性:
??? struct driver_attribute {
??????? struct attribute??????? attr;
??????? ssize_t (*show)(struct device_driver *, char * buf);
??????? ssize_t (*store)(struct device_driver *, const char * buf,
???????????????????????? size_t count);
??? };
??? 屬性的聲明:
??? DRIVER_ATTR(_name, _mode, _show, _store)
??? 屬性的創(chuàng)建和移除:
??? int driver_create_file(struct device_driver *, struct driver_attribute *);
??? void driver_remove_file(struct device_driver *, struct driver_attribute *);
總結(jié)
以上是生活随笔為你收集整理的DEVICE_ATTR的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 内核驱动中常见的miscdevice、p
- 下一篇: android camera(二):摄像