原帖地址:http://blog.csdn.net/undergrowth/article/details/9157817
开发板:TQ210
OS:Android 4.0.3
以下所有内容都是在TQ210开发板上实现,并且很多内容也是天嵌公司提供,我将一些内容进行了删减、替换,然后加入了一些自己的理解,同时也是记录自己学习的旅程。
废话不多说 先看硬件电路图 很简单 通过NPN三极管控制LED的阴极 NPN三极管的基极给高电平 则三级管导通 则LED等点亮 反之则熄灭
LED驱动源码
led_unders.c
- #include <linux/miscdevice.h> //包含miscdevice misc_register...
- #include <linux/init.h> //包含__init __exit...
- #include <linux/fs.h> //包含file_operations...
- #include <linux/err.h> //包含EINVAL..
- #include <mach/gpio.h> //包含S5PV210_GPC0() ...
- #include <plat/gpio-cfg.h> //包含S3C_GPIO_SFN() s3c_gpio_cfgpin() gpio_direction_output()..
- #define DEVICE_NAME "led_unders" //设备名
- #define GPIO_CTIOL_ON 1 //控制LED亮
- #define GPIO_CTIOL_OFF 0 //控制LED 灭
- static unsigned int gpio_table[]= //引用I/O引脚
- {
- S5PV210_GPC0(3), //开发板的手册上是GPC1 ,是错的
- S5PV210_GPC0(4),
- };
- static unsigned int gpio_cfg_table[]= //设置IO为输出
- {
- S3C_GPIO_SFN(1), //设置引脚为输出
- S3C_GPIO_SFN(1),
- };
- static int gpio_led_under_open(struct inode *inode,struct file *file) //打开led_unders设备
- {
- int ret=0,i;
- for(i=0;i<sizeof(gpio_table)/sizeof(gpio_table[0]);i++)
- {
- s3c_gpio_cfgpin(gpio_table[i], gpio_cfg_table[i]); //设置引脚为输出
- ret=gpio_direction_output(gpio_table[i],GPIO_CTIOL_OFF); //设置引脚为0
- }
- if(ret==0) printk("led_open success.\n");
- else {ret=-1; printk("led_open failed.\n");}
- return ret;
- }
- static int gpio_led_under_close(struct inode *inode,struct file *file)
- {
- printk(KERN_INFO "led_close success.\n");
- return 0;
- }
- static long gpio_led_under_ioctl(struct file *file,unsigned int cmd,unsigned long arg) //控制哪个led灯亮或者灭
- {
- int ret=0;
- printk(KERN_INFO "led ioctl.\n");
- arg=arg-1;
- if(arg>sizeof(gpio_table)/sizeof(gpio_table[0])) return -EINVAL; //判断传递的参数是否合法
- switch(cmd)
- {
- case GPIO_CTIOL_ON:
- gpio_direction_output(gpio_table[arg],GPIO_CTIOL_ON); //点亮LED
- break;
- case GPIO_CTIOL_OFF:
- gpio_direction_output(gpio_table[arg],GPIO_CTIOL_OFF); //熄灭LED
- break;
- default:
- ret=-1;
- printk(KERN_INFO "led ioctl error");
- }
- return ret;
- }
- static struct file_operations dev_fops=
- {
- .owner=THIS_MODULE,
- .unlocked_ioctl=gpio_led_under_ioctl,
- .open=gpio_led_under_open,
- .release=gpio_led_under_close,
- };
- static struct miscdevice misc_led=
- { //led混杂设备结构体定义
- .minor=MISC_DYNAMIC_MINOR, //动态分配次设备号
- .name=DEVICE_NAME, //设备名称
- .fops=&dev_fops, //设备操作结构体
- };
- static int __init led_init() //led初始化
- {
- int ret;
- ret=misc_register(&misc_led); //注册混杂设备成功注册返回0
- if(ret==0) printk(KERN_INFO "led_init driver success.\n");
- else { printk(KERN_INFO "led_init driver failed.\n"); ret=-1;}
- return ret;
- }
- static void __exit led_exit() //led卸载
- {
- int ret=misc_deregister(&misc_led); //卸载混杂设备 ,成功返回0
- if(ret==0) printk(KERN_INFO "led_exit driver success.\n");
- else printk(KERN_INFO "led_exit driver failed.\n");
- }
- //模块入口与出口
- module_init(led_init);
- module_exit(led_exit);
- MODULE_LICENSE("GPL"); //gpl许可
Makefile文件
- obj-m :=led_unders.o
- KERNELDIR :=~/java/Kernel_3.0.8_TQ210_for_Android_v1.0/
- PWD :=$(shell pwd)
- build:kernel_module
- kernel_module:
- make -C $(KERNELDIR) M=$(PWD) modules
- clean:
- make -C $(KERNELDIR) M=$(PWD) clean
Makefile的详细编写 参看GUN的Makefile手册 给一个简单实例连接 http://www.embedu.org/Column/Column310.htm
该驱动模块采用混杂设备来表示led设备,通过使用misc_register函数告诉内核misc_led设备所拥有的功能,
对于混杂设备我看了看源码,个人理解misc_register主要做了三件事,
1.通过MISC_DYNAMIC_MINOR这个标志获取到次设备号
2.通过class_device_create创建/dev/led_unders设备文件
3.通过list_add将misc_led添加到混杂设备链表
测试文件
led_under_driver_test.c
- #include <stdio.h>
- #include <fcntl.h> //文件操作
- #define DEVICE_NAME "/dev/led_unders" //设备名称
- #define GPIO_IOCTL_ON 1 //打开led
- #define GPIO_IOCTL_OFF 0 //关闭led
- #define LED1 1
- #define LED2 2
- /*
- usage: led1/led2 on/off
- */
- int main(int argc,char **argv)
- {
- int fd,ison=0,isnumber=0;
- fd=open(DEVICE_NAME,O_RDWR); //以可读可写的方式打开设备文件
- if(fd<0) //判断是否成功打开文件
- {
- printf("open %s failed.\n",DEVICE_NAME);
- return 0;
- }
- if(argc!=3) //判断参数是否合法
- {
- printf("usage:\n");
- printf("led1/led2 on/off\n");
- }
- if(strcmp(argv[2],"on")==0) ison=GPIO_IOCTL_ON; //判断是打开还是关闭LED
- else ison=GPIO_IOCTL_OFF;
- if(strcmp(argv[1],"led1")==0) isnumber=LED1; //判断是操作哪一个LED
- else isnumber=LED2;
- if(ison!=0&&isnumber!=0) ioctl(fd,ison,isnumber); //操作led
- return 0;
- }
通过输入的参数来控哪个led灯的亮或者灭
编译文件 Android.mk
- LOCAL_PATH :=$(call my-dir)
- include $(CLEAR_VARS)
- LOCAL_MODULE_TAGS :=eng
- LOCAL_SRC_FILES :=led_under_driver_test.c
- LOCAL_MODULE :=led_unders
- LOCAL_MODULE_PATH :=$(LOCAL_PATH)
- include $(BUILD_EXECUTABLE)
对于android编译系统 可以查看官网 http://www.kandroid.org/online-pdk/guide/build_system.html
但是对于LOCAL_MODULE_TAGS :=eng 这一项还不是很理解 LOCAL_MODULE_TAGS的设置与Build Variants有关,但是LOCAL_MODULE_TAGS :=eng为默认设置,即不设置默认就是LOCAL_MODULE_TAGS :=eng,但是在实际编译过程中,如果不加LOCAL_MODULE_TAGS :=eng的话,编译会出错,具体原因还不清楚,有清楚的朋友,麻烦告诉我一下哈。