搜索
bottom↓
回复: 10

转贴一个使用cdev开发的linux led 驱动程序

[复制链接]

出0入0汤圆

发表于 2015-6-6 20:35:51 | 显示全部楼层 |阅读模式
本帖最后由 embeddev_1 于 2015-6-6 20:39 编辑

这篇文章写得非常好,特地转来,希望有识之士在此基础上再完成移植到android 系统下的led驱动,网络上找的一些android led驱动多少都有些问题

2.6内核以后的大量驱动代码, 有许多字符驱动不使用之前代码的方法. 那是还没有更新到 2.6 内核接口的老代码. 因为那个代码实际上能用,这个更新可能很长时间不会发生. 为完整, 我们描述老的字符设备注册接口, 但是新代码不应当使用它; 这个机制在将来内核中可能会消失

/*
* 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[arg], ~(IOCTL_LED_ON));  
            break;  
        }  
        case IOCTL_LED_OFF:  
        {  
            s3c2410_gpio_setpin(led_table[arg], ~(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");

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出0入0汤圆

 楼主| 发表于 2015-6-6 20:37:32 | 显示全部楼层
在贴之前的老式linux  led驱动代码
/*
* 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[arg],~(IOCTL_LED_ON));  
break;  
}  
caseIOCTL_LED_OFF:  
{  
s3c2410_gpio_setpin(led_table[arg],~(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[i],led_cfg_table[i]);  
//由原理图可知LED电路是共阳极的(即各IO口输出低电平0才会点亮)  
//这里初始化为1,不让LED点亮  
s3c2410_gpio_setpin(led_table[i],~(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");  

出0入0汤圆

 楼主| 发表于 2015-6-6 20:38:02 | 显示全部楼层
应用程序

/*
==============================================
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[2],"%d", &index) != 1 || index < 1 || index > 4)  
    {  
        printf("Usage: led_test on|off1|2|3|4\n");  
        exit(1);  
    }  
   
    if(strcmp(argv[1], "on") == 0)  
    {  
        turn = 1;  
    }  
    else if(strcmp(argv[1], "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;  
}  

出0入0汤圆

 楼主| 发表于 2015-6-6 20:40:44 | 显示全部楼层
编译到内核并运行的步骤  

把LED驱动代码部署到内核中去
#cp -f tq2440_leds.c/linux-2.6.30.4/drivers/char    //把驱动源码复制到内核驱动的字符设备下

#vim /linux-2.6.30.4/drivers/char/Kconfig    //添加LED设备配置
[cpp] 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被点亮

出0入0汤圆

 楼主| 发表于 2015-6-6 20:45:00 | 显示全部楼层
再转个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驱动了

出0入0汤圆

 楼主| 发表于 2015-6-6 20:46:00 | 显示全部楼层
二,硬件抽象层

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

出0入0汤圆

 楼主| 发表于 2015-6-6 20:46:35 | 显示全部楼层
三,框架层(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

出0入0汤圆

 楼主| 发表于 2015-6-6 20:47:09 | 显示全部楼层
四,应用层(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文件。

出0入0汤圆

 楼主| 发表于 2015-6-6 20:50:46 | 显示全部楼层
和android下的驱动编写作对比.linux下就是个喳呀!

出0入0汤圆

发表于 2015-6-6 20:53:02 | 显示全部楼层
不明觉厉。

出0入0汤圆

发表于 2015-6-6 21:26:01 | 显示全部楼层
碉堡了            
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-3-29 01:45

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表