平台总线(二)

我们前面讲的不是平台总线。
只是设备驱动模型。他只是一个利用总线的驱动模型,而平台总线又再这个基础上扩展了一些接口。

平台总线里面的总线不需要创建内核已经创建好了(bus/platform)platform:平台

1, bus
platform_bus:不需要自己创建,开机的时候自动创建
struct bus_type platform_bus_type = {
.name = “platform”,
.dev_groups = platform_dev_groups,
.match = platform_match,
.uevent = platform_uevent,
.pm = &platform_dev_pm_ops,
};
匹配方法:
1,优先匹配pdriver中的id_table,里面包含了支持不同的平台的名字,
:drives里面有一个注册表,代表这个驱动可以匹配的平台名字,一个驱动可以匹配很多平台设备
2,直接匹配driver中名字和device中名字(如果不用id_table就用这个匹配方法)

2、device
设备模型主要存储的设备的信息,它与之前的设备驱动模型扩展了一个
struct resource *resource; // 资源:包括了一个设备的地址和中断
这个资源主要存储着设备的信息。
—————————————示例代码——————-——————

	#include <linux/module.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/platform_device.h>

#include <plat/irqs.h>

#define GPIO_BASE 0x11000000
/*LED 3*/
#define GPX1CON GPIO_BASE + 0x0C20
#define GPX1_SIZE 24
/*LED 2*/
#define GPX2CON GPIO_BASE + 0x0C40
#define GPX2_SIZE 24
/*LED 4 ,5*/
#define GPF3CON GPIO_BASE + 0x01E0
#define GPF3_SIZE 24

/* RESOURCE结构体成员
struct resource {
	resource_size_t start;
	resource_size_t end;
	const char *name;
	unsigned long flags;
	struct resource *parent, *sibling, *child;
};

*/
struct resource led_res[] = {

/*地址*/
	[0] = {
		.start = GPX1CON,
		.end = GPX1CON + GPX1_SIZE - 1,  	//起始地址为0所以要减一
		.flags = IORESOURCE_MEM,
	},
	[1] = {
		.start = GPX2CON,
		.end = GPX2CON + GPX2_SIZE - 1,
		.flags = IORESOURCE_MEM,
	},
	[2] = {
		.start = GPF3CON,
		.end = GPF3CON + GPF3_SIZE -1,
		.flags = IORESOURCE_MEM,
	},
/*中断*/
	[3] = {
		.start = 57,  		//57号中断
		.end = 57,
		.flags = IORESOURCE_IRQ,},
};


struct platform_device dev_led = {
		
	.name = "exynos4412_led",
	.id = -1,
	.num_resources = ARRAY_SIZE(led_res),
	.resource = led_res,

};


static  int  __init platf_led_dev_init(void){
	//注册设备结构体
	return platform_device_register(&dev_led);

}


static void __exit platf_led_dev_exit(void){
	platform_device_unregister(&dev_led);

}



module_init(platf_led_dev_init);
module_exit(platf_led_dev_exit);
MODULE_LICENSE("GPL");

—————————————————————————————————————
3.drives
前面也抛出了,申请设备号,设备节点,文件接口,地址映射等问题,
这里我们是在一个probe编写:这个接口会在匹配成功之后自动调用。
这里主要实现probe,和文件接口,
注意,匹配成功会执行probe。会去申请这些资源,而我们随便哪一个模块被卸载都会断开匹配,然后调用release里面的,所以我们要在release释放我们在probe中申请的资源。
通过probe的参数,系统自动把dev的资源传到drv里面使用。

#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/ioport.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <asm/io.h>
#include <asm/uaccess.h>


struct samsung_drv {
	unsigned int drvmaj;
	struct class *drvcls;
	struct device *drvdev;
	struct resource *drvres;
	void *reg_base;

};

struct samsung_drv *led_drv;

