ok6410学习笔记(15.platform平台总线驱动模型之混杂设备驱动led)

本节知识点:

1.这里就一个知识点设备资源:

设备资源前面说过,这里就不多说了
主要说说,在platform模型中,设备资源是定义在device模块中的,而使用是在driver模块中probe函数里面的,struct resource *platform_get_resource(struct platform_device *dev,unsigned int type,unsigned int num)  参数 dev是资源所属的设备  type 是获得资源的类型  num 获得资源数  通过这个函数在probe函数中获得定义在device模块中的资源

本节代码:

plat_drv.c:
#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/miscdevice.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/poll.h>
#include <linux/ioport.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
#include <linux/ioctl.h>
#include "plat-drv.h" 

MODULE_AUTHOR("Hao");
MODULE_LICENSE("Dual BSD/GPL");


volatile unsigned long  GPIOM_VA_BASE;//定义一个全局变量  保存ioremap映射的地址

#define GPIOM_CON_VA 	GPIOM_VA_BASE		
#define GPIOM_DAT_VA 	(GPIOM_VA_BASE+0x4)		
#define GPIOM_PUD_VA 	(GPIOM_VA_BASE+0x8)

struct resource led_res;

static void ok6410_led_setup(struct resource *led_resource)
{
		unsigned long temp; 
		led_res=*led_resource;
		request_mem_region(led_resource->start,(led_resource->end-led_resource->start),led_resource->name);//申请i/o内存 设备资源的名字
		//其实我觉得用上面那个资源的结构体意义不打  因为request_mem_region就是在跟系统申请这个资源  等价于了把上面的那个资源结构体拷贝到了内核中的设备资源链表
		GPIOM_VA_BASE = (volatile unsigned long )ioremap(led_resource->start, led_resource->end-led_resource->start);//

/****************************可以直接对地址进行操作***************************************/
		/*
		(*(volatile unsigned long *)GPIOM_VA_BASE)&=~0xffff;	
		(*(volatile unsigned long *)GPIOM_VA_BASE)|=0x1|(0x1<<4)|(0x1<<8)|(0x1<<12);
		temp=0;
		(*(volatile unsigned long*)GPIOM_DAT_VA)=temp;  //默认所有灯都亮
		*/
		
		
/*******************也可以用函数api进行操作  貌似这个方式更加安全***************************/
		temp&=~0xffff;
		temp|=0x1|(0x1<<4)|(0x1<<8)|(0x1<<12); 
		writel(temp, GPIOM_CON_VA);
		
		temp|=0xf;
		temp=0;
		writel(temp, GPIOM_DAT_VA);
		
}

static void ok6410_led_release(void)
{
	iounmap((void*)GPIOM_VA_BASE);
	release_mem_region(led_res.start,led_res.end-led_res.start);
}

/**************************************************************************
函数名:                     memdev_ioctl
函数功能:                   ioctl实现函数  命令实习函数
函数参数:                   无
函数返回值:                 返回ret为正常执行   返回-EINVAL命令号不正确
***************************************************************************/
static long memdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
	int ret=0;
	int err=0;
	int kernel_num=1991;
	//char kernel_buf[20]="hello kernel!!!";
	
	/*先判断命令号是否正确*/
	if (_IOC_TYPE(cmd) != CMD_KTYPE) //获得命令的type类型是否正确
        	return -EINVAL;
    	if (_IOC_NR(cmd) > LED_KCMD)    //获得命令的num类型  是否小于命令个数
        	return -EINVAL;
        	
        /*获命令的数据传输方向   根据各自的方向判断*/	
        if (_IOC_DIR(cmd) & _IOC_READ)
       		 err = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd));/*此函数是根据
       		 内核空间写的 是用来判断 arg应用程序传来的用户空间 是否有效的  所以对于用户空间来说是写*/
     	else if (_IOC_DIR(cmd) & _IOC_WRITE)
      		 err = !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd));//对于用户空间来说是读   成功返回1  失败返回0
    	if (err) 
        	return -EFAULT;
        	
        
        /*实现CMD的用法*/
        switch(cmd)
        {
        	case LEDR_KCMD:  
        		ret=__put_user(kernel_num, (int *)arg);  //把内核中的int型数据读入用户空间   unsigned long arg就是一个地址值   kernel->arg
        		break;
        	case LEDW_KCMD:
        		ret=__get_user(kernel_num, (int *)arg);   //arg->kernel_num   把用户空间的数据传递给kernel_num
        		printk(KERN_EMERG "WRITE_KCMD is in kernel!!!  kernel_num:%d \n",kernel_num);
        		if(1==kernel_num)
        			{
        					writel(0x0, GPIOM_DAT_VA);//将4个led全部点亮
        			}
        		if(0==kernel_num)
        			{
        					writel(0x1f, GPIOM_DAT_VA);//将4个led全部熄灭
        			}
        		break;
        	default:
        		return -EINVAL;
        		break;
       	}	
        
}

