涉及结构体/函数如下:
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
--------------------------------------------------------------------------------
实验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");
int cbus_match(struct device *dev, struct device_driver *drv);
int cbus_remove(struct device *dev);
struct bus_type cbus ={
.name = "cbus",
.match = cbus_match,
.remove = cbus_remove
};
EXPORT_SYMBOL(cbus);
int cbus_match(struct device *dev, struct device_driver *drv)
{
FUNC_IN(__FILE__,__FUNCTION__);
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;
}
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);
FUNC_OUT(__FILE__,__FUNCTION__);
return 0;
}
static void bus_exit(void)
{
FUNC_IN(__FILE__,__FUNCTION__);
bus_unregister(&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");
void devrelease(struct device *dev);
struct cdev_data cdev_data1 =
{
.name = "cdev1",
.id = 01,
.GPxCON = 0x11000100,
.GPxDAT = 0x11000104,
.gpio_num = 0,
};
extern struct bus_type cbus;
struct device cdev1 = {
.init_name = "cdev",
.bus = &cbus,
.platform_data = &cdev_data1,
.release = devrelease,
};
static int dev_init(void)
{
FUNC_IN(__FILE__,__FUNCTION__);
device_register(&cdev1);
FUNC_OUT(__FILE__,__FUNCTION__);
return 0;
}
static void dev_exit(void)
{
FUNC_IN(__FILE__,__FUNCTION__);
device_unregister(&cdev1);
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");
void devrelease(struct device *dev);
struct cdev_data cdev_data2 =
{
.name = "cdev2",
.id = 02,
.GPxCON = 0x11000060,
.GPxDAT = 0x11000064,
.gpio_num = 1,
};
extern struct bus_type cbus;
struct device cdev2 = {
.init_name = "cdev",
.bus = &cbus,
.platform_data = &cdev_data2,
.release = devrelease,
};
static int dev_init(void)
{
FUNC_IN(__FILE__,__FUNCTION__);
device_register(&cdev2);
FUNC_OUT(__FILE__,__FUNCTION__);
return 0;
}
static void dev_exit(void)
{
FUNC_IN(__FILE__,__FUNCTION__);
device_unregister(&cdev2);
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)))
static int LED_ON(unsigned long *,unsigned long *,unsigned int);
static int LED_OFF(unsigned long *,unsigned long *,unsigned int);
int c_probe (struct device *dev);
int c_remove (struct device *dev);
MODULE_LICENSE("GPL");
extern struct bus_type cbus;
struct device_driver cdrv = {
.name = "cdev",
.bus = &cbus,
.probe = c_probe,
.remove = c_remove
};
int c_probe (struct device *dev)
{
FUNC_IN(__FILE__,__FUNCTION__);
printk("========c_probe in========");
struct cdev_data * cdrv_cdev_data = (struct cdev_data*)dev->platform_data;
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_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;
}
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__);
}
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;
};
#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
[ 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
[ 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========
[ 5422.909686] cdrv_cdev_data->name is cdev1
[ 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]
[ 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]
[ 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
[ 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
[ 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========
[ 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]
[ 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]
[ 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========
>>结论:一个驱动程序驱动两个类似设备,实现软硬件分离,代码复用率提高