1、设备描述
Linux 系统中的每个设备由一个 struct device 描述。
struct device {
struct klist klist_children;
struct klist_node knode_parent; /* node in sibling list */
struct klist_node knode_driver;
struct klist_node knode_bus;
struct device *parent;
struct kobject kobj;
char bus_id[BUS_ID_SIZE]; /* position on parent bus */
struct device_type *type;
unsigned is_registered:1;
unsigned uevent_suppress:1;
struct device_attribute uevent_attr;
struct device_attribute *devt_attr;
struct semaphore sem; /* semaphore 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 *driver_data; /* data private to the driver */
void *platform_data; /* Platform specific data, device
core doesn't touch it */
struct dev_pm_info power;
#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. */
struct list_head dma_pools; /* dma pools (if dma'ble) */
struct dma_coherent_mem *dma_mem; /* internal for coherent mem
override */
/* arch specific additions */
struct dev_archdata archdata;
spinlock_t devres_lock;
struct list_head devres_head;
/* class_device migration path */
struct list_head node;
struct class *class;
dev_t devt; /* dev_t, creates the sysfs "dev" */
struct attribute_group **groups; /* optional groups */
void (*release)(struct device * dev);
};
2、设备注册、注销
int device_register(struct device * dev);
void device_unregister(struct device * dev);
一条总线也是个设备,也必须按设备注册。
3、设备属性
设备属性由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);
};
创建属性
int __must_check device_create_file(struct device *device,
struct device_attribute * entry);
删除属性
void device_remove_file(struct device * dev, struct device_attribute * attr);
4、参考实例
#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>
static void my_dev_release(struct device *dev)
{
printk("release\n");
}
struct device my_dev = {
.release = my_dev_release,
};
static ssize_t mydev_show(struct device *dev,struct device_attribute *attr, 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)
{
/* 初始化设备 */
my_dev.init_name = "my_dev"; // 设备名称
/*注册设备*/
device_register(&my_dev);
/*创建属性文件*/
device_create_file(&my_dev, &dev_attr_dev);
return 0;
}
static void my_device_exit(void)
{
device_unregister(&my_dev);
}
module_init(my_device_init);
module_exit(my_device_exit);
MODULE_LICENSE("Dual BSD/GPL");
Makefile
ifeq ($(KERNELRELEASE),)
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
all:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
$(MAKE) -C $(KERNELDIR) M=$(PWD) clean
else
obj-m := device.o
endif
验证结果:
在/sys/devices目录下创建my_dev目录。
test@ubuntu2018:/sys/devices/my_dev$ ls -l
total 0
-r--r--r-- 1 root root 4096 Jul 13 09:59 dev (属性文件)
drwxr-xr-x 2 root root 0 Jul 13 09:59 power
-rw-r--r-- 1 root root 4096 Jul 13 09:59 uevent
test@ubuntu2018:/sys/devices/my_dev$ cat dev
This is my device!
卸载该内核模块时,执行release所对应的函数。
5、参考实例
1)
#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>
static char *Version = "Revision: 1.0";
static int my_match(struct device *dev, struct device_driver *driver)
{
return !strncmp(dev->bus_id, driver->name, strlen(driver->name));
}
static void my_bus_release(struct device *dev)
{
printk(KERN_DEBUG "my bus release\n");
}
struct device my_bus = {
.bus_id = "my_bus0",
.release = my_bus_release
};
struct bus_type my_bus_type = {
.name = "my_bus",
.match = my_match,
};
EXPORT_SYMBOL(my_bus);
EXPORT_SYMBOL(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_LICENSE("Dual BSD/GPL");
Makefile
ifeq ($(KERNELRELEASE),)
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
all:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
$(MAKE) -C $(KERNELDIR) M=$(PWD) clean
else
obj-m := bus.o
endif
2)
#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)
{
printk("release\n");
}
struct device my_dev = {
.bus = &my_bus_type,// 设备依附的总线
.parent = &my_bus,// 父设备
.release = my_dev_release,
};
static ssize_t mydev_show(struct device *dev,struct device_attribute *attr, 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)
{
/* 初始化设备 */
strncpy(my_dev.bus_id, "my_dev", BUS_ID_SIZE);// 设备名称
/*注册设备*/
device_register(&my_dev);
/*创建属性文件*/
device_create_file(&my_dev, &dev_attr_dev);
return 0;
}
static void my_device_exit(void)
{
device_unregister(&my_dev);
}
module_init(my_device_init);
module_exit(my_device_exit);
MODULE_AUTHOR("Andy Lau");
MODULE_LICENSE("Dual BSD/GPL");
Makefile
ifeq ($(KERNELRELEASE),)
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
all:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
$(MAKE) -C $(KERNELDIR) M=$(PWD) clean
else
obj-m := device.o
endif