1 /*
2 * Copyright (c) 2006-2023, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2021-11-11 GuEe-GUI the first version
9 */
10
11 #include <rthw.h>
12 #include <rtthread.h>
13 #include <cpuport.h>
14
15 #ifdef RT_USING_VIRTIO_INPUT
16
17 #include <virtio_input.h>
18
_set_bit(rt_uint32_t nr,volatile rt_ubase_t * addr)19 static void _set_bit(rt_uint32_t nr, volatile rt_ubase_t *addr)
20 {
21 rt_ubase_t mask = BIT_MASK(nr);
22 rt_ubase_t *p = ((rt_ubase_t *)addr) + BIT_WORD(nr);
23
24 *p |= mask;
25 }
26
virtio_input_cfg_select(struct virtio_input_device * virtio_input_dev,rt_uint8_t select,rt_uint8_t subsel)27 static rt_ssize_t virtio_input_cfg_select(struct virtio_input_device *virtio_input_dev,
28 rt_uint8_t select, rt_uint8_t subsel)
29 {
30 struct virtio_input_config *config = virtio_input_dev->config;
31
32 rt_hw_dsb();
33 config->select = select;
34 config->subsel = subsel;
35 rt_hw_dsb();
36
37 return config->size;
38 }
39
virtio_input_cfg_bits(struct virtio_input_device * virtio_input_dev,rt_uint8_t select,rt_uint8_t subsel,rt_ubase_t * bits,rt_uint32_t bitcount)40 static void virtio_input_cfg_bits(struct virtio_input_device *virtio_input_dev,
41 rt_uint8_t select, rt_uint8_t subsel, rt_ubase_t *bits, rt_uint32_t bitcount)
42 {
43 int i;
44 rt_uint32_t bit;
45 rt_uint8_t bytes;
46 rt_uint8_t *virtio_bits;
47 void *config_base = virtio_input_dev->config;
48 rt_off_t offset = (rt_size_t)&((struct virtio_input_config *)0)->bitmap;
49
50 bytes = virtio_input_cfg_select(virtio_input_dev, select, subsel);
51
52 if (bytes == 0)
53 {
54 return;
55 }
56
57 if (bitcount > bytes * 8)
58 {
59 bitcount = bytes * 8;
60 }
61
62 /*
63 * Bitmap in virtio config space is a simple stream of bytes,
64 * with the first byte carrying bits 0-7, second bits 8-15 and
65 * so on.
66 */
67 virtio_bits = rt_malloc(bytes);
68
69 if (virtio_bits == RT_NULL)
70 {
71 return;
72 }
73
74 for (i = 0; i < bytes; ++i)
75 {
76 void *buffer = (void *)virtio_bits + i;
77
78 if (virtio_input_dev->virtio_dev.mmio_config->version == 1)
79 {
80 HWREG8(config_base + offset + i) = *((rt_uint8_t *)buffer);
81 }
82 else
83 {
84 rt_memcpy(config_base + offset + i, buffer, sizeof(rt_uint8_t));
85 }
86 }
87
88 for (bit = 0; bit < bitcount; ++bit)
89 {
90 if (virtio_bits[bit / 8] & (1 << (bit % 8)))
91 {
92 _set_bit(bit, bits);
93 }
94 }
95
96 rt_free(virtio_bits);
97
98 if (select == VIRTIO_INPUT_CFG_EV_BITS)
99 {
100 _set_bit(subsel, virtio_input_dev->ev_bit);
101 }
102 }
103
virtio_input_init(rt_device_t dev)104 static rt_err_t virtio_input_init(rt_device_t dev)
105 {
106 int i;
107 rt_uint16_t idx[VIRTIO_INPUT_QUEUE_MAX_SIZE];
108 struct virtio_input_device *virtio_input_dev = (struct virtio_input_device *)dev;
109 struct virtio_device *virtio_dev = &virtio_input_dev->virtio_dev;
110 struct virtq *queue_event, *queue_status;
111
112 virtio_input_cfg_bits(virtio_input_dev, VIRTIO_INPUT_CFG_EV_BITS, EV_KEY, virtio_input_dev->key_bit, KEY_CNT);
113 virtio_input_cfg_bits(virtio_input_dev, VIRTIO_INPUT_CFG_EV_BITS, EV_REL, virtio_input_dev->rel_bit, REL_CNT);
114 virtio_input_cfg_bits(virtio_input_dev, VIRTIO_INPUT_CFG_EV_BITS, EV_ABS, virtio_input_dev->abs_bit, ABS_CNT);
115
116 queue_event = &virtio_dev->queues[VIRTIO_INPUT_QUEUE_EVENT];
117 queue_status = &virtio_dev->queues[VIRTIO_INPUT_QUEUE_STATUS];
118
119 virtio_alloc_desc_chain(virtio_dev, VIRTIO_INPUT_QUEUE_EVENT, queue_event->num, idx);
120 virtio_alloc_desc_chain(virtio_dev, VIRTIO_INPUT_QUEUE_STATUS, queue_status->num, idx);
121
122 for (i = 0; i < queue_event->num; ++i)
123 {
124 rt_uint16_t id = i;
125 void *addr = &virtio_input_dev->recv_events[i];
126
127 virtio_fill_desc(virtio_dev, VIRTIO_INPUT_QUEUE_EVENT, id,
128 VIRTIO_VA2PA(addr), sizeof(struct virtio_input_event), VIRTQ_DESC_F_WRITE, 0);
129
130 virtio_submit_chain(virtio_dev, VIRTIO_INPUT_QUEUE_EVENT, id);
131 }
132 rt_hw_dsb();
133
134 queue_event->avail->flags = 0;
135 queue_status->avail->flags = VIRTQ_AVAIL_F_NO_INTERRUPT;
136
137 virtio_queue_notify(virtio_dev, VIRTIO_INPUT_QUEUE_EVENT);
138
139 return RT_EOK;
140 }
141
virtio_input_read(rt_device_t dev,rt_off_t pos,void * buffer,rt_size_t size)142 static rt_ssize_t virtio_input_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
143 {
144 struct virtio_input_device *virtio_input_dev = (struct virtio_input_device *)dev;
145
146 if (buffer == RT_NULL || pos + size >= virtio_input_dev->virtio_dev.queues[VIRTIO_INPUT_QUEUE_EVENT].num)
147 {
148 return 0;
149 }
150
151 rt_mutex_take(&virtio_input_dev->rw_mutex, RT_WAITING_FOREVER);
152
153 rt_memcpy(buffer, &virtio_input_dev->bcst_events[pos], size);
154
155 rt_mutex_release(&virtio_input_dev->rw_mutex);
156
157 return size;
158 }
159
virtio_input_write(rt_device_t dev,rt_off_t pos,const void * buffer,rt_size_t size)160 static rt_ssize_t virtio_input_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
161 {
162 struct virtio_input_device *virtio_input_dev = (struct virtio_input_device *)dev;
163
164 if (buffer == RT_NULL || pos + size >= virtio_input_dev->virtio_dev.queues[VIRTIO_INPUT_QUEUE_EVENT].num)
165 {
166 return 0;
167 }
168
169 rt_mutex_take(&virtio_input_dev->rw_mutex, RT_WAITING_FOREVER);
170
171 rt_memcpy(&virtio_input_dev->bcst_events[pos], buffer, size);
172
173 rt_mutex_release(&virtio_input_dev->rw_mutex);
174
175 return size;
176 }
177
virtio_input_control(rt_device_t dev,int cmd,void * args)178 static rt_err_t virtio_input_control(rt_device_t dev, int cmd, void *args)
179 {
180 rt_err_t status = RT_EOK;
181 struct virtio_input_device *virtio_input_dev = (struct virtio_input_device *)dev;
182 struct virtio_device *virtio_dev = &virtio_input_dev->virtio_dev;
183 struct virtio_input_config *config = virtio_input_dev->config;
184
185 if (args == RT_NULL)
186 {
187 return -RT_ERROR;
188 }
189
190 switch (cmd)
191 {
192 case VIRTIO_DEVICE_CTRL_INPUT_GET_TYPE:
193
194 *(enum virtio_input_type *)args = virtio_input_dev->type;
195
196 break;
197 case VIRTIO_DEVICE_CTRL_INPUT_BIND_BSCT_HANDLER:
198
199 virtio_input_dev->bsct_handler = args;
200
201 break;
202 case VIRTIO_DEVICE_CTRL_INPUT_GET_ABS_X_INFO:
203
204 virtio_input_cfg_select(virtio_input_dev, VIRTIO_INPUT_CFG_ABS_INFO, VIRTIO_INPUT_ABS_AXIS_X);
205 rt_memcpy(args, config, sizeof(struct virtio_input_config));
206
207 break;
208 case VIRTIO_DEVICE_CTRL_INPUT_GET_ABS_Y_INFO:
209
210 virtio_input_cfg_select(virtio_input_dev, VIRTIO_INPUT_CFG_ABS_INFO, VIRTIO_INPUT_ABS_AXIS_Y);
211 rt_memcpy(args, config, sizeof(struct virtio_input_config));
212
213 break;
214 case VIRTIO_DEVICE_CTRL_INPUT_SET_STATUS:
215 {
216 rt_uint16_t id;
217 void *addr;
218 struct virtq *queue_status = &virtio_dev->queues[VIRTIO_INPUT_QUEUE_STATUS];
219
220 #ifdef RT_USING_SMP
221 rt_base_t level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
222 #endif
223 id = queue_status->avail->idx % queue_status->num;
224 addr = &virtio_input_dev->xmit_events[id];
225
226 rt_memcpy(addr, args, sizeof(struct virtio_input_event));
227
228 virtio_free_desc(virtio_dev, VIRTIO_INPUT_QUEUE_STATUS, id);
229
230 virtio_fill_desc(virtio_dev, VIRTIO_INPUT_QUEUE_STATUS, id,
231 VIRTIO_VA2PA(addr), sizeof(struct virtio_input_event), 0, 0);
232
233 virtio_submit_chain(virtio_dev, VIRTIO_INPUT_QUEUE_STATUS, id);
234
235 virtio_queue_notify(virtio_dev, VIRTIO_INPUT_QUEUE_STATUS);
236
237 virtio_alloc_desc(virtio_dev, VIRTIO_INPUT_QUEUE_STATUS);
238
239 #ifdef RT_USING_SMP
240 rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
241 #endif
242 }
243 break;
244 case VIRTIO_DEVICE_CTRL_INPUT_GET_EV_BIT:
245
246 rt_memcpy(args, virtio_input_dev->ev_bit, sizeof(virtio_input_dev->ev_bit));
247
248 break;
249 case VIRTIO_DEVICE_CTRL_INPUT_GET_KEY_BIT:
250
251 rt_memcpy(args, virtio_input_dev->key_bit, sizeof(virtio_input_dev->key_bit));
252
253 break;
254 case VIRTIO_DEVICE_CTRL_INPUT_GET_REL_BIT:
255
256 rt_memcpy(args, virtio_input_dev->rel_bit, sizeof(virtio_input_dev->rel_bit));
257
258 break;
259 case VIRTIO_DEVICE_CTRL_INPUT_GET_ABS_BIT:
260
261 rt_memcpy(args, virtio_input_dev->abs_bit, sizeof(virtio_input_dev->abs_bit));
262
263 break;
264 default:
265 status = -RT_EINVAL;
266 break;
267 }
268
269 return status;
270 }
271
272 #ifdef RT_USING_DEVICE_OPS
273 const static struct rt_device_ops virtio_input_ops =
274 {
275 virtio_input_init,
276 RT_NULL,
277 RT_NULL,
278 virtio_input_read,
279 virtio_input_write,
280 virtio_input_control
281 };
282 #endif
283
virtio_input_isr(int irqno,void * param)284 static void virtio_input_isr(int irqno, void *param)
285 {
286 struct virtio_input_device *virtio_input_dev = (struct virtio_input_device *)param;
287 struct virtio_device *virtio_dev = &virtio_input_dev->virtio_dev;
288 struct virtq *event_queue = &virtio_dev->queues[VIRTIO_INPUT_QUEUE_EVENT];
289 const char *dev_name = virtio_input_dev->parent.parent.name;
290
291 #ifdef RT_USING_SMP
292 rt_base_t level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
293 #endif
294
295 virtio_interrupt_ack(virtio_dev);
296 rt_hw_dsb();
297
298 while (event_queue->used_idx != event_queue->used->idx)
299 {
300 rt_uint16_t id = event_queue->used->ring[event_queue->used_idx % event_queue->num].id;
301 rt_uint32_t len = event_queue->used->ring[event_queue->used_idx % event_queue->num].len;
302
303 if (len == sizeof(struct virtio_input_event))
304 {
305 struct virtio_input_event *recv_events = &virtio_input_dev->recv_events[id];
306 struct virtio_input_event *bcst_events = &virtio_input_dev->bcst_events[id];
307
308 if (recv_events->type >= EV_SYN && recv_events->type <= EV_ABS)
309 {
310 bcst_events->type = recv_events->type;
311 bcst_events->code = recv_events->code;
312 bcst_events->value = recv_events->value;
313
314 if (virtio_input_dev->bsct_handler != RT_NULL)
315 {
316 virtio_input_dev->bsct_handler(*bcst_events);
317 }
318 }
319 else
320 {
321 rt_kprintf("%s: Unsupport event[type: %02x, code: %02x, value: %08x]!\n",
322 dev_name, recv_events->type, recv_events->code, recv_events->value);
323 }
324 }
325 else
326 {
327 rt_kprintf("%s: Invalid event!\n", dev_name);
328 }
329
330 event_queue->used_idx++;
331
332 virtio_submit_chain(virtio_dev, VIRTIO_INPUT_QUEUE_EVENT, id);
333
334 virtio_queue_notify(virtio_dev, VIRTIO_INPUT_QUEUE_EVENT);
335 }
336
337 #ifdef RT_USING_SMP
338 rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
339 #endif
340 }
341
rt_virtio_input_init(rt_ubase_t * mmio_base,rt_uint32_t irq)342 rt_err_t rt_virtio_input_init(rt_ubase_t *mmio_base, rt_uint32_t irq)
343 {
344 rt_uint32_t flag;
345 static int dev_no = 0;
346 char dev_name[RT_NAME_MAX];
347 struct virtio_device *virtio_dev;
348 struct virtio_input_device *virtio_input_dev;
349
350 virtio_input_dev = rt_malloc(sizeof(struct virtio_input_device));
351
352 if (virtio_input_dev == RT_NULL)
353 {
354 goto _alloc_fail;
355 }
356
357 virtio_dev = &virtio_input_dev->virtio_dev;
358 virtio_dev->irq = irq;
359 virtio_dev->mmio_base = mmio_base;
360
361 virtio_input_dev->config = (struct virtio_input_config *)virtio_dev->mmio_config->config;
362 virtio_input_dev->bsct_handler = RT_NULL;
363
364 #ifdef RT_USING_SMP
365 rt_spin_lock_init(&virtio_dev->spinlock);
366 #endif
367
368 virtio_reset_device(virtio_dev);
369 virtio_status_acknowledge_driver(virtio_dev);
370
371 virtio_dev->mmio_config->driver_features = virtio_dev->mmio_config->device_features & ~(
372 (1 << VIRTIO_F_RING_EVENT_IDX) |
373 (1 << VIRTIO_F_RING_INDIRECT_DESC));
374
375 virtio_status_driver_ok(virtio_dev);
376
377 if (virtio_queues_alloc(virtio_dev, 2) != RT_EOK)
378 {
379 goto _alloc_fail;
380 }
381
382 if (virtio_queue_init(virtio_dev, VIRTIO_INPUT_QUEUE_EVENT, VIRTIO_INPUT_EVENT_QUEUE_SIZE) != RT_EOK)
383 {
384 goto _alloc_fail;
385 }
386
387 if (virtio_queue_init(virtio_dev, VIRTIO_INPUT_QUEUE_STATUS, VIRTIO_INPUT_STATUS_QUEUE_SIZE) != RT_EOK)
388 {
389 virtio_queue_destroy(virtio_dev, VIRTIO_INPUT_QUEUE_EVENT);
390
391 goto _alloc_fail;
392 }
393
394 virtio_input_cfg_select(virtio_input_dev, VIRTIO_INPUT_CFG_ID_DEVIDS, 0);
395
396 if (virtio_input_dev->config->ids.product == EV_ABS)
397 {
398 virtio_input_dev->type = VIRTIO_INPUT_TYPE_TABLET;
399
400 virtio_input_dev->parent.type = RT_Device_Class_Touch;
401
402 flag = RT_DEVICE_FLAG_STANDALONE | RT_DEVICE_FLAG_INT_RX;
403 }
404 else
405 {
406 if (virtio_input_dev->config->ids.product == EV_KEY)
407 {
408 virtio_input_dev->type = VIRTIO_INPUT_TYPE_KEYBOARD;
409 }
410 else
411 {
412 virtio_input_dev->type = VIRTIO_INPUT_TYPE_MOUSE;
413 }
414
415 /* Replace it to "KeyBoard" or "Mouse" if support in the future */
416 virtio_input_dev->parent.type = RT_Device_Class_Miscellaneous;
417
418 flag = RT_DEVICE_FLAG_RDWR;
419 }
420 #ifdef RT_USING_DEVICE_OPS
421 virtio_input_dev->parent.ops = &virtio_input_ops;
422 #else
423 virtio_input_dev->parent.init = virtio_input_init;
424 virtio_input_dev->parent.open = RT_NULL;
425 virtio_input_dev->parent.close = RT_NULL;
426 virtio_input_dev->parent.read = virtio_input_read;
427 virtio_input_dev->parent.write = virtio_input_write;
428 virtio_input_dev->parent.control = virtio_input_control;
429 #endif
430
431 rt_snprintf(dev_name, RT_NAME_MAX, "virtio-input%d", dev_no++);
432
433 rt_mutex_init(&virtio_input_dev->rw_mutex, dev_name, RT_IPC_FLAG_PRIO);
434
435 rt_hw_interrupt_install(irq, virtio_input_isr, virtio_input_dev, dev_name);
436 rt_hw_interrupt_umask(irq);
437
438 return rt_device_register((rt_device_t)virtio_input_dev, dev_name, flag);
439
440 _alloc_fail:
441
442 if (virtio_input_dev != RT_NULL)
443 {
444 virtio_queues_free(virtio_dev);
445 rt_free(virtio_input_dev);
446 }
447 return -RT_ENOMEM;
448 }
449 #endif /* RT_USING_VIRTIO_INPUT */
450