0
点赞
收藏
分享

微信扫一扫

[经验] wps怎么设置行间距离28磅 #学习方法#知识分享#媒体

九点韶留学 02-21 19:00 阅读 2
android

hdmi从插入到拔出经过底层一系列检测到应用层,应用层获取hdmi插入状态后又会做出一系列相应的动作,下面梳理了从应用层到底层一步步追踪到芯片的hpd-pin的检测过程。其大致原理就是framework层通过检测/sys/class/extcon/hdmi



frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java +775


    private class HdmiVideoExtconUEventObserver extends ExtconStateObserver<Boolean> {
        private static final String HDMI_EXIST = "HDMI=1";
        private static final String NAME = "hdmi";
        private final ExtconInfo mHdmi = new ExtconInfo(NAME);  //判断/sys/class/extcon/hdmi文件是否存在

        private boolean init() {
            boolean plugged = false;
            try {
                plugged = parseStateFromFile(mHdmi); //解析sys/class/extcon/hdmi/state这个文件内容
            } catch (FileNotFoundException e) {
                Slog.w(TAG, mHdmi.getStatePath()
                        + " not found while attempting to determine initial state", e);
            } catch (IOException e) {
                Slog.e(
                        TAG,
                        "Error reading " + mHdmi.getStatePath()
                                + " while attempting to determine initial state",
                        e);
            }
            startObserving(mHdmi);  //开始监控/sys/class/extcon/hdmi
            return plugged;
        }

        @Override
        public void updateState(ExtconInfo extconInfo, String eventName, Boolean state) {//通过这里更新hdmi plug状态,这个转态来自hal层
                 //这里的变化来自hdmicec_event.cpp 
						mDefaultDisplayPolicy.setHdmiPlugged(state);
        }

        @Override
        public Boolean parseState(ExtconInfo extconIfno, String state) {
            // extcon event state changes from kernel4.9
            // new state will be like STATE=HDMI=1
            return state.contains(HDMI_EXIST);
        }
    }

    void initializeHdmiStateInternal() {
        boolean plugged = false;
        // watch for HDMI plug messages if the hdmi switch exists
        if (new File("/sys/devices/virtual/switch/hdmi/state").exists()) {
            mHDMIObserver.startObserving("DEVPATH=/devices/virtual/switch/hdmi");

            final String filename = "/sys/class/switch/hdmi/state";
            FileReader reader = null;
            try {
                reader = new FileReader(filename);
                char[] buf = new char[15];
                int n = reader.read(buf);
                if (n > 1) {
                    plugged = 0 != Integer.parseInt(new String(buf, 0, n - 1));
                }
            } catch (IOException ex) {
                Slog.w(TAG, "Couldn't read hdmi state from " + filename + ": " + ex);
            } catch (NumberFormatException ex) {
                Slog.w(TAG, "Couldn't read hdmi state from " + filename + ": " + ex);
            } finally {
                if (reader != null) {
                    try {
                        reader.close();
                    } catch (IOException ex) {
                    }
                }
            }
        } else if (ExtconUEventObserver.extconExists()   //走这里  判断sys/class/extcon是否存在
                && ExtconUEventObserver.namedExtconDirExists(HdmiVideoExtconUEventObserver.NAME)) {
            Log.i("fan","xtconUEventObserver.extconExists");
            HdmiVideoExtconUEventObserver observer = new HdmiVideoExtconUEventObserver();//新建一个hdmi观察者,检测hdmi hpd引脚的变化
            plugged = observer.init();
            mHDMIObserver = observer;
        } else if (localLOGV) {
            Slog.v(TAG, "Not observing HDMI plug state because HDMI was not found.");
        }

        // This dance forces the code in setHdmiPlugged to run.
        // Always do this so the sticky intent is stuck (to false) if there is no hdmi.
        mDefaultDisplayPolicy.setHdmiPlugged(plugged, true /* force */);
    }
frameworks/base/core/java/android/view/WindowManagerPolicyConstants.java:78    
	String ACTION_HDMI_PLUGGED = "android.intent.action.HDMI_PLUGGED";

    public void setHdmiPlugged(boolean plugged) {
        setHdmiPlugged(plugged, false /* force */);
    }

    public void setHdmiPlugged(boolean plugged, boolean force) {
        if (force || mHdmiPlugged != plugged) {
            mHdmiPlugged = plugged;
            mService.updateRotation(true /* alwaysSendConfiguration */, true /* forceRelayout */);
            final Intent intent = new Intent(ACTION_HDMI_PLUGGED);
            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
            intent.putExtra(EXTRA_HDMI_PLUGGED_STATE, plugged);
            mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);//通知系统hdmi插入状态
        }
    }

    boolean isHdmiPlugged() {
        return mHdmiPlugged;
    }    
