2021-12-27 使用devm_extcon_dev_register架构上报拔出插入事件,demo实例测试extcon,app通过广播接收这个消息

一、kernel 驱动代码,注册成功后会生成/sys/class/extcon/extcon-demo这个文件夹

1、dts和extcon文件的修改

diff --git a/arch/arm64/boot/dts/rockchip/rk3566-rk817-tablet.dts b/arch/arm64/boot/dts/rockchip/rk3566-rk817-tablet.dts
index 483068a..4175b75 100755
--- a/arch/arm64/boot/dts/rockchip/rk3566-rk817-tablet.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3566-rk817-tablet.dts
@@ -157,7 +157,10 @@
 		pinctrl-0 = <&hp_det>;
 		io-channels = <&saradc 2>;
 	};
-
+	extcon_demo: extcon-demo  {
+		compatible = "extcon_demo";
+        status = "okay";
+	};
 	sdio_pwrseq: sdio-pwrseq {
 		compatible = "mmc-pwrseq-simple";
 		clocks = <&rk817 1>;
diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c
old mode 100644
new mode 100755
index def0649..df2f628
--- a/drivers/extcon/extcon.c
+++ b/drivers/extcon/extcon.c
@@ -121,6 +121,16 @@ static const struct __extcon_info {
 		.id = EXTCON_JACK_HEADPHONE,
 		.name = "HEADPHONE",
 	},
+	[EXTCON_DEMO_B] = {
+		.type = EXTCON_TYPE_MISC,
+		.id = EXTCON_DEMO_B,
+		.name = "EXTCON_DEMO_BJAP",
+	},
+	[EXTCON_DEMO_A] = {
+		.type = EXTCON_TYPE_MISC,
+		.id = EXTCON_DEMO_A,
+		.name = "EXTCON_DEMO_AENG",
+	},
 	[EXTCON_JACK_LINE_IN] = {
 		.type = EXTCON_TYPE_JACK,
 		.id = EXTCON_JACK_LINE_IN,
diff --git a/include/linux/extcon.h b/include/linux/extcon.h
old mode 100644
new mode 100755
index dfe0b89..82a93c1
--- a/include/linux/extcon.h
+++ b/include/linux/extcon.h
@@ -91,7 +91,11 @@
 #define EXTCON_JIG		61
 #define EXTCON_MECHANICAL	62
 
-#define EXTCON_NUM		63
+#define EXTCON_DEMO_A	64
+#define EXTCON_DEMO_B	65
+
+
+#define EXTCON_NUM		66
 
 /*
  * Define the properties of supported external connectors.

1、\kernel\drivers\char\extcon_demo.c


#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 


/*驱动注册的头文件,包含驱动的结构体和注册和卸载的函数*/
#include 
 
#define DRIVER_NAME "extcon_demo"
 
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("TOPEET");


struct extcon_dev *edev;

static const unsigned int headset_cable[] = {
	EXTCON_JACK_MICROPHONE,
	EXTCON_JACK_HEADPHONE,
	EXTCON_NONE,
};

static const unsigned int extcon_demo_cable[] = {
	EXTCON_DEMO_B,
	EXTCON_DEMO_A,
	EXTCON_NONE,
};

static ssize_t extcon_demo_show(struct device *dev, struct device_attribute *attr, char *buf)
{
    printk("extcon_demo_show!\n");
	//extcon_set_state_sync(edev,
	//				      EXTCON_JACK_MICROPHONE, true);
	extcon_set_state_sync(edev,
					      EXTCON_DEMO_B, true);
	return 0;
}
 
static ssize_t extcon_demo_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
    printk("extcon_demo_store\n");
	
	//extcon_set_state_sync(edev,
	//				      EXTCON_JACK_MICROPHONE, false);

	extcon_set_state_sync(edev,
	 			      EXTCON_DEMO_B, false);

	
	return count;
}
static DEVICE_ATTR(state, 0664, extcon_demo_show, extcon_demo_store);
 

static int extcon_demo_probe(struct platform_device *pdv){
	int err;
	int ret;
	printk(KERN_EMERG "\tinitialized\n");


	//edev = devm_extcon_dev_allocate(&pdv->dev, headset_cable);//extcon_demo_cable
	edev = devm_extcon_dev_allocate(&pdv->dev, extcon_demo_cable);//

	ret = devm_extcon_dev_register(&pdv->dev, edev);
	
    err = device_create_file(&pdv->dev, &dev_attr_state);
    if (err)
         printk(KERN_EMERG "\tdevice_create_file_error\n");
    else
         printk(KERN_EMERG "\t very good device_create_file_success\n");

	return 0;
}
 
static int extcon_demo_remove(struct platform_device *pdv){
	
	return 0;
}
static void extcon_demo_shutdown(struct platform_device *pdv){
	
	;
}
 
static int extcon_demo_resume(struct platform_device *pdv){
	
	return 0;
}

static const struct of_device_id extcon_demo_of_match[] = {
	{ .compatible = "extcon_demo", },
	{},
};

MODULE_DEVICE_TABLE(of, extcon_demo_of_match);

struct platform_driver extcon_demo_driver = {
	.probe = extcon_demo_probe,
	.remove = extcon_demo_remove,
	.shutdown = extcon_demo_shutdown,
	.resume = extcon_demo_resume,
	.driver = {
		.name = DRIVER_NAME,
		.owner = THIS_MODULE,
		.of_match_table = of_match_ptr(extcon_demo_of_match),
	}
};
 
 
static int extcon_demo_init(void)
{
	int DriverState;
	
	printk(KERN_EMERG "HELLO WORLD enter! extcon_demo\n");
	DriverState = platform_driver_register(&extcon_demo_driver);
	
	printk(KERN_EMERG "\t DriverState  extcon_demo is %d\n",DriverState);
	return 0;
}
 
static void extcon_demo_exit(void)
{
	printk(KERN_EMERG "HELLO WORLD exit!\n");
	
	platform_driver_unregister(&extcon_demo_driver);	
}
 
module_init(extcon_demo_init);
module_exit(extcon_demo_exit);

3、注册成功

2021-12-27 使用devm_extcon_dev_register架构上报拔出插入事件,demo实例测试extcon,app通过广播接收这个消息_第1张图片

 

二、上层接收这个消息的代码

1、frameworks\base\services\core\java\com\android\server\WiredAccessoryManager.java 里面的parseState和updateState更新信息。

2021-12-27 使用devm_extcon_dev_register架构上报拔出插入事件,demo实例测试extcon,app通过广播接收这个消息_第2张图片

 2、parseState和updateState在frameworks\base\services\core\java\com\android\server\ExtconStateObserver.java里面的onUEvent函数调用

2021-12-27 使用devm_extcon_dev_register架构上报拔出插入事件,demo实例测试extcon,app通过广播接收这个消息_第3张图片

 3、上面的onUEvent函数在  \frameworks\base\core\java\android\os\UEventObserver.java里面的的sendEvent调用。

2021-12-27 使用devm_extcon_dev_register架构上报拔出插入事件,demo实例测试extcon,app通过广播接收这个消息_第4张图片

  4、sendEvent在同文件的run里面调用。

2021-12-27 使用devm_extcon_dev_register架构上报拔出插入事件,demo实例测试extcon,app通过广播接收这个消息_第5张图片

   5、上面的nativeSetup和nativeWaitForNextEvent是jni获取底层的信息。nativeWaitForNextEvent里面会调用uevent_next_event, frameworks\base\core\jni\android_os_UEventObserver.cpp

2021-12-27 使用devm_extcon_dev_register架构上报拔出插入事件,demo实例测试extcon,app通过广播接收这个消息_第6张图片

2021-12-27 使用devm_extcon_dev_register架构上报拔出插入事件,demo实例测试extcon,app通过广播接收这个消息_第7张图片    6、上面的uevent_next_event是在hardware\libhardware_legacy\uevent.c,这个文件里面是读底层信息,这里把整个代码的贴出来。

/*
 * Copyright (C) 2008 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include 

#include 
#include 
#include 
#include 
#include 

#include 
#include 
#include 
#include 


LIST_HEAD(uevent_handler_head, uevent_handler) uevent_handler_list;
pthread_mutex_t uevent_handler_list_lock = PTHREAD_MUTEX_INITIALIZER;

struct uevent_handler {
    void (*handler)(void *data, const char *msg, int msg_len);
    void *handler_data;
    LIST_ENTRY(uevent_handler) list;
};

static int fd = -1;

/* Returns 0 on failure, 1 on success */
int uevent_init()
{
    struct sockaddr_nl addr;
    int sz = 64*1024;
    int s;

    memset(&addr, 0, sizeof(addr));
    addr.nl_family = AF_NETLINK;
    addr.nl_pid = getpid();
    addr.nl_groups = 0xffffffff;

    s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
    if(s < 0)
        return 0;

    setsockopt(s, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz));

    if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
        close(s);
        return 0;
    }

    fd = s;
    return (fd > 0);
}

