概述
文章目录
- 一、kobject的容器,体现设备驱动的层次关系
- 二、kset_create_and_add()函数
- 1、kset_create()函数
- 2、kset_register()函数
- (1) kset_init()函数
- 三、驱动源码
- 四、编译测试
一、kobject的容器,体现设备驱动的层次关系
/**
* struct kset - a set of kobjects of a specific type, belonging to a specific subsystem.
*
* A kset defines a group of kobjects. They can be individually
* different "types" but overall these kobjects all want to be grouped
* together and operated on in the same manner. ksets are used to
* define the attribute callbacks and other common events that happen to
* a kobject.
*
* @list: the list of all kobjects for this kset
* @list_lock: a lock for iterating over the kobjects
* @kobj: the embedded kobject for this kset (recursion, isn't it fun...)
* @uevent_ops: the set of uevent operations for this kset. These are
* called whenever a kobject has something happen to it so that the kset
* can add new environment variables, or filter out the uevents if so
* desired.
*/
struct kset {
struct list_head list;
spinlock_t list_lock;
struct kobject kobj;
const struct kset_uevent_ops *uevent_ops;
};
二、kset_create_and_add()函数
lib/kobject.c
负责产生一个 kset对象
,并与 sysfs 中的一个目录项
关联起来。
/* name:设置 kset 和 kset 对应的目录项的名称。
* uevent_ops:负责 kset 和用户空间通信的一系列函数接口。kobject 只能依靠上层 kset 对象来向用户空间发送消息。
* 用户空间的 mdev 或 udev 守护进程监测到 kset 发出的信息后,创建设备文件。
* parent_obj:设置 kset对象 上一层节点。
*/
struct kset *kset_create_and_add(const char *name,
const struct kset_uevent_ops *uevent_ops,
struct kobject *parent_kobj)
{
struct kset *kset;
int error;
/* 第一大步:
* 创建一个kset,并初始化其一些成员。
* 详见下。
*/
kset = kset_create(name, uevent_ops, parent_kobj);
if (!kset)
return NULL;
/* 第二大步:
* 注册 kset。
*/
error = kset_register(kset);
if (error) {
kfree(kset);
return NULL;
}
return kset;
}
1、kset_create()函数
lib/kobject.c
static struct kset *kset_create(const char *name,
const struct kset_uevent_ops *uevent_ops,
struct kobject *parent_kobj)
{
struct kset *kset;
int retval;
kset = kzalloc(sizeof(*kset), GFP_KERNEL);
if (!kset)
return NULL;
/* 设置 kobject 的名字
* 此函数内部会调用 kobject_set_name_vargs ,101节有详细介绍
* 其实基本等价于 kobject_set_name_vargs
*/
retval = kobject_set_name(&kset->kobj, "%s", name);
if (retval) {
kfree(kset);
return NULL;
}
/* 注册 消息发送接口。
* uevent_ops 是调用函数时作为参数传递进来的。
* 以后详细介绍此接口。
*/
kset->uevent_ops = uevent_ops;
/* 设置 kset 的上一层 kobject 节点。
* 作为参数传递进来。
*/
kset->kobj.parent = parent_kobj;
/* 操作属性接口 */
kset->kobj.ktype = &kset_ktype;
kset->kobj.kset = NULL;
return kset;
}
2、kset_register()函数
lib/kobject.c
int kset_register(struct kset *k)
{
int err;
if (!k)
return -EINVAL;
/* 其实就是初始化 kset->kobject 一些标志成员。
* 详见下。
*/
kset_init(k);
/* 创建一个目录项
* 并将 kobject 和 这个目录项 kernfs_node 关联起来。
* 详见 101。
*/
err = kobject_add_internal(&k->kobj);
if (err)
return err;
/* 此函数专门用来发送 驱动模型消息 到应用层。
* KOBJ_ADD 是消息类型,告诉应用层:新注册了一个 kset 或者 kobject
*/
kobject_uevent(&k->kobj, KOBJ_ADD);
return 0;
}
(1) kset_init()函数
lib/kobject.c
void kset_init(struct kset *k)
{
/* 初始化 kobject 一些标志成员。
* 详见 101。
*/
kobject_init_internal(&k->kobj);
/* 用于以后将一系列 kobject 节点串联起来 */
INIT_LIST_HEAD(&k->list);
spin_lock_init(&k->list_lock);
}
三、驱动源码
相比于上一次实验:本次只是先创建一个 kset 节点
,再在 此节点
下面创建一个 kobject
(用于控制 led)。
观察 /sys
目录下的层次关系;并通过 kobject
来控制 led,验证我们实现的 操作接口
是否正常工作。
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/kobject.h>
#include <linux/string.h>
#include <linux/sysfs.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <asm/io.h>
/* GPIO虚拟地址指针。
* __iomem 表示此指针指向的地址位于 io空间
*/
static void __iomem *IMX6U_CCM_CCGR1;
static void __iomem *SW_MUX_GPIO1_IO03;
static void __iomem *SW_PAD_GPIO1_IO03;
static void __iomem *GPIO1_DR;
static void __iomem *GPIO1_GDIR;
static int foo;
static ssize_t foo_show(struct kobject *kobj, struct kobj_attribute *attr,
char *buf)
{
return sprintf(buf, "%dn", foo);
}
static ssize_t foo_store(struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t count)
{
int ret;
ret = kstrtoint(buf, 10, &foo);
if (ret < 0)
return ret;
return count;
}
static struct kobj_attribute foo_attribute =
__ATTR(foo, 0664, foo_show, foo_store);
static ssize_t led_show(struct kobject *kobj, struct kobj_attribute *attr,
char *buf)
{
int var;
if (strcmp(attr->attr.name, "led") == 0)
var =123;
return sprintf(buf, "%dn", var);
}
static ssize_t led_store(struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t count)
{
if (strcmp(attr->attr.name, "led") == 0){
if(!memcmp(buf,"on",2)) {
iowrite32(0 << 3, GPIO1_DR);
} else if(!memcmp(buf,"off",3)) {
iowrite32(1 << 3, GPIO1_DR);
}
}
return count;
}
static struct kobj_attribute led_attribute =
__ATTR(led, 0664, led_show, led_store);
static struct attribute *attrs[] = {
&foo_attribute.attr,
&led_attribute.attr,
NULL, /* need to NULL terminate the list of attributes */
};
static struct attribute_group attr_group = {
.attrs = attrs,
};
static struct kset *example_kset;
static struct kobject *led_kobj;
static int __init led_init(void)
{
int retval;
/* GPIO相关寄存器映射 */
IMX6U_CCM_CCGR1 = ioremap(0x20c406c, 4);
SW_MUX_GPIO1_IO03 = ioremap(0x20e006c, 4);
SW_PAD_GPIO1_IO03 = ioremap(0x20e02f8, 4);
GPIO1_GDIR = ioremap(0x0209c004, 4);
GPIO1_DR = ioremap(0x0209c000, 4);
/* 使能GPIO1时钟 */
iowrite32(0xffffffff, IMX6U_CCM_CCGR1);
/* 设置GPIO1_IO03复用为普通GPIO*/
iowrite32(5, SW_MUX_GPIO1_IO03);
/*设置GPIO属性*/
iowrite32(0x10B0, SW_PAD_GPIO1_IO03);
/* 设置GPIO1_IO03为输出功能 */
iowrite32(1 << 3, GPIO1_GDIR);
/* LED输出高电平 */
iowrite32(1<< 3, GPIO1_DR);
/* 创建一个kset对象。
* 指定了名字。
* 第二个参数是向应用层发送消息的 ops。
* 第三个参数上层的 kobject 节点。
*/
example_kset = kset_create_and_add("kset_example", NULL, NULL);
if (!example_kset)
return -ENOMEM;
/* 创建一个kobject对象。
* 并把上面创建的 kset 对象对应的 kobject 作为此 kobject 的上层节点。
* 此函数详见 101.
*/
led_kobj = kobject_create_and_add("led_kobject", &example_kset->kobj);
if (!led_kobj)
return -ENOMEM;
/* 为kobject设置属性文件*/
retval = sysfs_create_group(led_kobj, &attr_group);
if (retval)
kobject_put(led_kobj);
return retval;
return 0;
}
static void __exit led_exit(void)
{
/* 取消映射 */
iounmap(IMX6U_CCM_CCGR1);
iounmap(SW_MUX_GPIO1_IO03);
iounmap(SW_PAD_GPIO1_IO03);
iounmap(GPIO1_DR);
iounmap(GPIO1_GDIR);
/* 注销字符设备驱动 */
kobject_put(led_kobj);
/*取消字符设备的注册*/
kset_unregister(example_kset);
}
module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("embedfire ");
MODULE_DESCRIPTION("led_module");
MODULE_ALIAS("led_module");
四、编译测试
/lib/modules/4.1.15 #
/lib/modules/4.1.15 # ls /sys/
block class devices fs module
bus dev firmware kernel power
/lib/modules/4.1.15 #
/lib/modules/4.1.15 #
/lib/modules/4.1.15 # insmod test.ko
/lib/modules/4.1.15 #
/lib/modules/4.1.15 # ls /sys
block dev fs module
bus devices kernel power
class firmware kset_example
/lib/modules/4.1.15 #
/lib/modules/4.1.15 # ls /sys/kset_example/
led_kobject
/lib/modules/4.1.15 #
/lib/modules/4.1.15 # ls /sys/kset_example/led_kobject/
foo led
/lib/modules/4.1.15 # echo 66 > random: nonblocking pool is initialized
/lib/modules/4.1.15 # echo 66 > /sys/kset_example/led_kobject/foo
/lib/modules/4.1.15 #
/lib/modules/4.1.15 # cat /sys/kset_example/led_kobject/foo
66
/lib/modules/4.1.15 #
/lib/modules/4.1.15 # cat /sys/kset_example/led_kobject/led
123
/lib/modules/4.1.15 # echo 'on' > /sys/kset_example/led_kobject/led
/lib/modules/4.1.15 # echo 'off' > /sys/kset_example/led_kobject/led
/lib/modules/4.1.15 #
最后
以上就是愤怒金鱼为你收集整理的104 kset:驱动的骨架的全部内容,希望文章能够帮你解决104 kset:驱动的骨架所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复