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