——————/总线
总线删除void bus_unregister(struct bus_type *bus)
match当一新设备或驱动被添加到总线,该方法被调用,用于判断指定驱动是否能处理指定设备,若可以返回非零值
uevent为用户空间产生热插拔事件之前,该方法允许总线添加环境变量
/12 # insmod bus.ko
/12 # cd /sys/bus/my_bus/
/sys/bus/my_bus # ls
devices drivers_autoprobe lyl
drivers drivers_probe uevent
/sys/bus/my_bus # cat lyl
lyl_bus
/sys/bus/my_bus # insmod /12/device.ko
/sys/bus/my_bus # cd devices/lyl_dev/ //进到/sys/devices/lyl_dev,链接
/sys/devices/lyl_dev # ls
dev power subsystem uevent
/sys/devices/lyl_dev # cat dev
This is my device!
/sys/bus/my_bus # insmod /12/driver.ko
my_probe
/sys/bus/my_bus # cd drivers/lyl_dev/
/sys/bus/my_bus/drivers/lyl_dev # ls
bind drv lyl_dev uevent unbind
/sys/bus/my_bus/drivers/lyl_dev # cat drv
This is my driver!
/sys/bus/my_bus # rmmod device
my_remove
my_dev_release
/sys/bus/my_bus # rmmod driver
/sys/bus/my_bus # rmmod bus
——————/注意
若只去掉:EXPORT_SYMBOL(my_bus_type);
/12 # insmod bus.ko
/12 # insmod driver.ko
driver: Unknown symbol my_bus_type (err 0)
insmod: can't insert 'driver.ko': unknown symbol in module or invalid parameter
若只去掉:extern struct bus_type my_bus_type; //driver.c
root@lyl:/home/test# make
error: 'my_bus_type' undeclared here
——————/实验
bus.c中定义函数my_print,driver.c中extern并在入口函数中调用:
void my_print(void)
{
printk("my_print\n");
}
/12 # insmod bus.ko
/12 # insmod driver.ko
Unknown symbol my_print
struct bus_type
const char *name; //总线名称
struct bus_attribute *bus_attrs; //总线属性
struct device_attribute *dev_attrs; //设备属性
struct driver_attribute *drv_attrs; //驱动属性
int (*match)(struct device *dev, struct device_driver *drv);
int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
总线注册int bus_register(struct bus_type *bus),若成功可在sysfs的/sys/bus下看到
总线删除void bus_unregister(struct bus_type *bus)
match当一新设备或驱动被添加到总线,该方法被调用,用于判断指定驱动是否能处理指定设备,若可以返回非零值
uevent为用户空间产生热插拔事件之前,该方法允许总线添加环境变量
struct bus_attribute {
struct attribute attr;
ssize_t (*show)(struct bus_type *bus, char *buf);
ssize_t (*store)(struct bus_type *bus, const char *buf, size_t count);
};
int bus_create_file(struct bus_type *bus,struct bus_attribute *attr)创建属性
void bus_remove_file(struct bus_type*bus, struct bus_attribute *attr)删除属性
——————/设备
struct device
struct kobject kobj;
const char *init_name;
struct bus_type *bus; /* type of bus device is on */
struct device_driver *driver; /* which driver has allocated this device */
void *platform_data;
int device_register(struct device *dev)注册设备
void device_unregister(struct device *dev)注销设备
一条总线也是个设备,必须按设备注册
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 device_create_file(struct device*device, struct device_attribute * entry)创建属性
void device_remove_file(struct device *dev, struct device_attribute * attr)删除属性
——————/驱动
struct device_driver
const char *name; //驱动程序名字
struct bus_type *bus; //驱动所在总线
int (*probe) (struct device *dev);
int (*remove) (struct device *dev); //所能处理设备被删除
int driver_register(struct device_driver *drv)注册驱动
void driver_unregister(struct device_driver *drv)注销驱动
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);
};
int driver_create_file(struct device_driver * drv,struct driver_attribute * attr)创建属性
void driver_remove_file(struct device_driver * drv,struct driver_attribute * attr)删除属性
——————/bus.c
#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>
static int my_match(struct device *dev, struct device_driver *driver)
{
return !strncmp(dev->kobj.name, driver->name,strlen(driver->name));
}
struct bus_type my_bus_type = {
.name = "my_bus",
.match = my_match,
};
static ssize_t show_bus(struct bus_type *bus, char *buf)
{
return sprintf(buf,"%s", "lyl_bus\n");
}
static BUS_ATTR(lyl, S_IRUGO, show_bus, NULL);
static int my_bus_init(void)
{
bus_register(&my_bus_type);
bus_create_file(&my_bus_type, &bus_attr_lyl);
return 0;
}
static void my_bus_exit(void)
{
bus_unregister(&my_bus_type);
}
EXPORT_SYMBOL(my_bus_type);
module_init(my_bus_init);
module_exit(my_bus_exit);
MODULE_LICENSE("GPL");
——————/device.c
#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 void my_dev_release(struct device *dev)
{
printk("my_dev_release\n");
}
struct device my_dev = {
.init_name="lyl_dev",
.bus = &my_bus_type,
.release = my_dev_release,
};
static ssize_t mydev_show(struct device *dev,struct device_attribute *attr, char *buf)
{
return sprintf(buf, "%s", "This is my device!\n");
}
static DEVICE_ATTR(dev, S_IRUGO, mydev_show, NULL);
static int my_device_init(void)
{
device_register(&my_dev);
device_create_file(&my_dev, &dev_attr_dev);
return 0;
}
static void my_device_exit(void)
{
device_unregister(&my_dev);
}
——————/driver.c
#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("my_probe\n");
return 0;
}
static int my_remove(struct device *dev)
{
printk("my_remove\n");
return 0;
}
struct device_driver my_driver = {
.name = "lyl_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", "This is my driver!\n");
}
static DRIVER_ATTR(drv, S_IRUGO, mydriver_show, NULL);
static int my_driver_init(void)
{
driver_register(&my_driver);
driver_create_file(&my_driver, &driver_attr_drv);
return 0;
}
static void my_driver_exit(void)
{
driver_unregister(&my_driver);
}
——————/
/12 # insmod bus.ko
/12 # cd /sys/bus/my_bus/
/sys/bus/my_bus # ls
devices drivers_autoprobe lyl
drivers drivers_probe uevent
/sys/bus/my_bus # cat lyl
lyl_bus
/sys/bus/my_bus # insmod /12/device.ko
/sys/bus/my_bus # cd devices/lyl_dev/ //进到/sys/devices/lyl_dev,链接
/sys/devices/lyl_dev # ls
dev power subsystem uevent
/sys/devices/lyl_dev # cat dev
This is my device!
/sys/bus/my_bus # insmod /12/driver.ko
my_probe
/sys/bus/my_bus # cd drivers/lyl_dev/
/sys/bus/my_bus/drivers/lyl_dev # ls
bind drv lyl_dev uevent unbind
/sys/bus/my_bus/drivers/lyl_dev # cat drv
This is my driver!
/sys/bus/my_bus # rmmod device
my_remove
my_dev_release
/sys/bus/my_bus # rmmod driver
/sys/bus/my_bus # rmmod bus
——————/注意
若只去掉:EXPORT_SYMBOL(my_bus_type);
/12 # insmod bus.ko
/12 # insmod driver.ko
driver: Unknown symbol my_bus_type (err 0)
insmod: can't insert 'driver.ko': unknown symbol in module or invalid parameter
若只去掉:extern struct bus_type my_bus_type; //driver.c
root@lyl:/home/test# make
error: 'my_bus_type' undeclared here
——————/实验
bus.c中定义函数my_print,driver.c中extern并在入口函数中调用:
void my_print(void)
{
printk("my_print\n");
}
/12 # insmod bus.ko
/12 # insmod driver.ko
Unknown symbol my_print