[RK3399][Android7.1]编写一个安卓的GPIO驱动

1、在kernel/drivers目录下新建ioctrl文件夹

# cd kernel/drivers

# mkdir ioctrl

在/driver/ioctrl目录下,新建ioctrl.c ,ioctrl.h , Kconfig, Makefile 等4个文件。

2、在Kconfig下添加代码:

config IOCTRL
        tristate "io Control"
        default y
        help
          when system setup,change the io state

在Makefile下添加代码:

obj-$(CONFIG_IOCTRL)                    += ioctrl.o

在ioctrl.c中添加代码:

/*
 * Driver for pwm demo on Firefly board ioctrl.
 *
 * Copyright (C) 2022, Zhongshan T-chip Intelligent Technology Co.,ltd.
 * Copyright 2006  Sam Chan
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */
/**********************************************************************
 * version control
 *
 * version: v1.0.0_20191022
 * creater: dulc
 * creat date: 2019.10.22
 * changer: 
 * chang date:
 */
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 


#define IOCTRL_MAJOR	97


struct firefly_ioctrl_info {
    int gpio_wireless_en;        // 3g/4g power control
    int gpio_we_value;
};



static int firefly_ioctrl_probe(struct platform_device *pdev);

// ioctrl operation 
ssize_t ioctrl_read( struct file * file, char * buf, size_t count, loff_t * f_ops );
ssize_t ioctrl_write( struct file * file, const char * buf, size_t count, loff_t *f_ops );
long ioctrl_ioctl( struct file *file, unsigned int cmd, unsigned long arg);
int ioctrl_open( struct inode * inode, struct file *file );
int ioctrl_release(struct inode *inode, struct file *file );
int ioctrl_led_control( char cmd, char subcmd );



/*********************************GPIO*************************************/
static struct of_device_id firefly_ioctrl_match_table[] = {
	{ .compatible = "firefly,rk3399-gpio1",},
	{},
};

static struct platform_driver firefly_ioctrl_driver = {
	.driver = {
		.name = "firefly-ioctrl",
		.owner = THIS_MODULE,
		.of_match_table = firefly_ioctrl_match_table,
	},
	.probe = firefly_ioctrl_probe,
};
/*********************************GPIO*************************************/





// the ioctrl operations device
static const struct file_operations io_ctrl_ops = {
	.owner		= THIS_MODULE,
	.open		= ioctrl_open,
	.read		= ioctrl_read,
	.write		= ioctrl_write,
	.unlocked_ioctl	= ioctrl_ioctl,
	.release	= ioctrl_release,
};



// gpio device
struct firefly_ioctrl_info *ioctrl_device_ctrl = NULL;




ssize_t ioctrl_read( struct file * file, char * buf, size_t count, loff_t * f_ops )
{
	ssize_t size = 0;

	return size;
}


ssize_t ioctrl_write(struct file * file, const char * buf, size_t count, loff_t *f_ops )
{
	ssize_t size = 0;

	return size;
}



long ioctrl_ioctl( struct file *file, unsigned int cmd, unsigned long arg)
{
	long ret = 0;
	
	if ( cmd == 0 )
        {
            gpio_direction_output(ioctrl_device_ctrl->gpio_wireless_en, false);
        }
	else
	{
            gpio_direction_output(ioctrl_device_ctrl->gpio_wireless_en, true);
	}

	return ret;
}



int ioctrl_open( struct inode * inode, struct file *file )
{
	return 0;
}



int ioctrl_release(struct inode *inode, struct file *file )
{
	return 0;
}



static int firefly_ioctrl_probe(struct platform_device *pdev)
{
    int gpio;
    enum of_gpio_flags flag;
    struct firefly_ioctrl_info *gpio_info;
    struct device_node *firefly_ioctrl_node = pdev->dev.of_node;

	gpio_info = devm_kzalloc(&pdev->dev,sizeof(struct firefly_ioctrl_info *), GFP_KERNEL);
	if (!gpio_info) {
        dev_err(&pdev->dev, "devm_kzalloc failed!\n");
		return -ENOMEM;
	}
	
    // 3g/4g power control
     gpio = of_get_named_gpio_flags(firefly_ioctrl_node, "firefly-gpio-wireless", 0, &flag);
    if (!gpio_is_valid(gpio)) {
        dev_err(&pdev->dev, "firefly-gpio-wireless: %d is invalid\n", gpio);
        return -ENODEV;
    }
    if (gpio_request(gpio, "firefly-gpio-wireless")) {
        dev_err(&pdev->dev, "firefly-gpio-wireless: %d request failed!\n", gpio);
        gpio_free(gpio);
        return -ENODEV;
    }
    
    printk("ioctrl driver register success!\n");

    gpio_info->gpio_wireless_en = gpio;
   // gpio_info->gpio_pe_value = (flag == OF_GPIO_ACTIVE_LOW) ? 0:1;
    gpio_direction_output(gpio_info->gpio_wireless_en, false);

    ioctrl_device_ctrl = gpio_info;


    return 0;
}




