android P驅動技巧曆程--基於imx8

GPIO例程:

DTS:
    pwn-gpios = <&gpio3 8 GPIO_ACTIVE_HIGH>;
    

#include <linux/of_gpio.h>
struct sensor_data {
...
    int pwn_gpio;
...
}
struct sensor_data *max9286_data;
dev = &max9286_data->client->dev;

	max9286_data->pwn_gpio = of_get_named_gpio(dev->of_node, "pwn-gpios", 0);
	if (!gpio_is_valid(max9286_data->pwn_gpio)) {
		dev_err(dev, "no sensor pwdn pin available\n");
		return -ENODEV;
	}
	retval = devm_gpio_request_one(dev, max9286_data->pwn_gpio, GPIOF_OUT_INIT_HIGH,
					"max9286_pwd");
	if (retval < 0)
		return retval;
  
  gpio_set_value(max9286_data->pwn_gpio, 1);

內核線程例程:

#include <linux/kthread.h>

static struct task_struct *tp_rst_task;

int tp_rst_threadfunc(void *data){
	printk("enter the kthread\n");
	int i=0;

	while(1){
		//set_current_state(TASK_UNINTERRUPTIBLE);//將當前的狀態表示設置爲休眠
		//if(kthread_should_stop()) 
		//	break;  //解釋見“注意”
		//if(1 == filereadp(filename,readbuf)){
		if(HasSignal != 0 ) {
			printk(" test HasSignal=0x%02x i=[%d]",HasSignal,i); 
			i++;
		}
		else{//條件爲假
			//讓出CPU運行其他線程,並在指定的時間內重新被調度
			//schedule_timeout(0.1*HZ);   // 休眠,與set_current_state配合使用,需要計算,這裏表示休眠一秒
			//printk("kthread sleep\n");
			//msleep(20);	
			;
		}
	
	}
	return 0;
}

static tp_rst_thread_init(void) 
{
	int err;
	tp_rst_task = kthread_create(tp_rst_threadfunc,NULL, "tp_rst_task");

	if(IS_ERR(tp_rst_task)){

		printk("Unable to start kernel thread.\n");

		err = PTR_ERR(tp_rst_task);

		tp_rst_task =NULL;

		return err;
	}		
	wake_up_process(tp_rst_task);
}
static tp_rst_thread_exit(void) 
{
	if(tp_rst_task){
		kthread_stop(tp_rst_task);
		tp_rst_task = NULL;
	}
}

ds90ub948_probe(...)
{
   tp_rst_thread_init(); 
}

內核線程狀態指示燈例程:

#define INDICATOR_LED_GPIO   3

int indicator_thread_func(void *data){
    	printk("start check arm workfunction thread\n");
    
     GPIO_MultiFun_Set(INDICATOR_LED_GPIO, PINMUX_LEVEL_GPIO_END_FLAG);
    	gpio_request(INDICATOR_LED_GPIO, "output");
    
    	while(1){
    		gpio_direction_output(INDICATOR_LED_GPIO,0);
    		msleep(1000);
    		gpio_direction_output(INDICATOR_LED_GPIO,1);
    		msleep(1000);
            if (kthread_should_stop())
                break;
    	}
    	return 0;
}

static indicator_thread_init(void) 
{
	int err;
	arm_check_task = kthread_create(indicator_thread_func, NULL, "arm_check_task");

	if(IS_ERR(arm_check_task)){

		printk("Unable to start kernel thread.\n");

		err = PTR_ERR(arm_check_task);

		arm_check_task =NULL;

		return err;
	}		
	wake_up_process(arm_check_task);
}
static indicator_thread_exit(void) 
{
	if(arm_check_task){
		kthread_stop(arm_check_task);
		arm_check_task = NULL;
	}
}

內核線程檢測aux拔插功能例程

