TQ210搭载Android4.0.3系统构建之LED从驱动到HAL到JNI到应用程序(驱动篇)

开发板: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.
");
	else {ret=-1; printk("led_open failed.
");}
	return ret;
}


static int gpio_led_under_close(struct inode *inode,struct file *file)
{
	printk(KERN_INFO "led_close success.
");
	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.
");
	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.
");
	else { printk(KERN_INFO "led_init driver failed.
"); 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.
");
	else printk(KERN_INFO "led_exit driver failed.
");
}


//模块入口与出口
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.
",DEVICE_NAME);
			return 0;
		}
	if(argc!=3)   //判断参数是否合法
		{
			printf("usage:
");
			printf("led1/led2 on/off
");
		}
	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


 

原文地址:https://www.cnblogs.com/liangxinzhi/p/4275633.html