// init the ioctrl driver
static int ioctrl_init(void)
{
	int ret = -ENODEV;
	int ret_val = 0xFFFFFFFF;
	struct class *ioctrl_dev_class;


	// register GPIO driver
	platform_driver_register(&firefly_ioctrl_driver);
	
	// register driver
	ret = register_chrdev( IOCTRL_MAJOR, "ioctrldrive", &io_ctrl_ops );
	if ( ret < 0 )
	{
		printk("register ioctrl driver error! \n");
		return ret;
	}
	// creat class
	ioctrl_dev_class = class_create( THIS_MODULE, "ioctrldrive" );
	if ( IS_ERR(ioctrl_dev_class) )
	{
		unregister_chrdev( IOCTRL_MAJOR, "capi20");
		return PTR_ERR(ioctrl_dev_class);
	}
	// creat node
	device_create( ioctrl_dev_class, NULL, MKDEV(IOCTRL_MAJOR,0),NULL, "ioctrl");

	
	return ret_val;
}
module_init(ioctrl_init);


static void ioctrl_exit(void)
{
	platform_driver_unregister(&firefly_ioctrl_driver);

}
module_exit(ioctrl_exit);


MODULE_AUTHOR("dulc ");
MODULE_DESCRIPTION("Firefly ioctrl demo driver");
MODULE_ALIAS("platform:firefly-ioctrl");
MODULE_LICENSE("GPL");

在kernel/drivers目录下的Makefile文件下,添加以下代码:

obj-$(CONFIG_IOCTRL)            += ioctrl/

在kernel/drivers目录下的Kconfig文件下,添加以下代码:

source "drivers/ioctrl/Kconfig"

这时代码默认就编译到了kernel中,在kernel文件夹下,执行指令

# make menuconfig

选择Device Drivers,可看到编译进去的驱动

[RK3399][Android7.1]编写一个安卓的GPIO驱动_第1张图片

(默认为选中状态(*),是由于ioctrl文件夹下的Kconfig配置为 tristate  "io Control"   default y,  io Control是名称,default y是默认开启,默认关闭用default n)

 

3、编写C语言测试程序。

在 your_android_src/external目录下,新建文件夹

# mkdir ioctrltest

在该文件夹下添加两个文件:Android.mk 、ioctrltest.c

在Android.mk文件中添加代码:

LOCAL_PATH:=$(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= ioctrltest.c
LOCAL_MODULE:=ioctrlapp
include $(BUILD_EXECUTABLE)

其中 LOCAL_SRC_FILES为测试程序的源文件,LOCAL_MODULE为生成的可执行文件。

在ioctrltest.c中添加代码:

#include 
#include 
#include 
#include 
#include 
#define DEVICE_NAME "/dev/ioctrl"


int main( int argc, char ** argv )
{
	int fd;
	char cmd, subcmd;
	int i;

	printf("\n -----turn on the 3g power ----- \n");
	fd = open(DEVICE_NAME, O_RDWR );
	printf("fd = %d \n", fd );

	if ( fd == -1 )
	{
		printf("open device %s error \n", DEVICE_NAME );
	}
	else
	{
		// turn on the 3g power
		ioctl(fd, 1, 0);
	}
}

在安卓目录下,执行

# make ioctrlapp

会在  out/target/product/rk3399_firefly_box/system/bin/ioctrlapp  生成相应的ioctrlapp (目录可能不同,根据自己实际情况操作)

把ioctrlapp拷贝到优盘中,启动rk3399,将优盘插入3399,然后在调试模式下,执行如下操作,可运行该程序

$su
#cp mnt/medea_rw/(upan_name)/ioctrlapp /mnt/ioctrlapp
#cd mnt
./ioctrlapp

注:在dev下生成的ioctrl驱动,要获取权限才可打开,临时获取权限,使用以下指令:

# chmod 777 /dev/ioctrl

永久获取权限,参照以下链接执行即可:

https://blog.csdn.net/d4l6c8/article/details/101345756

 

4、开启启动该程序ioctrlapp。

在device/rockchip/rk3399/device.mk中添加以下语句:

PRODUCT_COPY_FILES += \
        out/target/product/rk3399_firefly_aiojd4_mipi_box/system/bin/ioctrlapp:system/bin/ioctrlapp

在/device/rockchip/rk3399/rk3399_firefly_aiojd4_mipi_box目录下的init.rc 下添加以下语句:

#dlc add
service service_ioctrl /system/bin/ioctrlapp
    user root
    group root
    disabled
    oneshot

on property:sys.boot_completed=1

注意 service_ioctrl这个服务名称不能超过16个字节,否则认为该服务有问题,不会启动该服务。

在/device/rockchip/common/sepolicy目录下新增文件service_ioctrl.te,添加如下代码:

type service_ioctrl, domain;
type service_ioctrl_exec, exec_type, file_type;
permissive service_ioctrl;
init_daemon_domain(service_ioctrl)

在/device/rockchip/common/sepolicy目录下新增文件ioctrl_device.te,添加如下代码:

type ioctrl_device,file_type,dev_type;

在file_contexts文件中添加如下代码:

#service_ioctrl
/system/bin/ioctrlapp           u:object_r:service_ioctrl_exec:s0
/dev/ioctrl                     u:object_r:ioctrl_device:s0

到这里基本完成,路径根据自己的工程修改。

 

 

你可能感兴趣的:(Android)