首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

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

(转)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:
[cpp] view plaincopy


  • #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:

[cpp] view plaincopy


  • #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:

[cpp] view plaincopy


  • #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:

[cpp] view plaincopy


  • #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;   
  • }   


http://blog.csdn.net/mbh_1991/article/details/9199937
返回列表