ssize_t samsung_leddrv_read (struct file *filp, char __user *buf, size_t count , loff_t *fops){
	printk("--------%s--------\n",__FUNCTION__);
	return 0;

};
ssize_t samsung_leddrv_write (struct file *filp, const char __user *buf, size_t count, loff_t *fops){

	printk("--------%s--------\n",__FUNCTION__);
	int val;
	int ret;
	int i = 3;
	ret = copy_from_user(&val, buf, count);
	if(ret > 0)
	{
		printk("copy_from_user error\n");
		return -EFAULT;
	}
	
	switch(val){
	case 0:
			writel(readl(led_drv->reg_base + 4) & ~(0x3 << 4) , led_drv->reg_base+4);
			break;
	case 1:
			writel(readl(led_drv->reg_base + 4) | (0x3<<4) , led_drv->reg_base+4);
			break;
	case 2:
			for(;i<0;--i){
			writel(readl(led_drv->reg_base + 4) | (0x1<<4) , led_drv->reg_base+4);
			mdelay(30);
			writel(readl(led_drv->reg_base + 4) & ~(0x3 << 4) , led_drv->reg_base+4);
			writel(readl(led_drv->reg_base + 4) | (0x1<<5) , led_drv->reg_base+4);
			mdelay(30);
			writel(readl(led_drv->reg_base + 4) & ~(0x1 << 5) , led_drv->reg_base+ 4);
				}
			break;
	default:
		printk("input error\n");
		break;}
	return 0;

}
int samsung_leddrv_open (struct inode *inode, struct file *filp){
	printk("--------%s--------\n",__FUNCTION__);
	return 0;

}
int samsung_leddrv_close (struct inode *inode, struct file *filp){
	printk("--------%s--------\n",__FUNCTION__);
	return 0;

}
int samsung_leddrv_fasync (int fd, struct file *filp, int on){
	printk("--------%s--------\n",__FUNCTION__);
	return 0;

}
unsigned int samsung_leddrv_poll(struct file *filp, struct poll_table_struct * pts){
	printk("--------%s--------\n",__FUNCTION__);
	return 0;

}





const struct file_operations myfops = {

	.open = samsung_leddrv_open,
	.release = samsung_leddrv_close,
	.write  = samsung_leddrv_write,
	.read = samsung_leddrv_read,
	.poll = samsung_leddrv_poll,
	.fasync = samsung_leddrv_fasync,

};


int led_drv_probe(struct platform_device *pdev){
	printk("---------%s---------\n",__FUNCTION__);


	//申请结构体资源,初始化结构体
	led_drv = kzalloc(sizeof(struct samsung_drv), GFP_KERNEL);
	if(led_drv == NULL){
		printk("kzalloc error\n");
		return -ENOMEM;
	}
	//申请设备号
	led_drv->drvmaj = register_chrdev(0,"samsung_led", &myfops);
	if(led_drv->drvmaj < 0 ){
		printk("register_chrdev error\n");
		goto err0;
		return -EFAULT;
	}
//创建设备节点
	//创建类
	led_drv->drvcls = class_create(THIS_MODULE,"samsung_led_class");
	if(led_drv->drvcls == NULL ){
		printk("class_create error\n");
		goto err1;
		return -EFAULT;
		}
	//创建设备节点
	led_drv->drvcls = device_create(led_drv->drvcls,NULL, MKDEV(led_drv->drvmaj , 0), NULL, "SAMSUNG_LED_DRV");
	if(led_drv->drvcls == NULL ){
		printk("device_create\n");
		goto err2;
		return -EFAULT;
		}
	//获取匹配的设备地址信息
	led_drv->drvres = platform_get_resource(pdev, IORESOURCE_MEM, 2);
	//还可以获取设备中断信息


	//地址映射
	led_drv->reg_base = ioremap(led_drv->drvres->start,(led_drv->drvres->end - led_drv->drvres->start + 1));
	if(led_drv->reg_base == NULL ){
		printk("ioremap\n");
		goto err3;
		return -EFAULT;}

	//配置寄存器引脚设置为输出功能
	writel((readl(led_drv->reg_base) & (~(0xff << 16)) | (0x11 << 16)),led_drv->reg_base);
	printk("end\n");	
	
	return 0;

	
err3:
	device_destroy(led_drv->drvcls, NULL);
	
err2:
	class_destroy(led_drv->drvcls);
	
err1:
	unregister_chrdev(led_drv->drvmaj,"samsung_led");

err0:
	kfree(led_drv);
	
}
int led_drv_remove(struct platform_device *pdev){

	printk("---------%s---------\n",__FUNCTION__);
	device_destroy(led_drv->drvcls, NULL);
	class_destroy(led_drv->drvcls);
	unregister_chrdev(led_drv->drvmaj,"samsung_led");
	kfree(led_drv);
	return 0;
}
const struct platform_device_id led_id_table[] = {   //匹配表___表示这个驱动可以和哪些平台的设备匹配(名字得一样)
		{"exynos4412_led",0x1111},
		{"s5pv210_led",0x2222},
		{"sac2410led",0x33333},

};


struct platform_driver led_pdrv = {
	.probe = led_drv_probe,
	.remove = led_drv_remove,
	.driver = {
		.name = "samsung_led_drv",      			//如果不使用id_tabla则这里的name必须和dev的name一致才能匹配
									//如果有id_table这个名字的作用为 在/sys/bus/platform/drives/下挂载的驱动名称
	},
	.id_table = led_id_table, 			//优先使用ID_TABLE做匹配

};



static int __init platf_led_drv_init(void){

		return platform_driver_register(&led_pdrv);

}



static void __exit platf_led_drv_exit(void){

	platform_driver_unregister(&led_pdrv);

};



module_init(platf_led_drv_init);
module_exit(platf_led_drv_exit);
MODULE_LICENSE("GPL");
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值