目录
1.1.2 设备属性 struct device_attribute
2.1.1 struct device_driver驱动数据结构
2.1.2 struct driver_attribute 设备属性
一. device设备描述
1.1 内核结构
1.1.1 设备 struct device
struct device {
struct device *parent;
/*设备私有数据*/
struct device_private *p;
struct kobject kobj;
/*设备名*/
const char *init_name; /* initial name of the device */
/*设备类型*/
const struct device_type *type;
struct mutex mutex; /* mutex to synchronize calls to
* its driver.
*/
/* 设备所在总线 */
struct bus_type *bus; /* type of bus device is on */
/*管理该设备的驱动*/
struct device_driver *driver; /* which driver has allocated this
device */
/*板级支持包提供*/
void *platform_data; /* Platform specific data, device
core doesn't touch it */
/*该设备驱动使用的私有数据成员 */
void *driver_data; /* Driver data, set and get with
dev_set/get_drvdata */
struct dev_pm_info power;
struct dev_pm_domain *pm_domain;
#ifdef CONFIG_PINCTRL
struct dev_pin_info *pins;
#endif
#ifdef CONFIG_NUMA
int numa_node; /* NUMA node this device is close to */
#endif
u64 *dma_mask; /* dma mask (if dma'able device) */
u64 coherent_dma_mask;/* Like dma_mask, but for
alloc_coherent mappings as
not all hardware supports
64 bit addresses for consistent
allocations such descriptors. */
unsigned long dma_pfn_offset;
struct device_dma_parameters *dma_parms;
struct list_head dma_pools; /* dma pools (if dma'ble) */
struct dma_coherent_mem *dma_mem; /* internal for coherent mem
override */
#ifdef CONFIG_DMA_CMA
struct cma *cma_area; /* contiguous memory area for dma
allocations */
#endif
struct removed_region *removed_mem;
/* arch specific additions */
struct dev_archdata archdata;
/*设备树 系统启动时解析dtb得到*/
struct device_node *of_node; /* associated device tree node */
struct acpi_dev_node acpi_node; /* associated ACPI device node */
/*主次设备号 12:20 (主:次)*/
dev_t devt; /* dev_t, creates the sysfs "dev" */
u32 id; /* device instance */
spinlock_t devres_lock;
struct list_head devres_head;
struct klist_node knode_class;
struct class *class;
const struct attribute_group **groups; /* optional groups */
/*释放device空间的*/
void (*release)(struct device *dev);
struct iommu_group *iommu_group;
bool offline_disabled:1;
bool offline:1;
};
/*设备相关结构体*/
struct device_type {
const char *name;
/*属性文件*/
const struct attribute_group **groups;
/*当设备insmod时, uevent会通过bus type(kset)发送时间到用户层。*/
int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
char *(*devnode)(struct device *dev, umode_t *mode,
kuid_t *uid, kgid_t *gid);
void (*release)(struct device *dev);
/*电源管理相关*/
const struct dev_pm_ops *pm;
};
struct device_private {
struct klist klist_children;
struct klist_node knode_parent;
struct klist_node knode_driver;
struct klist_node knode_bus;
struct list_head deferred_probe;
/*反向指向自己device*/
struct device *device;
};
1.1.2 设备属性 struct 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);
};
1.2 相关操作接口
注:一条总线也是个设备,也必须按设备注册。
1.2.1 设备操作接口
/*1. 注册设备*/
extern int __must_check device_register(struct device *dev);
/*2. 注销设备*/
extern void device_unregister(struct device *dev);
extern int __must_check device_add(struct device *dev);
extern void device_del(struct device *dev);
/*遍历bus type下所有device*/
extern int device_for_each_child(struct device *dev, void *data,
int (*fn)(struct device *dev, void *data));
extern struct device *device_find_child(struct device *dev, void *data,
int (*match)(struct device *dev, void *data));
extern int device_rename(struct device *dev, const char *new_name);
extern int device_move(struct device *dev, struct device *new_parent,
enum dpm_order dpm_order);
extern const char *device_get_devnode(struct device *dev,
umode_t *mode, kuid_t *uid, kgid_t *gid,
const char **tmp);
/*引用计数*/
extern struct device *get_device(struct device *dev);
extern void put_device(struct device *dev);
/*获取私有成员(属性)*/
void *dev_get_drvdata(const struct device *dev)
void dev_set_drvdata(struct device *dev, void *data)
1.2.2 设备属性操作接口
/*1. 创建属性*/
extern int device_create_file(struct device *device,
const struct device_attribute *entry);
/*2. 删除属性*/
extern void device_remove_file(struct device *dev,
const struct device_attribute *attr);
二. driver设备驱动描述
2.1 内核结构
2.1.1 struct device_driver驱动数据结构
struct device_driver {
/*驱动程序的名字( 体现在 sysfs 中 )*/
const char *name;
/*驱动程序所在的总线*/
struct bus_type *bus;
struct module *owner;
const char *mod_name; /* used for built-in modules */
bool suppress_bind_attrs; /* disables bind/unbind via sysfs */
const struct of_device_id *of_match_table;
const struct acpi_device_id *acpi_match_table;
int (*probe) (struct device *dev);
int (*remove) (struct device *dev);
void (*shutdown) (struct device *dev);
int (*suspend) (struct device *dev, pm_message_t state);
int (*resume) (struct device *dev);
const struct attribute_group **groups;
const struct dev_pm_ops *pm;
struct driver_private *p;
};
2.1.2 struct driver_attribute 设备属性
/* sysfs interface for exporting driver attributes */
struct driver_attribute {
struct attribute attr;
ssize_t (*show)(struct device_driver *driver, char *buf);
ssize_t (*store)(struct device_driver *driver, const char *buf,
size_t count);
};
2.2 相关操作接口
2.2.1 驱动操作接口
/*1. 注册驱动*/
extern int __must_check driver_register(struct device_driver *drv);
/*2. 注销驱动*/
extern void driver_unregister(struct device_driver *drv);
2.2.2 驱动属性操作接口
/*1. 创建属性*/
extern int __must_check driver_create_file(struct device_driver *driver,
const struct driver_attribute *attr);
/*2. 删除属性*/
extern void driver_remove_file(struct device_driver *driver,
const struct driver_attribute *attr);
三. 设备、驱动配对之bus总线---实例
3.1 device实例
#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>
extern struct device my_bus;
extern struct bus_type my_bus_type;
static void my_dev_release(struct device *dev)
{
}
struct device my_dev = {
.bus = &my_bus_type,
.parent = &my_bus,
.release = my_dev_release,
};
static ssize_t mydev_show(struct device *dev, char *buf)
{
return sprintf(buf, "%s\n", "This is my device!");
}
static DEVICE_ATTR(dev, S_IRUGO, mydev_show, NULL);
static int __init my_device_init(void)
{
int ret = 0;
/*初始化设备*/
dev_set_name(&my_dev, "my_dev");
/*注册设备*/
device_register(&my_dev);
/*创建属性文件*/
device_create_file(&my_dev, &dev_attr_dev);
return ret;
}
static void __exit my_device_exit(void)
{
device_unregister(&my_dev);
}
module_init(my_device_init);
module_exit(my_device_exit);
MODULE_AUTHOR("vec");
MODULE_LICENSE("Dual BSD/GPL");
Makefile
ifneq ($(KERNELRELEASE),)
obj-m := device.o
else
PWD := $(shell pwd)
KDIR := /lib/modules/$(shell uname -r)/build
#解决:no symbol version 问题
KBUILD_EXTRA_SYMBOLS+=/home/vec/test_file/bus_test/bus/Module.symvers
export KBUILD_EXTRA_SYMBOLS
all:
$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
rm -rf .*.cmd *.o *.mod.c *.ko .tmp_versions modules.order Module.symvers
endif
3.2 driver实例
#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>
extern struct bus_type my_bus_type;
static int my_probe(struct device *dev)
{
printk("Driver found device which my driver can handle!\n");
return 0;
}
static int my_remove(struct device *dev)
{
printk("Driver found device unpluged!\n");
return 0;
}
struct device_driver my_driver = {
.name = "my_dev",
.bus = &my_bus_type,
.probe = my_probe,
.remove = my_remove,
};
static ssize_t mydriver_show(struct device_driver *driver, char *buf)
{
return sprintf(buf, "%s\n", "This is my driver!");
}
static DRIVER_ATTR(drv, S_IRUGO, mydriver_show, NULL);
static int __init my_driver_init(void)
{
int ret = 0;
/*注册驱动*/
driver_register(&my_driver);
/*创建属性文件*/
driver_create_file(&my_driver, &driver_attr_drv);
return ret;
}
static void my_driver_exit(void)
{
driver_unregister(&my_driver);
}
module_init(my_driver_init);
module_exit(my_driver_exit);
MODULE_AUTHOR("vec");
MODULE_LICENSE("Dual BSD/GPL");
Makefile
ifneq ($(KERNELRELEASE),)
obj-m := driver.o
else
PWD := $(shell pwd)
KDIR := /lib/modules/$(shell uname -r)/build
KBUILD_EXTRA_SYMBOLS=/home/vec/test_file/bus_test/bus/Module.symvers
export KBUILD_EXTRA_SYMBOLS
all:
$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
rm -rf .*.cmd *.o *.mod.c *.ko .tmp_versions modules.order Module.symvers
endif
3.3 bus实例
#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>
static char *version = "Revision: 2.0";
static int my_match(struct device *dev, struct device_driver *driver)
{
printk(KERN_DEBUG "func: %s: device name: %s: driver name: %s \n", __func__, dev_name(dev), driver->name);
return !strncmp(dev_name(dev), driver->name, strlen(driver->name));
}
static void my_bus_release(struct device *dev)
{
printk(KERN_DEBUG "func: %s \n", __func__);
}
struct device my_bus = {
.init_name = "my_bus0",
.release = my_bus_release
};
//EXPORT_SYMBOL(my_bus);
EXPORT_SYMBOL_GPL(my_bus);
struct bus_type my_bus_type = {
.name = "my_bus",
.match = my_match,
};
//EXPORT_SYMBOL(my_bus_type);
EXPORT_SYMBOL_GPL(my_bus_type);
static ssize_t show_bus_version(struct bus_type *bus, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%s\n", version);
}
static BUS_ATTR(version, S_IRUGO, show_bus_version, NULL);
static int __init my_bus_init(void)
{
int ret;
/*注册总线*/
ret = bus_register(&my_bus_type);
if (ret)
return ret;
/*创建属性文件*/
if (bus_create_file(&my_bus_type, &bus_attr_version))
printk(KERN_NOTICE "Fail to create version attribute!\n");
/*注册总线设备*/
ret = device_register(&my_bus);
if (ret)
printk(KERN_NOTICE "Fail to register device:my_bus!\n");
return ret;
}
static void my_bus_exit(void)
{
device_unregister(&my_bus);
bus_unregister(&my_bus_type);
}
module_init(my_bus_init);
module_exit(my_bus_exit);
MODULE_AUTHOR("vec");
MODULE_LICENSE("Dual BSD/GPL");
Makefile
ifneq ($(KERNELRELEASE),)
obj-m := bus.o
else
PWD := $(shell pwd)
KDIR := /lib/modules/$(shell uname -r)/build
all:
$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
rm -rf .*.cmd *.o *.mod.c *.ko .tmp_versions modules.order Module.symvers
endif
注:
1 . 先insmod bus.ko,然后在insmod device.ko和driver.ko。
2 . 由于bus总线初始化时的device和driver都为空,所以只insmod device.ko或driver.ko ,均不打印bus 的my_match()匹配函数。
来源:CSDN
作者:vertor11
链接:https://blog.csdn.net/vertor11/article/details/103749083