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
35 enum {
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
45 struct VirtinAbsinfo {
46 uint32_t min;
47 uint32_t max;
48 uint32_t fuzz;
49 uint32_t flat;
50 uint32_t res;
51 };
52
53 struct VirtinDevids {
54 uint16_t bus;
55 uint16_t vendor;
56 uint16_t product;
57 uint16_t version;
58 };
59
60 struct 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
75 struct VirtinEvent {
76 uint16_t type;
77 uint16_t code;
78 uint32_t value;
79 };
80
81 struct Virtin {
82 struct VirtmmioDev dev;
83
84 struct VirtinEvent ev[VIRTQ_EVENT_QSZ]; /* event receive buffer */
85 HdfWorkQueue wq; /* event work-queue */
86 };
87 static const InputDevice *g_virtInputDev; /* work thread need this data, using global for simplicity */
88
Feature0(uint32_t features,uint32_t * supported,void * dev)89 static 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
Feature1(uint32_t features,uint32_t * supported,void * dev)97 static 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
PopulateEventQ(const struct Virtin * in)110 static 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
VirtinWorkCallback(void * arg)127 static 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
VirtinHandleEv(struct Virtin * in)142 static 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
VirtinIRQhandle(uint32_t swIrq,void * dev)170 static 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
VirtinFillHidAbsInfo(struct VirtinConfig * conf,HidInfo * devInfo)185 static 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
VirtinFillHidCodeBitmap(struct VirtinConfig * conf,HidInfo * devInfo)206 static 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
VirtinFillHidDevIds(struct VirtinConfig * conf,HidInfo * devInfo)244 static 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
VirtinFillHidInfo(const struct Virtin * in,HidInfo * devInfo)257 static 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
HdfVirtinInitHid(struct Virtin * in)276 static 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
VirtinDeInit(struct Virtin * in)299 static 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
VirtinInitDev(void)307 static 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
348 ERR_OUT1:
349 VirtmmioInitFailed(&in->dev);
350 ERR_OUT:
351 VirtinDeInit(in);
352 return NULL;
353 }
354
HdfVirtinInit(struct HdfDeviceObject * device)355 static 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
HdfVirtinRelease(struct HdfDeviceObject * deviceObject)383 static 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
403 struct HdfDriverEntry g_virtInputEntry = {
404 .moduleVersion = 1,
405 .moduleName = "HDF_VIRTIO_MOUSE",
406 .Init = HdfVirtinInit,
407 .Release = HdfVirtinRelease,
408 };
409
410 HDF_INIT(g_virtInputEntry);
411