frameworks/base/services/core/java/com/android/server/ExtconUEventObserver.java    
     public static boolean extconExists() {
        File extconDir = new File("/sys/class/extcon"); //检查这个文件是否存在,对应上面的else if (ExtconUEventObserver.extconExists() 
        return extconDir.exists() && extconDir.isDirectory();
    }

\hardware\rockchip\hdmicec\hdmicec_event.cpp
static void *uevent_loop(void *param)
{
	hdmi_cec_context_t * ctx = reinterpret_cast<hdmi_cec_context_t *>(param);
	char thread_name[64] = HDMI_CEC_UEVENT_THREAD_NAME;
	hdmi_event_t cec_event;
	struct pollfd pfd[2];
	int fd[2];
	int ret, i;

	prctl(PR_SET_NAME, (unsigned long) &thread_name, 0, 0, 0);
	setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);

	fd[0] = ctx->fd;
	if (fd[0] < 0) {
		ALOGE ("%s:not able to open cec state node", __func__);
		return NULL;
	}

	pfd[0].fd = fd[0];
	if (pfd[0].fd >= 0)
		pfd[0].events = POLLIN | POLLRDNORM | POLLPRI;

	while (true) {
                usleep(1000);
		int err = poll(&pfd[0], 1, 20);

		if (!err) {
			continue;
		} else if(err > 0) {
			if (!ctx->enable || !ctx->system_control)
				continue;
			ALOGD("poll revent:%02x\n", pfd[0].revents);
			memset(&cec_event, 0, sizeof(hdmi_event_t));
			if (pfd[0].revents & (POLLIN)) {
				struct cec_msg cecframe;

				ALOGD("poll receive msg\n");
				ret = ioctl(pfd[0].fd, CEC_RECEIVE, &cecframe);
				if (!ret) {
					cec_event.type = HDMI_EVENT_CEC_MESSAGE;
					cec_event.dev = &ctx->device;
					cec_event.cec.initiator = (cec_logical_address_t)(cecframe.msg[0] >> 4);
					cec_event.cec.destination = (cec_logical_address_t)(cecframe.msg[0] & 0x0f);
					cec_event.cec.length = cecframe.len - 1;
					cec_event.cec.body[0] = cecframe.msg[1];
					if (!validcecmessage(cec_event)) {
						for (ret = 0; ret < cec_event.cec.length; ret++)
						     cec_event.cec.body [ret + 1] = cecframe.msg[ret + 2];
						for (i = 0; i < cecframe.len; i++)
							ALOGD("poll receive msg[%d]:%02x\n", i, cecframe.msg[i]);
						if (ctx->event_callback)
							ctx->event_callback(&cec_event, ctx->cec_arg);
					} else {
						ALOGE("%s cec_event length > 15 ", __func__);
					}
				} else {
					ALOGE("%s hdmi cec read error", __FUNCTION__);
				}
			}

			if (pfd[0].revents & (POLLPRI)) {
				int state = -1;
				struct cec_event event;

				ALOGI("poll receive event\n");
				ret = ioctl(pfd[0].fd, CEC_DQEVENT, &event);//取得一个cec事件,然后判断事件的状态,此部分内容在内核层
				if (!ret) {
					ALOGD("event:%d\n", event.event);
					if (event.event == CEC_EVENT_PIN_HPD_LOW) {//获取底层hpdin管教状态
						ALOGI("CEC_EVENT_PIN_HPD_LOW\n");
						ctx->hotplug = false;
						cec_event.type = HDMI_EVENT_HOT_PLUG;
						cec_event.dev = &ctx->device;
						cec_event.hotplug.connected = HDMI_NOT_CONNECTED;
						cec_event.hotplug.port_id = HDMI_CEC_PORT_ID;
						if (ctx->event_callback)
							ctx->event_callback(&cec_event, ctx->cec_arg);
					} else if (event.event == CEC_EVENT_PIN_HPD_HIGH) {//高为连接
						ALOGI("CEC_EVENT_PIN_HPD_HIGH\n");
						ctx->hotplug = true;
						cec_event.type = HDMI_EVENT_HOT_PLUG;
						cec_event.dev = &ctx->device;
						cec_event.hotplug.connected = HDMI_CONNECTED;
						cec_event.hotplug.port_id = HDMI_CEC_PORT_ID;
						if (ctx->event_callback)
							ctx->event_callback(&cec_event, ctx->cec_arg);
					} else if (event.event == CEC_EVENT_STATE_CHANGE) {
						ALOGD("adapt state change,phy_addr:%x,flags:%x\n", event.state_change.phys_addr, event.flags);

						/*
						 * Before cec HAL is initialized, hdmi hpd state may be
						 * changed. So we should confirm the hpd status
						 * after cec is initialized(Kernel will report
						 * CEC_EVENT_FL_INITIAL_STATE to notify HAL that
						 * initialization is done).
						 */
						if (event.flags & CEC_EVENT_FL_INITIAL_STATE) {
							ALOGD("cec adapter init complete, get connect state\n");
							ctx->hotplug = get_hpd_state_from_node(ctx);
							ctx->cec_init = true;

							/*
							 * Framework will start la polling when box turn on,
							 * In addition, as soon as framewrok receives hdmi
							 * plug in, it will start la polling immediately.
							 * There is not need to report plug in event if hdmi
							 * is connecting when box turn on. So we should report
							 * hdmi plug out only.
							 */
							if (!ctx->hotplug)
								report_hdp_event(ctx, ctx->hotplug);
						}
						ctx->phy_addr = event.state_change.phys_addr;
					}
				} else {
					ALOGE("%s cec event get err, ret:%d\n", __func__, ret);
				}
			}
		} else {
			ALOGE("%s: cec poll failed errno: %s", __FUNCTION__,
			strerror(errno));
			continue;
		}
	}
	return NULL;
}
hardware/rockchip/hdmicec/hdmicec_event.cpp
static void report_hdp_event(hdmi_cec_context_t* ctx, bool hpd)
{
        hdmi_event_t cec_event;

        cec_event.type = HDMI_EVENT_HOT_PLUG;
        cec_event.dev = &ctx->device;
        if (hpd)
                cec_event.hotplug.connected = HDMI_CONNECTED;
        else
                cec_event.hotplug.connected = HDMI_NOT_CONNECTED;
        cec_event.hotplug.port_id = HDMI_CEC_PORT_ID;
        if (ctx->event_callback)
                ctx->event_callback(&cec_event, ctx->cec_arg);
}
hardware/rockchip/hdmicec/hdmi_cec.cpp
static void hdmi_cec_register_event_callback(const struct hdmi_cec_device* dev,
                                             event_callback_t callback, void* arg)
{
        struct hdmi_cec_context_t* ctx = (struct hdmi_cec_context_t*)dev;

        ALOGI("%s", __func__);
        ctx->event_callback = callback;
        ctx->cec_arg = arg;
}	
static int hdmi_cec_device_open(const struct hw_module_t* module, const char* name,
                                struct hw_device_t** device)
{  
	....
	  dev->device.register_event_callback = hdmi_cec_register_event_callback;
	  ......
hardware/interfaces/tv/cec/2.0/default/HdmiCec.cpp 
IHdmiCec* HIDL_FETCH_IHdmiCec(const char* hal) {  
    hdmi_cec_device_t* hdmi_cec_device;
    int ret = 0;
    const hw_module_t* hw_module = nullptr;
    hdmi_cec_device_t* hdmi_cec_device;
    int ret = 0;
    const hw_module_t* hw_module = nullptr;

    ret = hw_get_module(HDMI_CEC_HARDWARE_MODULE_ID, &hw_module);  //找到ECE模块
    if (ret == 0) {
        ret = hdmi_cec_open(hw_module, &hdmi_cec_device); //打开设备
        if (ret != 0) {
            LOG(ERROR) << "hdmi_cec_open " << hal << " failed: " << ret;
        }
    } else {
        LOG(ERROR) << "hw_get_module " << hal << " failed: " << ret;
    }

    if (ret == 0) {
        return new HdmiCec(hdmi_cec_device);
    } else {
        LOG(ERROR) << "Passthrough failed to load legacy HAL.";
        return nullptr;
    }
}
	  
Return<void> HdmiCec::setCallback(const sp<IHdmiCecCallback>& callback) {
    if (mCallback != nullptr) {
        mCallback->unlinkToDeath(this);
        mCallback = nullptr;
    }

    if (callback != nullptr) {
        mCallback = callback;
        mCallback->linkToDeath(this, 0 /*cookie*/);
        mDevice->register_event_callback(mDevice, eventCallback, nullptr);  //注册回调通知framework层
    }
    return Void();
}
	  
Kernel/drivers/media/cec/cec-api.c 
static long cec_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 case CEC_DQEVENT:
                return cec_dqevent(adap, fh, block, parg);  //hal层调用这里获取一个cec事件,既然有获取事件就有把事件放入事件队列的地方
 drivers/media/cec/cec-adap.c
                
void cec_queue_pin_hpd_event(struct cec_adapter *adap, bool is_high, ktime_t ts)
{
        struct cec_event ev = {
                .event = is_high ? CEC_EVENT_PIN_HPD_HIGH :
                                   CEC_EVENT_PIN_HPD_LOW,
        };
        struct cec_fh *fh;

        if (!adap)
                return;
        /* hdmi HPD may occur before devnode is registered */
        if (!adap->devnode.registered)
                return;
        mutex_lock(&adap->devnode.lock);
        list_for_each_entry(fh, &adap->devnode.fhs, list)
                cec_queue_event_fh(fh, &ev, ktime_to_ns(ts)); //插入一个cec事件,把这个事件放入到ece事件队列,供hal层获取,hal层获取后传到framework层
        mutex_unlock(&adap->devnode.lock);
}
	
	

	
	

	
	

举报

相关推荐

0 条评论