一、总线模型
随着技术的不断进步,系统的拓扑结构也越来越复杂,对热插拔,跨平台移植性的要求也越来越高,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 <linux/module.h>
-
#include <linux/init.h>
-
#include <linux/kernel.h>
-
#include <linux/device.h>
-
-
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 <linux/module.h>
-
#include <linux/init.h>
-
#include <linux/kernel.h>
-
#include <linux/device.h>
-
-
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 <linux/module.h>
-
#include <linux/init.h>
-
#include <linux/device.h>
-
#include <linux/kernel.h>
-
-
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 <linux/module.h>
-
#include <linux/init.h>
-
#include <linux/platform_device.h>
-
#include <linux/interrupt.h>
-
-
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 <linux/module.h>
-
#include <linux/init.h>
-
#include <linux/miscdevice.h>
-
#include <linux/fs.h>
-
#include <asm/uaccess.h>
-
#include <linux/io.h>
-
#include <linux/irqreturn.h>
-
#include <linux/interrupt.h>
-
#include <linux/uaccess.h>
-
#include <linux/platform_device.h>
-
-
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 %d\n",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);
阅读(426) | 评论(0) | 转发(0) |