总线设备驱动模型和平台设备模型
时间:2019-10-09 15:38:01
手机看文章
扫描二维码
随时随地手机看文章
[导读]一、总线模型 随着技术的不断进步,系统的拓扑结构也越来越复杂,对热插拔,跨平台移植性的要求也越来越高,2.4内核已经难以满足这些需求。为适应这种形势的需要,从Linux 2.6内核开始提供了全新的设备
一、总线模型
随着技术的不断进步,系统的拓扑结构也越来越复杂,对热插拔,跨平台移植性的要求也越来越高,2.4内核已经难以满足这些需求。为适应这种形势的需要,从Linux 2.6内核开始提供了全新的设备模型。
2.1 描述结构
在 Linux 内核中, 总线由 bus_type 结构表示, 定义在 struct bus_type { const char *name; /*总线名称*/ int (*match) (struct device *dev, struct device_driver *drv); /*驱动与设备的匹配函数*/ ……… }
int (*match)(struct device * dev, struct device_driver * drv); 当一个新设备或者新驱动被添加到这个总线时,该函数被调用。用于判断指定的驱动程序是否能处理指定的设备。若可以,则返回非零。
2.2 总线注册与注销
总线的注册使用如下函数 bus_register(struct bus_type *bus); 若成功,新的总线将被添加进系统,并可在/sys/bus 下看到相应的目录。 总线的注销使用: void bus_unregister(struct bus_type *bus);
3.1 描述结构
在 Linux内核中, 驱动由 device_driver结构表示。 struct device_driver { { const char *name; /*驱动名称*/ struct bus_type *bus; /*驱动程序所在的总线*/ int (*probe) (struct device *dev); ……… }
3.2 驱动注册与注销
驱动的注册使用如下函数
int driver_register(struct device_driver *drv); 驱动的注销使用: void driver_unregister(struct device_driver *drv);
4.1 描述结构
在 Linux内核中, 设备由struct device结构表示。 struct device { { const char *init_name; /*设备的名字*/ struct bus_type *bus; /*设备所在的总线*/ ……… }
4.2 驱动注册与注销 设备的注册使用如下函数 int device_register(struct device *dev); 设备的注销使用: void device_unregister(struct device *dev);
5.编写代码
bus.c
#include
#include
#include
#include
MODULE_LICENSE("GPL");
int my_match(struct device *dev, struct device_driver *drv)
{
return !strncmp(dev->kobj.name, drv->name, strlen(drv->name));
}
struct bus_type my_bus_type = {
.name = "my_bus",
.match = my_match,
};
EXPORT_SYMBOL(my_bus_type);
int my_bus_init()
{
int ret;
ret = bus_register(&my_bus_type);
return ret;
}
void my_bus_exit()
{
bus_unregister(&my_bus_type);
}
module_init(my_bus_init);
module_exit(my_bus_exit); device.c:
#include
#include
#include
#include
MODULE_LICENSE("GPL");
extern struct bus_type my_bus_type;
struct device my_device = {
.init_name = "my_dev",
.bus = &my_bus_type,
};
int my_device_init()
{
int ret;
ret = device_register(&my_device);
return ret;
}
void my_device_exit()
{
device_unregister(&my_device);
}
module_init(my_device_init);
module_exit(my_device_exit); device.c:
#include
#include
#include
#include
MODULE_LICENSE("GPL");
extern struct bus_type my_bus_type;
int my_probe(struct device *dev)
{
printk("driver found the device it can handle!n");
return 0;
}
struct device_driver my_driver = {
.name = "my_dev",
.bus = &my_bus_type,
.probe = my_probe,
};
int my_driver_init()
{
int ret;
ret = driver_register(&my_driver);
return ret;
}
void my_driver_exit()
{
driver_unregister(&my_driver);
}
module_init(my_driver_init);
module_exit(my_driver_exit)
1.平台总线概述
平台总线(Platform bus)是linux2.6内核加入的一种虚拟总线,其优势在于采用了总线的模型对设备与驱动进行了管理,这样提高了程序的可移植性。
通过平台总线机制开发设备驱动的流程如图:
2.平台设备
平台设备使用struct platform_device来描述: struct platform_device { const char *name; /*设备名*/ int id; /*设备编号,配合设备名使用*/ struct device dev; u32 num_resources; struct resource *resource; /*设备资源*/ }
struct resource { resource_size_t start; resource_size_t end; const char *name; unsigned long flags; /*资源的类型*/ struct resource *parent, *sibling, *child; };
注册平台设备,使用函数: int platform_device_register(struct platform_device *pdev);
3.平台驱动 平台驱动使用struct platform_driver 描述: struct platform_driver { int (*probe)(struct platform_device *); int (*remove)(struct platform_device *); …… }
平台驱动注册使用函数: int platform_driver_register(struct platform_driver *);
将按键驱动修改为平台驱动模型
key_dev.c:
#include
#include
#include
#include
MODULE_LICENSE("GPL");
#define GPFCON 0x56000050
struct resource key_resource[] = { //设置资源,对应2440的芯片地址
[0] = {
.start = GPFCON,
.end = GPFCON + 8,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_EINT0,
.end = IRQ_EINT2,
.flags = IORESOURCE_IRQ,
},
};
struct platform_device key_device = { //这个是平台设备结构
.name = "my-key",
.id = 0,
.num_resources = 2,
.resource = key_resource,
};
int keydev_init()
{
platform_device_register(&key_device); //注册平台设备
}
void keydev_exit()
{
platform_device_unregister(&key_device); //注销平台设备
}
module_init(keydev_init);
module_exit(keydev_exit); key_drv.c:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
MODULE_LICENSE("GPL");
#define GPFCON (volatile unsigned long*) 0x56000050
#define GPFDAT (volatile unsigned long*) 0x56000054
unsigned int *gpio_data;
struct work_struct *work1;
struct timer_list key_timer;
wait_queue_head_t key_q;
struct resource *res_irq;
struct resource *res_mem;
unsigned int *key_base;
unsigned int key_num = 0;
void key_timer_func(unsigned long data)
{
unsigned int key_val;
key_val = readw(key_base+1);
if((key_val & 0x01) == 0)
{
key_num = 4;
}
else if((key_val& 0x02) == 0)
{
key_num = 1;
}
else if((key_val & 0x04) == 0)
{
key_num = 3;
}
else if((key_val & 0x10) == 0)
{
key_num = 2;
}
wake_up(&key_q);
}
void work1_func(struct work_struct *work)
{
mod_timer(&key_timer, jiffies + HZ/10);
}
irqreturn_t key_int(int irq, void *dev_id)
{
//1.检测是否发生了按键中断
//2.清除已经发生的按键中断
//3.提交下半部
schedule_work(work1);
return 0;
}
void key_hw_init()
{
unsigned short data;
data = readw(key_base);
data &= ~0x33f;
data |= 0x22a;
writew(data, key_base);
}
int key_open(struct inode *inode, struct file *filp)
{
return 0;
}
ssize_t key_read(struct file *filp, char __user *buf, size_t size, loff_t *pos)
{
wait_event(key_q, key_num);
printk("in kernel :key num is %dn",key_num);
copy_to_user(buf, &key_num, 4);
key_num = 0;
return 4;
}
struct file_operations key_fops = {
.open = key_open,
.read = key_read,
};
struct miscdevice key_miscdev = {
.minor = 200,
.name = "tq2440key",
.fops = &key_fops,
};
int key_probe(struct platform_device *pdev)
{
int ret,size;
ret = misc_register(&key_miscdev);
if (ret !=0)
printk("register fail!n");
//注册中断处理程序
res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); //获取资源
request_irq(res_irq->start,key_int,IRQF_TRIGGER_FALLING,"key",(void *)4); //设置中断
request_irq(res_irq->end,key_int,IRQF_TRIGGER_FALLING,"key",(void *)3);
//按键初始化
res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
size = (res_mem->end - res_mem->start) + 1;
key_base = ioremap(res_mem->start, size);
key_hw_init();
//. 创建工作
work1 = kmalloc(sizeof(struct work_struct),GFP_KERNEL);
INIT_WORK(work1, work1_func);
/* 初始化定时器 */
init_timer(&key_timer);
key_timer.function = key_timer_func;
/* 向内核注册一个定时器 */
add_timer(&key_timer);
/*初始化等待队列*/
init_waitqueue_head(&key_q);
return 0;
}
int key_remove(struct paltform_device *pdev)
{
misc_deregister(&key_miscdev);
//注销中断处理函数
//free_irq(IRQ_EINT0, 0);
//free_irq(IRQ_EINT1, 0);
//free_irq(IRQ_EINT2, 0);
//free_irq(IRQ_EINT4, 0);
return 0;
}
struct platform_driver key_driver = { //这里是平台驱动结构,与平台设备结构通过name进行对接
.probe = key_probe,
.remove = key_remove,
.driver = {
.owner = THIS_MODULE,
.name = "my-key",
},
};
static int button_init()
{
return platform_driver_register(&key_driver); //注册平台驱动
}
static void button_exit()
{
platform_driver_unregister(&key_driver); //注销平台驱动
}
module_init(button_init);
module_exit(button_exit);
阅读(40) | 评论(0) | 转发(0) | 0
随着技术的不断进步,系统的拓扑结构也越来越复杂,对热插拔,跨平台移植性的要求也越来越高,2.4内核已经难以满足这些需求。为适应这种形势的需要,从Linux 2.6内核开始提供了全新的设备模型。
2.1 描述结构
在 Linux 内核中, 总线由 bus_type 结构表示, 定义在 struct bus_type { const char *name; /*总线名称*/ int (*match) (struct device *dev, struct device_driver *drv); /*驱动与设备的匹配函数*/ ……… }
int (*match)(struct device * dev, struct device_driver * drv); 当一个新设备或者新驱动被添加到这个总线时,该函数被调用。用于判断指定的驱动程序是否能处理指定的设备。若可以,则返回非零。
2.2 总线注册与注销
总线的注册使用如下函数 bus_register(struct bus_type *bus); 若成功,新的总线将被添加进系统,并可在/sys/bus 下看到相应的目录。 总线的注销使用: void bus_unregister(struct bus_type *bus);
3.1 描述结构
在 Linux内核中, 驱动由 device_driver结构表示。 struct device_driver { { const char *name; /*驱动名称*/ struct bus_type *bus; /*驱动程序所在的总线*/ int (*probe) (struct device *dev); ……… }
3.2 驱动注册与注销
驱动的注册使用如下函数
int driver_register(struct device_driver *drv); 驱动的注销使用: void driver_unregister(struct device_driver *drv);
4.1 描述结构
在 Linux内核中, 设备由struct device结构表示。 struct device { { const char *init_name; /*设备的名字*/ struct bus_type *bus; /*设备所在的总线*/ ……… }
4.2 驱动注册与注销 设备的注册使用如下函数 int device_register(struct device *dev); 设备的注销使用: void device_unregister(struct device *dev);
5.编写代码
bus.c
#include
#include
#include
#include
MODULE_LICENSE("GPL");
int my_match(struct device *dev, struct device_driver *drv)
{
return !strncmp(dev->kobj.name, drv->name, strlen(drv->name));
}
struct bus_type my_bus_type = {
.name = "my_bus",
.match = my_match,
};
EXPORT_SYMBOL(my_bus_type);
int my_bus_init()
{
int ret;
ret = bus_register(&my_bus_type);
return ret;
}
void my_bus_exit()
{
bus_unregister(&my_bus_type);
}
module_init(my_bus_init);
module_exit(my_bus_exit); device.c:
#include
#include
#include
#include
MODULE_LICENSE("GPL");
extern struct bus_type my_bus_type;
struct device my_device = {
.init_name = "my_dev",
.bus = &my_bus_type,
};
int my_device_init()
{
int ret;
ret = device_register(&my_device);
return ret;
}
void my_device_exit()
{
device_unregister(&my_device);
}
module_init(my_device_init);
module_exit(my_device_exit); device.c:
#include
#include
#include
#include
MODULE_LICENSE("GPL");
extern struct bus_type my_bus_type;
int my_probe(struct device *dev)
{
printk("driver found the device it can handle!n");
return 0;
}
struct device_driver my_driver = {
.name = "my_dev",
.bus = &my_bus_type,
.probe = my_probe,
};
int my_driver_init()
{
int ret;
ret = driver_register(&my_driver);
return ret;
}
void my_driver_exit()
{
driver_unregister(&my_driver);
}
module_init(my_driver_init);
module_exit(my_driver_exit)
1.平台总线概述
平台总线(Platform bus)是linux2.6内核加入的一种虚拟总线,其优势在于采用了总线的模型对设备与驱动进行了管理,这样提高了程序的可移植性。
通过平台总线机制开发设备驱动的流程如图:
2.平台设备
平台设备使用struct platform_device来描述: struct platform_device { const char *name; /*设备名*/ int id; /*设备编号,配合设备名使用*/ struct device dev; u32 num_resources; struct resource *resource; /*设备资源*/ }
struct resource { resource_size_t start; resource_size_t end; const char *name; unsigned long flags; /*资源的类型*/ struct resource *parent, *sibling, *child; };
注册平台设备,使用函数: int platform_device_register(struct platform_device *pdev);
3.平台驱动 平台驱动使用struct platform_driver 描述: struct platform_driver { int (*probe)(struct platform_device *); int (*remove)(struct platform_device *); …… }
平台驱动注册使用函数: int platform_driver_register(struct platform_driver *);
将按键驱动修改为平台驱动模型
key_dev.c:
#include
#include
#include
#include
MODULE_LICENSE("GPL");
#define GPFCON 0x56000050
struct resource key_resource[] = { //设置资源,对应2440的芯片地址
[0] = {
.start = GPFCON,
.end = GPFCON + 8,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_EINT0,
.end = IRQ_EINT2,
.flags = IORESOURCE_IRQ,
},
};
struct platform_device key_device = { //这个是平台设备结构
.name = "my-key",
.id = 0,
.num_resources = 2,
.resource = key_resource,
};
int keydev_init()
{
platform_device_register(&key_device); //注册平台设备
}
void keydev_exit()
{
platform_device_unregister(&key_device); //注销平台设备
}
module_init(keydev_init);
module_exit(keydev_exit); key_drv.c:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
MODULE_LICENSE("GPL");
#define GPFCON (volatile unsigned long*) 0x56000050
#define GPFDAT (volatile unsigned long*) 0x56000054
unsigned int *gpio_data;
struct work_struct *work1;
struct timer_list key_timer;
wait_queue_head_t key_q;
struct resource *res_irq;
struct resource *res_mem;
unsigned int *key_base;
unsigned int key_num = 0;
void key_timer_func(unsigned long data)
{
unsigned int key_val;
key_val = readw(key_base+1);
if((key_val & 0x01) == 0)
{
key_num = 4;
}
else if((key_val& 0x02) == 0)
{
key_num = 1;
}
else if((key_val & 0x04) == 0)
{
key_num = 3;
}
else if((key_val & 0x10) == 0)
{
key_num = 2;
}
wake_up(&key_q);
}
void work1_func(struct work_struct *work)
{
mod_timer(&key_timer, jiffies + HZ/10);
}
irqreturn_t key_int(int irq, void *dev_id)
{
//1.检测是否发生了按键中断
//2.清除已经发生的按键中断
//3.提交下半部
schedule_work(work1);
return 0;
}
void key_hw_init()
{
unsigned short data;
data = readw(key_base);
data &= ~0x33f;
data |= 0x22a;
writew(data, key_base);
}
int key_open(struct inode *inode, struct file *filp)
{
return 0;
}
ssize_t key_read(struct file *filp, char __user *buf, size_t size, loff_t *pos)
{
wait_event(key_q, key_num);
printk("in kernel :key num is %dn",key_num);
copy_to_user(buf, &key_num, 4);
key_num = 0;
return 4;
}
struct file_operations key_fops = {
.open = key_open,
.read = key_read,
};
struct miscdevice key_miscdev = {
.minor = 200,
.name = "tq2440key",
.fops = &key_fops,
};
int key_probe(struct platform_device *pdev)
{
int ret,size;
ret = misc_register(&key_miscdev);
if (ret !=0)
printk("register fail!n");
//注册中断处理程序
res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); //获取资源
request_irq(res_irq->start,key_int,IRQF_TRIGGER_FALLING,"key",(void *)4); //设置中断
request_irq(res_irq->end,key_int,IRQF_TRIGGER_FALLING,"key",(void *)3);
//按键初始化
res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
size = (res_mem->end - res_mem->start) + 1;
key_base = ioremap(res_mem->start, size);
key_hw_init();
//. 创建工作
work1 = kmalloc(sizeof(struct work_struct),GFP_KERNEL);
INIT_WORK(work1, work1_func);
/* 初始化定时器 */
init_timer(&key_timer);
key_timer.function = key_timer_func;
/* 向内核注册一个定时器 */
add_timer(&key_timer);
/*初始化等待队列*/
init_waitqueue_head(&key_q);
return 0;
}
int key_remove(struct paltform_device *pdev)
{
misc_deregister(&key_miscdev);
//注销中断处理函数
//free_irq(IRQ_EINT0, 0);
//free_irq(IRQ_EINT1, 0);
//free_irq(IRQ_EINT2, 0);
//free_irq(IRQ_EINT4, 0);
return 0;
}
struct platform_driver key_driver = { //这里是平台驱动结构,与平台设备结构通过name进行对接
.probe = key_probe,
.remove = key_remove,
.driver = {
.owner = THIS_MODULE,
.name = "my-key",
},
};
static int button_init()
{
return platform_driver_register(&key_driver); //注册平台驱动
}
static void button_exit()
{
platform_driver_unregister(&key_driver); //注销平台驱动
}
module_init(button_init);
module_exit(button_exit);
阅读(40) | 评论(0) | 转发(0) | 0
上一篇:阻塞型驱动设计
下一篇:tty驱动程序架构
相关热门文章 SHTML是什么_SSI有什么用... 查看linux中某个端口(port)... 卡尔曼滤波的原理说明... shell中字符串操作 关于java中的“错误:找不到或... 给主人留下些什么吧!~~ 评论热议