int uevent_get_fd()
{
    return fd;
}

int uevent_next_event(char* buffer, int buffer_length)
{
    while (1) {
        struct pollfd fds;
        int nr;
    
        fds.fd = fd;
        fds.events = POLLIN;
        fds.revents = 0;
        nr = poll(&fds, 1, -1);
     
        if(nr > 0 && (fds.revents & POLLIN)) {
            int count = recv(fd, buffer, buffer_length, 0);
            if (count > 0) {
                struct uevent_handler *h;
                pthread_mutex_lock(&uevent_handler_list_lock);
                LIST_FOREACH(h, &uevent_handler_list, list)
                    h->handler(h->handler_data, buffer, buffer_length);
                pthread_mutex_unlock(&uevent_handler_list_lock);

                return count;
            } 
        }
    }
    
    // won't get here
    return 0;
}

int uevent_add_native_handler(void (*handler)(void *data, const char *msg, int msg_len),
                             void *handler_data)
{
    struct uevent_handler *h;

    h = malloc(sizeof(struct uevent_handler));
    if (h == NULL)
        return -1;
    h->handler = handler;
    h->handler_data = handler_data;

    pthread_mutex_lock(&uevent_handler_list_lock);
    LIST_INSERT_HEAD(&uevent_handler_list, h, list);
    pthread_mutex_unlock(&uevent_handler_list_lock);

    return 0;
}

