• 【转】android 驱动例子(LED控制)



    本例子,讲述在android2.1上完全自已开发一个驱动去控制硬件口并写应用测试该驱动,通过这样一个例子,解析android下的驱动开发流程的应用调用流程,可以说是很好的入门引导。
    要达到的效果:通过android的应用,调用驱动程序,在开发板上控制4个LED的亮灭。
     
    一、硬件原理
     
                                                                 
     
    如上图,通过4个IO口控制这LED,低电平LED亮,这4个IO口分别是GPM1, GPM2, GPM3, GPM4。
     
    二、驱动程序
    1、在kernel文件夹下的driver目录,新键驱动文件夹
    # cd kernel_android_2.6.28.6/drivers
    进到开发板的kernel目录,建驱动文件夹
     #mkdir ledtest2、在/driver/ledtest目录下,新建leddriver.c ,leddriver.h , Kconfig, Makefile 等4个文件
    leddriver.c
     #include
    #include
    #include
    #include             /* For __init/__exit/... */
    #include
    #include
    #include <asm/io.h>
    #include <asm/uaccess.h>
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include  //for register_chrdev()
    #include
    #include
    #include "leddriver.h"
    #include         /* For MODULE_ALIAS_MISCDEV
                                (WATCHDOG_MINOR) */
    #include         /* For the watchdog specific items */
    #include             /* For file operations */
    #define Viberator_MAJOR        97  //主设备号
    #define SCULL_NR_DEVS           4
    #define SCULL_QUANTUM         4000
    #define SCULL_QSET             1000
    //---do as the GIO driver
    #define DEVCOUNT                4
    #define GIO_MINOR            2    /* GIO minor no. */
    static dev_t dev;        //申  请  到的主  设备  号
    static struct cdev *cdev_p;
    static int openCnt;
    //--全局变量------------
    int VIB_major  = 97;//we asigment it for test
    int VIB_minor = 0;
    int VIB_nr_devs = SCULL_NR_DEVS;
    int VIB_quantum = SCULL_QUANTUM;
    int VIB_qset = SCULL_QSET;

    static struct class *vib_dev_class;
    #define GPNCON  S3C64XX_GPNCON
    #define GPNDAT  S3C64XX_GPNDAT
    #define GPNPUD  S3C64XX_GPNPUD
    #define GPMCON S3C64XX_GPMCON
    #define GPMDAT  S3C64XX_GPMDAT
    #define GPMPUD S3C64XX_GPMPUD

    #define VIB_ON 0x11
    #define  VIB_OFF 0x22
    static const struct file_operations GPIO_Viberator_ctl_ops={
        .owner        = THIS_MODULE,
        .open    = GPIO_VIB_open,
        .read    =GPIO_VIB_read,
        .write    =GPIO_VIB_write,
        .ioctl     = GPIO_VIB_ioctl,
        .release     =GPIO_VIB_release,
    };
    ssize_t GPIO_VIB_read(struct file * file,char * buf,size_t count,loff_t * f_ops)
    {
           char sdas[5]={1,3,8,1,6};
           ssize_t            status = 5;
        unsigned long    missing;
        missing = copy_to_user(buf, sdas, status);
        if (missing == status)
            status = -EFAULT;
        else
            status = status - missing;  
           printk(" GPIO_VIB_read = %d ,count = %d/r/n",status,count);
        gpio_direction_output(S3C64XX_GPM(3), 0);//
    return status ;
    }
    ssize_t GPIO_VIB_write (struct file * file,const char * buf, size_t count,loff_t * f_ops)
    {
        unsigned long missing;
         char inbuffer[512]={0};
        int i;
         missing = copy_from_user(inbuffer, buf, count);
        printk(" GPIO_VIB_write count = %d missing =%d /r/n",count,missing);
        gpio_direction_output(S3C64XX_GPM(3), 1);//
        for(i=0;i        {
                printk("Write:inbuffer[%d]=%d /r/n",i,inbuffer[i]);
            }
    return count;
    }

    //ssize_t GPIO_VIB_ioctl(struct inode *  inode,struct file * file,unsigned int cmd, long data)
    static int GPIO_VIB_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
    {
        printk(KERN_ERR"VIB:GPIO_VIB_ioctl --CMD=%x /n",cmd);
        switch(cmd)
            {
               case VIB_ON:
                gpio_direction_output(S3C64XX_GPM(1), 0);//
                gpio_direction_output(S3C64XX_GPM(2), 0);//
                gpio_direction_output(S3C64XX_GPM(3), 0);//
                gpio_direction_output(S3C64XX_GPM(4), 1);//
                printk(KERN_ERR"VIB:GPIO_VIB_ioctl --VIB_ON/n");
                break;
             case VIB_OFF:
                {
                printk(KERN_ERR"VIB:GPIO_VIB_ioctl --VIB_OFF/n");
                gpio_direction_output(S3C64XX_GPM(1), 1);//
                gpio_direction_output(S3C64XX_GPM(2), 1);//
                gpio_direction_output(S3C64XX_GPM(3), 1);//
                gpio_direction_output(S3C64XX_GPM(4), 0);//
                break;
             }
             default:break;
                   
        }
            //gpio_free(S3C64XX_GPN(7));
    }
    ssize_t GPIO_VIB_open(struct inode * inode,struct file * file)
    {
    //模块数
      //MOD_INC_USE_COUNT;
      printk("GPIO_VIB_open() /n");  
      return 0;
    }
    ssize_t GPIO_VIB_release(struct inode * inode, struct file * file)
    {
       // MOD_DEC_USE_COUNT;//模块数减1
         printk("GPIO_VIB_release() /n");  
        return 0;
    }
    static int GPIO_VIB_CTL_init(void)
    {
        int ret  = -ENODEV;
       int error ;
        printk("---------------------------------------------- /r/n");
        //初始化端口
            s3c_gpio_cfgpin(S3C64XX_GPM(1), S3C_GPIO_SFN(1));//GPM1 output
            s3c_gpio_cfgpin(S3C64XX_GPM(2), S3C_GPIO_SFN(1));//GPM2 output
            s3c_gpio_cfgpin(S3C64XX_GPM(3), S3C_GPIO_SFN(1));//GPM3 output
            s3c_gpio_cfgpin(S3C64XX_GPM(4), S3C_GPIO_SFN(1));//GPM4 output
    #if 1 /*静态方式注册驱动*/
    ret = register_chrdev(Viberator_MAJOR, "viberator", &GPIO_Viberator_ctl_ops);
    if (ret < 0) {
        printk(KERN_ERR "VIB: unable to get major %d/n", ret);
        return ret;
    }
    //创建class
    vib_dev_class = class_create(THIS_MODULE, "viberator");
    if (IS_ERR(vib_dev_class)) {
        unregister_chrdev(Viberator_MAJOR, "capi20");
        return PTR_ERR(vib_dev_class);
    }
    //创建节点,
    device_create(vib_dev_class, NULL, MKDEV(Viberator_MAJOR, 0), NULL, "vib");
    // create a point under /dev/class/vib 
    //通过上面这两步,驱动加载后,就会在/dev/class/下面生成vib节点,应用程序可以像操作文件那样操作这个节点,通过open ,write,read 等函数操作,详情可以看后面的应用示例程序。
      return 0;   
    #endif
    #if 0/* 注册动态 */
        if ((error = alloc_chrdev_region(&dev, 0, DEVCOUNT, "vibrate")) < 0)
            {
            printk(KERN_ERR
                   "VIB: Couldn't alloc_chrdev_region, error=%d/n",
                   error);
            return 1;
        }
             printk("dev = %d  /n",dev);
        cdev_p = cdev_alloc();
        cdev_p->ops = &GPIO_Viberator_ctl_ops;
        error = cdev_add(cdev_p, dev, DEVCOUNT);
        if (error) {
            printk(KERN_ERR
                   "VIB: Couldn't cdev_add, error=%d/n", error);
            return 1;
        }

        vib_dev_class = class_create(THIS_MODULE, "vib-dev");
        if (IS_ERR(vib_dev_class)) {
            res = PTR_ERR(vib_dev_class);
            goto out_unreg_class;
        }
        return 0;
    #endif
    out_unreg_class:
        class_destroy(vib_dev_class);
    return 1;
    }

    static int __init S3C6410_VIB_init(void)
    {
        int ret = -ENODEV;
        //调用函数   
            printk(KERN_ERR "Auly: S3C6410_VIB_init---/n");
        ret = GPIO_VIB_CTL_init();
        if(ret)
            {
            printk(KERN_ERR "Auly: S3C6410_VIB_init--Fail !!!/n");
            return ret;
        }
        return 0;
    }
    static void __exit cleanup_GPIO_VIB(void)
    {
        //注销设备
      //  devfs_unregister_chrdev(Viberator_MAJOR,"gpio_vib_ctl");
     #if 0
          cdev_del(cdev_p);
        unregister_chrdev_region(dev, DEVCOUNT);
        class_destroy(vib_dev_class);
    #endif
    device_destroy(vib_dev_class, MKDEV(Viberator_MAJOR, 0));
    class_destroy(vib_dev_class);
    unregister_chrdev(Viberator_MAJOR, "viberator");
    }
    MODULE_LICENSE("GPL");
    MODULE_DESCRIPTION("Peter first driver");
    MODULE_ALIAS_CHARDEV(Viberator_MAJOR, 0);

    module_init(S3C6410_VIB_init);
    module_exit(cleanup_GPIO_VIB);

     
    <<
     
    leddriver.h文件
     
    leddriver.h文件
    ssize_t GPIO_VIB_read(struct file * file,char * buf,size_t count,loff_t * f_ops);
    ssize_t GPIO_VIB_write (struct file * file,const char * buf, size_t count,loff_t * f_ops);
    static int GPIO_VIB_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
    ssize_t GPIO_VIB_open(struct inode * inode,struct file * file);
    ssize_t GPIO_VIB_release(struct inode * inode, struct file * file);
    static int GPIO_VIB_CTL_init(void);
    Kconfig 文件
    Kconfig 文件
    config LEDTEST
      tristate "LED test for ARMeasy"
      default n
      help
      this is a LED driver for ARMEASY with S3C6410
    Makefile文件
    Makefile文件
    obj-$(CONFIG_LEDTEST)+=leddriver.o
    3、在内核配置里菜单里加入本驱动的配置项
    达到的效果是,可以通过内核配置来选择是否把本驱动编译进内核里,也就是出现在make menuconfig 后出来的界面里,可以参考9.8章
    1)在arch/arm/Kconfig文件里 menu "Device Drivers"与 endmenu之间添加
    source "drivers/ledtest/Kconfig"
    2)在drivers/Kconfig    menu "Device Drivers"endmenu之间添加
    source "drivers/ledtest/Kconfig"
    3)修改/drivers/Makefile文件
    Obj-$(CONFIG_LEDTEST) +=ledtest/
    4、编译驱动
    在kernel目录下,终端输入
    #make menuconfig
    “Device Drivers” 下面会看到 “LED test for ARMeasy”,选择它,
    保存并退出
    #make
    这样,就会在/drivers/ledtest目录下得到leddrivr.ko文件,它就是驱动目标文件,已级编译进了zImage 里了,只要用这个kernel烧录到开发板,开机就会自动加载本驱动,
    PS,如果发现如上编译,没有在ledtest目录下生成leddriver.ko文件,也就是本根没有去编译本驱动,那就把ledtest目录入到/drivers/misc目录下,相应的修改misc下面,然后,在makefile里,不用选直接写成obj-y += leddriver.o,这样强制的包含进去编译。
    三、应用程序(测试驱动)
    用C语言写一个应用,测试上面写的驱动是否工作正常,这是一般的驱动开发流程
    主要有两个文件:Android.mk和ledtest.c
    1、在$(YOUR_ANDROID)/external/LEDTEST/目录编写ledtest.c文件,
    ledtest.c
    ledtest.c
    #include
    #include
    #include // contact the open(),close(),read(),write() and so on!
      #define DEVICE_NAME "/dev/vib"//device point
    #define LED_ON     0x11
    #define LED_OFF     0x22
    int main(int argc,char **argv)
    {   
        int fd;
        int ret;
        char *i;
        printf("\n start gpio_led_driver test \r\n");
        fd = open(DEVICE_NAME,O_RDWR);//Open device ,get the handle
        printf("fd = %d \n",fd);
        if(fd == -1) //open fail
        {
          printf("open device %s error \n",DEVICE_NAME);
        }
        else
        {
            while(1)
            {
              ioctl(fd,LED_OFF); //call the output function to off LEDs
              sleep(1);//wait 1 second
              ioctl(fd,LED_ON);
              sleep(1);
            }
            ret = close(fd); //close device
            printf("ret = %d \n",ret);
            printf("close gpio_led test \n");
        }
      return 0;
    }
    2、在$(YOUR_ANDROID)/external/ LEDTEST /目录编写Android.mk文件。这是Android Makefile的标准命名,不要更改。Android.mk文件的格式和内容可以参考其他已有的Android.mk文件的写法,针对helloworld程序的Android.mk文件内容如下:
    Android.mk
     
    LOCAL_PATH:= $(call my-dir)
    include $(CLEAR_VARS)
    LOCAL_SRC_FILES:= \/par     hello.c
    LOCAL_MODULE := ledtestapp
    include $(BUILD_EXECUTABLE)
     注意上面LOCAL_SRC_FILES用来指定源文件;
    LOCAL_MODULE指定要编译的模块的名字,下一步骤编译时就要用到;
    include $(BUILD_EXECUTABLE)表示要编译成一个可执行文件,如果想编译成动态库则可用BUILD_SHARED_LIBRARY,这些可以在
    $(YOUR_ANDROID)/build/core/config.mk查到。 
     
     
    3、 回到Android源代码顶层目录进行编译:
      # cd $(YOUR_ANDROID) && make ledtestapp例如我这里的实际操作是
      #cd android2.1  #make ledtestapp注意make ledtestapp中的目标名ledtestapp就是上面Android.mk文件中由LOCAL_MODULE指定的模块名。编译结果如下
      make ledtestapp  ============================================  PLATFORM_VERSION_CODENAME=REL  PLATFORM_VERSION=2.1-update1  TARGET_PRODUCT=generic  TARGET_BUILD_VARIANT=eng  TARGET_SIMULATOR=  TARGET_BUILD_TYPE=release  TARGET_ARCH=arm  HOST_ARCH=x86  HOST_OS=linux  HOST_BUILD_TYPE=release  BUILD_ID=ECLAIR  ============================================  /bin/bash: line 0: cd: sdk/layoutopt/app/src/resources: No such file or directory  target thumb C: ledtestapp <= external/LEDTEST/ledtest.c  Install: out/host/linux-x86/bin/apriori  Install: out/host/linux-x86/bin/soslim  target Executable: ledtestapp (out/target/product/generic/obj/EXECUTABLES/ledtestapp_intermediates/LINKED/ledtestapp)  target Non-prelinked: ledtestapp (out/target/product/generic/symbols/system/bin/ledtestapp)  target Strip: ledtestapp (out/target/product/generic/obj/EXECUTABLES/ledtestapp_intermediates/ledtestapp)  Install: out/target/product/generic/system/lib/libdl.so  Install: out/target/product/generic/system/lib/libc.so  Install: out/target/product/generic/system/lib/libstdc++.so  Install: out/target/product/generic/system/lib/libm.so  Install: out/target/product/generic/system/bin/ledtestapp4、如上面的编译结果所示,编译后的可执行文件存放在
    out/target/product/generic/system/bin/目录 可执行文件是ledtestapp
    5、拷贝ledtestapp可执行文件到T卡,插入开发板
    6、开电,在启动进入android的过程中,串口终端 按回车,进入命令行模式
    7、拷贝可执行文件到根目录
      #cp /sdcard/ledtestapp /   8、执行程序
      #./ledtestapp通过上面的步骤,可以看到开发板上相应的LED在闭,每秒钟闪一次!
     
    Android驱动例子(LED灯控制)

    转载请注明出处,文章来源:http://www.threeway.cc/sitecn/informationInfo.aspx?tid=1381&pid=1829

  • 相关阅读:
    Tomcat修改端口号
    如何修改localhost为自己指定的域名
    Tomcat启动时启动窗口中文乱码问题的解决方案
    Java Web 项目jsp页面无法加载样式
    vue 父传子(通过属性传递)
    vue 父传子 讲解
    表白小爱心
    响应式开发
    组件的重复调用
    reduce
  • 原文地址:https://www.cnblogs.com/gooogleman/p/2357246.html
Copyright © 2020-2023  润新知