DEVICE_ATTR的使用
類似的還有DRIVER_ATTR,BUS_ATTR,CLASS_ATTR。
這幾個東東的區別就是,DEVICE_ATTR對應的文件在/sys/devices/目錄中對應的device下面。
而其他幾個分別在driver,bus,class中對應的目錄下。
這次主要介紹DEVICE_ATTR,其他幾個類似。
在documentation/driver-model/Device.txt中有對DEVICE_ATTR的詳細介紹,這兒主要說明使用方法。
先看看DEVICE_ATTR的原型:
DEVICE_ATTR(_name, _mode, _show, _store)
_name:名稱,也就是將在sys fs中生成的文件名稱。
_mode:上述文件的訪問權限,與普通文件相同,UGO的格式。
_show:顯示函數,cat該文件時,此函數被調用。
_store:寫函數,echo內容到該文件時,此函數被調用。
看看我們怎么填充這些要素:
名稱可以隨便起一個,便于記憶,并能體現其功能即可。
模式可以為只讀0444,只寫0222,或者讀寫都行的0666。當然也可以對User\Group\Other進行區別。
顯示和寫入函數就需要實現了。
顯示函數的一般實現:
static ssize_t xxx_show(struct device *dev,
?struct device_attribute *attr, char *buf)
{
?return scnprintf(buf, PAGE_SIZE, "%d\n", dma_dump_flag);
}
實現相對簡單,調用了個很陽春的scnprintf,把數據放到buf中,就算大功告成了。
至于buf中的內容怎么顯示出來,這個先略過。
寫入函數的一般實現:
static ssize_t xxx_store(struct device *dev,
?struct device_attribute *attr, const char *buf, size_t count)
{
?unsigned long num;
?if (strict_strtoul(buf, 0, &num))
??return -EINVAL;
?if (num < 0)
??return -EINVAL;
?mutex_lock(&xxx_lock);
?dma_dump_flag = num;
?mutex_unlock(&xxx_lock);
?return count;
}
也挺直白,就不細說了。
其中加了個lock進行互斥。
函數名中的后綴_show和_store當然不是必須的。
只是便于標識。
DEVICE_ATTR的定義例子:
static DEVICE_ATTR(xxx, 0666, xxx_show, xxx_store);
該代碼可以防止文件的任何位置,只要別引起編譯錯誤!
是不是這樣就搞定了?
當然沒有,還需要調用函數device_create_file來傳教sys fs中的文件。
調用方法:
device_create_file(&pdev->dev, &dev_attr_xxx);
文件不是創建在某個device目錄下么,pdev->dev就是該device。
dev_attr_xxx就是在xxx前加上dev_attr_,好像是廢話,不過現實就是這樣。
開始還找了半天,dev_attr_xxx在哪兒定義?
最終發現這兒就是它唯一出現的地方。
device_create_file的調用例子:
??ret = device_create_file(&pdev->dev, &dev_attr_xxx);
??if (ret != 0) {
???dev_err(&pdev->dev,
????"Failed to create xxx sysfs files: %d\n", ret);
???return ret;
??}
這個代碼最好放在device的probe函數中。
原因么,在documentation/driver-model/Device.txt中有說明。
下面看看DEVICE_ATTR的定義:
#define DEVICE_ATTR(_name, _mode, _show, _store) \
struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)
dev_attr_##_name!!!!!
終于找到dev_attr_xxx定義的地方了!
#define __ATTR(_name,_mode,_show,_store) { \
?.attr = {.name = __stringify(_name), .mode = _mode },?\
?.show?= _show,?????\
?.store?= _store,?????\
}
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);
};
DEVICE_ATTR的功能就是定義一個device_attribute結構體對象。
device_create_file利用該對象在device下創建文件。
/**
?* device_create_file - create sysfs attribute file for device.
?* @dev: device.
?* @attr: device attribute descriptor.
?*/
int device_create_file(struct device *dev,
???????? const struct device_attribute *attr)
{
?int error = 0;
?if (dev)
??error = sysfs_create_file(&dev->kobj, &attr->attr);
?return error;
}
/**
?*?sysfs_create_file - create an attribute file for an object.
?*?@kobj:?object we're creating for.?
?*?@attr:?attribute descriptor.
?*/
int sysfs_create_file(struct kobject * kobj, const struct attribute * attr)
{
?BUG_ON(!kobj || !kobj->sd || !attr);
?return sysfs_add_file(kobj->sd, attr, SYSFS_KOBJ_ATTR);
}
sd的類型為struct sysfs_dirent。
/*
?* sysfs_dirent - the building block of sysfs hierarchy.? Each and
?* every sysfs node is represented by single sysfs_dirent.
?*
?* As long as s_count reference is held, the sysfs_dirent itself is
?* accessible.? Dereferencing s_elem or any other outer entity
?* requires s_active reference.
?*/
struct sysfs_dirent {
?atomic_t??s_count;
?atomic_t??s_active;
#ifdef CONFIG_DEBUG_LOCK_ALLOC
?struct lockdep_map?dep_map;
#endif
?struct sysfs_dirent?*s_parent;
?struct sysfs_dirent?*s_sibling;
?const char??*s_name;
?const void??*s_ns; /* namespace tag */
?union {
??struct sysfs_elem_dir??s_dir;
??struct sysfs_elem_symlink?s_symlink;
??struct sysfs_elem_attr??s_attr;
??struct sysfs_elem_bin_attr?s_bin_attr;
?};
?unsigned int??s_flags;
?unsigned short??s_mode;
?ino_t???s_ino;
?struct sysfs_inode_attrs *s_iattr;
};
int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr,
???? int type)
{
?return sysfs_add_file_mode(dir_sd, attr, type, attr->mode);
}
int sysfs_add_file_mode(struct sysfs_dirent *dir_sd,
???const struct attribute *attr, int type, mode_t amode)
{
?umode_t mode = (amode & S_IALLUGO) | S_IFREG;
?struct sysfs_addrm_cxt acxt;
?struct sysfs_dirent *sd;
?int rc;
?// 分配空間,并初始化部分成員。
?sd = sysfs_new_dirent(attr->name, mode, type);
?if (!sd)
??return -ENOMEM;
?sd->s_attr.attr = (void *)attr;
/*
?* Initialize a lock instance's lock-class mapping info:
?*/
?sysfs_dirent_init_lockdep(sd);
/**
?*?sysfs_addrm_start - prepare for sysfs_dirent add/remove
?*?@acxt: pointer to sysfs_addrm_cxt to be used
?*?@parent_sd: parent sysfs_dirent
?*
?*?This function is called when the caller is about to add or
?*?remove sysfs_dirent under @parent_sd.? This function acquires
?*?sysfs_mutex.? @acxt is used to keep and pass context to
?*?other addrm functions.
?*
?*?LOCKING:
?*?Kernel thread context (may sleep).? sysfs_mutex is locked on
?*?return.
?*/
?sysfs_addrm_start(&acxt, dir_sd);
?
/**
?*?sysfs_add_one - add sysfs_dirent to parent
?*?@acxt: addrm context to use
?*?@sd: sysfs_dirent to be added
?*
?*?Get @acxt->parent_sd and set sd->s_parent to it and increment
?*?nlink of parent inode if @sd is a directory and link into the
?*?children list of the parent.
?*
?*?This function should be called between calls to
?*?sysfs_addrm_start() and sysfs_addrm_finish() and should be
?*?passed the same @acxt as passed to sysfs_addrm_start().
?*
?*?LOCKING:
?*?Determined by sysfs_addrm_start().
?*
?*?RETURNS:
?*?0 on success, -EEXIST if entry with the given name already
?*?exists.
?*/
?rc = sysfs_add_one(&acxt, sd);
?
/**
?*?sysfs_addrm_finish - finish up sysfs_dirent add/remove
?*?@acxt: addrm context to finish up
?*
?*?Finish up sysfs_dirent add/remove.? Resources acquired by
?*?sysfs_addrm_start() are released and removed sysfs_dirents are
?*?cleaned up.
?*
?*?LOCKING:
?*?sysfs_mutex is released.
?*/
?sysfs_addrm_finish(&acxt);
?if (rc)
??sysfs_put(sd);
?return rc;
}
基本上知道是怎么回事了。
暫時先到這,就不再深入了。
總結
以上是生活随笔為你收集整理的DEVICE_ATTR的使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 普通人的节奏
- 下一篇: ADI收发器新品-ADRV9002特性与