1/*
2 * Copyright 2013, 2018, J��r��me Duval, jerome.duval@gmail.com.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include "VirtioPrivate.h"
8
9
10device_manager_info *gDeviceManager = NULL;
11
12
13//	#pragma mark -
14
15
16static status_t
17virtio_device_init(device_node *node, void **_device)
18{
19	CALLED();
20	VirtioDevice *device = new(std::nothrow) VirtioDevice(node);
21	if (device == NULL)
22		return B_NO_MEMORY;
23
24	status_t result = device->InitCheck();
25	if (result != B_OK) {
26		ERROR("failed to set up virtio device object\n");
27		delete device;
28		return result;
29	}
30
31	*_device = device;
32	return B_OK;
33}
34
35
36static void
37virtio_device_uninit(void *_device)
38{
39	CALLED();
40	VirtioDevice *device = (VirtioDevice *)_device;
41	delete device;
42}
43
44
45static void
46virtio_device_removed(void *_device)
47{
48	CALLED();
49	//VirtioDevice *device = (VirtioDevice *)_device;
50}
51
52
53//	#pragma mark -
54
55
56status_t
57virtio_negotiate_features(void* _device, uint64 supported,
58		uint64* negotiated, const char* (*get_feature_name)(uint64))
59{
60	CALLED();
61	VirtioDevice *device = (VirtioDevice *)_device;
62
63	return device->NegotiateFeatures(supported, negotiated, get_feature_name);
64}
65
66
67status_t
68virtio_clear_feature(void* _device, uint64 feature)
69{
70	CALLED();
71	VirtioDevice *device = (VirtioDevice *)_device;
72
73	return device->ClearFeature(feature);
74}
75
76
77status_t
78virtio_read_device_config(void* _device, uint8 offset, void* buffer,
79		size_t bufferSize)
80{
81	CALLED();
82	VirtioDevice *device = (VirtioDevice *)_device;
83
84	return device->ReadDeviceConfig(offset, buffer, bufferSize);
85}
86
87
88status_t
89virtio_write_device_config(void* _device, uint8 offset,
90		const void* buffer, size_t bufferSize)
91{
92	CALLED();
93	VirtioDevice *device = (VirtioDevice *)_device;
94
95	return device->WriteDeviceConfig(offset, buffer, bufferSize);
96}
97
98
99status_t
100virtio_alloc_queues(virtio_device _device, size_t count, virtio_queue *queues)
101{
102	CALLED();
103	VirtioDevice *device = (VirtioDevice *)_device;
104	return device->AllocateQueues(count, queues);
105}
106
107
108void
109virtio_free_queues(virtio_device _device)
110{
111	CALLED();
112	VirtioDevice *device = (VirtioDevice *)_device;
113	device->FreeQueues();
114}
115
116
117status_t
118virtio_setup_interrupt(virtio_device _device, virtio_intr_func config_handler,
119	void *driverCookie)
120{
121	CALLED();
122	VirtioDevice *device = (VirtioDevice *)_device;
123	return device->SetupInterrupt(config_handler, driverCookie);
124}
125
126
127status_t
128virtio_free_interrupts(virtio_device _device)
129{
130	CALLED();
131	VirtioDevice *device = (VirtioDevice *)_device;
132	return device->FreeInterrupts();
133}
134
135
136status_t
137virtio_queue_setup_interrupt(virtio_queue _queue, virtio_callback_func handler,
138	void *cookie)
139{
140	CALLED();
141	VirtioQueue *queue = (VirtioQueue *)_queue;
142	return queue->SetupInterrupt(handler, cookie);
143}
144
145
146status_t
147virtio_queue_request_v(virtio_queue _queue, const physical_entry* vector,
148		size_t readVectorCount, size_t writtenVectorCount, void *cookie)
149{
150	CALLED();
151	VirtioQueue *queue = (VirtioQueue *)_queue;
152	return queue->QueueRequest(vector, readVectorCount, writtenVectorCount,
153		cookie);
154}
155
156
157status_t
158virtio_queue_request(virtio_queue _queue, const physical_entry *readEntry,
159		const physical_entry *writtenEntry, void *cookie)
160{
161	physical_entry entries[2];
162	if (readEntry != NULL) {
163		entries[0] = *readEntry;
164		if (writtenEntry != NULL)
165			entries[1] = *writtenEntry;
166	} else if (writtenEntry != NULL)
167		entries[0] = *writtenEntry;
168
169	return virtio_queue_request_v(_queue, entries, readEntry != NULL ? 1 : 0,
170		writtenEntry != NULL? 1 : 0, cookie);
171}
172
173
174bool
175virtio_queue_is_full(virtio_queue _queue)
176{
177	VirtioQueue *queue = (VirtioQueue *)_queue;
178	return queue->IsFull();
179}
180
181
182bool
183virtio_queue_is_empty(virtio_queue _queue)
184{
185	VirtioQueue *queue = (VirtioQueue *)_queue;
186	return queue->IsEmpty();
187}
188
189
190uint16
191virtio_queue_size(virtio_queue _queue)
192{
193	VirtioQueue *queue = (VirtioQueue *)_queue;
194	return queue->Size();
195}
196
197
198bool
199virtio_queue_dequeue(virtio_queue _queue, void** _cookie, uint32* _usedLength)
200{
201	VirtioQueue *queue = (VirtioQueue *)_queue;
202	return queue->Dequeue(_cookie, _usedLength);
203}
204
205
206//	#pragma mark -
207
208
209status_t
210virtio_added_device(device_node *parent)
211{
212	CALLED();
213
214	uint16 deviceType;
215	if (gDeviceManager->get_attr_uint16(parent,
216		VIRTIO_DEVICE_TYPE_ITEM, &deviceType, true) != B_OK) {
217		ERROR("device type missing\n");
218		return B_ERROR;
219	}
220
221	device_attr attributes[] = {
222		// info about device
223		{ B_DEVICE_BUS, B_STRING_TYPE, { .string = "virtio" }},
224		{ VIRTIO_DEVICE_TYPE_ITEM, B_UINT16_TYPE,
225			{ .ui16 = deviceType }},
226		{ NULL }
227	};
228
229	return gDeviceManager->register_node(parent, VIRTIO_DEVICE_MODULE_NAME,
230		attributes, NULL, NULL);
231}
232
233
234status_t
235virtio_queue_interrupt_handler(virtio_sim sim, uint16 queue)
236{
237	VirtioDevice* device = (VirtioDevice*)sim;
238	return device->QueueInterrupt(queue);
239}
240
241
242status_t
243virtio_config_interrupt_handler(virtio_sim sim)
244{
245	VirtioDevice* device = (VirtioDevice*)sim;
246	return device->ConfigInterrupt();
247}
248
249
250static status_t
251std_ops(int32 op, ...)
252{
253	switch (op) {
254		case B_MODULE_INIT:
255		case B_MODULE_UNINIT:
256			return B_OK;
257
258		default:
259			break;
260	}
261
262	return B_ERROR;
263}
264
265
266//	#pragma mark -
267
268
269virtio_device_interface virtio_device_module = {
270	{
271		{
272			VIRTIO_DEVICE_MODULE_NAME,
273			0,
274			std_ops
275		},
276
277		NULL, // supported devices
278		NULL, // register node
279		virtio_device_init,
280		virtio_device_uninit,
281		NULL, // register child devices
282		NULL, // rescan
283		virtio_device_removed,
284		NULL, // suspend
285		NULL, // resume
286	},
287
288	virtio_negotiate_features,
289	virtio_clear_feature,
290	virtio_read_device_config,
291	virtio_write_device_config,
292	virtio_alloc_queues,
293	virtio_free_queues,
294	virtio_setup_interrupt,
295	virtio_free_interrupts,
296	virtio_queue_setup_interrupt,
297	virtio_queue_request,
298	virtio_queue_request_v,
299	virtio_queue_is_full,
300	virtio_queue_is_empty,
301	virtio_queue_size,
302	virtio_queue_dequeue
303};
304
305virtio_for_controller_interface virtio_for_controller_module = {
306	{
307		{
308			VIRTIO_FOR_CONTROLLER_MODULE_NAME,
309			0,
310			&std_ops
311		},
312
313		NULL, // supported devices
314		virtio_added_device,
315		NULL,
316		NULL,
317		NULL
318	},
319
320	virtio_queue_interrupt_handler,
321	virtio_config_interrupt_handler
322};
323
324
325module_dependency module_dependencies[] = {
326	{ B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&gDeviceManager },
327	{}
328};
329
330
331extern struct driver_module_info sVirtioBalloonDriver;
332extern struct driver_module_info sVirtioBalloonDeviceInterface;
333
334
335module_info *modules[] = {
336	(module_info *)&virtio_for_controller_module,
337	(module_info *)&virtio_device_module,
338	(module_info *)&sVirtioBalloonDriver,
339	(module_info *)&sVirtioBalloonDeviceInterface,
340	NULL
341};
342
343