02 - 总线模型


//=================================================================================================================================
涉及结构体/函数如下:
struct bus_type 
strncmp();
printk();
bus_register();
bus_unregister();
struct device
device_register();
device_unregister();
struct device_driver
ioremap()
readl()
writel()
driver_register()
driver_unregister()
//===============================================================================================================================
[1] >> 总线bus?
-->>总线结构如下
--------------------------------------------------------------------------------	
		↓ ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ←↑					 
	[driver1.ko] --> [driver2.ko] --> [driver3.ko] --> [driver4.ko]	 逻辑注册链表
--------------------------------------------------------------------------------
							bus总线					 
--------------------------------------------------------------------------------
	[device1.ko] --> [device2.ko] --> [device3.ko] --> [device4.ko]	 硬件注册链表
		↑  ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ↓				 
--------------------------------------------------------------------------------

//总线 = 高(速率)速总线 + 低(速率)速总线
			 ↙  ↓  ↘ 
	  I2C总线  SPI总线 ...
//=================================================================================================================================
[2] >> /sys目录结构
--------------------------------------------------------------------------------							  
			{		/class		/class1		/class2		/class3		/class4
			{  						| \	 	/  \            \        /
			{						|  \  /      \            \    /
			{						|	/\         \            \/
			{						| /   \          \         / \
	/sys	{		/device		/device1   /device2   /device3 	/device4
			{		
			{			{	  	{	/driver1 	/driver2	/driver3 
			{			{	/i2c{
			{			{		{	/device1 	/device2	/device3
			{			{			
			{			{		{	/driver1 	/driver2	/driver3
			{		/bus{	/spi{   	
						{		{	/device1 	/device2	/device3
						{		
						{		{	/driver1 	/driver2	/driver3 
						{	/usb{
						{	     {	/device1 	/device2	/device3
//class目录是对设备的分类
//device目录是存放所有设备		
//bus目录是存放各种总线目录,总线目录中包含总线驱动与总线设备
//bus目录中的device与device目录中的device通过软连接ln -s连接		 		
									
--------------------------------------------------------------------------------	

实验1:bus实验 ; 一个driver驱动两个device

bus.c文件


#include<linux/init.h>
#include<linux/module.h>
#include<linux/device.h>
#define FUNC_IN(FILE,FUNCTION)  (printk("\n>>kerner:=======%s:%s IN========\n",(FILE),(FUNCTION)))
#define FUNC_OUT(FILE,FUNCTION)  (printk("\n>>kerner:=======%s:%s OUT========\n",(FILE),(FUNCTION)))
MODULE_LICENSE("GPL"); //没有这GPL声明,模块不能加载在内核


//bus总线比对设备对象与设备驱动对象的name,匹配成功调用diver模块的probe接口
int cbus_match(struct device *dev, struct device_driver *drv);

//驱动与总线的remove接口;卸载驱动模块时会断开与总线的连接;此时bus与diver都会调用各自的remove接口
int cbus_remove(struct device *dev);

//总线对象
struct bus_type cbus  ={
	.name = "cbus",//总线的名字
	.match = cbus_match,  //总线match接口
	.remove = cbus_remove //总线remove接口
};
//任何数据,无论是函数/变量/结构体,想要在其他模块使用必须导出符号
EXPORT_SYMBOL(cbus);  


//bus总线比对设备对象与设备驱动对象的name,匹配成功(返回非0)调用diver模块的probe接口
int cbus_match(struct device *dev, struct device_driver *drv)
{
	FUNC_IN(__FILE__,__FUNCTION__);
	//设备对象的name会自动存储在struct kobject这个父类对象的name里面
	if(strncmp(dev->kobj.name, drv->name,sizeof(drv->name))==0)
	{
		printk("cbus_match success");
	}
	else
	{
		printk("cbus_match error");
		return 0;
	}
	FUNC_OUT(__FILE__,__FUNCTION__);
	return 1;
}

//驱动与总线的remove接口;卸载驱动模块时会断开与总线的连接;此时调用remove接口
int cbus_remove(struct device *dev)
{
	FUNC_IN(__FILE__,__FUNCTION__);
	FUNC_OUT(__FILE__,__FUNCTION__);	
	return 0;
}

static int bus_init(void)
{
	FUNC_IN(__FILE__,__FUNCTION__);
	bus_register(&cbus);  //注册总线cbus
	FUNC_OUT(__FILE__,__FUNCTION__);
	return 0;
}
static void bus_exit(void)
{
	FUNC_IN(__FILE__,__FUNCTION__);
	bus_unregister(&cbus); //注销总线cbus
	FUNC_OUT(__FILE__,__FUNCTION__);
}
module_init(bus_init);
module_exit(bus_exit);

dev1.c文件 (dev1 = led1)

#include<linux/init.h>
#include<linux/module.h>
#include<linux/device.h>
#include "dev.h"
#define FUNC_IN(FILE,FUNCTION)  (printk("\n>>kerner:=======%s:%s IN========\n",(FILE),(FUNCTION)))
#define FUNC_OUT(FILE,FUNCTION)  (printk("\n>>kerner:=======%s:%s OUT========\n",(FILE),(FUNCTION)))
MODULE_LICENSE("GPL");  //没有这GPL声明,模块不能加载在内核
void devrelease(struct device *dev);

//硬件设备led1的私有数据
struct cdev_data cdev_data1 = 
{
	.name = "cdev1", //硬件1的名字
	.id = 01,       
	.GPxCON = 0x11000100,//硬件1的控制寄存器物理地址
	.GPxDAT = 0x11000104,//硬件1的数据寄存器物理地址
	.gpio_num = 0,         //硬件1是gpio0
};

//调用bus.c的bus对象
extern struct bus_type cbus;

//硬件设备1对象
struct device  cdev1 = {
	.init_name = "cdev",  //设备对象的name;匹配用
	.bus = &cbus,         //设备对象挂载到cbus总线
	.platform_data = &cdev_data1,  //设备对象的私有结构体
	.release = devrelease,         //卸载设备对象的释放内存接口
};

static int dev_init(void)
{
	FUNC_IN(__FILE__,__FUNCTION__);
	device_register(&cdev1);//注册设备2
	FUNC_OUT(__FILE__,__FUNCTION__);
	return 0;
}
static void dev_exit(void)
{
	FUNC_IN(__FILE__,__FUNCTION__);
	device_unregister(&cdev1);//注销设备2
	FUNC_OUT(__FILE__,__FUNCTION__);
}

//卸载设备对象的释放内存接口
void devrelease(struct device *dev)
{}
module_init(dev_init);
module_exit(dev_exit);

dev2.c文件(dev2 = led2 ; dev2与dev1硬件寄存器地址不同,其他都一样)

#include<linux/init.h>
#include<linux/module.h>
#include<linux/device.h>
#include "dev.h"
#define FUNC_IN(FILE,FUNCTION)  (printk("\n>>kerner:=======%s:%s IN========\n",(FILE),(FUNCTION)))
#define FUNC_OUT(FILE,FUNCTION)  (printk("\n>>kerner:=======%s:%s OUT========\n",(FILE),(FUNCTION)))
MODULE_LICENSE("GPL");  //没有这GPL声明,模块不能加载在内核
void devrelease(struct device *dev);

//硬件设备led2的私有数据
struct cdev_data cdev_data2 = 
{
	.name = "cdev2",
	.id = 02,
	.GPxCON = 0x11000060,
	.GPxDAT = 0x11000064,
	.gpio_num = 1,
};
//调用bus.c的bus对象
extern struct bus_type cbus;

//硬件设备2对象
struct device  cdev2 = {
	.init_name = "cdev", //设备对象的name;匹配用
	.bus = &cbus, 		 //设备对象挂载到cbus总线
	.platform_data = &cdev_data2,//设备对象的私有结构体
	.release = devrelease,		  //卸载设备对象的释放内存接口
};
static int dev_init(void)
{
	FUNC_IN(__FILE__,__FUNCTION__);
	device_register(&cdev2);  //注册设备1
	FUNC_OUT(__FILE__,__FUNCTION__);
	return 0;
}
static void dev_exit(void)
{
	FUNC_IN(__FILE__,__FUNCTION__);
	device_unregister(&cdev2); //注销设备1
	FUNC_OUT(__FILE__,__FUNCTION__);
}
void devrelease(struct device *dev)
{}
module_init(dev_init);
module_exit(dev_exit);

drv.c文件

#include<linux/init.h>
#include<linux/module.h>
#include<linux/device.h>
#include<linux/io.h>
#include "dev.h"
//打印进入函数与退出函数的调试信息
#define FUNC_IN(FILE,FUNCTION)  (printk("\n>>kerner:=======%s:%s IN========\n",(FILE),(FUNCTION)))
#define FUNC_OUT(FILE,FUNCTION)  (printk("\n>>kerner:=======%s:%s OUT========\n",(FILE),(FUNCTION)))

//LED打开函数
static int LED_ON(unsigned long *,unsigned long *,unsigned int);
//LED关闭函数
static int LED_OFF(unsigned long *,unsigned long *,unsigned int);
//驱动与总线的probe接口;在match匹配后总线会将匹配到的设备对象信息发送给驱动模块
int c_probe (struct device *dev);
//驱动与总线的remove接口;卸载驱动模块时会断开与总线的连接;此时调用remove接口
int c_remove (struct device *dev);

MODULE_LICENSE("GPL"); //没有这GPL声明,模块不能加载在内核

extern struct bus_type	cbus; //调用bus.c的bus总线对象

struct device_driver  cdrv = {	//驱动对象
	.name = "cdev",     //驱动name
	.bus = &cbus,      //挂载在cbus总线
	.probe = c_probe,  //probe接口
	.remove = c_remove //remove接口
};


int c_probe (struct device *dev) 
{
	FUNC_IN(__FILE__,__FUNCTION__);
	printk("========c_probe in========");
	//第一步:接收device对象传过来的私有数据(使用结构体封装的设备信息)
	struct cdev_data * cdrv_cdev_data = (struct cdev_data*)dev->platform_data;  

	//打印device对象的私有数据
	printk("\n cdrv_cdev_data->name is %s\n",cdrv_cdev_data->name);
	printk("\n cdrv_cdev_data->id is %d\n",cdrv_cdev_data->id);
	printk("\n cdrv_cdev_data->con is %lx\n",cdrv_cdev_data->GPxCON);
	printk("\n cdrv_cdev_data->dat is %lx\n",cdrv_cdev_data->GPxDAT);
	printk("\n cdrv_cdev_data->gpio_num is %d\n",cdrv_cdev_data->gpio_num);

	//第二步:将寄存器物理地址映射
	unsigned long *gpxcon;
	unsigned long *gpxdat;
	gpxcon = ioremap(cdrv_cdev_data->GPxCON,8);
	gpxdat = gpxcon+1;

	//第三步:LED的操作
	LED_ON(gpxcon,gpxdat,cdrv_cdev_data->gpio_num);
	LED_OFF(gpxcon,gpxdat,cdrv_cdev_data->gpio_num);
	FUNC_OUT(__FILE__,__FUNCTION__);

	return 0;
}

int c_remove (struct device *dev)
{
	FUNC_IN(__FILE__,__FUNCTION__);
	printk("========c_probe out========");	
	FUNC_OUT(__FILE__,__FUNCTION__);
	return 0;
}

/*gpxcon = 控制寄存器虚拟地址
 *gpxdat = 数据寄存器虚拟地址
 *gpio_num = 控制寄存器第几位*/
static int LED_ON(unsigned long *gpxcon,unsigned long *gpxdat,unsigned int gpio_num)
{
	FUNC_IN(__FILE__,__FUNCTION__);
	unsigned int reg_vlu = 0;
	reg_vlu = readl(gpxcon);		//读取映射地址数据	
	reg_vlu |= (0x1 << gpio_num*4); 
	writel(reg_vlu,gpxcon); 	    //向映射地址写数据
		
	reg_vlu = readl(gpxdat);		//读取映射地址数据
	reg_vlu |= (0x1<<gpio_num);
	writel(reg_vlu,gpxdat); 	    //向映射地址写数据	
	FUNC_OUT(__FILE__,__FUNCTION__);
}

/*gpxcon = 控制寄存器虚拟地址
 *gpxdat = 数据寄存器虚拟地址
 *gpio_num = 控制寄存器第几位*/
static int LED_OFF(unsigned long *gpxcon,unsigned long *gpxdat,unsigned int gpio_num)
{
	FUNC_IN(__FILE__,__FUNCTION__);
	unsigned int reg_vlu = 0;
	reg_vlu = readl(gpxcon);		//读取映射地址数据	
	reg_vlu |= (0x1 << gpio_num*4); 
	writel(reg_vlu,gpxcon); 	    //向映射地址写数据
	
	reg_vlu = readl(gpxdat);		//读取映射地址数据
	reg_vlu &= ~(0x1<<gpio_num);
	writel(reg_vlu,gpxdat); 	    //向映射地址写数据	
	FUNC_OUT(__FILE__,__FUNCTION__);
}

static int drv_init(void)
{
	FUNC_IN(__FILE__,__FUNCTION__);
	driver_register(&cdrv);  //注册设备驱动
	FUNC_OUT(__FILE__,__FUNCTION__);
	return 0;
}
static void drv_exit(void)
{
	FUNC_IN(__FILE__,__FUNCTION__);
	driver_unregister(&cdrv);  //注销设备驱动
	FUNC_OUT(__FILE__,__FUNCTION__);
}
module_init(drv_init);
module_exit(drv_exit);

dev.h

#ifndef __DEV_H__
#define __DEV_H__

//设备私有信息
struct cdev_data {
	char*name;  //设备名
	unsigned int id; //设备编号
	unsigned long GPxCON;  //设备控制寄存器物理地址
	unsigned long GPxDAT;  //设备数据寄存器物理地址
	unsigned int gpio_num; //操作寄存器的第N位用
};
#endif 

Makefile文件

obj-m += bus.o
obj-m += dev1.o
obj-m += dev2.o

obj-m += drv.o

KERNER = /home/topeet/iTop4412_Kernel_3.0
 
PWD = $(shell pwd)

name1 = bus
name2 = dev1
name3 = dev2
name4 = drv
all:
	make -C $(KERNER) M=$(PWD) modules

install:
	cp $(name1).ko $(name2).ko $(name3).ko $(name4).ko /home/topeet/minilinux/yqj_file/modul_pro3/

运行结构如下


//注意先加载总线,在挂载设备,最后挂载驱动 ; 先卸载驱动 ,在卸载设备,最后卸载总线
======================下面是驱动与设备1的测试==============
[root@iTOP-4412]# insmod bus.ko  //第一步:加载bus总线
[ 5401.859589]
[ 5401.859596] >>kerner:=======/home/topeet/share/bus_pro/bus.c:bus_init IN========
[ 5401.872737]
[ 5401.872744] >>kerner:=======/home/topeet/share/bus_pro/bus.c:bus_init OUT========
[root@iTOP-4412]# insmod dev1.ko  //第二步:加载设备1
[ 5411.541101]
[ 5411.541105] >>kerner:=======/home/topeet/share/bus_pro/dev1.c:dev_init IN========
[ 5411.551605]
[ 5411.551609] >>kerner:=======/home/topeet/share/bus_pro/dev1.c:dev_init OUT========
[root@iTOP-4412]# insmod drv.ko   //第三步:加载设备驱动
[ 5422.863723]
[ 5422.863726] >>kerner:=======/home/topeet/share/bus_pro/drv.c:drv_init IN========
[ 5422.871594] Driver 'cdev' needs updating - please use bus_type methods
[ 5422.877899]
[ 5422.877902] >>kerner:=======/home/topeet/share/bus_pro/bus.c:cbus_match IN========
[ 5422.887740] cbus_match success  //匹配成功
[ 5422.889514] >>kerner:=======/home/topeet/share/bus_pro/bus.c:cbus_match OUT========
[ 5422.897358]
[ 5422.897360] >>kerner:=======/home/topeet/share/bus_pro/drv.c:c_probe IN========
[ 5422.906154] ========c_probe in========  //跳转到设备驱动对象的probe接口
[ 5422.909686]  cdrv_cdev_data->name is cdev1  //打印设备1信息
[ 5422.913935]
[ 5422.913937]  cdrv_cdev_data->id is 1
[ 5422.918952]
[ 5422.918954]  cdrv_cdev_data->con is 11000100
[ 5422.924692]
[ 5422.924694]  cdrv_cdev_data->dat is 11000104
[ 5422.930411]
[ 5422.930413]  cdrv_cdev_data->gpio_num is 0
[ 5422.935982]
[ 5422.935984] >>kerner:=======/home/topeet/share/bus_pro/drv.c:LED_ON IN========
[ 5422.944672]        //这里LED1亮起来
[ 5422.944674] >>kerner:=======/home/topeet/share/bus_pro/drv.c:LED_ON OUT========
[ 5422.953410]
[ 5422.953412] >>kerner:=======/home/topeet/share/bus_pro/drv.c:LED_OFF IN========
[ 5422.962177]        //这里LED1关掉
[ 5422.962179] >>kerner:=======/home/topeet/share/bus_pro/drv.c:LED_OFF OUT========
[ 5422.971030]
[ 5422.971032] >>kerner:=======/home/topeet/share/bus_pro/drv.c:c_probe OUT========
[ 5422.981694]
[ 5422.981701] >>kerner:=======/home/topeet/share/bus_pro/drv.c:drv_init OUT========
[root@iTOP-4412]#


======================下面是卸载驱动与卸载设备1,重新加载设备2与驱动==============
[root@iTOP-4412]# rmmod drv //卸载驱动
[ 5675.152872]
[ 5675.152889] >>kerner:=======/home/topeet/share/bus_pro/drv.c:drv_exit IN========
[ 5675.185881]
[ 5675.185899] >>kerner:=======/home/topeet/share/bus_pro/bus.c:cbus_remove IN========
[ 5675.214468]
[ 5675.214485] >>kerner:=======/home/topeet/share/bus_pro/bus.c:cbus_remove OUT========
[ 5675.279325]
[ 5675.279342] >>kerner:=======/home/topeet/share/bus_pro/drv.c:drv_exit OUT========
[root@iTOP-4412]# rmmod dev1 //卸载设备1
[ 5684.265934]
[ 5684.265936] >>kerner:=======/home/topeet/share/bus_pro/dev1.c:dev_exit IN========
[ 5684.274836]   
[ 5684.274838] >>kerner:=======/home/topeet/share/bus_pro/dev1.c:dev_exit OUT========

======================下面是驱动与设备1的测试==============
[root@iTOP-4412]# insmod dev2.ko  //加载设备2
[ 5799.792706]
[ 5799.792719] >>kerner:=======/home/topeet/share/bus_pro/dev2.c:dev_init IN========
[ 5799.809223]
[ 5799.809235] >>kerner:=======/home/topeet/share/bus_pro/dev2.c:dev_init OUT========
[root@iTOP-4412]# insmod drv.ko  //加载驱动
[ 5807.934793]
[ 5807.934809] >>kerner:=======/home/topeet/share/bus_pro/drv.c:drv_init IN========
[ 5807.944957] Driver 'cdev' needs updating - please use bus_type methods
[ 5807.951247]
[ 5807.951263] >>kerner:=======/home/topeet/share/bus_pro/bus.c:cbus_match IN========
[ 5807.965785] cbus_match success  //匹配成功
[ 5807.967303] >>kerner:=======/home/topeet/share/bus_pro/bus.c:cbus_match OUT========
[ 5807.975499]
[ 5807.975514] >>kerner:=======/home/topeet/share/bus_pro/drv.c:c_probe IN========
[ 5807.983895] ========c_probe in========   //匹配成功接入驱动的probe函数
[ 5807.987414]  cdrv_cdev_data->name is cdev2
[ 5807.991669]  
[ 5807.991681]  cdrv_cdev_data->id is 2
[ 5807.996695]
[ 5807.996708]  cdrv_cdev_data->con is 11000060
[ 5808.002639]
[ 5808.002652]  cdrv_cdev_data->dat is 11000064
[ 5808.008164]
[ 5808.008176]  cdrv_cdev_data->gpio_num is 1
[ 5808.013783]
[ 5808.013797] >>kerner:=======/home/topeet/share/bus_pro/drv.c:LED_ON IN========
[ 5808.022405]    //这里设备2这个led亮起来
[ 5808.022418] >>kerner:=======/home/topeet/share/bus_pro/drv.c:LED_ON OUT========
[ 5808.031298]
[ 5808.031312] >>kerner:=======/home/topeet/share/bus_pro/drv.c:LED_OFF IN========
[ 5808.039932]    //这里设备2这个led熄灭
[ 5808.039945] >>kerner:=======/home/topeet/share/bus_pro/drv.c:LED_OFF OUT========
[ 5808.048782]
[ 5808.048794] >>kerner:=======/home/topeet/share/bus_pro/drv.c:c_probe OUT========
[ 5808.060242]
[ 5808.060259] >>kerner:=======/home/topeet/share/bus_pro/drv.c:drv_init OUT========


>>结论:一个驱动程序驱动两个类似设备,实现软硬件分离,代码复用率提高
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
IEEE-30总线系统是一个经典的电力系统样例,由IEEE(美国电气电子工程师协会)制定,用于研究电力系统稳定性、传输能力和电力负荷分配等问题。 IEEE-30总线系统由30个母线节点、41条传输线和6个发电机组成。其中,母线用于表示电力系统的节点,传输线用于表示输电线路,发电机用于提供电力。每个母线节点都有一个节点编号,用于标识不同的节点。 通过对IEEE-30总线系统进行分析,可以得到电力系统的特性和状态参数。例如,可以计算电压、功率和频率等关键参数。这些参数用于评估电力系统的性能和稳定性,确保电力系统的正常运行。 通过研究IEEE-30总线系统,可以得到以下结论: 1. 描述一个真实电力系统的基本要素:母线、传输线和发电机; 2. 提供了实际电力系统的拓扑结构,以便于研究电力系统的不同部分之间的相互影响; 3. 帮助分析电力系统的稳态和暂态行为,以确定系统是否稳定并能满足电力需求; 4. 用于评估电力系统的传输能力,以便于规划电网的扩建和优化电力分配。 总之,IEEE-30总线系统是一个常用的电力系统模型,它提供了电力系统的基本特性和参数,帮助研究人员更好地了解电力系统,并针对不同的问题进行分析和优化。它对电力系统的稳定性、可靠性和经济性的研究和评估起到了重要的作用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值