1.平台设备总线简介
像 IIC 设备、SPI 设备、USB 设备等,如何和 CPU 通信? 通过挂载到对应的总线上和 CPU 通信,但是嵌入式设备并不是所有的设备都可以挂到这些总线上,内核为了统一,就把那些无法挂载到物理总线上的设备 统统挂载 到一根虚拟总线上platform—平台设备总线
平台设备总线提供一套完整的接口和机制,方便管理内核中的设备
平台设备总线分为 设备端 和 驱动端
将之前的驱动程序 做分割,框架性的代码叫做驱动端 硬件资源相关的内容叫做设备端
总线 分为三部分, 设备端 驱动端 总线
熟悉的 IIC SPI 平台设备总线 内核已经做好了,仅需要做设备端和驱动端 机制一样 机制:当加载一个设备端到总线上时,此时会和总线上所有的驱动端匹配,一旦匹配成功,执行驱动端的探测函 数,没有匹配成功,以及挂载到总线上,等待下一次驱动端加载时匹配 当加载一个驱动端到总线上时,此时会和总线上所有的设备端匹配, 一旦匹配成功,执行驱动端的探测函数
1》驱动端注册函数
int platform_driver_register(struct platform_driver *drv)
2》平台设备总线设备端注册
int platform_device_register(struct platform_device *pdev)
注意:start 值比 end 值小
例题:通过应用层输入0、1实现开关灯
app.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <poll.h>
#include <stdlib.h>
#include <signal.h>
int main(int argc,char *argv[])
{
int fd = open("/dev/led",O_RDWR);
int data;
while(1)
{
scanf("%d",&data);
write(fd,&data,4);
}
return 0;
}
device.c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/ioport.h>
#include <linux/gpio.h>
void dev_release(struct device *dev)
{
printk("设备端 release 被调用\n");
}
struct resource res = {
.start = 1,
.end = EXYNOS4X12_GPM4(0),
.flags = IORESOURCE_MEM
};
struct platform_device dev={
.name = "mytest",
.id = -1,
.dev.release = dev_release,
.resource = &res,
.num_resources = 1
};
static int __init my_device_init(void)
{
int ret = platform_device_register(&dev);
if(ret < 0)
printk("平台设备总线设备端 注册失败\n");
else
printk("平台设备总线设备端 注册成功\n");
return 0;
}
static void __exit my_device_exit(void)
{
platform_device_unregister(&dev);
}
module_init(my_device_init);
module_exit(my_device_exit);
MODULE_LICENSE("GPL");
driver.c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/gpio.h>
#include <linux/uaccess.h>
struct resource *res = NULL;
ssize_t beep_write (struct file *f, const char __user *buf, size_t s, loff_t *l)
{
int value;
copy_from_user(&value,buf,sizeof(value));
gpio_set_value(res->end,value);
return 0;
}
struct file_operations ops = {
.owner = THIS_MODULE,
.write = beep_write
};
struct miscdevice misc ={
.minor = 255,
.name = "led",
.fops = &ops
};
int beep_probe(struct platform_device *dev)
{
int ret;
printk("驱动端 探测函数...\n");
res = platform_get_resource(dev,IORESOURCE_MEM,0);
if(res == NULL){
printk("资源获取失败\n");
return 0;
}
printk("获取资源: start=%d end=%d type=%lu\n",res->start,res->end,res->flags);
ret = misc_register(&misc);
if(ret == 0)
printk("杂项注册成功\n");
gpio_request(res->end,"led");
gpio_direction_output(res->end,!res->start);
return 0;
}
int beep_remove(struct platform_device *dev)
{
printk("驱动端 remove !!!\n");
if(res!=NULL){
misc_deregister(&misc);
gpio_free(res->end);
}
return 0;
}
struct platform_driver drv={
.probe = beep_probe,
.remove = beep_remove,
.driver.name = "mytest"
};
static int __init my_driver_init(void)
{
//平台设备总线 驱动端的注册
int ret = platform_driver_register(&drv);
if(ret < 0)
printk("平台设备总线驱动端 注册失败\n");
else
printk("平台设备总线驱动端 注册成功\n");
return 0;
}
static void __exit my_driver_exit(void)
{
platform_driver_unregister(&drv);
}
module_init(my_driver_init);
module_exit(my_driver_exit);
MODULE_LICENSE("GPL");
Makefile
obj-m += device.o driver.o
KDIR = /home/fuck/桌面/linux-3.5
all:
make -C ${KDIR} M=${PWD} modules
arm-linux-gcc app.c -o app
clean:
make -C ${KDIR} M=${PWD} modules clean
rm app