1.平台设备总线简介

像 IIC 设备、SPI 设备、USB 设备等,如何和 CPU 通信? 通过挂载到对应的总线上和 CPU 通信,但是嵌入式设备并不是所有的设备都可以挂到这些总线上,内核为了统一,就把那些无法挂载到物理总线上的设备 统统挂载 到一根虚拟总线上platform—平台设备总线

平台设备总线提供一套完整的接口和机制,方便管理内核中的设备

平台设备总线分为 设备端驱动端

将之前的驱动程序 做分割,框架性的代码叫做驱动端 硬件资源相关的内容叫做设备端

总线 分为三部分, 设备端 驱动端 总线

熟悉的 IIC SPI 平台设备总线 内核已经做好了,仅需要做设备端和驱动端 机制一样 机制:当加载一个设备端到总线上时,此时会和总线上所有的驱动端匹配,一旦匹配成功,执行驱动端的探测函 数,没有匹配成功,以及挂载到总线上,等待下一次驱动端加载时匹配 当加载一个驱动端到总线上时,此时会和总线上所有的设备端匹配, 一旦匹配成功,执行驱动端的探测函数

1》驱动端注册函数

int platform_driver_register(struct platform_driver *drv)

Linux-平台设备总线_linux

2》平台设备总线设备端注册

int platform_device_register(struct platform_device *pdev)

Linux-平台设备总线_linux_02


Linux-平台设备总线_加载_03

注意:start 值比 end 值小

Linux-平台设备总线_#include_04

例题:通过应用层输入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