安卓开发linux内核驱动
2016-01-18 14:52
459 查看
1.我们把整个安卓系统当成linux内核来使用,所以这里我们编写内核驱动,这些教程比较多,推荐看一些书籍把,这里转载一编博客
点击打开链接
本例子,讲述在android2.1上完全自已开发一个驱动去控制硬件口并写应用测试该驱动,通过这样一个例子,解析android下的驱动开发流程的应用调用流程,可以说是很好的入门引导
要达到的效果:通过android的应用,调用驱动程序,在开发板上控制4个LED的亮灭。
一、硬件原理
![](http://hi.csdn.net/attachment/201104/12/0_1302572053zf9e.gif)
如上图,通过4个IO口控制这LED,低电平LED亮,
这4个IO口分别是GPM1, GPM2, GPM3, GPM4,
二、驱动程序
1、在kernel文件夹下的driver目录,新键驱动文件夹
# cd kernel_android_2.6.28.6/drivers
进到开发板的kernel目录,建驱动文件夹
2、在/driver/ledtest目录下,新建leddriver.c ,leddriver.h , Kconfig, Makefile 等4个文件
leddriver.c
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,constchar *
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章<android添加新驱动方法>
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 <stdio.h>
#include <stdlib.h>
#include <fcntl.h>// 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源代码顶层目录进行编译:
例如我这里的实际操作是
注意make ledtestapp中的目标名ledtestapp就是上面Android.mk文件中由LOCAL_MODULE指定的模块名。编译结果如下
4、如上面的编译结果所示,编译后的可执行文件存放在
out/target/product/generic/system/bin/目录 可执行文件是ledtestapp
5、拷贝ledtestapp可执行文件到T卡,插入开发板
6、开电,在启动进入android的过程中,串口终端 按回车,进入命令行模式
7、拷贝可执行文件到根目录
8、执行程序
通过上面的步骤,可以看到开发板上相应的LED在闭,每秒钟闪一次!
买开发板的话,推荐下面4款,你可以根据你的经济能力来选一个
1、高级嵌入式开发板 ARM-A8内核,价格在2200~2700
X-210开发板(代码开放度高,XBOOT很牛)
Mini210开发板 (友善的板子,有沉淀)
2、入门级嵌入式开发板 ARM11内核 ,价格在500~650之间
Tiny6410 (友善之臂经典之作)
OK6410 (特点是支持WINCE7.0)
可以去风火轮团队的店里看一下,在他们那里买板有个好处,他们提从更周到的技术支持
风火轮技术开发团队 http://www.arm-cn.com/
官方淘宝店:smartfire.taobao.com
![](http://hi.csdn.net/attachment/201104/14/0_1302766085rb2S.gif)
后语:近来老发现有网站盗用我的博客文章,又不注明出处,很不尊重我的劳动果实,所以设计了以上签名,做成图片,望理解!
点击打开链接
[转]android驱动例子(LED灯控制
本文转自:/article/8176212.html本例子,讲述在android2.1上完全自已开发一个驱动去控制硬件口并写应用测试该驱动,通过这样一个例子,解析android下的驱动开发流程的应用调用流程,可以说是很好的入门引导
要达到的效果:通过android的应用,调用驱动程序,在开发板上控制4个LED的亮灭。
一、硬件原理
![](http://hi.csdn.net/attachment/201104/12/0_1302572053zf9e.gif)
如上图,通过4个IO口控制这LED,低电平LED亮,
这4个IO口分别是GPM1, GPM2, GPM3, GPM4,
二、驱动程序
1、在kernel文件夹下的driver目录,新键驱动文件夹
# cd kernel_android_2.6.28.6/drivers
进到开发板的kernel目录,建驱动文件夹
#mkdir ledtest
2、在/driver/ledtest目录下,新建leddriver.c ,leddriver.h , Kconfig, Makefile 等4个文件
leddriver.c
#include <linux/kernel.h> #include <linux/sched.h> #include <linux/timer.h> #include <linux/init.h> /* For __init/__exit/... */ #include <linux/module.h> #include <mach/hardware.h> #include <asm/io.h> #include <asm/uaccess.h> #include <plat/gpio-cfg.h> #include <plat/regs-clock.h> #include <plat/regs-lcd.h> #include <plat/regs-gpio.h> #include <mach/map.h> #include <linux/gpio.h> #include <plat/gpio-bank-m.h> #include <linux/cdev.h> #include <linux/fs.h> //for register_chrdev() #include <linux/device.h> #include <mach/map.h> #include "leddriver.h" #include <linux/miscdevice.h> /* For MODULE_ALIAS_MISCDEV (WATCHDOG_MINOR) */ #include <linux/watchdog.h> /* For the watchdog specific items */ #include <linux/fs.h> /* 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<count;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,constchar *
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章<android添加新驱动方法>
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 <stdio.h>
#include <stdlib.h>
#include <fcntl.h>// 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: <span class="kwrd" style="color: rgb(0, 0, 255);">out</span>/host/linux-x86/bin/apriori
Install: out/host/linux-x86/bin/soslim
target Executable: ledtestapp (<span class="kwrd" style="color: rgb(0, 0, 255);">out</span>/target/product/generic/obj/EXECUTABLES/ledtestapp_intermediates/LINKED/ledtestapp)
target Non-prelinked: ledtestapp (out/target/product/generic/symbols/system/bin/ledtestapp)
target Strip: ledtestapp (<span class="kwrd" style="color: rgb(0, 0, 255);">out</span>/target/product/generic/obj/EXECUTABLES/ledtestapp_intermediates/ledtestapp)
Install: out/target/product/generic/system/lib/libdl.so
Install: <span class="kwrd" style="color: rgb(0, 0, 255);">out</span>/target/product/generic/system/lib/libc.so
Install: out/target/product/generic/system/lib/libstdc++.so
Install: <span class="kwrd" style="color: rgb(0, 0, 255);">out</span>/target/product/generic/system/lib/libm.so
Install: out/target/product/generic/system/bin/ledtestapp
4、如上面的编译结果所示,编译后的可执行文件存放在
out/target/product/generic/system/bin/目录 可执行文件是ledtestapp
5、拷贝ledtestapp可执行文件到T卡,插入开发板
6、开电,在启动进入android的过程中,串口终端 按回车,进入命令行模式
7、拷贝可执行文件到根目录
#cp /sdcard/ledtestapp /
8、执行程序
#./ledtestapp
通过上面的步骤,可以看到开发板上相应的LED在闭,每秒钟闪一次!
买开发板的话,推荐下面4款,你可以根据你的经济能力来选一个
1、高级嵌入式开发板 ARM-A8内核,价格在2200~2700
X-210开发板(代码开放度高,XBOOT很牛)
Mini210开发板 (友善的板子,有沉淀)
2、入门级嵌入式开发板 ARM11内核 ,价格在500~650之间
Tiny6410 (友善之臂经典之作)
OK6410 (特点是支持WINCE7.0)
可以去风火轮团队的店里看一下,在他们那里买板有个好处,他们提从更周到的技术支持
风火轮技术开发团队 http://www.arm-cn.com/
官方淘宝店:smartfire.taobao.com
![](http://hi.csdn.net/attachment/201104/14/0_1302766085rb2S.gif)
后语:近来老发现有网站盗用我的博客文章,又不注明出处,很不尊重我的劳动果实,所以设计了以上签名,做成图片,望理解!
相关文章推荐
- Linux下百度云盘报 获取bdstoken失败
- Linux 标准输入输出及重定向
- linux设备驱动--内核等待队列知识点---结合中断使用
- linux 环境变量
- 基于5532制作的实用话放(单电源供电)
- Linux下安装QT之版本qt
- 成功移植linux2.6.38内核到TQ2440(转)
- linux find
- Linux下的PCI总线驱动
- Linux 常用基本命令之十三 whereis
- Centos运行级别和开机过程
- Linux 零拷贝技术
- Linux系统是32位还是64位操作系统
- Linux下 ntp 时间同步服务ntpd 出现 the NTP socket is in use, exiting 解决
- linux设置安全连接设置(私钥)
- Linux学习之traceroute命令
- Linux远程秘钥登录方式
- Linux之-atime、ctime、mtime
- Linux下的PCI驱动编程
- linux 常用基本命令之十二 which