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

leddriver.c
1.#include <linux/kernel.h>
2.#include <linux/sched.h>
3.#include <linux/timer.h>
4.#include <linux/init.h>            /* For __init/__exit/... */
5.#include <linux/module.h>
6.#include <mach/hardware.h>
7.#include <asm/io.h>
8.#include <asm/uaccess.h>
9.#include <plat/gpio-cfg.h>
10.#include <plat/regs-clock.h>
11.#include <plat/regs-lcd.h>
12.#include <plat/regs-gpio.h>
13.#include <mach/map.h>
14.#include <linux/gpio.h>
15.#include <plat/gpio-bank-m.h>
16.#include <linux/cdev.h>
17.#include <linux/fs.h> //for register_chrdev()
18.#include <linux/device.h>
19.#include <mach/map.h>
20.#include "leddriver.h"
21.#include <linux/miscdevice.h>        /* For MODULE_ALIAS_MISCDEV
22.                            (WATCHDOG_MINOR) */
23.#include <linux/watchdog.h>        /* For the watchdog specific items */
24.#include <linux/fs.h>            /* For file operations */
25.#define Viberator_MAJOR        97  //?÷éè±?o?
26.#define SCULL_NR_DEVS           4
27.#define SCULL_QUANTUM         4000
28.#define SCULL_QSET             1000
29.//---do as the GIO driver
30.#define DEVCOUNT                4
31.#define GIO_MINOR            2    /* GIO minor no. */
32.static dev_t dev;        //éê ?? μ?μ??÷ éè±? o?
33.static struct cdev *cdev_p;
34.static int openCnt;
35.//--è???±?á?------------
36.int VIB_major  = 97;//we asigment it for test
37.int VIB_minor = 0;
38.int VIB_nr_devs = SCULL_NR_DEVS;
39.int VIB_quantum = SCULL_QUANTUM;
40.int VIB_qset = SCULL_QSET;
41. 
42.static struct class *vib_dev_class;
43.#define GPNCON  S3C64XX_GPNCON
44.#define GPNDAT  S3C64XX_GPNDAT
45.#define GPNPUD  S3C64XX_GPNPUD
46.#define GPMCON S3C64XX_GPMCON
47.#define GPMDAT  S3C64XX_GPMDAT
48.#define GPMPUD S3C64XX_GPMPUD
49. 
50.#define VIB_ON 0x11
51.  #defineVIB_OFF 0x22
52.static const struct file_operations GPIO_Viberator_ctl_ops={
53.    .owner        = THIS_MODULE,
54.    .open    = GPIO_VIB_open,
55.    .read    =GPIO_VIB_read,
56.    .write    =GPIO_VIB_write,
57.    .ioctl     = GPIO_VIB_ioctl,
58.    .release     =GPIO_VIB_release,
59.};
60.ssize_t GPIO_VIB_read(struct file * file,char * buf,size_t count,loff_t * f_ops)
61.{
62.    printk(" GPIO_VIB_read \r\n");
63.    gpio_direction_output(S3C64XX_GPM(3), 0);//
64.    return count ;
65.}
66.ssize_t GPIO_VIB_write (struct file * file,const char * buf, size_t count,loff_t * f_ops)
67.{
68.      printk(" GPIO_VIB_write \r\n");
69.      gpio_direction_output(S3C64XX_GPM(3), 1);//
70.   return count;
71.}
72. 
73.//ssize_t GPIO_VIB_ioctl(struct inode *  inode,struct file * file,unsigned int cmd, long data)
74.static int GPIO_VIB_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
75.{
76.    printk(KERN_ERR"VIB:GPIO_VIB_ioctl --CMD=%x \n",cmd);
77.    switch(cmd)
78.        {
79.           case VIB_ON:
80.            gpio_direction_output(S3C64XX_GPM(1), 0);//
81.            gpio_direction_output(S3C64XX_GPM(2), 0);//
82.            gpio_direction_output(S3C64XX_GPM(3), 0);//
83.            gpio_direction_output(S3C64XX_GPM(4), 1);//
84.            printk(KERN_ERR"VIB:GPIO_VIB_ioctl --VIB_ON\n");
85.            break;
86.         case VIB_OFF:
87.            {
88.            printk(KERN_ERR"VIB:GPIO_VIB_ioctl --VIB_OFF\n");
89.            gpio_direction_output(S3C64XX_GPM(1), 1);//
90.            gpio_direction_output(S3C64XX_GPM(2), 1);//
91.            gpio_direction_output(S3C64XX_GPM(3), 1);//
92.            gpio_direction_output(S3C64XX_GPM(4), 0);//
93.            break;
94.         }
95.         default:break;
96.                
97.    }
98.        //gpio_free(S3C64XX_GPN(7));
99.}
100.ssize_t GPIO_VIB_open(struct inode * inode,struct file * file)
101.{
102.//?£?éêy
103.  //MOD_INC_USE_COUNT;
104.  printk("GPIO_VIB_open() \n");   
105.  return 0;
106.}
107.ssize_t GPIO_VIB_release(struct inode * inode, struct file * file)
108.{
109.   // MOD_DEC_USE_COUNT;//?£?éêy??
110.     printk("GPIO_VIB_release() \n");   
111.    return 0;
112.}
113.static int GPIO_VIB_CTL_init(void)
114.{
115.    int ret  = -ENODEV;
116.   int error ;
117.    printk("---------------------------------------------- \r\n");
118.    //3?ê??ˉ???ú
119.        s3c_gpio_cfgpin(S3C64XX_GPM(1), S3C_GPIO_SFN(1));//GPM1 output
120.        s3c_gpio_cfgpin(S3C64XX_GPM(2), S3C_GPIO_SFN(1));//GPM2 output
121.        s3c_gpio_cfgpin(S3C64XX_GPM(3), S3C_GPIO_SFN(1));//GPM3 output
122.        s3c_gpio_cfgpin(S3C64XX_GPM(4), S3C_GPIO_SFN(1));//GPM4 output
123.#if 1 /*?2ì?·?ê?×¢2á?y?ˉ*/
124.ret = register_chrdev(Viberator_MAJOR, "viberator", &GPIO_Viberator_ctl_ops);
125.if (ret < 0) {
126.    printk(KERN_ERR "VIB: unable to get major %d\n", ret);
127.    return ret;
128.}
129.//′′?¨\uc1class
130.vib_dev_class = class_create(THIS_MODULE, "viberator");
131.if (IS_ERR(vib_dev_class)) {
132.    unregister_chrdev(Viberator_MAJOR, "capi20");
133.    return PTR_ERR(vib_dev_class);
134.}
135.//′′?¨?úμ?£?
136.device_create(vib_dev_class, NULL, MKDEV(Viberator_MAJOR, 0), NULL, "vib");
137.// create a point under /dev/class/vib  
138.//í¨1yé????aá?2?£??y?ˉ?ó??oó£??í?á?ú/dev/class/????éú3é\uc1vib?úμ?£?ó|ó?3ìDò?éò???2ù×÷???t???ù2ù×÷?a???úμ?£?í¨1y\uc1open ,write,read μèoˉêy2ù×÷£??ê?é?éò??′oó??μ?ó|ó?ê?ày3ìDò?£
139.  return 0;    
140.#endif
141.#if 0/* ×¢2á?ˉì?*/
142.    if ((error = alloc_chrdev_region(&dev, 0, DEVCOUNT, "vibrate")) < 0)
143.        {
144.        printk(KERN_ERR
145.               "VIB: Couldn't alloc_chrdev_region, error=%d\n",
146.               error);
147.        return 1;
148.    }
149.         printk("dev = %d  \n",dev);
150.    cdev_p = cdev_alloc();
151.    cdev_p->ops = &GPIO_Viberator_ctl_ops;
152.    error = cdev_add(cdev_p, dev, DEVCOUNT);
153.    if (error) {
154.        printk(KERN_ERR
155.               "VIB: Couldn't cdev_add, error=%d\n", error);
156.        return 1;
157.    }
158. 
159.    vib_dev_class = class_create(THIS_MODULE, "vib-dev");
160.    if (IS_ERR(vib_dev_class)) {
161.        res = PTR_ERR(vib_dev_class);
162.        goto out_unreg_class;
163.    }
164.    return 0;
165.#endif
166.out_unreg_class:
167.    class_destroy(vib_dev_class);
168.return 1;
169.}
170. 
171.static int __init S3C6410_VIB_init(void)
172.{
173.    int ret = -ENODEV;
174.    //μ÷ó?oˉêy   
175.        printk(KERN_ERR "Auly: S3C6410_VIB_init---\n");
176.    ret = GPIO_VIB_CTL_init();
177.    if(ret)
178.        {
179.        printk(KERN_ERR "Auly: S3C6410_VIB_init--Fail !!!\n");
180.        return ret;
181.    }
182.    return 0;
183.}
184.static void __exit cleanup_GPIO_VIB(void)
185.{
186.    //×¢?úéè±?
187.  //  devfs_unregister_chrdev(Viberator_MAJOR,"gpio_vib_ctl");
188.#if 0
189.      cdev_del(cdev_p);
190.    unregister_chrdev_region(dev, DEVCOUNT);
191.    class_destroy(vib_dev_class);
192.#endif
193.device_destroy(vib_dev_class, MKDEV(Viberator_MAJOR, 0));
194.class_destroy(vib_dev_class);
195.unregister_chrdev(Viberator_MAJOR, "viberator");
196.}
197.MODULE_LICENSE("GPL");
198.MODULE_DESCRIPTION("Peter first driver");
199.MODULE_ALIAS_CHARDEV(Viberator_MAJOR, 0);
200. 
201.module_init(S3C6410_VIB_init);
202.module_exit(cleanup_GPIO_VIB);

 

