1/*
2 * Copyright 2002-2013, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		J��r��me Duval, korli@berlios.de
7 *		Axel D��rfler, axeld@pinc-software.de
8 *		David Reid
9 */
10
11
12#include <stdio.h>
13
14#include <device_manager.h>
15#include <Drivers.h>
16#include <generic_syscall.h>
17#include <kernel.h>
18#include <malloc.h>
19#include <random_defs.h>
20#include <string.h>
21#include <util/AutoLock.h>
22
23#include "yarrow_rng.h"
24
25
26//#define TRACE_DRIVER
27#ifdef TRACE_DRIVER
28#	define TRACE(x...) dprintf("random: " x)
29#else
30#	define TRACE(x...) ;
31#endif
32#define CALLED() 			TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
33
34
35#define	RANDOM_DRIVER_MODULE_NAME "bus_managers/random/driver_v1"
36#define RANDOM_DEVICE_MODULE_NAME "bus_managers/random/device_v1"
37
38
39static mutex sRandomLock;
40static void *sRandomCookie;
41device_manager_info* gDeviceManager;
42
43
44typedef struct {
45	device_node*			node;
46} random_driver_info;
47
48
49static status_t
50random_queue_randomness(uint64 value)
51{
52	MutexLocker locker(&sRandomLock);
53	RANDOM_ENQUEUE(value);
54	return B_OK;
55}
56
57
58//	#pragma mark - device module API
59
60
61static status_t
62random_init_device(void* _info, void** _cookie)
63{
64	return B_OK;
65}
66
67
68static void
69random_uninit_device(void* _cookie)
70{
71}
72
73
74static status_t
75random_open(void *deviceCookie, const char *name, int flags, void **cookie)
76{
77	TRACE("open(\"%s\")\n", name);
78	return B_OK;
79}
80
81
82static status_t
83random_read(void *cookie, off_t position, void *_buffer, size_t *_numBytes)
84{
85	TRACE("read(%lld,, %ld)\n", position, *_numBytes);
86
87	MutexLocker locker(&sRandomLock);
88	return RANDOM_READ(sRandomCookie, _buffer, _numBytes);
89}
90
91
92static status_t
93random_write(void *cookie, off_t position, const void *buffer, size_t *_numBytes)
94{
95	TRACE("write(%lld,, %ld)\n", position, *_numBytes);
96	MutexLocker locker(&sRandomLock);
97	return RANDOM_WRITE(sRandomCookie, buffer, _numBytes);
98}
99
100
101static status_t
102random_control(void *cookie, uint32 op, void *arg, size_t length)
103{
104	TRACE("ioctl(%ld)\n", op);
105	return B_ERROR;
106}
107
108
109static status_t
110random_generic_syscall(const char* subsystem, uint32 function, void* buffer,
111	size_t bufferSize)
112{
113	switch (function) {
114		case RANDOM_GET_ENTROPY:
115		{
116			random_get_entropy_args args;
117			if (bufferSize != sizeof(args) || !IS_USER_ADDRESS(buffer))
118				return B_BAD_VALUE;
119
120			if (user_memcpy(&args, buffer, sizeof(args)) != B_OK)
121				return B_BAD_ADDRESS;
122			if (!IS_USER_ADDRESS(args.buffer))
123				return B_BAD_ADDRESS;
124
125			status_t result = random_read(NULL, 0, args.buffer, &args.length);
126			if (result < 0)
127				return result;
128
129			return user_memcpy(buffer, &args, sizeof(args));
130		}
131	}
132	return B_BAD_HANDLER;
133}
134
135
136static status_t
137random_close(void *cookie)
138{
139	TRACE("close()\n");
140	return B_OK;
141}
142
143
144static status_t
145random_free(void *cookie)
146{
147	TRACE("free()\n");
148	return B_OK;
149}
150
151
152static status_t
153random_select(void *cookie, uint8 event, selectsync *sync)
154{
155	TRACE("select()\n");
156
157	if (event == B_SELECT_READ) {
158		/* tell there is already data to read */
159		notify_select_event(sync, event);
160	} else if (event == B_SELECT_WRITE) {
161		/* we're now writable */
162		notify_select_event(sync, event);
163	}
164	return B_OK;
165}
166
167
168static status_t
169random_deselect(void *cookie, uint8 event, selectsync *sync)
170{
171	TRACE("deselect()\n");
172	return B_OK;
173}
174
175
176//	#pragma mark - driver module API
177
178
179static float
180random_supports_device(device_node *parent)
181{
182	CALLED();
183	const char *bus;
184
185	// make sure parent is really device root
186	if (gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false))
187		return -1;
188
189	if (strcmp(bus, "root"))
190		return 0.0;
191
192	return 1.0;
193}
194
195
196static status_t
197random_register_device(device_node *node)
198{
199	CALLED();
200
201	// ready to register
202	device_attr attrs[] = {
203		{ B_DEVICE_PRETTY_NAME, B_STRING_TYPE, { .string = "Random" }},
204		{ B_DEVICE_FLAGS, B_UINT32_TYPE, { .ui32 = B_KEEP_DRIVER_LOADED }},
205		{ NULL }
206	};
207
208	return gDeviceManager->register_node(node, RANDOM_DRIVER_MODULE_NAME,
209		attrs, NULL, NULL);
210}
211
212
213static status_t
214random_init_driver(device_node *node, void **cookie)
215{
216	CALLED();
217
218	random_driver_info* info = (random_driver_info*)malloc(
219		sizeof(random_driver_info));
220	if (info == NULL)
221		return B_NO_MEMORY;
222
223	mutex_init(&sRandomLock, "/dev/random lock");
224	RANDOM_INIT();
225
226	memset(info, 0, sizeof(*info));
227
228	info->node = node;
229
230	register_generic_syscall(RANDOM_SYSCALLS, random_generic_syscall, 1, 0);
231
232	*cookie = info;
233	return B_OK;
234}
235
236
237static void
238random_uninit_driver(void *_cookie)
239{
240	CALLED();
241
242	unregister_generic_syscall(RANDOM_SYSCALLS, 1);
243
244	RANDOM_UNINIT();
245
246	mutex_destroy(&sRandomLock);
247
248	random_driver_info* info = (random_driver_info*)_cookie;
249	free(info);
250}
251
252
253static status_t
254random_register_child_devices(void* _cookie)
255{
256	CALLED();
257	random_driver_info* info = (random_driver_info*)_cookie;
258	status_t status = gDeviceManager->publish_device(info->node, "random",
259		RANDOM_DEVICE_MODULE_NAME);
260	if (status == B_OK) {
261		gDeviceManager->publish_device(info->node, "urandom",
262			RANDOM_DEVICE_MODULE_NAME);
263	}
264	return status;
265}
266
267
268//	#pragma mark -
269
270
271module_dependency module_dependencies[] = {
272	{B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&gDeviceManager},
273	{}
274};
275
276
277struct device_module_info sRandomDevice = {
278	{
279		RANDOM_DEVICE_MODULE_NAME,
280		0,
281		NULL
282	},
283
284	random_init_device,
285	random_uninit_device,
286	NULL, // remove,
287
288	random_open,
289	random_close,
290	random_free,
291	random_read,
292	random_write,
293	NULL,
294	random_control,
295
296	random_select,
297	random_deselect,
298};
299
300
301struct driver_module_info sRandomDriver = {
302	{
303		RANDOM_DRIVER_MODULE_NAME,
304		0,
305		NULL
306	},
307
308	random_supports_device,
309	random_register_device,
310	random_init_driver,
311	random_uninit_driver,
312	random_register_child_devices,
313	NULL,	// rescan
314	NULL,	// removed
315};
316
317
318random_for_controller_interface sRandomForControllerModule = {
319	{
320		{
321			RANDOM_FOR_CONTROLLER_MODULE_NAME,
322			0,
323			NULL
324		},
325
326		NULL, // supported devices
327		NULL,
328		NULL,
329		NULL,
330		NULL
331	},
332
333	random_queue_randomness,
334};
335
336
337module_info* modules[] = {
338	(module_info*)&sRandomDriver,
339	(module_info*)&sRandomDevice,
340	(module_info*)&sRandomForControllerModule,
341	NULL
342};
343