1 /*
2 * Copyright (c) 2020-2021 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 "osal.h"
17 #include "osal_io.h"
18 #include "hdf_device_desc.h"
19 #include "hdf_input_device_manager.h"
20 #include "hdf_hid_adapter.h"
21 #include "hdf_syscall_adapter.h"
22 #include "los_memory.h"
23 #include "los_arch_interrupt.h"
24 #include "los_interrupt.h"
25 #include "los_task.h"
26 #include "cmsis_os2.h"
27 #include "virtmmio.h"
28
29 #define VIRTQ_EVENT_QSZ 8
30 #define VIRTQ_STATUS_QSZ 1
31 #define VIRTMMIO_INPUT_NAME "virtinput"
32
33 #define VIRTIN_PRECEDE_DOWN_YES 0
34 #define VIRTIN_PRECEDE_DOWN_NO 1
35 #define VIRTIN_PRECEDE_DOWN_SYN 2
36
37 enum {
38 VIRTIO_INPUT_CFG_UNSET = 0x00,
39 VIRTIO_INPUT_CFG_ID_NAME = 0x01,
40 VIRTIO_INPUT_CFG_ID_SERIAL = 0x02,
41 VIRTIO_INPUT_CFG_ID_DEVIDS = 0x03,
42 VIRTIO_INPUT_CFG_PROP_BITS = 0x10,
43 VIRTIO_INPUT_CFG_EV_BITS = 0x11,
44 VIRTIO_INPUT_CFG_ABS_INFO = 0x12,
45 };
46
47 struct VirtinAbsinfo {
48 uint32_t min;
49 uint32_t max;
50 uint32_t fuzz;
51 uint32_t flat;
52 uint32_t res;
53 };
54
55 struct VirtinDevids {
56 uint16_t bus;
57 uint16_t vendor;
58 uint16_t product;
59 uint16_t version;
60 };
61
62 struct VirtinConfig {
63 uint8_t select;
64 uint8_t subsel;
65 uint8_t size;
66 #define VIRTIN_PADDINGS 5
67 uint8_t reserved[VIRTIN_PADDINGS];
68 union {
69 #define VIRTIN_PROP_LEN 128
70 char string[VIRTIN_PROP_LEN];
71 uint8_t bitmap[VIRTIN_PROP_LEN];
72 struct VirtinAbsinfo abs;
73 struct VirtinDevids ids;
74 } u;
75 };
76
77 struct VirtinEvent {
78 uint16_t type;
79 uint16_t code;
80 uint32_t value;
81 };
82
83 struct Virtin {
84 struct VirtmmioDev dev;
85 osThreadId_t tid;
86 osSemaphoreId_t sem;
87 struct VirtinEvent ev[VIRTQ_EVENT_QSZ]; /* event receive buffer */
88 };
89 static const InputDevice *g_virtInputDev; /* work thread need this data, using global for simplicity */
90
Feature0(uint32_t features, uint32_t *supported, void *dev)91 static bool Feature0(uint32_t features, uint32_t *supported, void *dev)
92 {
93 (void)features;
94 (void)supported;
95 (void)dev;
96 return true;
97 }
98
Feature1(uint32_t features, uint32_t *supported, void *dev)99 static bool Feature1(uint32_t features, uint32_t *supported, void *dev)
100 {
101 (void)dev;
102 if (features & VIRTIO_F_VERSION_1) {
103 *supported |= VIRTIO_F_VERSION_1;
104 } else {
105 HDF_LOGE("[%s]virtio-mmio input has no VERSION_1 feature", __func__);
106 return false;
107 }
108
109 return true;
110 }
111
PopulateEventQ(const struct Virtin *in)112 static void PopulateEventQ(const struct Virtin *in)
113 {
114 const struct Virtq *q = &in->dev.vq[0];
115 int i;
116
117 for (i = 0; i < VIRTQ_EVENT_QSZ; i++) {
118 q->desc[i].pAddr = u32_to_u64(VMM_TO_DMA_ADDR((VADDR_T)&in->ev[i]));
119 q->desc[i].len = sizeof(struct VirtinEvent);
120 q->desc[i].flag = VIRTQ_DESC_F_WRITE;
121
122 q->avail->ring[i] = i;
123 }
124
125 in->dev.vq[0].avail->index += in->dev.vq[0].qsz;
126 OSAL_WRITEL(0, in->dev.base + VIRTMMIO_REG_QUEUENOTIFY);
127 }
128
129 /*
130 * When VM captures mouse, the event is incomplete. We should filter it
131 * out: a left-button-up event happened with no left-button-down preceded.
132 * We don't know when mouse released, so have to check the signature often.
133 */
VirtinGrabbed(const struct VirtinEvent *ev)134 static bool VirtinGrabbed(const struct VirtinEvent *ev)
135 {
136 static int precedeDown = VIRTIN_PRECEDE_DOWN_NO;
137
138 if (ev->type == EV_KEY && ev->code == BTN_LEFT) {
139 if (ev->value == 1) { /* left-button-down: must already captured */
140 precedeDown = VIRTIN_PRECEDE_DOWN_YES;
141 } else if (precedeDown == VIRTIN_PRECEDE_DOWN_YES) { /* left-button-up: have preceded DOWN, counteract */
142 precedeDown = VIRTIN_PRECEDE_DOWN_NO;
143 } else { /* left-button-up: no preceded DOWN, filter this and successive EV_SYN */
144 precedeDown = VIRTIN_PRECEDE_DOWN_SYN;
145 return false;
146 }
147 }
148 if (precedeDown == VIRTIN_PRECEDE_DOWN_SYN) { /* EV_SYN */
149 precedeDown = VIRTIN_PRECEDE_DOWN_NO;
150 return false;
151 }
152 return true;
153 }
154
VirtinHandleEv(struct Virtin *in)155 static void VirtinHandleEv(struct Virtin *in)
156 {
157 struct Virtq *q = &in->dev.vq[0];
158 uint16_t idx;
159 uint16_t add = 0;
160
161 q->avail->flag = VIRTQ_AVAIL_F_NO_INTERRUPT;
162 while (q->last != q->used->index) {
163 DSB;
164 idx = q->used->ring[q->last % q->qsz].id;
165
166 if (VirtinGrabbed(&in->ev[idx])) {
167 struct VirtinEvent *ev = &in->ev[idx];
168 HidReportEvent(g_virtInputDev, ev->type, ev->code, ev->value);
169 }
170
171 q->avail->ring[(q->avail->index + add++) % q->qsz] = idx;
172 q->last++;
173 }
174 DSB;
175 q->avail->index += add;
176 q->avail->flag = 0;
177
178 if (q->used->flag != VIRTQ_USED_F_NO_NOTIFY) {
179 OSAL_WRITEL(0, in->dev.base + VIRTMMIO_REG_QUEUENOTIFY);
180 }
181 OSAL_WRITEL(VIRTMMIO_IRQ_NOTIFY_USED, in->dev.base + VIRTMMIO_REG_INTERRUPTACK);
182 }
183
VirtinIRQhandle(void *param)184 static uint32_t VirtinIRQhandle(void *param)
185 {
186 struct Virtin *in = (struct Virtin *)param;
187
188 if (!(OSAL_READL(in->dev.base + VIRTMMIO_REG_INTERRUPTSTATUS) & VIRTMMIO_IRQ_NOTIFY_USED)) {
189 return HDF_FAILURE;
190 }
191 osSemaphoreRelease(in->sem);
192 return HDF_SUCCESS;
193 }
194
VirtinFillHidCodeBitmap(struct VirtinConfig *conf, HidInfo *devInfo)195 static bool VirtinFillHidCodeBitmap(struct VirtinConfig *conf, HidInfo *devInfo)
196 {
197 uint8_t *qDest = NULL;
198 uint32_t i, evType, len;
199
200 devInfo->eventType[0] = 0;
201 for (evType = 0; evType < HDF_EV_CNT; evType++) {
202 DSB;
203 conf->select = VIRTIO_INPUT_CFG_EV_BITS;
204 conf->subsel = evType;
205 DSB;
206 if (conf->size == 0) {
207 continue;
208 }
209 switch (evType) {
210 case EV_KEY:
211 len = DIV_ROUND_UP(HDF_KEY_CNT, BYTE_HAS_BITS);
212 qDest = (uint8_t *)devInfo->keyCode;
213 break;
214 case EV_REL:
215 len = DIV_ROUND_UP(HDF_REL_CNT, BYTE_HAS_BITS);
216 qDest = (uint8_t *)devInfo->relCode;
217 break;
218 case EV_ABS:
219 len = DIV_ROUND_UP(HDF_ABS_CNT, BYTE_HAS_BITS);
220 qDest = (uint8_t *)devInfo->absCode;
221 break;
222 default:
223 HDF_LOGE("[%s]unsupported event type: %d", __func__, evType);
224 return false;
225 }
226 devInfo->eventType[0] |= 1 << evType;
227 for (i = 0; i < len && i < VIRTIN_PROP_LEN; i++) {
228 qDest[i] = conf->u.bitmap[i];
229 }
230 }
231
232 return true;
233 }
234
VirtinFillHidDevIds(struct VirtinConfig *conf, HidInfo *devInfo)235 static void VirtinFillHidDevIds(struct VirtinConfig *conf, HidInfo *devInfo)
236 {
237 conf->select = VIRTIO_INPUT_CFG_ID_DEVIDS;
238 conf->subsel = 0;
239 DSB;
240 if (conf->size) {
241 devInfo->bustype = conf->u.ids.bus;
242 devInfo->vendor = conf->u.ids.vendor;
243 devInfo->product = conf->u.ids.product;
244 devInfo->version = conf->u.ids.version;
245 }
246 }
247
VirtinFillHidInfo(const struct Virtin *in, HidInfo *devInfo)248 static bool VirtinFillHidInfo(const struct Virtin *in, HidInfo *devInfo)
249 {
250 struct VirtinConfig *conf = (struct VirtinConfig *)(in->dev.base + VIRTMMIO_REG_CONFIG);
251 uint32_t before, after;
252
253 devInfo->devType = INDEV_TYPE_MOUSE; /* only mouse and keyboard available */
254 devInfo->devName = VIRTMMIO_INPUT_NAME;
255
256 do {
257 before = OSAL_READL(in->dev.base + VIRTMMIO_REG_CONFIGGENERATION);
258
259 VirtinFillHidDevIds(conf, devInfo);
260
261 if (!VirtinFillHidCodeBitmap(conf, devInfo)) {
262 return false;
263 }
264
265 after = OSAL_READL(in->dev.base + VIRTMMIO_REG_CONFIGGENERATION);
266 } while (before != after);
267
268 return true;
269 }
270
HdfVirtinInitHid(struct Virtin *in)271 static int32_t HdfVirtinInitHid(struct Virtin *in)
272 {
273 int32_t ret = HDF_SUCCESS;
274
275 HidInfo *devInfo = OsalMemCalloc(sizeof(HidInfo));
276 if (devInfo == NULL) {
277 HDF_LOGE("[%s]alloc HidInfo memory failed", __func__);
278 return HDF_ERR_MALLOC_FAIL;
279 }
280
281 if (!VirtinFillHidInfo(in, devInfo)) {
282 ret = HDF_ERR_NOT_SUPPORT;
283 goto ERR_OUT;
284 }
285
286 SendInfoToHdf(devInfo);
287
288 g_virtInputDev = HidRegisterHdfInputDev(devInfo);
289 if (g_virtInputDev == NULL) {
290 HDF_LOGE("[%s]register input device failed", __func__);
291 ret = HDF_FAILURE;
292 }
293
294 ERR_OUT:
295 OsalMemFree(devInfo);
296 return ret;
297 }
298
VirtinDeInit(struct Virtin *in)299 static void VirtinDeInit(struct Virtin *in)
300 {
301 if (in->sem) {
302 osSemaphoreDelete(in->sem);
303 in->sem = NULL;
304 }
305
306 if (in->tid) {
307 osThreadTerminate(in->tid);
308 in->tid = NULL;
309 }
310
311 if (in->dev.irq) {
312 LOS_HwiDelete(in->dev.irq, NULL);
313 }
314
315 LOS_MemFree(OS_SYS_MEM_ADDR, in);
316 }
317
VirtinInitDev(void)318 static struct Virtin *VirtinInitDev(void)
319 {
320 struct Virtin *in = NULL;
321 VADDR_T base;
322 uint16_t qsz[VIRTQ_NUM];
323 int32_t ret, len;
324
325 len = sizeof(struct Virtin) + VirtqSize(VIRTQ_EVENT_QSZ) + VirtqSize(VIRTQ_STATUS_QSZ);
326 in = LOS_MemAlloc(OS_SYS_MEM_ADDR, len * sizeof(void *));
327 if (in != NULL) {
328 (void)memset_s(in, len * sizeof(void *), 0, len * sizeof(void *));
329 } else {
330 HDF_LOGE("[%s]alloc virtio-input memory failed", __func__);
331 return NULL;
332 }
333
334 if (!VirtmmioDiscover(VIRTMMIO_DEVICE_ID_INPUT, &in->dev)) {
335 goto ERR_OUT;
336 }
337
338 VirtmmioInitBegin(&in->dev);
339
340 if (!VirtmmioNegotiate(&in->dev, Feature0, Feature1, in)) {
341 goto ERR_OUT1;
342 }
343
344 base = ALIGN((VADDR_T)in + sizeof(struct Virtin), VIRTQ_ALIGN_DESC);
345 qsz[0] = VIRTQ_EVENT_QSZ;
346 qsz[1] = VIRTQ_STATUS_QSZ;
347 if (VirtmmioConfigQueue(&in->dev, base, qsz, VIRTQ_NUM) == 0) {
348 goto ERR_OUT1;
349 }
350
351 if (!VirtmmioRegisterIRQ(&in->dev, (HWI_PROC_FUNC)VirtinIRQhandle, in, VIRTMMIO_INPUT_NAME)) {
352 HDF_LOGE("[%s]register IRQ failed: %d", __func__, ret);
353 goto ERR_OUT1;
354 }
355
356 return in;
357
358 ERR_OUT1:
359 VirtmmioInitFailed(&in->dev);
360 ERR_OUT:
361 VirtinDeInit(in);
362 return NULL;
363 }
364
InputWorkTask(void *arg)365 static int32_t InputWorkTask(void *arg)
366 {
367 struct Virtin *in = (struct Virtin *)arg;
368
369 while (1) {
370 int32_t r = osSemaphoreAcquire(in->sem, osWaitForever);
371 if (r != 0) {
372 continue;
373 }
374 VirtinHandleEv(in);
375 }
376 return HDF_FAILURE;
377 }
378
HdfVirtinInit(struct HdfDeviceObject *device)379 static int32_t HdfVirtinInit(struct HdfDeviceObject *device)
380 {
381 struct Virtin *in = NULL;
382 int32_t ret;
383
384 if (device == NULL) {
385 HDF_LOGE("[%s]device is null", __func__);
386 return HDF_ERR_INVALID_PARAM;
387 }
388
389 if ((in = VirtinInitDev()) == NULL) {
390 return HDF_FAILURE;
391 }
392 device->priv = in;
393
394 if ((ret = HdfVirtinInitHid(in)) != HDF_SUCCESS) {
395 VirtinDeInit(in);
396 return ret;
397 }
398
399 in->sem = osSemaphoreNew(1, 0, NULL);
400 if (in->sem == NULL) {
401 HDF_LOGE("%s: osSemaphoreNew failed", __func__);
402 VirtinDeInit(in);
403 return HDF_FAILURE;
404 }
405
406 osThreadAttr_t attr = {0};
407 attr.stack_size = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
408 attr.priority = osPriorityNormal;
409 attr.name = "InputWorkTask";
410 in->tid = osThreadNew((osThreadFunc_t)InputWorkTask, in, &attr);
411 if (in->tid == NULL) {
412 HDF_LOGE("%s: osThreadNew failed", __func__);
413 VirtinDeInit(in);
414 return HDF_FAILURE;
415 }
416
417 PopulateEventQ(in);
418 VritmmioInitEnd(&in->dev); /* now virt queue can be used */
419 return HDF_SUCCESS;
420 }
421
HdfVirtinRelease(struct HdfDeviceObject *deviceObject)422 static void HdfVirtinRelease(struct HdfDeviceObject *deviceObject)
423 {
424 if (deviceObject == NULL) {
425 return;
426 }
427
428 struct Virtin *in = deviceObject->priv;
429 if (in == NULL) {
430 return;
431 }
432
433 if (g_virtInputDev) {
434 HidUnregisterHdfInputDev(g_virtInputDev);
435 }
436 VirtinDeInit(in);
437 }
438
439 struct HdfDriverEntry g_virtInputEntry = {
440 .moduleVersion = 1,
441 .moduleName = "HDF_VIRTIO_MOUSE",
442 .Init = HdfVirtinInit,
443 .Release = HdfVirtinRelease,
444 };
445
446 HDF_INIT(g_virtInputEntry);
447
GetHdfDeviceObject(void)448 struct HdfDeviceObject *GetHdfDeviceObject(void)
449 {
450 if(g_virtInputDev != NULL){
451 return g_virtInputDev->hdfDevObj;
452 }
453 return NULL;
454 }
455