• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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