static int aux_detect_kthread_func(void *unused)
{
    char *envp[2];
    int pre_gpio_value,cur_gpio_value;
    
    printk("enter %s!\n",__func__);
    
    GPIO_MultiFun_Set(AUX_DECT_GPIO, PINMUX_LEVEL_GPIO_END_FLAG);
    gpio_request(AUX_DECT_GPIO, "input");
    gpio_direction_input(AUX_DECT_GPIO);
    envp[1] = NULL;
    while(1) {
        cur_gpio_value = gpio_get_value(AUX_DECT_GPIO);
        //printk("cur_gpio_value = %d!\n",cur_gpio_value);
        
        if (pre_gpio_value != cur_gpio_value) {
            
         	if(0 == cur_gpio_value)
        		envp[0] = "AUX_STATUS=PLUG_IN";
        	else
        		envp[0] = "AUX_STATUS=PLUG_OUT";  
            
            printk("Send uevent: %s!\n",envp[0]);
            kobject_uevent_env(&_mic_dev.dev.kobj, KOBJ_CHANGE, envp);
            pre_gpio_value = cur_gpio_value;
        }
        msleep(500);
        if (kthread_should_stop())
            break;
    }

    gpio_free(AUX_DECT_GPIO);
    
    return 0;
}

static void aux_detect_thread_init()
{
    aux_detect_thread_tsk = kthread_run(aux_detect_kthread_func, NULL, "aux_detect_kthread_func");    
    if (!aux_detect_thread_tsk) {        
        printk("[%s] create  aux_detect_kthread_func fail!\n",__func__);    
    }
}

static void aux_detect_thread_exit()
{
	if(aux_detect_thread_tsk){
		kthread_stop(aux_detect_thread_tsk);
		aux_detect_thread_tsk = NULL;
	}
}

sysfs文件節點創建

#include <linux/fs.h>

unsigned char HasSignal = 0;

//devfs文件系統的讀接口
static ssize_t sysfs_read(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
	ssize_t ss;
	ss=  sprintf(buf, "sysfs_read:[%d]\r\n", HasSignal);
	HasSignal =0;
	return ss;
}
//devfs文件系統的寫接口
static ssize_t sysfs_write(struct kobject *kobj, struct kobj_attribute *attr, const char *buf,ssize_t  count)
{
    int val = 0;
	//字符串轉爲數字
	val = simple_strtol(buf, NULL, 10);
    if(val == 0)
    {
        ...
    }
    else
    {
        ...
    }
     return count;
}


//devfs文件系統的設備屬性
static struct kobj_attribute SignalType_read =__ATTR(SignalType, S_IRUGO | S_IWUSR, sysfs_read, NULL);
static struct kobj_attribute SignalType_write =__ATTR(write, S_IWUGO, NULL,sysfs_write);

static struct attribute *tsc_rst[] = {
	 &SignalType_read.attr,
	 &SignalType_write.attr,
	 NULL,
};

static struct attribute_group my_attr_group = {
 	.attrs = tsc_rst,
};

static int sysfs_status = 0 ;
struct kobject *soc_kobj = NULL;
//文件節點名稱爲tsc_rst
#define SYSFS_NAME "tsc_rst"

static int sys_decodernode(void)
{
	int ret = 0;
	cyttsp6_dbg("==>func = %s ,line = %d\n",__func__,__LINE__);
	soc_kobj = kobject_create_and_add(SYSFS_NAME, NULL);
	if (!soc_kobj)
	goto err_board_obj;
   //創建devfs文件系統接口設備
	ret = sysfs_create_group(soc_kobj, &my_attr_group);
	if (ret)
	goto err_soc_sysfs_create;
	sysfs_status = 1;
	return 0;
}

xxx_probe(...)
{
    sys_decodernode();
}

void sysnode_exit(void)
{
 	cyttsp6_dbg("==>func = %s ,line = %d\n",__func__,__LINE__);
 	if(sysfs_status == 1){
  		sysfs_status = 0;
  		kobject_put(soc_kobj);
  		sysfs_remove_group(soc_kobj, &my_attr_group);
 	}
}

static int cyttsp6_i2c_remove(struct i2c_client *client)
{
    sysnode_exit();
}

