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