// 参考 Linux设备驱动程序(lld3)
// 实现一个简单的虚拟总线 simple bus
// simple_bus_type为总线类型
// simple_bus为总线设备
//
// simple.c 实现
#include "simple.h"
// 增加设备引用计数
static struct simple_device *simple_dev_get(struct simple_device *dev)
{
if (dev)
get_device(&dev->device);
return dev;
}
// 递减设备引用计数
static void simple_dev_put(struct simple_device *dev)
{
if (dev)
put_device(&dev->device);
}
// 匹配设备/驱动
// 当有新设备或新驱动添加到总线时,判断是否匹配
// 调用路径:核心设备子系统->
static int simple_device_match(struct device *dev, struct device_driver *drv)
{
struct simple_device *sim_dev = to_simple_device(dev);
struct simple_driver *sim_drv = to_simple_driver(drv);
struct simple_class_id *ids = sim_drv->classes;
if (ids)
while (ids->class_id != SIMPLE_CLASS_END)
{
if (ids->class_id == sim_dev->class_id.class_id)
return 1;
ids++;
}
return 0;
}
// 添加设备/驱动
// 当simple_device_match返回true,说明device和driver匹配,通过
// 调用probe调用驱动的probe函数,初始化设备
// 调用路径:核心设备子系统->
static int simple_device_probe(struct device *dev)
{
int ret = 0;
struct simple_device *sim_dev;
struct simple_driver *sim_drv;
sim_dev = to_simple_device(dev);
sim_drv = to_simple_driver(dev->driver);
simple_dev_get(sim_dev);
if (sim_drv->probe)
ret = sim_drv->probe(sim_dev);
if (ret)
simple_dev_put(sim_dev);
return ret;
}
// 热插拔设备
// 总线上设备被热插拔
// 调用路径:核心设备子系统->
static int simple_device_remove(struct device *dev)
{
struct simple_device *sim_dev = to_simple_device(dev);
struct simple_driver *sim_drv = to_simple_driver(dev->driver);
if (sim_drv)
{
if (sim_drv->remove)
{
sim_drv->remove(sim_dev);
}
}
simple_dev_put(sim_dev);
return 0;
}
// 获取设备class id
static ssize_t simple_device_show_class_id(struct device *dev, struct device_attribute *attr, char *buf)
{
struct simple_device *sim_dev = to_simple_device(dev);
sprintf(buf, "0x%x\n", sim_dev->class_id.class_id);
return strlen(buf) + 1;
}
// simple bus 设备属性
struct device_attribute simple_device_attrs[] =
{
__ATTR(class_id, S_IRUGO, simple_device_show_class_id, NULL),
__ATTR_NULL
};
// simple bus 总线类型
struct bus_type simple_bus_type =
{
.name = "simple",
.match = simple_device_match,
.probe = simple_device_probe,
.remove = simple_device_remove,
.dev_attrs = simple_device_attrs
};
static void simple_bus_release(struct device *dev)
{
return;
}
// simple bus 总线设备
struct simple_bus simple_bus;
// simple bus 模块初始化
static int __init simple_init(void)
{
int ret;
/* create /sys/bus/simple.*/
if ((ret = bus_register(&simple_bus_type)) < 0)
{
printk(KERN_ALERT "[SIMPLE] bus_register failed.\n");
goto err_bus_register;
}
simple_bus.dev.release = simple_bus_release;
//simple_bus.dev.parent为null,表示为该总线的顶层设备
dev_set_name(&simple_bus.dev, "simple");
/* create /sys/devices/simple.*/
if ((ret = device_register(&simple_bus.dev)))
{
printk(KERN_ALERT "[SIMPLE] device_register failed.\n");
goto err_dev_register;
}
return ret;
err_dev_register:
bus_unregister(&simple_bus_type);
err_bus_register:
return ret;
}
// simple bus 模块卸载
static void __exit simple_exit(void)
{
device_unregister(&simple_bus.dev);
bus_unregister(&simple_bus_type);
}
static void simple_device_release(struct device *dev)
{
return;
}
// 注册设备
// 向simple bus注册设备
int simple_register_device(struct simple_device *dev)
{
dev_set_name(&dev->device, dev->name);
//设备类型为实现的simple_bus_type
dev->device.bus = &simple_bus_type;
//挂载的总线为simple_bus
dev->device.parent = &simple_bus.dev;
dev->device.release = simple_device_release;
return device_register(&dev->device);
}
EXPORT_SYMBOL(simple_register_device);
// 注销设备
// 从simple bus注销设备
void simple_unregister_device(struct simple_device *dev)
{
/*
* device_unregister will do in two parts, first, remove it from all the subsystems with device_del(),
* then decrement the reference count via put_device(). If that is the final reference count,
* the device will be cleaned up via device_release() above. Otherwise, the structure will stick
* around until the final reference to the device is dropped.
*/
device_unregister(&dev->device);
}
EXPORT_SYMBOL(simple_unregister_device);
// 注册驱动
// 向simple bus注册驱动
int simple_register_driver(struct simple_driver *drv)
{
int ret = 0;
drv->driver.name= drv->name;
drv->driver.bus = &simple_bus_type;
ret = driver_register(&drv->driver);
return ret;
}
EXPORT_SYMBOL(simple_register_driver);
// 注销驱动
// 从simple bus注销驱动
void simple_unregister_driver(struct simple_driver *drv)
{
driver_unregister(&drv->driver);
}
EXPORT_SYMBOL(simple_unregister_driver);
module_init(simple_init);
module_exit(simple_exit);
MODULE_LICENSE("GPL");
// simple.h,类型声明
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
#ifndef _SIMPLE_BUS_H_
#define _SIMPLE_BUS_H_
#define to_simple_device(dev) container_of(dev, struct simple_device, device)
#define to_simple_driver(drv) container_of(drv, struct simple_driver, driver)
#define SIMPLE_CLASS_END 0xffff
struct simple_class_id
{
u16 class_id;
};
struct simple_device
{
char *name;
struct device device;
struct simple_class_id class_id;
};
struct simple_driver
{
char *name;
struct device_driver driver;
struct simple_class_id *classes;
int (*probe) (struct simple_device *dev);
/*Device removed (NULL if not a hot-plug capable driver) */
int (*remove) (struct simple_device *dev);
};
struct simple_bus
{
struct device dev;
};
extern int simple_register_device(struct simple_device *dev);
extern void simple_unregister_device(struct simple_device *dev);
extern int simple_register_driver(struct simple_driver *drv);
extern void simple_unregister_driver(struct simple_driver *drv);
#endif