Android sysfs文件節點讀寫

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

File awakeTimeFile = new File("/sys/devices/platform/5b0d0000.usb/ci_hdrc.0/driver/ci_hdrc.0/role");
FileWriter fr;

寫操作:
try {
    fr = new FileWriter(awakeTimeFile);
    fr_xen = new FileWriter(awakeTimeFileXen);
    writebuf[0] = 'h';
    writebuf[1] = 'o';
    writebuf[2] = 's';
    writebuf[3] = 't';
    fr.write(writebuf);
    fr_xen.write(writebuf);
    Log.d("ROOT","write host finish!");
    fr.close();
    os.writeBytes("exit\n");
    os.flush();
}
catch (IOException e) {
    e.printStackTrace();
}

讀操作:
try{
    File readFile = new File("/sys/devices/platform/5b0d0000.usb/ci_hdrc.0/driver/ci_hdrc.0/role");
    FileReader inCmd = new FileReader(readFile);
    try{
        while((hasRead = inCmd.read(readbuf)) > 0){
            for(int i = 0; i < readbuf.length; i ++) {
                System.out.println(readbuf[i] + "\n");
            }
        }
    }catch (IOException e){
        e.printStackTrace();
    }
} catch (FileNotFoundException e){
    e.printStackTrace();
}

Android如何增加自己的服務

並開機自啓動,以android9.0 selinuxswitch爲例
1.首先增加selinux權限

device/fsl/imx8q/sepolicy_car/selinuxswitch.te
type selinuxswitch, domain;
type selinuxswitch_exec, exec_type, vendor_file_type, file_type;

init_daemon_domain(selinuxswitch)

set_prop(selinuxswitch, public_vendor_default_prop)

allow selinuxswitch vendor_shell_exec:file rx_file_perms;
allow selinuxswitch vendor_toolbox_exec:file rx_file_perms;

# Allow insmod
allow selinuxswitch self:capability sys_module;
allow selinuxswitch system_file:file { getattr setattr open read write create };

allow selinuxswitch vendor_file:file { getattr setattr open read write create };

allow selinuxswitch wc_prop:property_service { set };

allow selinuxswitch shell_exec:file { map read execute getattr setattr create append };

allow selinuxswitch sysfs:file { getattr setattr };
allow selinuxswitch sysfs:dir { getattr setattr };

allow selinuxswitch selinuxswitch:capability  { dac_read_search chown fowner fsetid };

allow selinuxswitch toolbox_exec:file { getattr setattr execute read open write execute_no_trans map };
allow selinuxswitch wifi_data_file:dir { read getattr setattr open search };
allow selinuxswitch wifi_data_file:file { read getattr setattr };
allow selinuxswitch wpa_socket:dir { read getattr setattr open search };
allow selinuxswitch wpa_socket:file { read getattr setattr };
allow selinuxswitch wpa_socket:sock_file { read getattr setattr };
allow selinuxswitch selinuxfs:file { read write open };
allow selinuxswitch system_wpa_socket:sock_file { read getattr setattr  };

device/fsl/imx8q/sepolicy_car/file_contexts

/vendor/bin/selinuxswitch                               u:object_r:selinuxswitch_exec:s0

2.拷貝執行文件

device/fsl/imx8q/mek_8q/BoardConfig.mk
120:            device/fsl/imx8q/etc/selinuxswitch:vendor/bin/selinuxswitch         \

3.在init.rc增加觸發

device/fsl/imx8q/mek_8q/init_car.rc +150
148 on property:vendor.all.setup_core.ready=1
149     start boot_completed_main_sh
150         start selinuxswitch

174 service selinuxswitch /vendor/bin/selinuxswitch
175    class main
176    user root
177    group root shell
178    disabled
179    oneshot

或者自己增加環境變量觸發的方法也可以
#on 後面的是觸發器 option是指令

on property:test.wugn=wugn_test
	start selinuxswitch

觸發條件:

 setprop test.wugn wugn_test
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章