int mem_release(struct inode *inode, struct file *filp)
{
    return 0;
}

int mem_open(struct inode *inode,struct file *filp)
{
		return 0; 
}


static const struct file_operations mem_fops =  //定义此字符设备的file_operations
{						//这里是对结构体整体赋值的方式
    .owner = THIS_MODULE, //函数名都可以自己定义  都是函数指针
    .open = mem_open,
    .release = mem_release,
    .unlocked_ioctl=memdev_ioctl,
};

static struct miscdevice misc = {
	.minor = 0,//设置为0  系统自动分配次设备号
	.name = "misc_led",  //我觉得这个是设备节点的名字  就是/dev路径下的文件的名字
	.fops = &mem_fops,  //文件操作
};


static int led_drv_probe(struct platform_device *dev)   //这里面写功能驱动
{
		int ret;
		struct resource *res;
		printk("Driver found device which my driver can handle!\n");
		res=platform_get_resource(dev,IORESOURCE_MEM,0);
		if(res==NULL)
			{
						printk("no memory resource\n");
						return 0;
			}
		ok6410_led_setup(res);
		ret=misc_register(&misc);
    return ret;
}

static int led_drv_remove(struct platform_device *dev)
{
		printk("Driver found device unpluged!\n");
		ok6410_led_release();  
    misc_deregister(&misc);
    return 0;
}

struct platform_driver led_drv={
		.probe=led_drv_probe,
		.remove=led_drv_remove,
		.driver={
					.owner=THIS_MODULE,
					.name="plat_led",  //platform总线  里面驱动的名字   这个名字要和设备的名字一样
			}
};


static int __init platform_led_drv_int(void)
{
		return platform_driver_register(&led_drv);
}


static void __exit platform_led_drv_exit(void)
{
		platform_driver_unregister(&led_drv);
}


module_init(platform_led_drv_int);
module_exit(platform_led_drv_exit);


plat_dev.c:
#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/init.h>
#include <linux/platform_device.h>

MODULE_AUTHOR("Hao");
MODULE_LICENSE("Dual BSD/GPL");


#define GPIOM_PA_BASE   0x7f008820


struct resource led_resource []= {  
    [0]={
		    .name  = "led io-mem",  //设备资源的名字  
		    .start = GPIOM_PA_BASE,  
		    .end   = GPIOM_PA_BASE + 0xc,  
		    .flags = IORESOURCE_MEM,
  			}  
};

struct platform_device led_dev={
	.name="plat_led",  //platform总线  里面设备的名字   这个名字要和驱动的名字一样
	.id=-1,	
	.num_resources=ARRAY_SIZE(led_resource),  //ARRAY_SIZE求资源结构体的个数的
	.resource=led_resource,
};

static int __init platform_led_dev_init(void)
{
		int ret=0;
		ret=platform_device_register(&led_dev);
		if(ret)
		{
				printk("platform_device_register failed!!\n");
		}
		return ret;
}

static void __exit platform_led_dev_exit(void)
{
		platform_device_unregister(&led_dev);
}

module_init(platform_led_dev_init);
module_exit(platform_led_dev_exit);

plat_drv.h:
#ifndef _LED_H_
#define _LED_H_

#include <linux/ioctl.h>

#define CMD_KTYPE 'k' //定义命令幻数   也叫命令类型

#define LEDR_KCMD   _IOR(CMD_KTYPE,1,int)   //定义读方向的命令
#define LEDW_KCMD  _IOW(CMD_KTYPE,2,int)  //定义写方向的命令

#define LED_KCMD 2  //命令个数  后面判断命令是否有效 用的


#endif /* _MEMDEV_H_ */


app_led.c:
#include <stdio.h>  
#include <string.h>  
#include <stdlib.h>  
#include <unistd.h>  
#include<sys/types.h>  
#include<sys/stat.h>  
#include<fcntl.h>  
#include "plat-drv.h"  
  
int main(int argc, char *argv[])  
{  
    int fd=0;  
    printf("\n%d\n",*argv[1]);  
    unsigned int arg=(unsigned int)(*argv[1]-'0');  
    char buf[40]="WRITE_STR_KCMD is in kernel";  
    if(-1==(fd=open("/dev/misc_led",O_RDWR)))  //设备节点名称为memdev0  
    {  
        printf("Open Dev Mem0 Error!\n");  
        _exit(EXIT_FAILURE);  
    }  
    printf("begin WRITE_KCMD!!!\n");  //写入一个int型arg  
    ioctl(fd,LEDW_KCMD,&arg);  
    close(fd);  
    return 0;  
} 




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值