EDA365电子论坛网
标题:
Linux设备模型 (3)
[打印本页]
作者:
pulbieup
时间:
2021-7-22 09:58
标题:
Linux设备模型 (3)
! U$ M+ D+ t4 d( f7 b+ t
在上文中,我们介绍到如何使用default attribute。Default attribute使用很方便,但不够灵活。比如上篇文章在Kobject一节中提到的那个例子,name和val这两个attribute使用同一个show/store函数来访问,如果attribute非常多,show/store函数里的分支就会很凌乱。
5 ^2 N6 M5 n3 a) J( E
! |- w# U0 ~9 _6 Q- [$ T, u; l
为了解决这个问题,我们可以参考内核提供的kobj_attribute。在内核里,kobj_attibute是这样定义的:
1 u& |$ A' v1 I7 y0 y* y
a" m/ D3 i3 \2 m3 X3 e! C* D
struct kobj_attribute {
struct attribute attr;
ssize_t (*show)(struct kobject *kobj, struct kobj_attribute *attr,
char *buf);
ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t count);
};
! K. O6 E; ^* S
# @: x# S/ L# R4 X0 [9 p, b
j& B4 N& l0 u) c) J' S
每一个attribute会对应自己的show/store函数,这样就极大的提高了灵活性。可是,在上一篇文章中我们的认知是,sysfs是通过kobject里的kobj_type->sysfs_ops来读写attribute的,那如果要利用kobj_attribute中的show/store来读写attribute的话,就必须在kobj_type->sysfs_ops里指定。Linux内核提供了一个默认的kobj_type类型dynamic_kobj_ktype来实现上述的操作。
. k! _$ G- G% g1 ?
1 W _; G7 |7 `4 v. G
/* default kobject attribute operations */
static ssize_t kobj_attr_show(struct kobject *kobj, struct attribute *attr,
char *buf)
{
struct kobj_attribute *kattr;
ssize_t ret = -EIO;
kattr = container_of(attr, struct kobj_attribute, attr);
if (kattr->show)
ret = kattr->show(kobj, kattr, buf);
return ret;
}
static ssize_t kobj_attr_store(struct kobject *kobj, struct attribute *attr,
const char *buf, size_t count)
{
struct kobj_attribute *kattr;
ssize_t ret = -EIO;
kattr = container_of(attr, struct kobj_attribute, attr);
if (kattr->store)
ret = kattr->store(kobj, kattr, buf, count);
return ret;
}
const struct sysfs_ops kobj_sysfs_ops = {
.show = kobj_attr_show,
.store = kobj_attr_store,
};
static void dynamic_kobj_release(struct kobject *kobj)
{
pr_debug("kobject: (%p): %s\n", kobj, __func__);
kfree(kobj);
}
static struct kobj_type dynamic_kobj_ktype = {
.release = dynamic_kobj_release,
.sysfs_ops = &kobj_sysfs_ops,
};
$ s1 I# j- A& A- p+ t! l
% x" h4 [ _3 ?* v, ]. O2 U
$ d Q4 Y! ^( \1 J% {1 C
kobj_attribute是内核提供给我们的一种更加灵活的处理attribute的方式,但是它还不够。只有当我们使用kobject_create来创建kobject时,使用kobj_attribute才比较方便,但大部分情况下,我们是把kobject内嵌到自己的结构里,此时就无法直接使用内核提供的dynamic_kobj_ktype,因此,我们需要创建自己的kobj_attribute。
7 J/ i7 r* o% V5 `. B8 ?
- ^3 r4 h: w7 G+ q$ i+ r( _
本文接下来将围绕一个实作来看看如何创建自己的kobj_attribute,sample code可以从这里下载。这个sample code是基于上篇文章kobject中的例子修改而来的,看过那个例子的读者应该会比较轻松。
1 Z0 q n& B: u4 n a0 X2 j0 h
! n, ^. F% `: B5 M T, l* Y
首先,我们需要定义自己的attribute:
4 E& T! w+ q4 [# O
1 H: r6 g+ n8 u: L
struct my_attribute {
struct attribute attr;
ssize_t (*show)(struct my_kobj *obj, struct my_attribute *attr,
char *buf);
ssize_t (*store)(struct my_kobj *obj, struct my_attribute *attr,
const char *buf, size_t count);
};
" h5 J9 H. `# P- y
/ [3 s( K" _8 `: o' q- V
& W; g, [& u1 M
在my_attribute里,我们的show/store直接操作my_kobj,这样更加方便。
* n2 s& L" B* u8 k# U3 g
; i* E- i" w6 L' L6 H7 V2 p- ?1 i: y
参考Linux内核,kobj_type里的sysfs_ops这样定义:
; |. e1 z u$ W$ j% X) X
# M* f6 d* U/ m) ?# `; e' ~' `2 Y: F
static ssize_t my_attr_show(struct kobject *kobj, struct attribute *attr,
char *buf)
{
struct my_attribute *my_attr;
ssize_t ret = -EIO;
my_attr = container_of(attr, struct my_attribute, attr);
if (my_attr->show)
ret = my_attr->show(container_of(kobj, struct my_kobj, kobj),
my_attr, buf);
return ret;
}
static ssize_t my_attr_store(struct kobject *kobj, struct attribute *attr,
const char *buf, size_t count)
{
struct my_attribute *my_attr;
ssize_t ret = -EIO;
my_attr = container_of(attr, struct my_attribute, attr);
if (my_attr->store)
ret = my_attr->store(container_of(kobj, struct my_kobj, kobj),
my_attr, buf, count);
return ret;
}
5 a% \6 x5 X# b& u- O
8 Y' P0 k5 p! C; F8 R" M
7 U: H3 C+ i* Z9 w. r; v
下面就可以分别对name和val两个attribute定义自己的show/store。name这个attribute是只读的,只要为它定义show即可。
; S" [* f' T) h4 V
$ P* \7 R/ f" F# B
ssize_t name_show(struct my_kobj *obj, struct my_attribute *attr, char *buffer)
{
return sprintf(buffer, "%s\n", kobject_name(&obj->kobj));
}
ssize_t val_show(struct my_kobj *obj, struct my_attribute *attr, char *buffer)
{
return sprintf(buffer, "%d\n", obj->val);
}
ssize_t val_store(struct my_kobj *obj, struct my_attribute *attr,
const char *buffer, size_t size)
{
sscanf(buffer, "%d", &obj->val);
return size;
}
_# a6 u" Z7 l5 m1 W" @- X
) H7 ~$ o) Z/ _4 U# w; K4 V5 Q7 D
0 d" z M: V) l4 o; p8 e
接下来,利用内核提供的宏__ATTR来初始化my_attribute,并建立attribute数组。
5 {6 V" q0 G2 _0 s) e- L0 p4 G( k2 r
% H9 r D3 L1 `+ ^6 B# X2 O/ u( M# n
struct my_attribute name_attribute = __ATTR(name, 0444, name_show, NULL);
struct my_attribute val_attribute = __ATTR(val, 0666, val_show, val_store);
struct attribute *my_attrs[] = {
&name_attribute.attr,
&val_attribute.attr,
NULL,
};
! W! a( v K# I3 K3 ?# S e
! L+ }$ J" `' A$ ^2 z
; t4 O8 ~$ b8 ^" B
其中,宏__ATTR的定义如下:
/ }; y1 _ ~( M- R7 D0 Z4 w& \
) z# v2 ~/ V- P6 |. Z- _) m
#define __ATTR(_name,_mode,_show,_store) { \
.attr = {.name = __stringify(_name), .mode = _mode }, \
.show = _show, \
.store = _store, \
}
5 @9 J* G! Z0 ^: O+ p
& Q0 e; c# `) |1 ~& v
* b1 T8 g! [$ y& I
在module_init里,我们调用sysfs_create_files来把attribute增加到sysfs中。
/ H& h/ U: |9 ]8 g. O" r, h6 a
: g8 Z# F# S1 d+ d' C8 C
retval = sysfs_create_files(&obj->kobj,
(const struct attribute **)my_attrs);
if (retval) {
// ...
}
! }% ]' |/ A3 _# U7 s
5 @7 L$ ]! |: e- ^9 [* F
1 Z) q# f% r# i. B' z- q0 y
在kobject对应的目录里,还可以创建子目录,Linux内核里是用attribute_group来实现。在本例中,我们可以这么做:
' }0 d/ s% S$ x! w% h4 p: \
. |6 u( r8 ~ g0 N( Z' R6 y5 k
struct attribute_group my_group = {
.name = "mygroup",
.attrs = my_attrs,
};
3 |, U+ x+ {1 v" @; w
+ X7 P* {- P4 a( @& F0 M
# M3 [; [/ e$ U2 }
然后在module_init里调用sysfs_create_group来添加。
, \9 v5 [, b8 c7 A! s
9 i3 k6 p: h( W3 }- X7 I
retval = sysfs_create_group(&obj->kobj, &my_group);
if (retval) {
// ...
}
$ Z; g, e5 [. w6 U
6 c' q* w3 w1 i- ]7 E3 i3 c$ s
& x' l8 _! z0 }& x
本例创建的attribute_group中包含的attribute也是my_attrs,所以在子目录mygroup下的文件和mykobj目录下的文件完全一致。
# {- S' f7 [" F ?, _2 M& h; X4 y
7 y, t5 g- A, \$ m: |& }
最后我们得到的目录结构是这样的。
2 O' U5 D, B8 W1 f0 n
5 s# H# l5 g* V$ U3 m
mykobj/
( t# Q& p/ h8 w7 s8 `6 |( `) y
|-- mygroup
5 H- ?% M- A1 Z- ~
| |-- name
% g* r1 f5 f" ~/ L2 J
| `-- val
& c: ?6 d! `: o( H. }/ S( ^2 J- L
|-- name
7 l, |/ g* Q1 \6 [* o
`-- val
8 Z. e: _ v7 ?1 i
% _0 ?' u6 L$ ~5 j6 s J
, n: v1 N" W) X. e) F' _1 Q
完成这个实作之后,你可以用命令echo 2 > /sys/mykobj/val来修改mykobj下的val文件,可以观察到/sys/mykobj/mygroup/val的内容也会变成2,反之亦然。
9 ?$ L4 e* w/ t6 A7 P% d, k: [
作者:
NNNei256
时间:
2021-7-22 11:17
Linux设备模型 (3)
作者:
CCxiaom
时间:
2021-7-22 11:17
Linux设备模型 (3)
作者:
qUzalq
时间:
2021-7-22 11:18
Linux设备模型 (3)
欢迎光临 EDA365电子论坛网 (https://bbs.eda365.com/)
Powered by Discuz! X3.2