• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "los_queue.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 
86     struct VirtinEvent ev[VIRTQ_EVENT_QSZ]; /* event receive buffer */
87 };
88 static const InputDevice *g_virtInputDev; /* work thread need this data, using global for simplicity */
89 
90 static UINT32 g_queue;
91 
Feature0(uint32_t features,uint32_t * supported,void * dev)92 static bool Feature0(uint32_t features, uint32_t *supported, void *dev)
93 {
94     (void)features;
95     (void)supported;
96     (void)dev;
97     return true;
98 }
99 
Feature1(uint32_t features,uint32_t * supported,void * dev)100 static bool Feature1(uint32_t features, uint32_t *supported, void *dev)
101 {
102     (void)dev;
103     if (features & VIRTIO_F_VERSION_1) {
104         *supported |= VIRTIO_F_VERSION_1;
105     } else {
106         HDF_LOGE("[%s]virtio-mmio input has no VERSION_1 feature", __func__);
107         return false;
108     }
109 
110     return true;
111 }
112 
PopulateEventQ(const struct Virtin * in)113 static void PopulateEventQ(const struct Virtin *in)
114 {
115     const struct Virtq *q = &in->dev.vq[0];
116     int i;
117 
118     for (i = 0; i < VIRTQ_EVENT_QSZ; i++) {
119         q->desc[i].pAddr = u32_to_u64(VMM_TO_DMA_ADDR((VADDR_T)&in->ev[i]));
120         q->desc[i].len = sizeof(struct VirtinEvent);
121         q->desc[i].flag = VIRTQ_DESC_F_WRITE;
122 
123         q->avail->ring[i] = i;
124     }
125 
126     in->dev.vq[0].avail->index += in->dev.vq[0].qsz;
127     OSAL_WRITEL(0, in->dev.base + VIRTMMIO_REG_QUEUENOTIFY);
128 }
129 
VirtinWorkCallback(void * arg)130 static void VirtinWorkCallback(void *arg)
131 {
132     struct VirtinEvent *ev = arg;
133     HidReportEvent(g_virtInputDev, ev->type, ev->code, ev->value);
134 }
135 
136 /*
137  * When VM captures mouse, the event is incomplete. We should filter it
138  * out: a left-button-up event happened with no left-button-down preceded.
139  * We don't know when mouse released, so have to check the signature often.
140  */
VirtinGrabbed(const struct VirtinEvent * ev)141 static bool VirtinGrabbed(const struct VirtinEvent *ev)
142 {
143     static int precedeDown = VIRTIN_PRECEDE_DOWN_NO;
144 
145     if (ev->type == EV_KEY && ev->code == BTN_LEFT) {
146         if (ev->value == 1) {       /* left-button-down: must already captured */
147             precedeDown = VIRTIN_PRECEDE_DOWN_YES;
148         } else if (precedeDown == VIRTIN_PRECEDE_DOWN_YES) {  /* left-button-up: have preceded DOWN, counteract */
149             precedeDown = VIRTIN_PRECEDE_DOWN_NO;
150         } else {                    /* left-button-up: no preceded DOWN, filter this and successive EV_SYN */
151             precedeDown = VIRTIN_PRECEDE_DOWN_SYN;
152             return false;
153         }
154     }
155     if (precedeDown == VIRTIN_PRECEDE_DOWN_SYN) {    /* EV_SYN */
156         precedeDown = VIRTIN_PRECEDE_DOWN_NO;
157         return false;
158     }
159     return true;
160 }
161 
VirtinHandleEv(struct Virtin * in)162 static void VirtinHandleEv(struct Virtin *in)
163 {
164     struct Virtq *q = &in->dev.vq[0];
165     uint16_t idx;
166     uint16_t add = 0;
167 
168     q->avail->flag = VIRTQ_AVAIL_F_NO_INTERRUPT;
169     while (q->last != q->used->index) {
170         DSB;
171         idx = q->used->ring[q->last % q->qsz].id;
172 
173         if (VirtinGrabbed(&in->ev[idx])) {
174             int ret = 0;
175             ret = LOS_QueueWriteCopy(g_queue, &in->ev[idx], sizeof(struct VirtinEvent), 0);
176             if(ret != LOS_OK) {
177                 HDF_LOGE("send message failure, error: %x\n", ret);
178             }
179         }
180 
181         q->avail->ring[(q->avail->index + add++) % q->qsz] = idx;
182         q->last++;
183     }
184     DSB;
185     q->avail->index += add;
186     q->avail->flag = 0;
187 
188     if (q->used->flag != VIRTQ_USED_F_NO_NOTIFY) {
189         OSAL_WRITEL(0, in->dev.base + VIRTMMIO_REG_QUEUENOTIFY);
190     }
191 }
192 
VirtinIRQhandle(HwiIrqParam * param)193 static uint32_t VirtinIRQhandle(HwiIrqParam *param)
194 {
195     struct Virtin *in = param->pDevId;
196 
197     if (!(OSAL_READL(in->dev.base + VIRTMMIO_REG_INTERRUPTSTATUS) & VIRTMMIO_IRQ_NOTIFY_USED)) {
198 
199         return 1;
200     }
201     VirtinHandleEv(in);
202 
203     OSAL_WRITEL(VIRTMMIO_IRQ_NOTIFY_USED, in->dev.base + VIRTMMIO_REG_INTERRUPTACK);
204     return 0;
205 }
206 
VirtinFillHidCodeBitmap(struct VirtinConfig * conf,HidInfo * devInfo)207 static bool VirtinFillHidCodeBitmap(struct VirtinConfig *conf, HidInfo *devInfo)
208 {
209     uint8_t *qDest = NULL;
210     uint32_t i, evType, len;
211 
212     devInfo->eventType[0] = 0;
213     for (evType = 0; evType < HDF_EV_CNT; evType++) {
214         DSB;
215         conf->select = VIRTIO_INPUT_CFG_EV_BITS;
216         conf->subsel = evType;
217         DSB;
218         if (conf->size == 0) {
219             continue;
220         }
221         switch (evType) {
222             case EV_KEY:
223                 len = DIV_ROUND_UP(HDF_KEY_CNT, BYTE_HAS_BITS);
224                 qDest = (uint8_t *)devInfo->keyCode;
225                 break;
226             case EV_REL:
227                 len = DIV_ROUND_UP(HDF_REL_CNT, BYTE_HAS_BITS);
228                 qDest = (uint8_t *)devInfo->relCode;
229                 break;
230             case EV_ABS:
231                 len = DIV_ROUND_UP(HDF_ABS_CNT, BYTE_HAS_BITS);
232                 qDest = (uint8_t *)devInfo->absCode;
233                 break;
234             default:
235                 HDF_LOGE("[%s]unsupported event type: %d", __func__, evType);
236                 return false;
237         }
238         devInfo->eventType[0] |= 1 << evType;
239         for (i = 0; i < len && i < VIRTIN_PROP_LEN; i++) {
240             qDest[i] = conf->u.bitmap[i];
241         }
242     }
243 
244     return true;
245 }
246 
VirtinFillHidDevIds(struct VirtinConfig * conf,HidInfo * devInfo)247 static void VirtinFillHidDevIds(struct VirtinConfig *conf, HidInfo *devInfo)
248 {
249     conf->select = VIRTIO_INPUT_CFG_ID_DEVIDS;
250     conf->subsel = 0;
251     DSB;
252     if (conf->size) {
253         devInfo->bustype = conf->u.ids.bus;
254         devInfo->vendor = conf->u.ids.vendor;
255         devInfo->product = conf->u.ids.product;
256         devInfo->version = conf->u.ids.version;
257     }
258 }
259 
VirtinFillHidInfo(const struct Virtin * in,HidInfo * devInfo)260 static bool VirtinFillHidInfo(const struct Virtin *in, HidInfo *devInfo)
261 {
262     struct VirtinConfig *conf = (struct VirtinConfig *)(in->dev.base + VIRTMMIO_REG_CONFIG);
263     uint32_t before, after;
264 
265     devInfo->devType = INDEV_TYPE_MOUSE;    /* only mouse and keyboard available */
266     devInfo->devName = VIRTMMIO_INPUT_NAME;
267 
268     do {
269         before = OSAL_READL(in->dev.base + VIRTMMIO_REG_CONFIGGENERATION);
270 
271         VirtinFillHidDevIds(conf, devInfo);
272 
273         if (!VirtinFillHidCodeBitmap(conf, devInfo)) {
274             return false;
275         }
276 
277         after = OSAL_READL(in->dev.base + VIRTMMIO_REG_CONFIGGENERATION);
278     } while (before != after);
279 
280     return true;
281 }
282 
HdfVirtinInitHid(struct Virtin * in)283 static int32_t HdfVirtinInitHid(struct Virtin *in)
284 {
285     int32_t ret = HDF_SUCCESS;
286 
287     HidInfo *devInfo = OsalMemCalloc(sizeof(HidInfo));
288     if (devInfo == NULL) {
289         HDF_LOGE("[%s]alloc HidInfo memory failed", __func__);
290         return HDF_ERR_MALLOC_FAIL;
291     }
292 
293     if (!VirtinFillHidInfo(in, devInfo)) {
294         ret = HDF_ERR_NOT_SUPPORT;
295         goto ERR_OUT;
296     }
297 
298     SendInfoToHdf(devInfo);
299 
300     g_virtInputDev = HidRegisterHdfInputDev(devInfo);
301     if (g_virtInputDev == NULL) {
302         HDF_LOGE("[%s]register input device failed", __func__);
303         ret = HDF_FAILURE;
304     }
305 
306 ERR_OUT:
307     OsalMemFree(devInfo);
308     return ret;
309 }
310 
VirtinDeInit(struct Virtin * in)311 static void VirtinDeInit(struct Virtin *in)
312 {
313     if (in->dev.irq) {
314         LOS_HwiDelete(in->dev.irq, NULL);
315     }
316     LOS_MemFree(OS_SYS_MEM_ADDR, in);
317 }
318 
VirtinInitDev(void)319 static struct Virtin *VirtinInitDev(void)
320 {
321     struct Virtin *in = NULL;
322     VADDR_T base;
323     uint16_t qsz[VIRTQ_NUM];
324     int32_t ret, len;
325 
326     len = sizeof(struct Virtin) + VirtqSize(VIRTQ_EVENT_QSZ) + VirtqSize(VIRTQ_STATUS_QSZ);
327     in = LOS_MemAlloc(OS_SYS_MEM_ADDR, len * sizeof(void *));
328     if (in != NULL) {
329         memset_s(in, len * sizeof(void *), 0, len * sizeof(void *));
330     } else {
331         HDF_LOGE("[%s]alloc virtio-input memory failed", __func__);
332         return NULL;
333     }
334 
335     if (!VirtmmioDiscover(VIRTMMIO_DEVICE_ID_INPUT, &in->dev)) {
336         goto ERR_OUT;
337     }
338 
339     VirtmmioInitBegin(&in->dev);
340 
341     if (!VirtmmioNegotiate(&in->dev, Feature0, Feature1, in)) {
342         goto ERR_OUT1;
343     }
344 
345     base = ALIGN((VADDR_T)in + sizeof(struct Virtin), VIRTQ_ALIGN_DESC);
346     qsz[0] = VIRTQ_EVENT_QSZ;
347     qsz[1] = VIRTQ_STATUS_QSZ;
348     if (VirtmmioConfigQueue(&in->dev, base, qsz, VIRTQ_NUM) == 0) {
349         goto ERR_OUT1;
350     }
351 
352     if (!VirtmmioRegisterIRQ(&in->dev, (HWI_PROC_FUNC)VirtinIRQhandle, in, VIRTMMIO_INPUT_NAME)) {
353         HDF_LOGE("[%s]register IRQ failed: %d", __func__, ret);
354         goto ERR_OUT1;
355     }
356 
357     return in;
358 
359 ERR_OUT1:
360     VirtmmioInitFailed(&in->dev);
361 ERR_OUT:
362     VirtinDeInit(in);
363     return NULL;
364 }
365 
WorkTask(void)366 static int32_t WorkTask(void) {
367     UINT32 ret = 0;
368     struct VirtinEvent ev;
369     UINT32 readLen = sizeof(ev);
370 
371     while(1) {
372         ret = LOS_QueueReadCopy(g_queue, &ev, &readLen, 0);
373         if(ret == LOS_OK) {
374             HDF_LOGI("VirtinEvent Type: %d, Code: %d, Value: %d\n",
375                 ev.type, ev.code, ev.value);
376             VirtinWorkCallback(&ev);
377         }
378     }
379 }
380 
HdfVirtinInit(struct HdfDeviceObject * device)381 static int32_t HdfVirtinInit(struct HdfDeviceObject *device)
382 {
383     struct Virtin *in = NULL;
384     int32_t ret;
385 
386     if (device == NULL) {
387         HDF_LOGE("[%s]device is null", __func__);
388         return HDF_ERR_INVALID_PARAM;
389     }
390 
391     if ((in = VirtinInitDev()) == NULL) {
392         return HDF_FAILURE;
393     }
394     device->priv = in;
395 
396     if ((ret = HdfVirtinInitHid(in)) != HDF_SUCCESS) {
397         return ret;
398     }
399 
400     ret = LOS_QueueCreate("queue", 50, &g_queue, 0, sizeof(struct VirtinEvent));
401     if(ret != LOS_OK) {
402         HDF_LOGE("create queue failure, error: %x\n", ret);
403     }
404 
405     LOS_TaskLock();
406     UINT32 g_taskLoId;
407     TSK_INIT_PARAM_S initParam = {0};
408 
409     initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)WorkTask;
410     initParam.usTaskPrio = 9;
411     initParam.pcName = "WorkTask";
412     initParam.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
413 
414     ret = LOS_TaskCreate(&g_taskLoId, &initParam);
415     if (ret != HDF_SUCCESS) {
416         HDF_LOGE("Create Task failed! ERROR: 0x%x\n", ret);
417     }
418     LOS_TaskUnlock();
419 
420     PopulateEventQ(in);
421     VritmmioInitEnd(&in->dev);  /* now virt queue can be used */
422     return HDF_SUCCESS;
423 }
424 
HdfVirtinRelease(struct HdfDeviceObject * deviceObject)425 static void HdfVirtinRelease(struct HdfDeviceObject *deviceObject)
426 {
427     if (deviceObject == NULL) {
428         return;
429     }
430 
431     struct Virtin *in = deviceObject->priv;
432     if (in == NULL) {
433         return;
434     }
435 
436     LOS_QueueDelete(g_queue);
437 
438     if (g_virtInputDev) {
439         HidUnregisterHdfInputDev(g_virtInputDev);
440     }
441     VirtinDeInit(in);
442 }
443 
444 struct HdfDriverEntry g_virtInputEntry = {
445     .moduleVersion = 1,
446     .moduleName = "HDF_VIRTIO_MOUSE",
447     .Init = HdfVirtinInit,
448     .Release = HdfVirtinRelease,
449 };
450 
451 HDF_INIT(g_virtInputEntry);
452 
GetHdfDeviceObject(void)453 struct HdfDeviceObject *GetHdfDeviceObject(void)
454 {
455     if(g_virtInputDev != NULL){
456         return g_virtInputDev->hdfDevObj;
457     }
458     return HDF_FAILURE;
459 }
460