參考:https://www.cnblogs.com/Cqlismy/p/11454573.html
在Linux驅(qū)動中經(jīng)常會用到DEVICE_ATTR宏奄喂,可以定義一個struct device_attribute設(shè)備屬性焙糟,并使用sysfs的API函數(shù)率寡,便可以在設(shè)備目錄下創(chuàng)建出屬性文件悼沈,當我們在驅(qū)動程序中實現(xiàn)了show和store函數(shù)后,便可以使用cat和echo命令對創(chuàng)建出來的設(shè)備屬性文件進行讀寫执解,從而達到控制設(shè)備的功能或听。
接下來是相關(guān)的基本結(jié)構(gòu)體:
struct attribute{}
里面有兩個重要的成員:
name:屬性的名稱
mode:屬性的讀寫權(quán)限
struct device_attribute{}對struct attribute結(jié)構(gòu)體進一步封裝,提供了兩個函數(shù)指針
show函數(shù):用于讀取設(shè)備的屬性文件
store函數(shù):用于寫設(shè)備的屬性文件
可以使用cat和echo命令對設(shè)備屬性文件進行讀寫操作
#define DEVICE_ATTR(_name, _mode, _show, _store) \
struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)
宏DEVICE_ATTR實現(xiàn)的功能就是定義了一個struct device_attribute結(jié)構(gòu)體變量dev_attr_name审丘,并對里面的成員進行初始化,包括struct attribute結(jié)構(gòu)體里面的name和mode成員變量勾给,然后還有實現(xiàn)屬性文件讀寫的show和store函數(shù)賦值备恤。
案例:
//讀操作
static ssize_t mydevice_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
return sprintf(buf, "%s\n", mybuf);
}
//寫操作
static ssize_t mydevice_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
sprintf(mybuf, "%s", buf);
return count;
}
static DEVICE_ATTR(mydevice, 0644, mydevice_show, mydevice_store);//定義一個自己的屬性文件,并賦予權(quán)限
以上锦秒,使用宏DEVICE_ATTR定義了一個mydevice的屬性文件,而且這個屬性文件的讀寫權(quán)限為:文件所擁有者可讀寫喉镰,組和其他人只能讀旅择。代碼還實現(xiàn)了該屬性文件的讀寫函數(shù)mydevice_show()和mydevice_store(),當在用戶空間中使用cat和echo命令時侣姆,將會調(diào)用到驅(qū)動程序中實現(xiàn)的兩個函數(shù)生真。
模塊加載函數(shù),當模塊加載時將會被調(diào)用
static int __init mydevice_init(void)//初始化
{
int ret;
struct device *mydevice;
major = register_chrdev(0, "mydevice", &myfops); //1捺宗、主設(shè)備號動態(tài)申請
if (major < 0) {
ret = major;
return ret;
}
myclass = class_create(THIS_MODULE, "myclass"); //動態(tài)創(chuàng)建設(shè)備所屬 的類myclass
if (IS_ERR(myclass)) {
ret = -EBUSY;
goto fail;
}
mydevice = device_create(myclass, NULL, MKDEV(major, 0), NULL, "mydevice");//動態(tài)創(chuàng)建mydevice設(shè)備
if (IS_ERR(mydevice)) { //錯誤檢測
class_destroy(myclass);
ret = -EBUSY;
goto fail; //出現(xiàn)問題goto fail進行對注冊的設(shè)備號的注銷
}
ret = sysfs_create_file(&mydevice->kobj, &dev_attr_mydevice.attr);//在sysfs中創(chuàng)建出設(shè)備的屬性文件
if (ret < 0)
return ret;
return 0;
fail:
unregister_chrdev(major, "mydevice");
return ret;
}
進行主設(shè)備的動態(tài)申請并調(diào)用class_dreate()和device_create()函數(shù)動態(tài)創(chuàng)建類和設(shè)備柱蟀,并且對其進行錯誤檢測,組后使用sysfs'的API函數(shù)sysfs_create_file()在sysfs中創(chuàng)建出設(shè)備的屬性文件蚜厉,完成驅(qū)動模塊的加載长已。
模塊卸載函數(shù)
需要調(diào)用device_destory()和class_destory()對模塊加載創(chuàng)建的myclass和mydevice進行銷毀,然后調(diào)用unregister_chrdev()將動態(tài)分配的主設(shè)備號進行釋放。
static void __exit mydevice_exit(void)
{
device_destroy(myclass, MKDEV(major, 0));
class_destroy(myclass);
unregister_chrdev(major, "mydevice");
}
測試:
編譯之后通過cd /sys/devices/virtual/myclass/mydevice/可以在其目錄下看到新建的mydevice設(shè)備屬性文件
通過cat和echo來進行讀寫
cat mydevice
echo "I am a simplest driver." > mydevice
cat mydevice