转贴一个使用cdev开发的linux led 驱动程序
本帖最后由 embeddev_1 于 2015-6-6 20:39 编辑这篇文章写得非常好,特地转来,希望有识之士在此基础上再完成移植到android 系统下的led驱动,网络上找的一些android led驱动多少都有些问题{:biggrin:}
2.6内核以后的大量驱动代码, 有许多字符驱动不使用之前代码的方法. 那是还没有更新到 2.6 内核接口的老代码. 因为那个代码实际上能用,这个更新可能很长时间不会发生. 为完整, 我们描述老的字符设备注册接口, 但是新代码不应当使用它; 这个机制在将来内核中可能会消失{:biggrin:}
/*
* tq2440_leds.c
*
*Created on: 2011-11-29
* Author: liufei_learning
*
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <mach/hardware.h>
#include <mach/regs-gpio.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/types.h>
#include <linux/kdev_t.h>
#define DEVICE_NAME "tq2440_leds" //设备名称
#define LED_MAJOR 231 //主设备号
#define IOCTL_LED_ON 1 //LED亮状态
#define IOCTL_LED_OFF 0 //LED灭状态
static led_major = LED_MAJOR;
struct cdev led_cdev;
//控制LED的IO口
static unsigned long led_table[] =
{
S3C2410_GPB5,
S3C2410_GPB6,
S3C2410_GPB7,
S3C2410_GPB8,
};
//LED IO口的模式
static unsigned int led_cfg_table[] =
{
S3C2410_GPB5_OUTP,
S3C2410_GPB6_OUTP,
S3C2410_GPB7_OUTP,
S3C2410_GPB8_OUTP,
};
static struct class *leds_class;
static int __init leds_open(struct inode *inode, struct file *file)
{
return 0;
}
static int __init leds_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
//检测是第几个LED,因开发板上只有4个,索引从0开始
if(arg < 0 || arg > 3)
{
return -EINVAL;
}
//判断LED要执行哪种状态
switch(cmd)
{
case IOCTL_LED_ON:
{
s3c2410_gpio_setpin(led_table, ~(IOCTL_LED_ON));
break;
}
case IOCTL_LED_OFF:
{
s3c2410_gpio_setpin(led_table, ~(IOCTL_LED_OFF));
break;
}
default:
{
return -EINVAL;
}
}
return 0;
}
static struct file_operations led_fops =
{
.owner = THIS_MODULE,
.open = leds_open,
.ioctl = leds_ioctl,
};
static int __init leds_init(void)
{
int ret;
int i;
for(i = 0; i < 4; i++)
{
//初始化各IO口为输出模式
s3c2410_gpio_cfgpin(led_table, led_cfg_table);
//由原理图可知LED电路是共阳极的(即各IO口输出低电平0才会点亮)
//这里初始化为1,不让LED点亮
s3c2410_gpio_setpin(led_table, ~(IOCTL_LED_OFF));
}
<span style="color:#ff0000;">dev_t devno = MKDEV(led_major, 0);
/* 静态申请设备号*/
if (led_major)
ret = register_chrdev_region(devno, 2, DEVICE_NAME);
else /* 动态分配设备号 */
{
ret = alloc_chrdev_region(&devno, 0, 2, DEVICE_NAME);
led_major = MAJOR(devno);
}
if (ret < 0)
return ret;
/*初始化cdev结构*/
cdev_init(&led_cdev, &led_fops);
led_cdev.owner = THIS_MODULE;
led_cdev.ops = &led_fops;
/* 注册字符设备 */
cdev_add(&led_cdev, MKDEV(led_major, 0), 1);</span>
//注册一个类,使mdev可以在/dev/下面建立设备节点
leds_class = class_create(THIS_MODULE, DEVICE_NAME);
if( IS_ERR(leds_class) )
{
printk("creat leds_class failed!");
return -1;
}
//创建一个设备节点,节点名字为DEVICE_NAME
device_create(leds_class, NULL, MKDEV(led_major, 0), NULL, DEVICE_NAME);
printk(DEVICE_NAME "initialized!");
return 0;
}
static void __init leds_exit(void)
{
cdev_del(&led_cdev); /*注销设备*/
unregister_chrdev_region(MKDEV(led_major, 0), 2); /*释放设备号*/
//删除设备节点
device_destroy(leds_class, MKDEV(led_major, 0));
//注销类
class_destroy(leds_class);
}
module_init( leds_init);
module_exit( leds_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("liufei_learning");
MODULE_DESCRIPTION("tq2440 leds driver"); 在贴之前的老式linuxled驱动代码
/*
* tq2440_leds.c
*
* Created on: 2011-11-29
* Author: liufei_learning
*
*/
#include<linux/module.h>
#include<linux/init.h>
#include<linux/fs.h>
#include<mach/hardware.h>
#include<mach/regs-gpio.h>
#include<linux/device.h>
#defineDEVICE_NAME "tq2440_leds" //设备名称
#defineLED_MAJOR 231 //主设备号
#defineIOCTL_LED_ON 1 //LED亮状态
#defineIOCTL_LED_OFF 0 //LED灭状态
//控制LED的IO口
static unsigned longled_table[] =
{
S3C2410_GPB5,
S3C2410_GPB6,
S3C2410_GPB7,
S3C2410_GPB8,
};
//LED IO口的模式
static unsigned intled_cfg_table[] =
{
S3C2410_GPB5_OUTP,
S3C2410_GPB6_OUTP,
S3C2410_GPB7_OUTP,
S3C2410_GPB8_OUTP,
};
static struct class*leds_class;
static int __initleds_open(struct inode *inode, struct file *file)
{
return0;
}
static int __initleds_ioctl(struct inode *inode, struct file *file,
unsignedint cmd, unsigned long arg)
{
//检测是第几个LED,因开发板上只有4个,索引从0开始
if(arg< 0 || arg > 3)
{
return-EINVAL;
}
//判断LED要执行哪种状态
switch(cmd)
{
caseIOCTL_LED_ON:
{
s3c2410_gpio_setpin(led_table,~(IOCTL_LED_ON));
break;
}
caseIOCTL_LED_OFF:
{
s3c2410_gpio_setpin(led_table,~(IOCTL_LED_OFF));
break;
}
default:
{
return-EINVAL;
}
}
return0;
}
static structfile_operations led_fops =
{
.owner= THIS_MODULE,
.open= leds_open,
.ioctl= leds_ioctl,
};
static int __initleds_init(void)
{
intret;
int i;
for(i= 0; i < 4; i++)
{
//初始化各IO口为输出模式
s3c2410_gpio_cfgpin(led_table,led_cfg_table);
//由原理图可知LED电路是共阳极的(即各IO口输出低电平0才会点亮)
//这里初始化为1,不让LED点亮
s3c2410_gpio_setpin(led_table,~(IOCTL_LED_OFF));
}
//注册LED设备为字符设备
ret =register_chrdev(LED_MAJOR, DEVICE_NAME, &led_fops);
if(ret< 0)
{
printk(DEVICE_NAME" major number register falid!\n");
returnret;
}
//注册一个类,使mdev可以在/dev/下面建立设备节点
leds_class= class_create(THIS_MODULE, DEVICE_NAME);
if(IS_ERR(leds_class) )
{
printk("creatleds_class failed!");
return-1;
}
//创建一个设备节点,节点名字为DEVICE_NAME
device_create(leds_class,NULL, MKDEV(LED_MAJOR, 0), NULL, DEVICE_NAME);
printk(DEVICE_NAME"initialized!");
return0;
}
static void __initleds_exit(void)
{
//注销设备
unregister_chrdev(LED_MAJOR,DEVICE_NAME);
//删除设备节点
device_destroy(leds_class,MKDEV(LED_MAJOR, 0));
//注销类
class_destroy(leds_class);
}
module_init( leds_init);
module_exit( leds_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("liufei_learning");
MODULE_DESCRIPTION("tq2440leds driver");
应用程序 {:biggrin:}
/*
==============================================
Name : led_test.c
Author : liufei_learning
Date : 11/27/2011
Description : tq2440 led driver test
==============================================
*/
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include<sys/ioctl.h>
int main(int argc, char**argv)
{
int turn, index, fd;
//检测输入的参数合法性
if(argc != 3 || sscanf(argv,"%d", &index) != 1 || index < 1 || index > 4)
{
printf("Usage: led_test on|off1|2|3|4\n");
exit(1);
}
if(strcmp(argv, "on") == 0)
{
turn = 1;
}
else if(strcmp(argv, "off") ==0)
{
turn = 0;
}
else
{
printf("Usage: led_test on|off1|2|3|4\n");
exit(1);
}
//打开LED设备
fd = open("/dev/tq2440_leds", 0);
if(fd < 0)
{
printf("Open Led DeviceFaild!\n");
exit(1);
}
//IO控制
ioctl(fd, turn, index - 1);
//关闭LED设备
close(fd);
return 0;
} 编译到内核并运行的步骤{:biggrin:}
把LED驱动代码部署到内核中去
#cp -f tq2440_leds.c/linux-2.6.30.4/drivers/char //把驱动源码复制到内核驱动的字符设备下
#vim /linux-2.6.30.4/drivers/char/Kconfig //添加LED设备配置
view plaincopyprint?
config TQ2440_LEDS
tristate "TQ2440 Leds Device"
depends on ARCH_S3C2440
default y
---help---
TQ2440User Leds
#vim /linux-2.6.30.4/drivers/char/Makefile //添加LED设备配置
obj-$(CONFIG_TQ2440_LEDS) +=tq2440_leds.o
5. 配置内核,选择LED设备选项
#make menuconfig
Device Drivers --->
Character devices --->
<*> TQ2440 Leds Device (NEW)
6.编译内核make zImage
7.编译测试程序#arm-linux-gcc -o led_test led_test.c 将生成的文件复制到开发板 /usr/sbin下
8.开发板上测试
查看已加载的设备:#cat/proc/devices,可以看到tq2440_leds的主设备号为231
控制led输入led_test on 1可以看到对应led被点亮 再转个android 下led的驱动,分4步,这个多少是有点问题
1: 内核硬件驱动层
2: HAL(硬件抽象层)
3: 框架层(framework,包含JNI和实现硬件服务的JAVA接口)
4: JAVA应用层
一,首先是第一层,内核硬件驱动层
在kernel\driver\下新建一个目录swt,在swt下再新建led文件夹,并新建swtled.c swtled.h,通过注册模块方式,实现ioctl,write,read接口。之后通过设备名给上层访问。
swtled.c部分
点击(此处)折叠或打开
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/uaccess.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
#include <linux/fs.h>
#include <asm/io.h>
#include <mach/gpio.h>
#include <asm/uaccess.h>
#define LED_ON _IO ('k',1)
#define LED_OFF _IO ('k',2)
struct light_dev
{
struct cdev cdev;
unsigned char value;
};
static struct light_dev *light_devp;
static struct class * light_class = NULL;
int light_major = 250;
#if 0
static ssize_t light_val_show(struct device* dev, struct device_attribute* attr, char* buf)
{
return 0;
}
static ssize_t light_val_store(struct device* dev, struct device_attribute* attr, const char* buf, size_t count)
{
return 0;
}
static DEVICE_ATTR(val, S_IRUGO | S_IWUSR, light_val_show, light_val_store);
#endif
void led_off(int arg)
{
switch(arg)
{
case 1: gpio_set_value(RK29_PIN6_PB3,GPIO_LOW); //GPIO8
break;
case 2: gpio_set_value(RK29_PIN6_PC2,GPIO_LOW); //GPIO10
break;
default:
break;
}
}
void led_on(int arg)
{
switch(arg)
{
case 1: gpio_set_value(RK29_PIN6_PB3,GPIO_HIGH);
break;
case 2: gpio_set_value(RK29_PIN6_PC2,GPIO_HIGH);
break;
default:
break;
}
}
int light_open(struct inode *inode, struct file *filp)
{
struct light_dev *dev;
int ret = 0;
printk(KERN_ALERT"light_open()");
dev = container_of(inode->i_cdev, struct light_dev, cdev);
filp->private_data = dev;
ret = gpio_request(RK29_PIN6_PB3, NULL);
if(ret != 0)
{
gpio_free(RK29_PIN6_PB3);
}
gpio_direction_output(RK29_PIN6_PB3, 0);
ret = gpio_request(RK29_PIN6_PC2, NULL);
if(ret != 0)
{
gpio_free(RK29_PIN6_PC2);
}
gpio_direction_output(RK29_PIN6_PC2, 0);
return 0;
}
int light_release(struct inode *inode, struct file *filp)
{
printk(KERN_ALERT"light_release()");
return 0;
}
ssize_t light_read(struct file *filp, char __user *buf, size_t count, loff_t*f_pos)
{
struct light_dev *dev = filp->private_data;
printk(KERN_ALERT"light_read()");
if (copy_to_user(buf, &(dev->value), 1))
{
return -EFAULT;
}
return 1;
}
ssize_t light_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
struct light_dev *dev = filp->private_data;
printk(KERN_ALERT"light_write()");
if (copy_from_user(&(dev->value), buf, 1))
{
return -EFAULT;
}
if (dev->value == 1)
printk(KERN_ALERT"LED on");
else
printk(KERN_ALERT"LED off");
return 1;
}
int light_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
{
struct light_dev *dev = filp->private_data;
printk(KERN_ALERT"light_ioctl(cmd = %d)", cmd);
switch (cmd)
{
case LED_ON:
led_on(arg);
break;
case LED_OFF:
led_off(arg);
break;
default: break;
}
return 0;
}
struct file_operations light_fops =
{
.owner = THIS_MODULE,
.read = light_read,
.write = light_write,
.ioctl = light_ioctl,
.open = light_open,
.release = light_release,
};
static int light_setup_cdev(struct light_dev *dev, int index)
{
int err, devno = MKDEV(light_major, index);
cdev_init(&dev->cdev, &light_fops);
dev->cdev.owner = THIS_MODULE;
dev->cdev.ops = &light_fops;
dev->value = 0;
err = cdev_add(&dev->cdev, devno, 1);
return err;
}
int light_init(void)
{
int result = 0;
struct device * temp = NULL;
dev_t dev = MKDEV(light_major, 0);
printk(KERN_ALERT"light_init()");
if (light_major) {
result = register_chrdev_region(dev, 1, "LED");
}
else {
result = alloc_chrdev_region(&dev, 0, 1, "LED");
light_major = MAJOR(dev);
}
if (result < 0) {
goto failed;
}
light_devp = kmalloc(sizeof(struct light_dev), GFP_KERNEL);
if (!light_devp){
result = -ENOMEM;
goto unregister;
}
memset(light_devp, 0, sizeof(struct light_dev));
result = light_setup_cdev(light_devp, 0);
if(result) {
goto cleanup;
}
light_class = class_create(THIS_MODULE, "led");
if(IS_ERR(light_class)) {
printk(KERN_ALERT"Failed to create light class./n");
goto destroy_cdev;
}
temp = device_create(light_class, NULL, dev, "%s", "swtled");
if(IS_ERR(temp)) {
printk(KERN_ALERT"Failed to create hello device.");
goto destroy_class;
}
#if 0
result = device_create_file(temp, &dev_attr_val);
if(result < 0) {
printk(KERN_ALERT"Failed to create attribute val.");
goto destroy_device;
}
dev_set_drvdata(temp, light_devp);
#endif
return 0;
destroy_device:
device_destroy(light_class, dev);
destroy_class:
class_destroy(light_class);
destroy_cdev:
cdev_del(&(light_devp->cdev));
cleanup:
kfree(light_devp);
unregister:
unregister_chrdev_region(dev, 1);
failed:
printk(KERN_ALERT"light_init failed.");
return result;
}
void light_cleanup(void)
{
printk(KERN_ALERT"light_cleanup()");
if(light_class) {
device_destroy(light_class, MKDEV(light_major, 0));
class_destroy(light_class);
}
if(light_devp) {
cdev_del(&light_devp->cdev);
kfree(light_devp);
}
unregister_chrdev_region(MKDEV(light_major, 0), 1);
}
module_init(light_init);
module_exit(light_cleanup);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("led driver");
MODULE_ALIAS("led module");
led文件夹中Kconfig文件
点击(此处)折叠或打开
config SWT_XXX_LED
bool "swt led"
default n
help
This compiles in support for the led of xxx.
led文件夹中MakeFile文件
点击(此处)折叠或打开
obj-$(CONFIG_SWT_XXX_LED)+=swt_led.o
swtled文件中Kconfig文件
点击(此处)折叠或打开
menu "swtled Drivers"
source "drivers/swt/led/Kconfig"
endmenu
swtled文件夹中MakeFile文件
点击(此处)折叠或打开
obj-y += led/
接下来,就要修改kernel/driver下的MakeFile和Kconfig文件了,在分别其中添加一句
MakeFile文件
点击(此处)折叠或打开
obj-y += swt/
Kconfig文件
点击(此处)折叠或打开
source "drivers/swt/Kconfig"
保存所有之后,执行make
编译成功后,就可以在swt/led目录下看到swtled.o文件了,这时候编译出来的img已经包含了swtled驱动了 二,硬件抽象层
1,在hardware\libhardware\include\hardware下新建swtled.h文件
swtled.h
点击(此处)折叠或打开
#ifndef ANDROID_SWTLED_INTERFACE_H
#define ANDROID_SWTLED_INTERFACE_H
#include <hardware/hardware.h>
__BEGIN_DECLS
//module interface
struct swtled_module_t
{
struct hw_module_t common;
};
//device interface
struct swtled_device_t
{
struct hw_device_t common;
int fd;
int (*set_on)(struct swtled_device_t* dev,int number);
int (*set_off)(struct swtled_device_t* dev,int number);
};
#define SWTLED_HARDWARE_MODULE_ID "swtled"
__END_DECLS
#endif
2:在hardware/libhardware/module下新建swtled文件夹并新建swtled.c
点击(此处)折叠或打开
#define LOG_TAG "swtledStub"
#include <hardware/hardware.h>
#include <hardware/swtled.h>
#include <fcntl.h>
#include <errno.h>
#include <cutils/log.h>
#include <cutils/atomic.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#define LED_ON _IO('k',1)
#define LED_OFF _IO('k',2)
#define DEVICE_NAME "/dev/swt_led"
#define MODULE_NAME "swtled"
#define MODULE_AUTHOR "zc"
//open or close device interface
static int swtled_device_open(const struct hw_module_t* module,const char* name, struct hw_device_t** device);
static int swtled_device_close(struct hw_device_t* device);
//light-on light-off
static int swtled_set_on(struct swtled_device_t* dev,int number);
static int swtled_set_off(struct swtled_device_t* dev,int number);
static int swtled_device_open(const struct hw_module_t* module,const char* name, struct hw_device_t** device)
{
struct swtled_device_t * dev;
dev = (struct swtled_device_t*)malloc(sizeof(struct swtled_device_t));
if (!dev)
{
LOGE("Swtled Stub:failed to alloc space");
return -EFAULT;
}
memset(dev,0,sizeof(struct swtled_device_t));
dev->common.tag = HARDWARE_DEVICE_TAG;
dev->common.version = 0;
dev->common.module = (hw_module_t*)module;
dev->common.close = swtled_device_close;
dev->set_on = swtled_set_on;
dev->set_off = swtled_set_off;
if ((dev->fd = open(DEVICE_NAME,O_RDWR)) == -1)
{
LOGE("Swtled Stub:failed to open /dev/swt_led -- %s.",strerror(errno));
free(dev);
return -EFAULT;
}
*device = &(dev->common);
LOGI("Swtled Stub: open /dev/swt_led successfully");
return 0;
}
static int swtled_device_close(struct hw_device_t* device)
{
struct swtled_device_t* swtled_device = (struct swtled_device_t*)device;
if (swtled_device)
{
close(swtled_device->fd);
free(swtled_device);
}
return 0;
}
//------------------------------------------------------------------------------
//number: 1: light one 2:light two
//------------------------------------------------------------------------------
static int swtled_set_on(struct swtled_device_t* device,int number)
{
ioctl(device->fd,LED_ON,number);
return 0;
}
//------------------------------------------------------------------------------
//number: 1: light one 2:light two
//------------------------------------------------------------------------------
static int swtled_set_off(struct swtled_device_t* device,int number)
{
ioctl(device->fd,LED_OFF,number);
return 0;
}
//module method table
static struct hw_module_methods_t swtled_module_methods =
{
open: swtled_device_open
};
const struct swtled_module_t HAL_MODULE_INFO_SYM = {
common:
{
tag: HARDWARE_MODULE_TAG,
version_major: 1,
version_minor: 0,
id: SWTLED_HARDWARE_MODULE_ID,
name:MODULE_NAME,
author: MODULE_AUTHOR,
methods: &swtled_module_methods,
}
};
这里主要是通过hw_module_t和hw_device_t结构体形式将内核中led的驱动封装一层,
导出set_on和set_off接口,到时供JNI层的CPP调用。由于权限问题,应用层在打开dev时可能提示permission deny,所以需要修改
system\core\rootdir下的ueventd.rc文件,在其中添加一句
点击(此处)折叠或打开
/dev/swt_led 0666 root root
3,在同目录下添加Android.mk
点击(此处)折叠或打开
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_SRC_FILES := swtled.c
LOCAL_MODULE := swtled.default
include $(BUILD_SHARED_LIBRARY)
4,编译
(1 进入到gingerbread目录下,执行mmm hardware/libhardware/modules/swtled会
编译成功后,就可以在out/target/product/generic/system/lib/hw目录下看到swtled.default.so文件了
(2 再执行make snod,使system.img镜像文件中包名硬件抽象模块swtled.default.so 三,框架层(framework)
这里主要实现两部分
(1: 为Android HAL编写JNI方法,以便使得上层的APP能够使用下层提供的硬件服务
(2: 在Android系统的框架层提供Java接口的硬件服务
1,在frameworks/base/services/jni中新建com_android_server_swtled.cpp
点击(此处)折叠或打开
#define LOG_TAG "SwtledService"
#include "jni.h"
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"
#include <utils/misc.h>
#include <utils/Log.h>
#include <hardware/hardware.h>
#include <hardware/swtled.h>
#include <stdio.h>
namespace android
{
struct swtled_device_t* swtled_device = NULL;
static void swtled_set_on(JNIEnv* env, jobject clazz,jint number)
{
int num = number;
LOGI("Swtled JNI: select lighton is %d",num);
if (!swtled_device)
{
LOGI("Swtled JNI:device is not open.");
return;
}
swtled_device->set_on(swtled_device,num);
}
static void swtled_set_off(JNIEnv* env, jobject clazz,jint number)
{
int num = number;
LOGI("Swtled JNI: select lightoff is %d",num);
if (!swtled_device)
{
LOGI("Swtled JNI:device is not open.");
return;
}
swtled_device->set_off(swtled_device,num);
}
static inline int swtled_device_open(hw_module_t* module,swtled_device_t** device)
{
return module->methods->open(module,SWTLED_HARDWARE_MODULE_ID,(hw_device_t**)device);
}
static jboolean swtled_init(JNIEnv* env,jclass clazz)
{
swtled_module_t* swtledmodule;
LOGI("Swtled JNI: initializing...");
if (hw_get_module(SWTLED_HARDWARE_MODULE_ID,(const struct hw_module_t**)&swtledmodule)==0)
{
LOGI("Swtled JNI: swtled stub be found.");
if (swtled_device_open(&(swtledmodule->common),&swtled_device) == 0)
{
LOGI("Swtled JNI: swtled device open successful.");
return 0;
}
LOGI("Swtled JNI: failed to open swtled device.");
return -1;
}
LOGI("Swtled JNI: failed to get swtled stub module.");
return -1;
}
static const JNINativeMethod method_table[] =
{
{"init_native", "()Z", (void*)swtled_init},
{"setOn_native","(I)V",(void*)swtled_set_on},
{"setOff_native","(I)V",(void*)swtled_set_off},
};
int register_android_server_SwtledService(JNIEnv* env)
{
return jniRegisterNativeMethods(env,"com/android/server/SwtledService",method_table,NELEM(method_table));
}
}
修改同级目录下的Android.mk和Onload.cpp文件
在Android.mk的LOCAL_SRC_FILES:=下添加
点击(此处)折叠或打开
LOCAL_SRC_FILES:= \
....
com_android_server_swtled.cpp \
在Onload.cpp中的namespace android {下加入
点击(此处)折叠或打开
int register_android_server_SwtledService(JNIEnv* env);
同时在JNI_OnLoad函数下加入
点击(此处)折叠或打开
register_android_server_SwtledService(env);
2,编译
(1,执行mmm framework/base/services/jni
(2,make snod
3,在frameworks/base/core/java/android/os 新建ISwtledService.aidl,代码如下
点击(此处)折叠或打开
package android.os;
interface ISwtledService {
void setOn(int number);
void setOff(int number);
}
返回到frameworks/base目录,打开Android.mk文件,修改LOCAL_SRC_FILES变量的值,增加 ISwtledService.aidl源文件
点击(此处)折叠或打开
LOCAL_SRC_FILES += /
....................................................................
core/java/android/os/IVibratorService.aidl /
core/java/android/os/ISwtledService.aidl /
core/java/android/service/urlrenderer/IUrlRendererService.aidl /
4,编译ISwtledService接口
mmm framework/base,如果正确,那么会根据ISwtledService.aidl生成对应的ISwtledService.Stub接口
5,进入到frameworks/base/services/java/com/android/server目录,新增ISwtledService.java文件:
点击(此处)折叠或打开
package com.android.server;
import android.content.Context;
import android.os.ISwtledService;
import android.util.Slog;
public class SwtledService extends ISwtledService.Stub {
private static final String TAG = "SwtledService";
SwtledService()
{
init_native();
}
public void setOn(int number)
{
setOn_native(number);
}
public void setOff(int number)
{
setOff_native(number);
}
private static native boolean init_native();
private static native void setOn_native(int number);
private static native void setOff_native(int number);
};
6,修改同目录下的SystemServer.java文件,在ServerThread::run方法里加入
点击(此处)折叠或打开
try{
Slog.i(TAG, "Swtled Service");
ServiceManager.addService("swtled", new SwtledService());
} catch (Throwable e) {
Slog.e(TAG, "Failure starting Swtled Service", e);
}
7,编译SwtledService.java并打包进system.img
(1)mmm framework/base/services/java
(2)make snod 四,应用层(APP)
1,为了方便,使用Eclipse编写一个简单的控制灯的应用,添加四个button,分配控制灯1亮,灯1灭,灯2亮,灯2灭,Activity代码如下
点击(此处)折叠或打开
package com.android.swtled;
import android.app.Activity;
import android.os.Bundle;
import android.os.ISwtledService;
import android.os.ServiceManager;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.os.RemoteException;
public class swtled extends Activity {
private static final String LOG_TAG = "com.android.swtled";
private ISwtledService swtledService = null;
private Button setOnLight1Button = null;
private Button setOffLight1Button = null;
private Button setOnLight2Button = null;
private Button setOffLight2Button = null;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
swtledService = ISwtledService.Stub.asInterface(ServiceManager.getService("swtled"));
setOnLight1Button = (Button)findViewById(R.id.button_seton_light1);
setOffLight1Button = (Button)findViewById(R.id.button_setoff_light1);
setOnLight2Button = (Button)findViewById(R.id.button_seton_light2);
setOffLight2Button = (Button)findViewById(R.id.button_setoff_light2);
setOnLight1Button.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
try{
swtledService.setOn(1);
}catch(RemoteException e)
{
Log.e(LOG_TAG, "Exception while setOn Light.");
}
}
});
setOffLight1Button.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
try{
swtledService.setOff(1);
}catch(RemoteException e)
{
Log.e(LOG_TAG, "Exception while setOn Light.");
}
}
});
setOnLight2Button.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
try{
swtledService.setOn(2);
}catch(RemoteException e)
{
Log.e(LOG_TAG, "Exception while setOn Light.");
}
}
});
setOffLight2Button.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
try{
swtledService.setOff(2);
}catch(RemoteException e)
{
Log.e(LOG_TAG, "Exception while setOn Light.");
}
}
});
}
}
2, AndroidManifest.xml脚本
点击(此处)折叠或打开
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.swtled"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".swtled"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
3,字符串文件res/values/strings.xml
点击(此处)折叠或打开
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="hello">Hello World, swtled!</STRING>
<string name="app_name">swtled</string>
<string name="seton_light1"></string>
<string name="setoff_light1"></string>
<string name="seton_light2"></string>
<string name="setoff_light2"></string>
</resources>
4,布局文件脚本main.xml
点击(此处)折叠或打开
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center">
<Button
android:id="@+id/button_seton_light1"
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:text = "@string/seton_light1"
/>
<Button
android:id = "@+id/button_setoff_light1"
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:text = "@string/setoff_light1"
/>
<Button
android:id="@+id/button_seton_light2"
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:text = "@string/seton_light2"
/>
<Button
android:id = "@+id/button_setoff_light2"
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:text = "@string/setoff_light2"
/>
</LinearLayout>
</LinearLayout>
5,由于是编译器是Eclipse,但实际编译却是要在android源代码环境下编译,于是,将工程目录的三个文件
src,res以及AndroidManifest.xml复制到gingerbread源码目录的package/experimental/swtled下,其中
swtled文件是需要自己新建的,复制完成之后,进入编译阶段
6,编译app并生成apk文件
(1) mmm package/experimental/swtled
编译成功后,便可以在out/target/product/generic/system/app目录下看到swtled.apk文件
(2) 重新打包系统镜像文件system.img
make snod
7,开机测试
8,注意事项:
在工程中需要import两个包是
import android.os.ISwtledService;
import android.os.ServiceManager;
程序通过ServiceManager.getService("swtled")来获得SwtledService,
接着通过ISwtledService.Stub.asInterface函数转换为ISwtledService接口。
其中,服务名字“swtled”是系统启动时加载SwtledService时指定的,
而ISwtledService接口定义在android.os.ISwtledService中
需要注意的是,虽然用Eclipse编译这个应用,但是无法用Eclipse编译,最后还是需要将工程中res,src以及AndroidManifest.xml三个文件copy到gingerbread/package/experimental/swtled,swtled是自己再新建的文件夹, 然后使用 mmm package/experimental/swtled编译,如果正确,最后会生成.apk文件。 和android下的驱动编写作对比.linux下就是个喳呀!{:lol:} 不明觉厉。 碉堡了
页:
[1]