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
22device_manager_info* gDeviceManager;
23random_for_controller_interface *gRandom;
24dpc_module_info *gDPC;
25
26
27static void
28handleDPC(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
41static int32
42handleTimerHook(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
54static status_t
55register_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
68static status_t
69init_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
112static void
113uninit_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
129module_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
137static 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
154module_info* modules[] = {
155	(module_info* )&gCcpAcpiDevice,
156	(module_info* )&sCcpDeviceModule,
157	(module_info* )&gCcpPciDevice,
158	NULL
159};
160