leddriver.h文件

leddriver.h文件
1.ssize_t GPIO_VIB_read(struct file * file,char * buf,size_t count,loff_t * f_ops);
2.ssize_t GPIO_VIB_write (struct file * file,const char * buf, size_t count,loff_t * f_ops);
3.static int GPIO_VIB_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
4.ssize_t GPIO_VIB_open(struct inode * inode,struct file * file);
5.ssize_t GPIO_VIB_release(struct inode * inode, struct file * file);
6.static int GPIO_VIB_CTL_init(void);
Kconfig 文件

Kconfig 文件
1.config LEDTEST
2.  tristate "LED test for ARMeasy"
3.  default n
4.  help
5.  this is a LED driver for ARMEASY with S3C6410
Makefile文件

Makefile文件
1.obj-$(CONFIG_LEDTEST)+=leddriver.o
3、在内核配置里菜单里加入本驱动的配置项

达到的效果是,可以通过内核配置来选择是否把本驱动编译进内核里,也就是出现在make menuconfig 后出来的界面里,可以参考9.8章<Android添加新驱动方法>

1)在arch/arm/Kconfig文件里 menu "Device Drivers"与 endmenu之间添加

1.source "drivers/ledtest/Kconfig"
2)在drivers/Kconfig menu "Device Drivers" 和 endmenu之间添加

