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