int uevent_remove_native_handler(void (*handler)(void *data, const char *msg, int msg_len))
{
    struct uevent_handler *h;
    int err = -1;

    pthread_mutex_lock(&uevent_handler_list_lock);
    LIST_FOREACH(h, &uevent_handler_list, list) {
        if (h->handler == handler) {
            LIST_REMOVE(h, list);
            err = 0;
            break;
       }
    }
    pthread_mutex_unlock(&uevent_handler_list_lock);

    return err;
}

    7、开始StartWiredAccessoryManager,frameworks\base\services\java\com\android\server\SystemServer.java

2021-12-27 使用devm_extcon_dev_register架构上报拔出插入事件,demo实例测试extcon,app通过广播接收这个消息_第8张图片

三、上面的分析完了,我们来实际测试一下底层发信息到上层,从log上看,WiredAccessoryManager.java里面接受到底层通过extcon架构发过来的信息。

2021-12-27 使用devm_extcon_dev_register架构上报拔出插入事件,demo实例测试extcon,app通过广播接收这个消息_第9张图片

四、那app如何收到这个变化的信息呢?解决方案是发广播,然后app接收这个广播。我这里是为了测试,用一个reboot的广播代码,代码修改如下。执行cat   /sys/devices/platform/extcon-demo/state 后,WiredAccessoryManager里面接受到信息后会发reboot广播,机器会reboot。

2021-12-27 使用devm_extcon_dev_register架构上报拔出插入事件,demo实例测试extcon,app通过广播接收这个消息_第10张图片

2021-12-27 使用devm_extcon_dev_register架构上报拔出插入事件,demo实例测试extcon,app通过广播接收这个消息_第11张图片

2021-12-27 使用devm_extcon_dev_register架构上报拔出插入事件,demo实例测试extcon,app通过广播接收这个消息_第12张图片

五、参考文章:

Android驱动——audio输入输出插拔检测_zhaojy5453的博客-CSDN博客

Android HDMI audio设备插拔事件_代码搬运工小弟的博客-CSDN博客_android audio hdmi

你可能感兴趣的:(Android,架构)