构建一个简单的bus驱动框架

首先我们要了解bus驱动框架是由三部分组成的:Device(硬件相关),Bus(中间媒介),Driver(软件)

构建一个简单的bus驱动框架_第1张图片

为了实现高内聚,低耦合,解决重复代码过多,对整个驱动进行了分层。硬件相关的部分被抽象成Device部分,纯软件部分抽象成Driver部分,为了将这两部分匹配起来就创建了bus这一中间媒介。

接下来搭建一个基础的框架

(一)Bus的构建

1 先来看看bus中的bus_type结构体

struct bus_type {
	const char		*name;
	const char		*dev_name;
	struct device		*dev_root;
	struct device_attribute	*dev_attrs;	/* use dev_groups instead */
	const struct attribute_group **bus_groups;
	const struct attribute_group **dev_groups;
	const struct attribute_group **drv_groups;

	int (*match)(struct device *dev, struct device_driver *drv);
	int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
	int (*probe)(struct device *dev);
	int (*remove)(struct device *dev);
	void (*shutdown)(struct device *dev);

	int (*online)(struct device *dev);
	int (*offline)(struct device *dev);

	int (*suspend)(struct device *dev, pm_message_t state);
	int (*resume)(struct device *dev);

	const struct dev_pm_ops *pm;

	struct iommu_ops *iommu_ops;

	struct subsys_private *p;
	struct lock_class_key lock_key;
};

里面含有非常多的成员,而在我们这个简单框架中要定义的成员只有以下两项

const char		*name;//该bus总线的名字
int (*match)(struct device *dev, struct device_driver *drv);//dev和drv的匹配方法

2 内核提供的注册bus的API和销毁bus的API

注册:

int bus_register(struct bus_type *bus);

销毁:

void bus_unregister(struct bus_type *bus);

3 bus代码如下:

#include
#include
#include

/*
	做一个bus的总线驱动
*/

//返回值为1时正确匹配,非1则匹配失败
int mybus_match(struct device *dev, struct device_driver *drv)
{
        //按名字匹配dev和drv
	if(strncmp(drv->name, dev->kobj->name, sizeof(drv->name)) == 0)
	{
		return 1;
	}else
	{
		return 0;
	}
	
}

struct bus_type mybus = {	
	.name = "mybus",
	.match = mybus_match,
};
EXPORT_SYMBOL(mybus);   //将mybus提供到内核中供别的代码使用                                            

static int __init mybus_init(void)
{
	printk("-----------%s-----------", __FUNCTION__);
	bus_register(&mybus);//调用API注册mybus
	return 0;
}

static void __init mybus_exit(void)
{
	printk("-----------%s-----------", __FUNCTION__);

	bus_unregister(&mybus);//调用API销毁mybus
}

module_init(mybus_init);
module_exit(mybus_exit);
MODULE_LICENSE("GPL");

其中需要注意的部分是,在match函数中,我们是使用了名字来匹配drv和dev,自然就需要strncmp两个结构体中的名字成员。而在内核运行时,系统会将我们在dev中定义的*init_name(设备名字),提取放到kobj中的链表,并将*init_name置为NULL。因此我们在match中要对比的是dev->kobj->name和drv->name。

 

(二)Device的构建

1 硬件的数据抽取在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 */
	struct dev_pm_info	power;
	struct dev_pm_domain	*pm_domain;

        ...........

}

因为成员过多,这里只放出公用的成员。其中在我们这个简单框架中需要定义的成员如下:

const char		*init_name;//名字
struct bus_type	*bus;//挂载的bus总线名字
void		*platform_data;//要给drv的数据
void	(*release)(struct device *dev);//释放该dev时需要调用的函数

2 内核提供的注册dev的API和销毁dev的API

注册:

int device_register(struct device *dev);

销毁:

void device_unregister(struct device *dev);

3 dev部分代码如下:

#include
#include
#include

/*
	做一个bus 的设备
*/
extern struct bus_type mybus;

void	mydev_release(struct device *dev)
{
	printk("-------------%s------------\n",__FUNCTION__);

}

struct device mydev ={

	.init_name = "mydev",
	.bus = &mybus,
	.release = mydev_release,
};


static int __init mydev_init(void)
{
	printk("-----------%s-----------", __FUNCTION__);
	
	device_register(&mydev);
	return 0;
}

static void __init mydev_exit(void)
{
	printk("-----------%s-----------", __FUNCTION__);

	device_unregister(&mydev);
}

module_init(mydev_init);
module_exit(mydev_exit);
MODULE_LICENSE("GPL");

 

(三)Driver的构建

1 还是先来看看结构体device_driver

struct device_driver {
	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;
};

在我们这个框架中需要定义的成员如下:

const char		*name;//名字(与dev中要匹配)
struct bus_type		*bus;//挂载的bus总线名字
int (*probe) (struct device *dev);//匹配到dev后对dev的数据进行操作的函数
int (*remove) (struct device *dev);//与probe成对使用

2 内核提供的注册drv的API和销毁drv的API

注册:

int driver_register(struct device_driver *drv);

销毁:

void driver_unregister(struct device_driver *drv);

3 drv部分代码如下:

#include
#include
#include

/*
	做一个bus 的驱动
*/

extern struct bus_type mybus;

int mydrv_probe(struct device *dev)
{
	return 0;
}

int mydrv_remove(struct device *dev)
{
	return 0;
}

struct device_driver mydrv = {
	.name = "mydev",
	.bus = &mybus,
	.probe = mydrv_probe,
	.remove = mydrv_remove,
};

static int __init mydrv_init(void)
{
	printk("-----------%s-----------", __FUNCTION__);
	
	driver_register(&mydrv);
	return 0;
}


static void __init mydrv_exit(void)
{
	printk("-----------%s-----------", __FUNCTION__);

	driver_unregister(&mydrv);
	
}

module_init(mydrv_init);
module_exit(mydrv_exit);
MODULE_LICENSE("GPL");

 

完成以上三份文件后,一个基础的bus框架就搭建好了。

编译成.ko文件再在板子上跑起来,我们可以用:

ls /sys/bus/

查看在sys/bus目录下有没有我们的mybus

然后可以进入mybus目录下,分别查看devices和dirvers目录下有没有mydev和mydrv

[root@farsight ]# ls /sys/bus/mybus/devices/
mydev
[root@farsight ]# ls /sys/bus/mybus/drivers
mydev

也可以直接用:lsmod命令查看加载的驱动:

mydrv 912 0 - Live 0xbf008000 (O)
mydev 1247 0 - Live 0xbf004000 (O)
mybus 1060 2 mydrv,mydev, Live 0xbf000000 (O)

 

你可能感兴趣的:(嵌入式驱动开发)