您的位置:首页 > 其它

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

2013-06-28 21:55 411 查看

本节知识点:

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: