1 /*
2  * Copyright (c) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "hdf_audio_input_event.h"
17 #include <fcntl.h>
18 #include <poll.h>
19 #include <pthread.h>
20 #include <unistd.h>
21 #include <linux/input.h>
22 #include "hdf_audio_pnp_server.h"
23 #include "osal_time.h"
24 #include "securec.h"
25 #include "audio_uhdf_log.h"
26 
27 #define HDF_LOG_TAG             HDF_AUDIO_HAL_HOST
28 #define INPUT_EVT_MAX_CNT       4
29 #define WAIT_THREAD_END_TIME_MS 1
30 static struct pollfd g_fdSets[INPUT_EVT_MAX_CNT];
31 static int32_t g_inputDevCnt = 0;
32 static bool g_bRunThread = false;
33 
AudioAnalogHeadsetDeviceCheck(struct input_event evt)34 static int32_t AudioAnalogHeadsetDeviceCheck(struct input_event evt)
35 {
36     struct AudioEvent audioEvent;
37 
38     AUDIO_FUNC_LOGI("enter.");
39     audioEvent.eventType = (evt.value == 0) ? AUDIO_DEVICE_REMOVE : AUDIO_DEVICE_ADD;
40     audioEvent.deviceType = AUDIO_DEVICE_UNKNOWN;
41     switch (evt.code) {
42         case SW_HEADPHONE_INSERT:
43             audioEvent.deviceType = AUDIO_HEADPHONE;
44             break;
45         case SW_MICROPHONE_INSERT:
46             audioEvent.deviceType = AUDIO_HEADSET;
47             break;
48         case SW_LINEOUT_INSERT:
49             audioEvent.deviceType = AUDIO_LINEOUT;
50             break;
51         default: // SW_JACK_PHYSICAL_INSERT = 0x7, SW_LINEIN_INSERT = 0xd and other.
52             AUDIO_FUNC_LOGE("n't surpport code =0x%{public}x\n", evt.code);
53             return HDF_FAILURE;
54     }
55     return AudioPnpUpdateInfoOnly(audioEvent);
56 }
57 
AudioPnpInputCheck(struct input_event evt)58 static void AudioPnpInputCheck(struct input_event evt)
59 {
60     switch (evt.type) {
61         case EV_SYN:
62             break;
63         case EV_SW:
64             // The code possible is SW_HEADPHONE_INSERT=2,SW_MICROPHONE_INSERT=4,SW_LINEOUT_INSERT=6
65             // or SW_LINEIN_INSERT=13.
66             AUDIO_FUNC_LOGD("evt.type = EV_SW5, code =0x%{public}d, value = %{public}d\n", evt.code,
67                 evt.value);
68             (void)AudioAnalogHeadsetDeviceCheck(evt);
69             break;
70         case EV_KEY:
71             // The key on the board or on the analog headset.
72             // The code possible is KEY_MEDIA=226,KEY_KP7=0x71(mute),KEY_KP8=0x72(volumn-),
73             // KEY_KP9=0x73(vol+) or KEY_KPMINUS=0x74(power).
74             if ((evt.code == KEY_MEDIA) || (evt.code == KEY_KP7) || (evt.code == KEY_KP8) || (evt.code == KEY_KP9)) {
75                 AUDIO_FUNC_LOGD("evt.type = EV_KEY1, code = 0x%{public}x, value = %{public}d.", evt.code, evt.value);
76             }
77             break;
78         case EV_REL: // mouse move event.
79         case EV_MSC:
80         default:
81             break;
82     }
83 }
84 
AudioPnpInputPollAndRead(void)85 static int32_t AudioPnpInputPollAndRead(void)
86 {
87     int32_t i;
88     int32_t ret;
89     int32_t n = g_inputDevCnt;
90     struct input_event evt;
91 
92     ret = poll(g_fdSets, (nfds_t)n, -1);
93     if (ret < 0) {
94         AUDIO_FUNC_LOGE("[poll] failed, %{public}d", errno);
95         return HDF_FAILURE;
96     }
97 
98     for (i = 0; i < n; i++) {
99         if ((uint32_t)g_fdSets[i].revents & POLLIN) {
100             if (read(g_fdSets[i].fd, (void *)&evt, sizeof(evt)) < 0) {
101                 AUDIO_FUNC_LOGE("[read] failed, %{public}d", errno);
102                 return HDF_FAILURE;
103             }
104             AudioPnpInputCheck(evt);
105         }
106     }
107 
108     return HDF_SUCCESS;
109 }
110 
AudioPnpInputOpen(void)111 static int32_t AudioPnpInputOpen(void)
112 {
113     int32_t i;
114     int32_t j;
115     char *devices[INPUT_EVT_MAX_CNT] = {
116         "/dev/input/event1",
117         "/dev/input/event2",
118         "/dev/input/event3",
119         "/dev/input/event4"
120     };
121 
122     AUDIO_FUNC_LOGI("enter.");
123     j = 0;
124     for (i = 0; i < INPUT_EVT_MAX_CNT; i++) {
125         g_fdSets[j].fd = open(devices[i], O_RDONLY);
126         if (g_fdSets[j].fd < 0) {
127             AUDIO_FUNC_LOGW("[open] %{public}s failed!", devices[i]);
128             continue;
129         }
130         AUDIO_FUNC_LOGI("[open] %{public}s success!", devices[i]);
131         g_fdSets[j].events = POLLIN;
132         j++;
133     }
134     g_inputDevCnt = j;
135 
136     return (j == 0) ? HDF_FAILURE : HDF_SUCCESS;
137 }
138 
AudioPnpInputStart(void * useless)139 static void AudioPnpInputStart(void *useless)
140 {
141     int ret;
142     (void)useless;
143 
144     AUDIO_FUNC_LOGI("audio input start.");
145     if (AudioPnpInputOpen() != HDF_SUCCESS) {
146         return;
147     }
148 
149     do {
150         ret = AudioPnpInputPollAndRead();
151         if (ret != HDF_SUCCESS) {
152             AUDIO_FUNC_LOGE("[AudioPnpInputPollAndRead] failed!");
153             return;
154         }
155     } while (g_bRunThread);
156 
157     return;
158 }
159 
AudioHeadsetPnpInputStartThread(void)160 int32_t AudioHeadsetPnpInputStartThread(void)
161 {
162     const char *threadName = "pnp_headset";
163     AUDIO_FUNC_LOGI("create audio headset pnp uevent thread");
164     g_bRunThread = true;
165 
166     FfrtTaskAttr attr;
167     FfrtAttrInitFunc()(&attr);
168     FfrtAttrSetQosFunc()(&attr, FFRT_QOS_DEFAULT);
169     FfrtAttrSetNameFunc()(&attr, threadName);
170     FfrtSubmitBaseFunc()(FfrtCreateFunctionWrapper(AudioPnpInputStart, NULL, NULL), NULL, NULL, &attr);
171 
172     return HDF_SUCCESS;
173 }
174 
AudioHeadsetPnpInputEndThread(void)175 void AudioHeadsetPnpInputEndThread(void)
176 {
177     AUDIO_FUNC_LOGI("audio headset pnp uevent thread exit");
178     g_bRunThread = false;
179     OsalMSleep(WAIT_THREAD_END_TIME_MS);
180 }
181