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_input_device_manager.h"
19d6aed566Sopenharmony_ci#include "hdf_hid_adapter.h"
20d6aed566Sopenharmony_ci#include "utils/hdf_workqueue.h"
21d6aed566Sopenharmony_ci#include "los_vm_iomap.h"
22d6aed566Sopenharmony_ci#include "virtmmio.h"
23d6aed566Sopenharmony_ci
24d6aed566Sopenharmony_ci#define VIRTQ_EVENT_QSZ     8
25d6aed566Sopenharmony_ci#define VIRTQ_STATUS_QSZ    1
26d6aed566Sopenharmony_ci#define VIRTMMIO_INPUT_NAME "virtinput"
27d6aed566Sopenharmony_ci
28d6aed566Sopenharmony_ci/*
29d6aed566Sopenharmony_ci * QEMU virtio-tablet coordinates sit in a fixed square:
30d6aed566Sopenharmony_ci#define INPUT_EVENT_ABS_MIN    0x0000
31d6aed566Sopenharmony_ci#define INPUT_EVENT_ABS_MAX    0x7FFF
32d6aed566Sopenharmony_ci */
33d6aed566Sopenharmony_ci#define QEMU_TABLET_LEN        0x8000
34d6aed566Sopenharmony_ci
35d6aed566Sopenharmony_cienum {
36d6aed566Sopenharmony_ci    VIRTIO_INPUT_CFG_UNSET      = 0x00,
37d6aed566Sopenharmony_ci    VIRTIO_INPUT_CFG_ID_NAME    = 0x01,
38d6aed566Sopenharmony_ci    VIRTIO_INPUT_CFG_ID_SERIAL  = 0x02,
39d6aed566Sopenharmony_ci    VIRTIO_INPUT_CFG_ID_DEVIDS  = 0x03,
40d6aed566Sopenharmony_ci    VIRTIO_INPUT_CFG_PROP_BITS  = 0x10,
41d6aed566Sopenharmony_ci    VIRTIO_INPUT_CFG_EV_BITS    = 0x11,
42d6aed566Sopenharmony_ci    VIRTIO_INPUT_CFG_ABS_INFO   = 0x12,
43d6aed566Sopenharmony_ci};
44d6aed566Sopenharmony_ci
45d6aed566Sopenharmony_cistruct VirtinAbsinfo {
46d6aed566Sopenharmony_ci    uint32_t min;
47d6aed566Sopenharmony_ci    uint32_t max;
48d6aed566Sopenharmony_ci    uint32_t fuzz;
49d6aed566Sopenharmony_ci    uint32_t flat;
50d6aed566Sopenharmony_ci    uint32_t res;
51d6aed566Sopenharmony_ci};
52d6aed566Sopenharmony_ci
53d6aed566Sopenharmony_cistruct VirtinDevids {
54d6aed566Sopenharmony_ci    uint16_t bus;
55d6aed566Sopenharmony_ci    uint16_t vendor;
56d6aed566Sopenharmony_ci    uint16_t product;
57d6aed566Sopenharmony_ci    uint16_t version;
58d6aed566Sopenharmony_ci};
59d6aed566Sopenharmony_ci
60d6aed566Sopenharmony_cistruct VirtinConfig {
61d6aed566Sopenharmony_ci    uint8_t select;
62d6aed566Sopenharmony_ci    uint8_t subsel;
63d6aed566Sopenharmony_ci    uint8_t size;
64d6aed566Sopenharmony_ci#define VIRTIN_PADDINGS  5
65d6aed566Sopenharmony_ci    uint8_t reserved[VIRTIN_PADDINGS];
66d6aed566Sopenharmony_ci    union {
67d6aed566Sopenharmony_ci#define VIRTIN_PROP_LEN  128
68d6aed566Sopenharmony_ci        char string[VIRTIN_PROP_LEN];
69d6aed566Sopenharmony_ci        uint8_t bitmap[VIRTIN_PROP_LEN];
70d6aed566Sopenharmony_ci        struct VirtinAbsinfo abs;
71d6aed566Sopenharmony_ci        struct VirtinDevids ids;
72d6aed566Sopenharmony_ci    } u;
73d6aed566Sopenharmony_ci};
74d6aed566Sopenharmony_ci
75d6aed566Sopenharmony_cistruct VirtinEvent {
76d6aed566Sopenharmony_ci    uint16_t type;
77d6aed566Sopenharmony_ci    uint16_t code;
78d6aed566Sopenharmony_ci    uint32_t value;
79d6aed566Sopenharmony_ci};
80d6aed566Sopenharmony_ci
81d6aed566Sopenharmony_cistruct Virtin {
82d6aed566Sopenharmony_ci    struct VirtmmioDev dev;
83d6aed566Sopenharmony_ci
84d6aed566Sopenharmony_ci    struct VirtinEvent ev[VIRTQ_EVENT_QSZ]; /* event receive buffer */
85d6aed566Sopenharmony_ci    HdfWorkQueue wq;                        /* event work-queue */
86d6aed566Sopenharmony_ci};
87d6aed566Sopenharmony_cistatic const InputDevice *g_virtInputDev; /* work thread need this data, using global for simplicity */
88d6aed566Sopenharmony_ci
89d6aed566Sopenharmony_cistatic bool Feature0(uint32_t features, uint32_t *supported, void *dev)
90d6aed566Sopenharmony_ci{
91d6aed566Sopenharmony_ci    (void)features;
92d6aed566Sopenharmony_ci    (void)supported;
93d6aed566Sopenharmony_ci    (void)dev;
94d6aed566Sopenharmony_ci    return true;
95d6aed566Sopenharmony_ci}
96d6aed566Sopenharmony_ci
97d6aed566Sopenharmony_cistatic bool Feature1(uint32_t features, uint32_t *supported, void *dev)
98d6aed566Sopenharmony_ci{
99d6aed566Sopenharmony_ci    (void)dev;
100d6aed566Sopenharmony_ci    if (features & VIRTIO_F_VERSION_1) {
101d6aed566Sopenharmony_ci        *supported |= VIRTIO_F_VERSION_1;
102d6aed566Sopenharmony_ci    } else {
103d6aed566Sopenharmony_ci        HDF_LOGE("[%s]virtio-mmio input has no VERSION_1 feature", __func__);
104d6aed566Sopenharmony_ci        return false;
105d6aed566Sopenharmony_ci    }
106d6aed566Sopenharmony_ci
107d6aed566Sopenharmony_ci    return true;
108d6aed566Sopenharmony_ci}
109d6aed566Sopenharmony_ci
110d6aed566Sopenharmony_cistatic void PopulateEventQ(const struct Virtin *in)
111d6aed566Sopenharmony_ci{
112d6aed566Sopenharmony_ci    const struct Virtq *q = &in->dev.vq[0];
113d6aed566Sopenharmony_ci    int i;
114d6aed566Sopenharmony_ci
115d6aed566Sopenharmony_ci    for (i = 0; i < VIRTQ_EVENT_QSZ; i++) {
116d6aed566Sopenharmony_ci        q->desc[i].pAddr = VMM_TO_DMA_ADDR((VADDR_T)&in->ev[i]);
117d6aed566Sopenharmony_ci        q->desc[i].len = sizeof(struct VirtinEvent);
118d6aed566Sopenharmony_ci        q->desc[i].flag = VIRTQ_DESC_F_WRITE;
119d6aed566Sopenharmony_ci
120d6aed566Sopenharmony_ci        q->avail->ring[i] = i;
121d6aed566Sopenharmony_ci    }
122d6aed566Sopenharmony_ci
123d6aed566Sopenharmony_ci    in->dev.vq[0].avail->index += in->dev.vq[0].qsz;
124d6aed566Sopenharmony_ci    OSAL_WRITEL(0, in->dev.base + VIRTMMIO_REG_QUEUENOTIFY);
125d6aed566Sopenharmony_ci}
126d6aed566Sopenharmony_ci
127d6aed566Sopenharmony_cistatic void VirtinWorkCallback(void *arg)
128d6aed566Sopenharmony_ci{
129d6aed566Sopenharmony_ci    struct VirtinEvent *ev = arg;
130d6aed566Sopenharmony_ci    if (ev->type == EV_ABS) {
131d6aed566Sopenharmony_ci        if (ev->code == ABS_X) {    /* scale to actual screen */
132d6aed566Sopenharmony_ci            ev->value = ev->value * VirtgpuGetXres() / QEMU_TABLET_LEN;
133d6aed566Sopenharmony_ci            ev->code = ABS_MT_POSITION_X;   /* OHOS WMS only support this code for EV_ABS */
134d6aed566Sopenharmony_ci        } else if (ev->code == ABS_Y) {
135d6aed566Sopenharmony_ci            ev->value = ev->value * VirtgpuGetYres() / QEMU_TABLET_LEN;
136d6aed566Sopenharmony_ci            ev->code = ABS_MT_POSITION_Y;
137d6aed566Sopenharmony_ci        }
138d6aed566Sopenharmony_ci    }
139d6aed566Sopenharmony_ci    HidReportEvent(g_virtInputDev, ev->type, ev->code, ev->value);
140d6aed566Sopenharmony_ci}
141d6aed566Sopenharmony_ci
142d6aed566Sopenharmony_cistatic void VirtinHandleEv(struct Virtin *in)
143d6aed566Sopenharmony_ci{
144d6aed566Sopenharmony_ci    struct Virtq *q = &in->dev.vq[0];
145d6aed566Sopenharmony_ci    uint16_t idx;
146d6aed566Sopenharmony_ci    uint16_t add = 0;
147d6aed566Sopenharmony_ci    HdfWork w;
148d6aed566Sopenharmony_ci
149d6aed566Sopenharmony_ci    q->avail->flag = VIRTQ_AVAIL_F_NO_INTERRUPT;
150d6aed566Sopenharmony_ci    while (q->last != q->used->index) {
151d6aed566Sopenharmony_ci        DSB;
152d6aed566Sopenharmony_ci        idx = q->used->ring[q->last % q->qsz].id;
153d6aed566Sopenharmony_ci
154d6aed566Sopenharmony_ci        if (HdfWorkInit(&w, VirtinWorkCallback, &in->ev[idx]) == HDF_SUCCESS) {
155d6aed566Sopenharmony_ci            (void)HdfAddWork(&in->wq, &w);  /* HDF will alloc for 'realwork' */
156d6aed566Sopenharmony_ci        }
157d6aed566Sopenharmony_ci
158d6aed566Sopenharmony_ci        q->avail->ring[(q->avail->index + add++) % q->qsz] = idx;
159d6aed566Sopenharmony_ci        q->last++;
160d6aed566Sopenharmony_ci    }
161d6aed566Sopenharmony_ci    DSB;
162d6aed566Sopenharmony_ci    q->avail->index += add;
163d6aed566Sopenharmony_ci    q->avail->flag = 0;
164d6aed566Sopenharmony_ci
165d6aed566Sopenharmony_ci    if (q->used->flag != VIRTQ_USED_F_NO_NOTIFY) {
166d6aed566Sopenharmony_ci        OSAL_WRITEL(0, in->dev.base + VIRTMMIO_REG_QUEUENOTIFY);
167d6aed566Sopenharmony_ci    }
168d6aed566Sopenharmony_ci}
169d6aed566Sopenharmony_ci
170d6aed566Sopenharmony_cistatic uint32_t VirtinIRQhandle(uint32_t swIrq, void *dev)
171d6aed566Sopenharmony_ci{
172d6aed566Sopenharmony_ci    (void)swIrq;
173d6aed566Sopenharmony_ci    struct Virtin *in = dev;
174d6aed566Sopenharmony_ci
175d6aed566Sopenharmony_ci    if (!(OSAL_READL(in->dev.base + VIRTMMIO_REG_INTERRUPTSTATUS) & VIRTMMIO_IRQ_NOTIFY_USED)) {
176d6aed566Sopenharmony_ci        return 1;
177d6aed566Sopenharmony_ci    }
178d6aed566Sopenharmony_ci
179d6aed566Sopenharmony_ci    VirtinHandleEv(in);
180d6aed566Sopenharmony_ci
181d6aed566Sopenharmony_ci    OSAL_WRITEL(VIRTMMIO_IRQ_NOTIFY_USED, in->dev.base + VIRTMMIO_REG_INTERRUPTACK);
182d6aed566Sopenharmony_ci    return 0;
183d6aed566Sopenharmony_ci}
184d6aed566Sopenharmony_ci
185d6aed566Sopenharmony_cistatic void VirtinFillHidAbsInfo(struct VirtinConfig *conf, HidInfo *devInfo)
186d6aed566Sopenharmony_ci{
187d6aed566Sopenharmony_ci    int32_t i;
188d6aed566Sopenharmony_ci
189d6aed566Sopenharmony_ci    for (i = 0; i < HDF_ABS_CNT; i++) {
190d6aed566Sopenharmony_ci        DSB;
191d6aed566Sopenharmony_ci        conf->select = VIRTIO_INPUT_CFG_ABS_INFO;
192d6aed566Sopenharmony_ci        conf->subsel = i;
193d6aed566Sopenharmony_ci        DSB;
194d6aed566Sopenharmony_ci        if (conf->size == 0) {
195d6aed566Sopenharmony_ci            continue;
196d6aed566Sopenharmony_ci        }
197d6aed566Sopenharmony_ci        devInfo->axisInfo[i].axis = i;
198d6aed566Sopenharmony_ci        devInfo->axisInfo[i].min = (int32_t)conf->u.abs.min;
199d6aed566Sopenharmony_ci        devInfo->axisInfo[i].max = (int32_t)conf->u.abs.max;
200d6aed566Sopenharmony_ci        devInfo->axisInfo[i].fuzz = (int32_t)conf->u.abs.fuzz;
201d6aed566Sopenharmony_ci        devInfo->axisInfo[i].flat = (int32_t)conf->u.abs.flat;
202d6aed566Sopenharmony_ci        devInfo->axisInfo[i].range = (int32_t)conf->u.abs.res;
203d6aed566Sopenharmony_ci    }
204d6aed566Sopenharmony_ci}
205d6aed566Sopenharmony_ci
206d6aed566Sopenharmony_cistatic void VirtinFillHidCodeBitmap(struct VirtinConfig *conf, HidInfo *devInfo)
207d6aed566Sopenharmony_ci{
208d6aed566Sopenharmony_ci    uint8_t *qDest = NULL;
209d6aed566Sopenharmony_ci    uint32_t i, evType, len;
210d6aed566Sopenharmony_ci
211d6aed566Sopenharmony_ci    devInfo->eventType[0] = 0;
212d6aed566Sopenharmony_ci    for (evType = 0; evType < HDF_EV_CNT; evType++) {
213d6aed566Sopenharmony_ci        DSB;
214d6aed566Sopenharmony_ci        conf->select = VIRTIO_INPUT_CFG_EV_BITS;
215d6aed566Sopenharmony_ci        conf->subsel = evType;
216d6aed566Sopenharmony_ci        DSB;
217d6aed566Sopenharmony_ci        if (conf->size == 0) {
218d6aed566Sopenharmony_ci            continue;
219d6aed566Sopenharmony_ci        }
220d6aed566Sopenharmony_ci        switch (evType) {
221d6aed566Sopenharmony_ci            case EV_KEY:
222d6aed566Sopenharmony_ci                len = DIV_ROUND_UP(HDF_KEY_CNT, BYTE_HAS_BITS);
223d6aed566Sopenharmony_ci                qDest = (uint8_t *)devInfo->keyCode;
224d6aed566Sopenharmony_ci                break;
225d6aed566Sopenharmony_ci            case EV_REL:
226d6aed566Sopenharmony_ci                len = DIV_ROUND_UP(HDF_REL_CNT, BYTE_HAS_BITS);
227d6aed566Sopenharmony_ci                qDest = (uint8_t *)devInfo->relCode;
228d6aed566Sopenharmony_ci                break;
229d6aed566Sopenharmony_ci            case EV_ABS:
230d6aed566Sopenharmony_ci                len = DIV_ROUND_UP(HDF_ABS_CNT, BYTE_HAS_BITS);
231d6aed566Sopenharmony_ci                qDest = (uint8_t *)devInfo->absCode;
232d6aed566Sopenharmony_ci                break;
233d6aed566Sopenharmony_ci            default:
234d6aed566Sopenharmony_ci                HDF_LOGW("[%s]unsupported event type: %d", __func__, evType);
235d6aed566Sopenharmony_ci                continue;
236d6aed566Sopenharmony_ci        }
237d6aed566Sopenharmony_ci        devInfo->eventType[0] |= 1 << evType;
238d6aed566Sopenharmony_ci        for (i = 0; i < len && i < VIRTIN_PROP_LEN; i++) {
239d6aed566Sopenharmony_ci            qDest[i] = conf->u.bitmap[i];
240d6aed566Sopenharmony_ci        }
241d6aed566Sopenharmony_ci    }
242d6aed566Sopenharmony_ci}
243d6aed566Sopenharmony_ci
244d6aed566Sopenharmony_cistatic void VirtinFillHidDevIds(struct VirtinConfig *conf, HidInfo *devInfo)
245d6aed566Sopenharmony_ci{
246d6aed566Sopenharmony_ci    conf->select = VIRTIO_INPUT_CFG_ID_DEVIDS;
247d6aed566Sopenharmony_ci    conf->subsel = 0;
248d6aed566Sopenharmony_ci    DSB;
249d6aed566Sopenharmony_ci    if (conf->size) {
250d6aed566Sopenharmony_ci        devInfo->bustype = conf->u.ids.bus;
251d6aed566Sopenharmony_ci        devInfo->vendor = conf->u.ids.vendor;
252d6aed566Sopenharmony_ci        devInfo->product = conf->u.ids.product;
253d6aed566Sopenharmony_ci        devInfo->version = conf->u.ids.version;
254d6aed566Sopenharmony_ci    }
255d6aed566Sopenharmony_ci}
256d6aed566Sopenharmony_ci
257d6aed566Sopenharmony_cistatic void VirtinFillHidInfo(const struct Virtin *in, HidInfo *devInfo)
258d6aed566Sopenharmony_ci{
259d6aed566Sopenharmony_ci    struct VirtinConfig *conf = (struct VirtinConfig *)(in->dev.base + VIRTMMIO_REG_CONFIG);
260d6aed566Sopenharmony_ci    uint32_t before, after;
261d6aed566Sopenharmony_ci
262d6aed566Sopenharmony_ci    devInfo->devType = INDEV_TYPE_MOUSE;    /* only mouse and keyboard available */
263d6aed566Sopenharmony_ci    devInfo->devName = VIRTMMIO_INPUT_NAME;
264d6aed566Sopenharmony_ci
265d6aed566Sopenharmony_ci    do {
266d6aed566Sopenharmony_ci        before = OSAL_READL(in->dev.base + VIRTMMIO_REG_CONFIGGENERATION);
267d6aed566Sopenharmony_ci
268d6aed566Sopenharmony_ci        VirtinFillHidDevIds(conf, devInfo);
269d6aed566Sopenharmony_ci        VirtinFillHidCodeBitmap(conf, devInfo);
270d6aed566Sopenharmony_ci        VirtinFillHidAbsInfo(conf, devInfo);
271d6aed566Sopenharmony_ci
272d6aed566Sopenharmony_ci        after = OSAL_READL(in->dev.base + VIRTMMIO_REG_CONFIGGENERATION);
273d6aed566Sopenharmony_ci    } while (before != after);
274d6aed566Sopenharmony_ci}
275d6aed566Sopenharmony_ci
276d6aed566Sopenharmony_cistatic int32_t HdfVirtinInitHid(struct Virtin *in)
277d6aed566Sopenharmony_ci{
278d6aed566Sopenharmony_ci    int32_t ret = HDF_SUCCESS;
279d6aed566Sopenharmony_ci
280d6aed566Sopenharmony_ci    HidInfo *devInfo = OsalMemCalloc(sizeof(HidInfo));
281d6aed566Sopenharmony_ci    if (devInfo == NULL) {
282d6aed566Sopenharmony_ci        HDF_LOGE("[%s]alloc HidInfo memory failed", __func__);
283d6aed566Sopenharmony_ci        return HDF_ERR_MALLOC_FAIL;
284d6aed566Sopenharmony_ci    }
285d6aed566Sopenharmony_ci
286d6aed566Sopenharmony_ci    VirtinFillHidInfo(in, devInfo);
287d6aed566Sopenharmony_ci    SendInfoToHdf(devInfo);
288d6aed566Sopenharmony_ci
289d6aed566Sopenharmony_ci    g_virtInputDev = HidRegisterHdfInputDev(devInfo);
290d6aed566Sopenharmony_ci    if (g_virtInputDev == NULL) {
291d6aed566Sopenharmony_ci        HDF_LOGE("[%s]register input device failed", __func__);
292d6aed566Sopenharmony_ci        ret = HDF_FAILURE;
293d6aed566Sopenharmony_ci    }
294d6aed566Sopenharmony_ci
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->dev.irq & ~_IRQ_MASK) {
302d6aed566Sopenharmony_ci        OsalUnregisterIrq(in->dev.irq & _IRQ_MASK, in);
303d6aed566Sopenharmony_ci    }
304d6aed566Sopenharmony_ci    LOS_DmaMemFree(in);
305d6aed566Sopenharmony_ci}
306d6aed566Sopenharmony_ci
307d6aed566Sopenharmony_cistatic struct Virtin *VirtinInitDev(void)
308d6aed566Sopenharmony_ci{
309d6aed566Sopenharmony_ci    struct Virtin *in = NULL;
310d6aed566Sopenharmony_ci    VADDR_T base;
311d6aed566Sopenharmony_ci    uint16_t qsz[VIRTQ_NUM];
312d6aed566Sopenharmony_ci    int32_t ret, len;
313d6aed566Sopenharmony_ci
314d6aed566Sopenharmony_ci    len = sizeof(struct Virtin) + VirtqSize(VIRTQ_EVENT_QSZ) + VirtqSize(VIRTQ_STATUS_QSZ);
315d6aed566Sopenharmony_ci    in = LOS_DmaMemAlloc(NULL, len, sizeof(void *), DMA_CACHE);
316d6aed566Sopenharmony_ci    if (in == NULL) {
317d6aed566Sopenharmony_ci        HDF_LOGE("[%s]alloc virtio-input memory failed", __func__);
318d6aed566Sopenharmony_ci        return NULL;
319d6aed566Sopenharmony_ci    }
320d6aed566Sopenharmony_ci
321d6aed566Sopenharmony_ci    if (!VirtmmioDiscover(VIRTMMIO_DEVICE_ID_INPUT, &in->dev)) {
322d6aed566Sopenharmony_ci        goto ERR_OUT;
323d6aed566Sopenharmony_ci    }
324d6aed566Sopenharmony_ci
325d6aed566Sopenharmony_ci    VirtmmioInitBegin(&in->dev);
326d6aed566Sopenharmony_ci
327d6aed566Sopenharmony_ci    if (!VirtmmioNegotiate(&in->dev, Feature0, Feature1, in)) {
328d6aed566Sopenharmony_ci        goto ERR_OUT1;
329d6aed566Sopenharmony_ci    }
330d6aed566Sopenharmony_ci
331d6aed566Sopenharmony_ci    base = ALIGN((VADDR_T)in + sizeof(struct Virtin), VIRTQ_ALIGN_DESC);
332d6aed566Sopenharmony_ci    qsz[0] = VIRTQ_EVENT_QSZ;
333d6aed566Sopenharmony_ci    qsz[1] = VIRTQ_STATUS_QSZ;
334d6aed566Sopenharmony_ci    if (VirtmmioConfigQueue(&in->dev, base, qsz, VIRTQ_NUM) == 0) {
335d6aed566Sopenharmony_ci        goto ERR_OUT1;
336d6aed566Sopenharmony_ci    }
337d6aed566Sopenharmony_ci
338d6aed566Sopenharmony_ci    ret = OsalRegisterIrq(in->dev.irq, OSAL_IRQF_TRIGGER_NONE, (OsalIRQHandle)VirtinIRQhandle,
339d6aed566Sopenharmony_ci                                                                VIRTMMIO_INPUT_NAME, in);
340d6aed566Sopenharmony_ci    if (ret != HDF_SUCCESS) {
341d6aed566Sopenharmony_ci        HDF_LOGE("[%s]register IRQ failed: %d", __func__, ret);
342d6aed566Sopenharmony_ci        goto ERR_OUT1;
343d6aed566Sopenharmony_ci    }
344d6aed566Sopenharmony_ci    in->dev.irq |= ~_IRQ_MASK;
345d6aed566Sopenharmony_ci
346d6aed566Sopenharmony_ci    return in;
347d6aed566Sopenharmony_ci
348d6aed566Sopenharmony_ciERR_OUT1:
349d6aed566Sopenharmony_ci    VirtmmioInitFailed(&in->dev);
350d6aed566Sopenharmony_ciERR_OUT:
351d6aed566Sopenharmony_ci    VirtinDeInit(in);
352d6aed566Sopenharmony_ci    return NULL;
353d6aed566Sopenharmony_ci}
354d6aed566Sopenharmony_ci
355d6aed566Sopenharmony_cistatic int32_t HdfVirtinInit(struct HdfDeviceObject *device)
356d6aed566Sopenharmony_ci{
357d6aed566Sopenharmony_ci    struct Virtin *in = NULL;
358d6aed566Sopenharmony_ci    int32_t ret;
359d6aed566Sopenharmony_ci
360d6aed566Sopenharmony_ci    if (device == NULL) {
361d6aed566Sopenharmony_ci        HDF_LOGE("[%s]device is null", __func__);
362d6aed566Sopenharmony_ci        return HDF_ERR_INVALID_PARAM;
363d6aed566Sopenharmony_ci    }
364d6aed566Sopenharmony_ci
365d6aed566Sopenharmony_ci    if ((in = VirtinInitDev()) == NULL) {
366d6aed566Sopenharmony_ci        return HDF_FAILURE;
367d6aed566Sopenharmony_ci    }
368d6aed566Sopenharmony_ci    device->priv = in;
369d6aed566Sopenharmony_ci
370d6aed566Sopenharmony_ci    if ((ret = HdfVirtinInitHid(in)) != HDF_SUCCESS) {
371d6aed566Sopenharmony_ci        return ret;
372d6aed566Sopenharmony_ci    }
373d6aed566Sopenharmony_ci
374d6aed566Sopenharmony_ci    if ((ret = HdfWorkQueueInit(&in->wq, VIRTMMIO_INPUT_NAME)) != HDF_SUCCESS) {
375d6aed566Sopenharmony_ci        return ret;
376d6aed566Sopenharmony_ci    }
377d6aed566Sopenharmony_ci
378d6aed566Sopenharmony_ci    PopulateEventQ(in);
379d6aed566Sopenharmony_ci    VritmmioInitEnd(&in->dev);  /* now virt queue can be used */
380d6aed566Sopenharmony_ci    return HDF_SUCCESS;
381d6aed566Sopenharmony_ci}
382d6aed566Sopenharmony_ci
383d6aed566Sopenharmony_cistatic void HdfVirtinRelease(struct HdfDeviceObject *deviceObject)
384d6aed566Sopenharmony_ci{
385d6aed566Sopenharmony_ci    if (deviceObject == NULL) {
386d6aed566Sopenharmony_ci        return;
387d6aed566Sopenharmony_ci    }
388d6aed566Sopenharmony_ci
389d6aed566Sopenharmony_ci    struct Virtin *in = deviceObject->priv;
390d6aed566Sopenharmony_ci    if (in == NULL) {
391d6aed566Sopenharmony_ci        return;
392d6aed566Sopenharmony_ci    }
393d6aed566Sopenharmony_ci
394d6aed566Sopenharmony_ci    if (in->wq.realWorkQueue) {
395d6aed566Sopenharmony_ci        HdfWorkQueueDestroy(&in->wq);
396d6aed566Sopenharmony_ci    }
397d6aed566Sopenharmony_ci    if (g_virtInputDev) {
398d6aed566Sopenharmony_ci        HidUnregisterHdfInputDev(g_virtInputDev);
399d6aed566Sopenharmony_ci    }
400d6aed566Sopenharmony_ci    VirtinDeInit(in);
401d6aed566Sopenharmony_ci}
402d6aed566Sopenharmony_ci
403d6aed566Sopenharmony_cistruct HdfDriverEntry g_virtInputEntry = {
404d6aed566Sopenharmony_ci    .moduleVersion = 1,
405d6aed566Sopenharmony_ci    .moduleName = "HDF_VIRTIO_MOUSE",
406d6aed566Sopenharmony_ci    .Init = HdfVirtinInit,
407d6aed566Sopenharmony_ci    .Release = HdfVirtinRelease,
408d6aed566Sopenharmony_ci};
409d6aed566Sopenharmony_ci
410d6aed566Sopenharmony_ciHDF_INIT(g_virtInputEntry);
411