1.source "drivers/ledtest/Kconfig"
3)修改/drivers/Makefile文件

1.Obj-$(CONFIG_LEDTEST) +=ledtest/
4、编译驱动

在kernel目录下,终端输入

1.#make menuconfig
“Device Drivers” 下面会看到 “LED test for ARMeasy”,选择它,

保存并退出

1.#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
1.#include <stdio.h>
2.#include <stdlib.h>
3.#include <fcntl.h> // contact the open(),close(),read(),write() and so on!
4.  #define DEVICE_NAME "/dev/vib"//device point
5.#define LED_ON     0x11
6.#define LED_OFF     0x22
7.int main(int argc,char **argv)
8.{   
9.    int fd;
10.    int ret;
11.    char *i;
12.    printf("\n start gpio_led_driver test \r\n");
13.    fd = open(DEVICE_NAME,O_RDWR);//Open device ,get the handle
14.    printf("fd = %d \n",fd);
15.    if(fd == -1) //open fail
16.    {
17.      printf("open device %s error \n",DEVICE_NAME);
18.    }
19.    else
20.    {
21.        while(1)
22.        {
23.          ioctl(fd,LED_OFF); //call the output function to off LEDs
24.          sleep(1);//wait 1 second
25.          ioctl(fd,LED_ON);
26.          sleep(1);
27.        }
28.        ret = close(fd); //close device
29.        printf("ret = %d \n",ret);
30.        printf("close gpio_led test \n");
31.    }
32.  return 0;
33.}
2、在$(YOUR_Android)/external/ LEDTEST /目录编写Android.mk文件。这是Android Makefile的标准命名,不要更改。Android.mk文件的格式和内容可以参考其他已有的Android.mk文件的写法,针对helloworld程序的Android.mk文件内容如下:

Android.mk
1. 
2.LOCAL_PATH:= $(call my-dir)
3.include $(CLEAR_VARS)
4.LOCAL_SRC_FILES:= \\par     hello.c
5.LOCAL_MODULE := ledtestapp
6.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=RELPLATFORM_VERSION=2.1-update1TARGET_PRODUCT=genericTARGET_BUILD_VARIANT=engTARGET_SIMULATOR=TARGET_BUILD_TYPE=releaseTARGET_ARCH=armHOST_ARCH=x86HOST_OS=linuxHOST_BUILD_TYPE=releaseBUILD_ID=ECLAIR============================================/bin/bash: line 0: cd: sdk/layoutopt/app/src/resources: No such file or directorytarget thumb C: ledtestapp <= external/LEDTEST/ledtest.cInstall: out/host/linux-x86/bin/aprioriInstall: out/host/linux-x86/bin/soslimtarget 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.soInstall: out/target/product/generic/system/lib/libc.soInstall: out/target/product/generic/system/lib/libstdc++.soInstall: out/target/product/generic/system/lib/libm.soInstall: 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在闭,每秒钟闪一次!


本篇文章来源于 Linux公社网站(www.linuxidc.com)  原文链接:http://www.linuxidc.com/Linux/2011-04/34541p3.htm

 http://www.linuxidc.com/Linux/2011-08/40508.htm

http://www.linuxidc.com/Linux/2011-04/34541.htm

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值