1/*
2 * Copyright 2013, J��r��me Duval, korli@users.berlios.de.
3 * Copyright 2021, Haiku, Inc. All rights reserved.
4 * Distributed under the terms of the MIT License.
5 */
6
7
8#include <virtio.h>
9#include <virtio_defs.h>
10
11#include <stdio.h>
12#include <string.h>
13#include <stdlib.h>
14#include <new>
15
16#include <kernel.h>
17#include <fs/devfs.h>
18#include <int.h>
19
20#include <virtio_input_driver.h>
21
22#include <AutoDeleter.h>
23#include <AutoDeleterOS.h>
24#include <AutoDeleterDrivers.h>
25#include <debug.h>
26
27
28//#define TRACE_VIRTIO_INPUT
29#ifdef TRACE_VIRTIO_INPUT
30#	define TRACE(x...) dprintf("virtio_input: " x)
31#else
32#	define TRACE(x...) ;
33#endif
34#define ERROR(x...)			dprintf("virtio_input: " x)
35#define CALLED() 			TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
36
37#define VIRTIO_INPUT_DRIVER_MODULE_NAME "drivers/input/virtio_input/driver_v1"
38#define VIRTIO_INPUT_DEVICE_MODULE_NAME "drivers/input/virtio_input/device_v1"
39#define VIRTIO_INPUT_DEVICE_ID_GENERATOR "virtio_input/device_id"
40
41
42struct Packet {
43	VirtioInputPacket data;
44	int32 next;
45};
46
47
48struct VirtioInputDevice {
49	device_node* node;
50	::virtio_device virtio_device;
51	virtio_device_interface* virtio;
52	::virtio_queue virtio_queue;
53
54	uint64 features;
55
56	uint32 packetCnt;
57	int32 freePackets;
58	int32 readyPackets, lastReadyPacket;
59	AreaDeleter packetArea;
60	phys_addr_t physAdr;
61	Packet* packets;
62
63	SemDeleter sem_cb;
64};
65
66
67struct VirtioInputHandle {
68	VirtioInputDevice*		info;
69};
70
71
72device_manager_info* gDeviceManager;
73
74#ifdef TRACE_VIRTIO_INPUT
75static void
76WriteInputPacket(const VirtioInputPacket &pkt)
77{
78	switch (pkt.type) {
79		case kVirtioInputEvSyn:
80			TRACE("syn");
81			break;
82		case kVirtioInputEvKey:
83			TRACE("key, ");
84			switch (pkt.code) {
85				case kVirtioInputBtnLeft:
86					TRACE("left");
87					break;
88				case kVirtioInputBtnRight:
89					TRACE("middle");
90					break;
91				case kVirtioInputBtnMiddle:
92					TRACE("right");
93					break;
94				case kVirtioInputBtnGearDown:
95					TRACE("gearDown");
96					break;
97				case kVirtioInputBtnGearUp:
98					TRACE("gearUp");
99					break;
100				default:
101					TRACE("%d", pkt.code);
102			}
103			break;
104		case kVirtioInputEvRel:
105			TRACE("rel, ");
106			switch (pkt.code) {
107				case kVirtioInputRelX:
108					TRACE("relX");
109					break;
110				case kVirtioInputRelY:
111					TRACE("relY");
112					break;
113				case kVirtioInputRelZ:
114					TRACE("relZ");
115					break;
116				case kVirtioInputRelWheel:
117					TRACE("relWheel");
118					break;
119				default:
120					TRACE("%d", pkt.code);
121			}
122			break;
123		case kVirtioInputEvAbs:
124			TRACE("abs, ");
125			switch (pkt.code) {
126				case kVirtioInputAbsX:
127					TRACE("absX");
128					break;
129				case kVirtioInputAbsY:
130					TRACE("absY");
131					break;
132				case kVirtioInputAbsZ:
133					TRACE("absZ");
134					break;
135				default:
136					TRACE("%d", pkt.code);
137			}
138			break;
139		case kVirtioInputEvRep:
140			TRACE("rep");
141			break;
142		default:
143			TRACE("?(%d)", pkt.type);
144	}
145	switch (pkt.type) {
146		case kVirtioInputEvSyn:
147			break;
148		case kVirtioInputEvKey:
149			TRACE(", ");
150			if (pkt.value == 0) {
151				TRACE("up");
152			} else if (pkt.value == 1) {
153				TRACE("down");
154			} else {
155				TRACE("%" B_PRId32, pkt.value);
156			}
157			break;
158		default:
159			TRACE(", %" B_PRId32, pkt.value);
160	}
161}
162#endif
163
164static void
165InitPackets(VirtioInputDevice* dev, uint32 count)
166{
167	TRACE("InitPackets(%p, %" B_PRIu32 ")\n", dev, count);
168	size_t size = ROUNDUP(sizeof(Packet)*count, B_PAGE_SIZE);
169
170	dev->packetArea.SetTo(create_area("VirtIO input packets",
171		(void**)&dev->packets, B_ANY_KERNEL_ADDRESS, size,
172		B_CONTIGUOUS, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA));
173	if (!dev->packetArea.IsSet()) {
174		ERROR("Unable to set packet area!");
175		return;
176	}
177
178	physical_entry pe;
179	if (get_memory_map(dev->packets, size, &pe, 1) < B_OK) {
180		ERROR("Unable to get memory map for input packets!");
181		return;
182	}
183	dev->physAdr = pe.address;
184	memset(dev->packets, 0, size);
185	dprintf("  size: 0x%" B_PRIxSIZE "\n", size);
186	dprintf("  virt: %p\n", dev->packets);
187	dprintf("  phys: %p\n", (void*)dev->physAdr);
188
189	dev->packetCnt = count;
190
191	dev->freePackets = 0;
192	for (uint32 i = 0; i < dev->packetCnt - 1; i++)
193		dev->packets[i].next = i + 1;
194	dev->packets[dev->packetCnt - 1].next = -1;
195
196	dev->readyPackets = -1;
197	dev->lastReadyPacket = -1;
198}
199
200
201static const physical_entry
202PacketPhysEntry(VirtioInputDevice* dev, Packet* pkt)
203{
204	physical_entry pe;
205	pe.address = dev->physAdr + (uint8*)pkt - (uint8*)dev->packets;
206	pe.size = sizeof(VirtioInputPacket);
207	return pe;
208}
209
210
211static void
212ScheduleReadyPacket(VirtioInputDevice* dev, Packet* pkt)
213{
214	if (dev->readyPackets < 0)
215		dev->readyPackets = pkt - dev->packets;
216	else
217		dev->packets[dev->lastReadyPacket].next = pkt - dev->packets;
218
219	dev->lastReadyPacket = pkt - dev->packets;
220}
221
222
223static Packet*
224ConsumeReadyPacket(VirtioInputDevice* dev)
225{
226	if (dev->readyPackets < 0)
227		return NULL;
228	Packet* pkt = &dev->packets[dev->readyPackets];
229	dev->readyPackets = pkt->next;
230	if (dev->readyPackets < 0)
231		dev->lastReadyPacket = -1;
232	return pkt;
233}
234
235
236static void
237virtio_input_callback(void* driverCookie, void* cookie)
238{
239	CALLED();
240	VirtioInputDevice* dev = (VirtioInputDevice*)cookie;
241
242	Packet* pkt;
243	while (dev->virtio->queue_dequeue(dev->virtio_queue, (void**)&pkt, NULL)) {
244#ifdef TRACE_VIRTIO_INPUT
245		TRACE("%" B_PRIdSSIZE ": ", pkt - dev->packets);
246		WriteInputPacket(pkt->data);
247		TRACE("\n");
248#endif
249		ScheduleReadyPacket(dev, pkt);
250		release_sem_etc(dev->sem_cb.Get(), 1, B_DO_NOT_RESCHEDULE);
251	}
252}
253
254
255//	#pragma mark - device module API
256
257
258static status_t
259virtio_input_init_device(void* _info, void** _cookie)
260{
261	CALLED();
262	VirtioInputDevice* info = (VirtioInputDevice*)_info;
263
264	DeviceNodePutter<&gDeviceManager> parent(
265		gDeviceManager->get_parent_node(info->node));
266
267	gDeviceManager->get_driver(parent.Get(),
268		(driver_module_info **)&info->virtio,
269		(void **)&info->virtio_device);
270
271	info->virtio->negotiate_features(info->virtio_device, 0,
272		&info->features, NULL);
273
274	status_t status = B_OK;
275/*
276	status = info->virtio->read_device_config(
277		info->virtio_device, 0, &info->config,
278		sizeof(struct virtio_blk_config));
279	if (status != B_OK)
280		return status;
281*/
282
283	InitPackets(info, 8);
284
285	status = info->virtio->alloc_queues(info->virtio_device, 1,
286		&info->virtio_queue);
287	if (status != B_OK) {
288		ERROR("queue allocation failed (%s)\n", strerror(status));
289		return status;
290	}
291	TRACE("  queue: %p\n", info->virtio_queue);
292
293	status = info->virtio->queue_setup_interrupt(info->virtio_queue,
294		virtio_input_callback, info);
295	if (status < B_OK)
296		return status;
297
298	for (uint32 i = 0; i < info->packetCnt; i++) {
299		Packet* pkt = &info->packets[i];
300		physical_entry pe = PacketPhysEntry(info, pkt);
301		info->virtio->queue_request(info->virtio_queue, NULL, &pe, pkt);
302	}
303
304	*_cookie = info;
305	return B_OK;
306}
307
308
309static void
310virtio_input_uninit_device(void* _cookie)
311{
312	CALLED();
313	VirtioInputDevice* info = (VirtioInputDevice*)_cookie;
314	(void)info;
315}
316
317
318static status_t
319virtio_input_open(void* _info, const char* path, int openMode, void** _cookie)
320{
321	CALLED();
322	VirtioInputDevice* info = (VirtioInputDevice*)_info;
323
324	ObjectDeleter<VirtioInputHandle>
325		handle(new(std::nothrow) (VirtioInputHandle));
326
327	if (!handle.IsSet())
328		return B_NO_MEMORY;
329
330	handle->info = info;
331
332	*_cookie = handle.Detach();
333	return B_OK;
334}
335
336
337static status_t
338virtio_input_close(void* cookie)
339{
340	CALLED();
341	return B_OK;
342}
343
344
345static status_t
346virtio_input_free(void* cookie)
347{
348	CALLED();
349	ObjectDeleter<VirtioInputHandle> handle((VirtioInputHandle*)cookie);
350	return B_OK;
351}
352
353
354static status_t
355virtio_input_read(void* cookie, off_t pos, void* buffer, size_t* _length)
356{
357	return B_ERROR;
358}
359
360
361static status_t
362virtio_input_write(void* cookie, off_t pos, const void* buffer,
363	size_t* _length)
364{
365	*_length = 0;
366	return B_ERROR;
367}
368
369
370static status_t
371virtio_input_ioctl(void* cookie, uint32 op, void* buffer, size_t length)
372{
373	CALLED();
374
375	VirtioInputHandle* handle = (VirtioInputHandle*)cookie;
376	VirtioInputDevice* info = handle->info;
377	(void)info;
378
379	TRACE("ioctl(op = %" B_PRIu32 ")\n", op);
380
381	switch (op) {
382		case virtioInputRead: {
383			TRACE("virtioInputRead\n");
384			if (buffer == NULL || length < sizeof(VirtioInputPacket))
385				return B_BAD_VALUE;
386
387			status_t res = acquire_sem(info->sem_cb.Get());
388			if (res < B_OK)
389				return res;
390
391			Packet* pkt = ConsumeReadyPacket(info);
392			TRACE("  pkt: %" B_PRIdSSIZE "\n", pkt - info->packets);
393
394			physical_entry pe = PacketPhysEntry(info, pkt);
395			info->virtio->queue_request(info->virtio_queue, NULL, &pe, pkt);
396
397			res = user_memcpy(buffer, pkt, sizeof(Packet));
398			if (res < B_OK)
399				return res;
400
401			return B_OK;
402		}
403	}
404
405	return B_DEV_INVALID_IOCTL;
406}
407
408
409//	#pragma mark - driver module API
410
411
412static float
413virtio_input_supports_device(device_node *parent)
414{
415	CALLED();
416
417	const char *bus;
418	uint16 deviceType;
419
420	// make sure parent is really the Virtio bus manager
421	if (gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false))
422		return -1;
423
424	if (strcmp(bus, "virtio"))
425		return 0.0;
426
427	// check whether it's really a Direct Access Device
428	if (gDeviceManager->get_attr_uint16(parent, VIRTIO_DEVICE_TYPE_ITEM,
429			&deviceType, true) != B_OK || deviceType != kVirtioDevInput)
430		return 0.0;
431
432	TRACE("Virtio input device found!\n");
433
434	return 0.6;
435}
436
437
438static status_t
439virtio_input_register_device(device_node *node)
440{
441	CALLED();
442
443	device_attr attrs[] = {
444		{ B_DEVICE_PRETTY_NAME, B_STRING_TYPE, { .string = "VirtIO input" }},
445		{ NULL }
446	};
447
448	return gDeviceManager->register_node(node, VIRTIO_INPUT_DRIVER_MODULE_NAME,
449		attrs, NULL, NULL);
450}
451
452
453static status_t
454virtio_input_init_driver(device_node *node, void **cookie)
455{
456	CALLED();
457
458	ObjectDeleter<VirtioInputDevice>
459		info(new(std::nothrow) VirtioInputDevice());
460
461	if (!info.IsSet())
462		return B_NO_MEMORY;
463
464	memset(info.Get(), 0, sizeof(*info.Get()));
465
466	info->sem_cb.SetTo(create_sem(0, "virtio_input_cb"));
467	if (!info->sem_cb.IsSet())
468		return info->sem_cb.Get();
469
470	info->node = node;
471
472	*cookie = info.Detach();
473	return B_OK;
474}
475
476
477static void
478virtio_input_uninit_driver(void *_cookie)
479{
480	CALLED();
481	ObjectDeleter<VirtioInputDevice> info((VirtioInputDevice*)_cookie);
482}
483
484
485static status_t
486virtio_input_register_child_devices(void* _cookie)
487{
488	CALLED();
489	VirtioInputDevice* info = (VirtioInputDevice*)_cookie;
490	status_t status;
491
492	int32 id = gDeviceManager->create_id(VIRTIO_INPUT_DEVICE_ID_GENERATOR);
493	if (id < 0)
494		return id;
495
496	char name[64];
497	snprintf(name, sizeof(name), "input/virtio/%" B_PRId32 "/raw", id);
498
499	status = gDeviceManager->publish_device(info->node, name,
500		VIRTIO_INPUT_DEVICE_MODULE_NAME);
501
502	if (status < B_OK) {
503		ERROR("publish_device error: 0x%" B_PRIx32 "(%s) \n", status,
504			strerror(status));
505	}
506
507	return status;
508}
509
510
511//	#pragma mark -
512
513
514module_dependency module_dependencies[] = {
515	{ B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&gDeviceManager },
516	{ NULL }
517};
518
519
520struct device_module_info sVirtioInputDevice = {
521	{
522		VIRTIO_INPUT_DEVICE_MODULE_NAME,
523		0,
524		NULL
525	},
526
527	virtio_input_init_device,
528	virtio_input_uninit_device,
529	NULL, // remove,
530
531	virtio_input_open,
532	virtio_input_close,
533	virtio_input_free,
534	virtio_input_read,
535	virtio_input_write,
536	NULL,
537	virtio_input_ioctl,
538
539	NULL,	// select
540	NULL,	// deselect
541};
542
543struct driver_module_info sVirtioInputDriver = {
544	{
545		VIRTIO_INPUT_DRIVER_MODULE_NAME,
546		0,
547		NULL
548	},
549
550	virtio_input_supports_device,
551	virtio_input_register_device,
552	virtio_input_init_driver,
553	virtio_input_uninit_driver,
554	virtio_input_register_child_devices,
555	NULL,	// rescan
556	NULL,	// removed
557};
558
559module_info* modules[] = {
560	(module_info*)&sVirtioInputDriver,
561	(module_info*)&sVirtioInputDevice,
562	NULL
563};
564