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