文章目录
总线
总线是处理器和设备之间的通道,在设备模型中,所有的设备都通过总线相连,甚至是内部虚拟的“platform”总线。在Linux设备模型中,总线由 bus_type 结构表示,定义在<linux/device.h>中。
总线的描述
总线的注册/删除
- 总线的注册使用:
bus_register(struct bus_type *bus)
若成功注册,新的总线将被添加进系统,并可以在 sysfs 的 /sys/bus 下看到。 - 总线的删除使用:
void bus_unregister(struct bus_type *bus)
总线方法
在 bus_type 中一些总线方法是比较重要的。
- int (*match)(struct device * dev,struct device_driver * drv)
当一个新设备或者驱动被添加到这个总线时,该方法被调用。用于判断指定的驱动程序是否能处理指定的设备。若可以,则返回非零值。 - int (*uevent)(struct device *dev,char **envp,int num_envp,char *buffer,int buffer_size)
在为用户空间产生热插拔事件之前,这个方法允许总线添加环境变量。
总线属性
在 bus_type 中,总线属性由结构 bus_attribute 描述,定义如下:
struct bus_attribute
{
struct attribute attr;
ssize_t (*show)(struct bus_type *,char *buf);
ssize_t (*store)(struct bus_type *,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)
实例:创建总线
(1)代码:bus_create.c
特别提醒: linux2.6.3x与之前linux内核不同在于,linux2.6.3x中device结构体中中没有 bus_id 成员,但有:
const char init_name; / initial name of the device *
要把结构中的**.bus_id** = “my_bus0”, 改为 .init_name = “my_bus0”,
同时上网搜到,return !strncmp(dev->bus_id, driver->name, strlen(driver->name));这句也要改成:
return !strncmp(dev_name(dev), driver->name, strlen(driver->name));
另外: 如果要设置设备的名字,也不再使用strncpy(my_dev.bus_id, “my_dev”, BUS_ID_SIZE); 而改用:
dev_set_name(&dev, “name”);
#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>
MODULE_AUTHOR("zhangbin");
MODULE_LICENSE("Dual BSD/GPL");
static char *Version = "$Revision:1.0 $";
static int my_match(struct device *dev,struct device_driver *driver)
{
return !strncmp(dev_name(dev),driver->name,strlen(driver->name));
}
struct bus_type my_bus_type =
{
.name = "my_bus",
.match = my_match,
};
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");
return ret;
}
static void my_bus_exit(void)
{
bus_unregister(&my_bus_type);
}
module_init(my_bus_init);
module_exit(my_bus_exit);
(2)Makefile
ifneq ($(KERNELRELEASE),)
else
KDIR := /home/zhangbin/mini6410/linux-2.6.38
all:
make -C $(KDIR) M=$(PWD) ARCH=arm CROSS_COMPILE=arm-linux-
clean:
rm -f *.ko *.o *.mod.c *.symvers
endif
(3)演示实例
设备描述
设备注册与注销
- 注册设备
int device_register(struct device *dev) - 注销设备
void device_unregister(struct device *dev)
(一条总线也是个设备,也必须按设备注册)
设备属性
设备属性由 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 device_create_file(struct device *device,struct device_attribute *entry) -
删除属性
void device_remove_file(struct device *dev,struct device_attribute *attr)
代码实例(linux2.6.38内核)
bus.c
#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>
MODULE_AUTHOR("zhangbin");
MODULE_LICENSE("Dual BSD/GPL");
static char *Version = "$Revision:1.9 $";
static int my_match(struct device *dev,struct device_driver *driver)
{
return !strncmp(dev_name(dev),driver->name,strlen(driver->name));
}
static void my_bus_release(struct device *dev)
{
printk(KERN_DEBUG "my bus release\n");
}
struct device my_bus =
{
.init_name = "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);
/*
*export a simple attribute
* */
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)
{
bus_unregister(&my_bus_type);
device_unregister(&my_bus);
}
module_init(my_bus_init);
module_exit(my_bus_exit);
device.c
#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>
MODULE_AUTHOR("zhangbin");
MODULE_LICENSE("Dual BSD/GPL");
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,
}
/*
*export a simple attribute
* */
static ssize_t my_dev_show(struct device *dev,char *buf)
{
return sprintf(buf,"%s\n","This is my device!");
}
static DEVICE_ATTR(dev,S_IRUGO,my_dev_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 my_device_exit(void)
{
device_unregister(&my_dev);
}
module_init(my_device_init);
module_exit(my_device_exit);
Makefie在可以根据前边的来自己编写
实例演示
安装完成之后的效果,安装的指令就是 inmod ***.ko ,比较简单,不展示
驱动描述
驱动程序由 struct device_driver 描述:
驱动的注册与注销
-
驱动的注册
int driver_register(struct device_driver *drv) -
驱动的注销
int driver_unregister(struct device_driver *drv)
驱动属性
驱动的属性使用 struct driver_attribute 来描述
创建于删除驱动属性
- 创建属性
int driver_create_file(struct device_driver *drv,struct driver_attribute *attr) - 删除属性
void driver_remove_file(struct device_driver *drv,struct driver_attribute *attr)
代码实例
driver.c
#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>
MODULE_AUTHOR("zhangbin");
MODULE_LICENSE("Dual BSD/GPL");
extern struct bus_type my_bus_type;
static int my_probe(struct device *dev)
{
printk("Driver found 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,
};
/*
*export a simple attribute
* */
static ssize_t my_driver_show(struct device_driver *driver,char *buf)
{
return snprintf(buf,"%s\n","This is my driver!");
}
static DRIVER_ATTR(drv,S_IRUGO,my_driver_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);
综合演示:
先安装总线(insmod bus.ko),再安装设备(insmod device.ko),最后安装驱动(insmod driver.ko)
后两者可以调换顺序,但是必须先安装总线(bus)
安装后效果