BPicture: Fix archive constructor.
[haiku.git] / src / add-ons / kernel / busses / random / VirtioRNGDevice.cpp
blob2e569c8d387ca6569d3099fca7d4ea2362a1a124
1 /*
2 * Copyright 2013, Jérôme Duval, korli@users.berlios.de.
3 * Distributed under the terms of the MIT License.
4 */
7 #include "VirtioRNGPrivate.h"
9 #include <new>
10 #include <stdlib.h>
11 #include <string.h>
13 #include <util/AutoLock.h>
16 const char *
17 get_feature_name(uint32 feature)
19 switch (feature) {
21 return NULL;
25 VirtioRNGDevice::VirtioRNGDevice(device_node *node)
27 fNode(node),
28 fVirtio(NULL),
29 fVirtioDevice(NULL),
30 fStatus(B_NO_INIT),
31 fOffset(BUFFER_SIZE),
32 fExpectsInterrupt(false)
34 CALLED();
36 B_INITIALIZE_SPINLOCK(&fInterruptLock);
37 fInterruptCondition.Init(this, "virtio rng transfer");
39 get_memory_map(fBuffer, BUFFER_SIZE, &fEntry, 1);
41 // get the Virtio device from our parent's parent
42 device_node *parent = gDeviceManager->get_parent_node(node);
43 device_node *virtioParent = gDeviceManager->get_parent_node(parent);
44 gDeviceManager->put_node(parent);
46 gDeviceManager->get_driver(virtioParent, (driver_module_info **)&fVirtio,
47 (void **)&fVirtioDevice);
48 gDeviceManager->put_node(virtioParent);
50 fVirtio->negociate_features(fVirtioDevice,
51 0, &fFeatures, &get_feature_name);
53 fStatus = fVirtio->alloc_queues(fVirtioDevice, 1, &fVirtioQueue);
54 if (fStatus != B_OK) {
55 ERROR("queue allocation failed (%s)\n", strerror(fStatus));
56 return;
59 fStatus = fVirtio->setup_interrupt(fVirtioDevice, NULL, this);
60 if (fStatus != B_OK) {
61 ERROR("interrupt setup failed (%s)\n", strerror(fStatus));
62 return;
67 VirtioRNGDevice::~VirtioRNGDevice()
72 status_t
73 VirtioRNGDevice::InitCheck()
75 return fStatus;
79 status_t
80 VirtioRNGDevice::Read(void* _buffer, size_t* _numBytes)
82 CALLED();
84 if (fOffset >= BUFFER_SIZE) {
86 InterruptsSpinLocker locker(fInterruptLock);
87 fExpectsInterrupt = true;
88 fInterruptCondition.Add(&fInterruptConditionEntry);
90 status_t result = fVirtio->queue_request(fVirtioQueue, NULL, &fEntry,
91 _RequestCallback, this);
92 if (result != B_OK) {
93 ERROR("queueing failed (%s)\n", strerror(result));
94 return result;
97 result = fInterruptConditionEntry.Wait(B_CAN_INTERRUPT);
100 InterruptsSpinLocker locker(fInterruptLock);
101 fExpectsInterrupt = false;
104 if (result == B_OK) {
105 fOffset = 0;
106 } else if (result != B_INTERRUPTED) {
107 ERROR("request failed (%s)\n", strerror(result));
111 if (fOffset < BUFFER_SIZE) {
112 size_t size = min_c(BUFFER_SIZE - fOffset, *_numBytes);
113 memcpy(_buffer, fBuffer + fOffset, size);
114 fOffset += size;
115 *_numBytes = size;
116 } else
117 *_numBytes = 0;
118 return B_OK;
122 void
123 VirtioRNGDevice::_RequestCallback(void* driverCookie, void* cookie)
125 VirtioRNGDevice* device = (VirtioRNGDevice*)driverCookie;
126 device->_RequestInterrupt();
130 void
131 VirtioRNGDevice::_RequestInterrupt()
133 SpinLocker locker(fInterruptLock);
134 fInterruptCondition.NotifyAll();