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.cleddriver.c1.#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_MISCDEV22.(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 427.#define SCULL_QUANTUM 400028.#define SCULL_QSET 100029.//---do as the GIO driver30.#define DEVCOUNT 431.#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 test37.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_GPNCON44.#define GPNDAT S3C64XX_GPNDAT45.#define GPNPUD S3C64XX_GPNPUD46.#define GPMCON S3C64XX_GPMCON47.#define GPMDAT S3C64XX_GPMDAT48.#define GPMPUD S3C64XX_GPMPUD49.50.#define VIB_ON 0x1151.#define VIB_OFF 0x2252.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 intcmd, long data)74.static int GPIO_VIB_ioctl(struct inode *inode, struct file *file, unsigned intcmd, 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.//?£?éêy103.//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_ct l_ops);125.if (ret < 0) {126. printk(KERN_ERR "VIB: unable to get major %d\n", ret);127.return ret;128.}129.//′′?¨\uc1class130.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, "vi b");137.// create a point under /dev/class/vib138.//í¨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.#endif141.#if 0/* ×¢2á?ˉì?*/142.if ((error = alloc_chrdev_region(&dev, 0, DEVCOUNT, "vibrate")) < 0)143. {144. printk(KERN_ERR145."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_ERR155."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.#endif166.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ˉêy175. 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 0189. cdev_del(cdev_p);190. unregister_chrdev_region(dev, DEVCOUNT);191. class_destroy(vib_dev_class);192.#endif193.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文件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 intcmd, 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 文件1.config LEDTEST2. tristate "LED test for ARMeasy"3.default n4. help5.this is a LED driver for ARMEASY with S3C6410Makefile文件1.obj-$(CONFIG_LEDTEST)+=leddriver.o3、在内核配置里菜单里加入本驱动的配置项达到的效果是,可以通过内核配置来选择是否把本驱动编译进内核里,也就是出现在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,这样强制的包含进去编译。