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 <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/spi/spidev.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/list.h>
#include <linux/device.h>
#include <linux/delay.h>
#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 <[email protected]>");
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,可看到編譯進去的驅動

(預設為選中狀态(*),是由于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 <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#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
到這裡基本完成,路徑根據自己的工程修改。