xref: /haiku/src/add-ons/kernel/busses/random/ccp/ccp.cpp (revision 52c4471a3024d2eb81fe88e2c3982b9f8daa5e56)
1 /*
2  * Copyright 2022, Jérôme Duval, jerome.duval@gmail.com.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include <new>
8 #include <stdio.h>
9 #include <string.h>
10 
11 #include <condition_variable.h>
12 #include <dpc.h>
13 
14 #include "random.h"
15 
16 #include "ccp.h"
17 
18 
19 #define CCP_REG_TRNG	0xc
20 
21 
22 device_manager_info* gDeviceManager;
23 random_for_controller_interface *gRandom;
24 dpc_module_info *gDPC;
25 
26 
27 static void
28 handleDPC(void *arg)
29 {
30 	CALLED();
31 	ccp_device_info* bus = reinterpret_cast<ccp_device_info*>(arg);
32 
33 	uint32 lowValue = read32(bus->registers + CCP_REG_TRNG);
34 	uint32 highValue = read32(bus->registers + CCP_REG_TRNG);
35 	if (lowValue == 0 || highValue == 0)
36 		return;
37 	gRandom->queue_randomness((uint64)lowValue | ((uint64)highValue << 32));
38 }
39 
40 
41 static int32
42 handleTimerHook(struct timer* timer)
43 {
44 	ccp_device_info* bus = reinterpret_cast<ccp_device_info*>(timer->user_data);
45 
46 	gDPC->queue_dpc(bus->dpcHandle, handleDPC, bus);
47 	return B_HANDLED_INTERRUPT;
48 }
49 
50 
51 //	#pragma mark -
52 
53 
54 static status_t
55 register_device(device_node* parent)
56 {
57 	device_attr attrs[] = {
58 		{B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {.string = "CCP device"}},
59 		{B_DEVICE_BUS, B_STRING_TYPE, {.string = "CCP"}},
60 		{}
61 	};
62 
63 	return gDeviceManager->register_node(parent,
64 		CCP_DEVICE_MODULE_NAME, attrs, NULL, NULL);
65 }
66 
67 
68 static status_t
69 init_bus(device_node* node, void** bus_cookie)
70 {
71 	CALLED();
72 
73 	driver_module_info* driver;
74 	ccp_device_info* bus;
75 	device_node* parent = gDeviceManager->get_parent_node(node);
76 	gDeviceManager->get_driver(parent, &driver, (void**)&bus);
77 	gDeviceManager->put_node(parent);
78 
79 	TRACE_ALWAYS("init_bus() addr 0x%" B_PRIxPHYSADDR " size 0x%" B_PRIx64
80 		" \n", bus->base_addr, bus->map_size);
81 
82 	bus->registersArea = map_physical_memory("CCP memory mapped registers",
83 		bus->base_addr, bus->map_size, B_ANY_KERNEL_ADDRESS,
84 		B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA,
85 		(void **)&bus->registers);
86 	if (bus->registersArea < 0)
87 		return bus->registersArea;
88 
89 	status_t status = gDPC->new_dpc_queue(&bus->dpcHandle, "ccp timer",
90 		B_LOW_PRIORITY);
91 	if (status != B_OK) {
92 		ERROR("dpc setup failed (%s)\n", strerror(status));
93 		return status;
94 	}
95 
96 	bus->extractTimer.user_data = bus;
97 	status = add_timer(&bus->extractTimer, &handleTimerHook, 1 * 1000 * 1000, B_PERIODIC_TIMER);
98 	if (status != B_OK) {
99 		ERROR("timer setup failed (%s)\n", strerror(status));
100 		return status;
101 	}
102 
103 	// trigger also now
104 	gDPC->queue_dpc(bus->dpcHandle, handleDPC, bus);
105 
106 	*bus_cookie = bus;
107 	return B_OK;
108 
109 }
110 
111 
112 static void
113 uninit_bus(void* bus_cookie)
114 {
115 	ccp_device_info* bus = (ccp_device_info*)bus_cookie;
116 
117 	cancel_timer(&bus->extractTimer);
118 	gDPC->delete_dpc_queue(&bus->dpcHandle);
119 
120 	if (bus->registersArea >= 0)
121 		delete_area(bus->registersArea);
122 
123 }
124 
125 
126 //	#pragma mark -
127 
128 
129 module_dependency module_dependencies[] = {
130 	{ B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&gDeviceManager },
131 	{ RANDOM_FOR_CONTROLLER_MODULE_NAME, (module_info**)&gRandom },
132 	{ B_DPC_MODULE_NAME, (module_info **)&gDPC },
133 	{}
134 };
135 
136 
137 static driver_module_info sCcpDeviceModule = {
138 	{
139 		CCP_DEVICE_MODULE_NAME,
140 		0,
141 		NULL
142 	},
143 
144 	NULL,	// supports device
145 	register_device,
146 	init_bus,
147 	uninit_bus,
148 	NULL,	// register child devices
149 	NULL,	// rescan
150 	NULL, 	// device removed
151 };
152 
153 
154 module_info* modules[] = {
155 	(module_info* )&gCcpAcpiDevice,
156 	(module_info* )&sCcpDeviceModule,
157 	(module_info* )&gCcpPciDevice,
158 	NULL
159 };
160