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
37enum {
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
47struct VirtinAbsinfo {
48    uint32_t min;
49    uint32_t max;
50    uint32_t fuzz;
51    uint32_t flat;
52    uint32_t res;
53};
54
55struct VirtinDevids {
56    uint16_t bus;
57    uint16_t vendor;
58    uint16_t product;
59    uint16_t version;
60};
61
62struct 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
77struct VirtinEvent {
78    uint16_t type;
79    uint16_t code;
80    uint32_t value;
81};
82
83struct Virtin {
84    struct VirtmmioDev dev;
85    osThreadId_t tid;
86    osSemaphoreId_t sem;
87    struct VirtinEvent ev[VIRTQ_EVENT_QSZ]; /* event receive buffer */
88};
89static const InputDevice *g_virtInputDev; /* work thread need this data, using global for simplicity */
90
91static 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
99static 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
112static 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 */
134static 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
155static 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
184static 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
195static 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
235static 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
248static 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
271static 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
294ERR_OUT:
295    OsalMemFree(devInfo);
296    return ret;
297}
298
299static 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
318static 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
358ERR_OUT1:
359    VirtmmioInitFailed(&in->dev);
360ERR_OUT:
361    VirtinDeInit(in);
362    return NULL;
363}
364
365static 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
379static 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
422static 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
439struct HdfDriverEntry g_virtInputEntry = {
440    .moduleVersion = 1,
441    .moduleName = "HDF_VIRTIO_MOUSE",
442    .Init = HdfVirtinInit,
443    .Release = HdfVirtinRelease,
444};
445
446HDF_INIT(g_virtInputEntry);
447
448struct HdfDeviceObject *GetHdfDeviceObject(void)
449{
450    if(g_virtInputDev != NULL){
451        return g_virtInputDev->hdfDevObj;
452    }
453    return NULL;
454}
455