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 <ACPI.h>
12#include <ByteOrder.h>
13#include <condition_variable.h>
14
15extern "C" {
16#	include "acpi.h"
17}
18
19
20#define DRIVER_NAME "ccp_rng_acpi"
21#include "ccp.h"
22
23
24typedef struct {
25	ccp_device_info info;
26	acpi_device_module_info* acpi;
27	acpi_device device;
28
29} ccp_acpi_sim_info;
30
31
32struct ccp_crs {
33	uint32	addr_bas;
34	uint32	addr_len;
35};
36
37
38static acpi_status
39ccp_scan_parse_callback(ACPI_RESOURCE *res, void *context)
40{
41	struct ccp_crs* crs = (struct ccp_crs*)context;
42
43	if (res->Type == ACPI_RESOURCE_TYPE_FIXED_MEMORY32) {
44		crs->addr_bas = res->Data.FixedMemory32.Address;
45		crs->addr_len = res->Data.FixedMemory32.AddressLength;
46	}
47
48	return B_OK;
49}
50
51
52//	#pragma mark -
53
54
55static status_t
56init_device(device_node* node, void** device_cookie)
57{
58	CALLED();
59	status_t status = B_OK;
60
61	ccp_acpi_sim_info* bus = (ccp_acpi_sim_info*)calloc(1,
62		sizeof(ccp_acpi_sim_info));
63	if (bus == NULL)
64		return B_NO_MEMORY;
65
66	acpi_device_module_info* acpi;
67	acpi_device device;
68	{
69		device_node* acpiParent = gDeviceManager->get_parent_node(node);
70		gDeviceManager->get_driver(acpiParent, (driver_module_info**)&acpi,
71			(void**)&device);
72		gDeviceManager->put_node(acpiParent);
73	}
74
75	bus->acpi = acpi;
76	bus->device = device;
77
78	struct ccp_crs crs;
79	status = acpi->walk_resources(device, (ACPI_STRING)"_CRS",
80		ccp_scan_parse_callback, &crs);
81	if (status != B_OK) {
82		ERROR("Error while getting resouces\n");
83		free(bus);
84		return status;
85	}
86	if (crs.addr_bas == 0 || crs.addr_len == 0) {
87		TRACE("skipping non configured CCP devices\n");
88		free(bus);
89		return B_BAD_VALUE;
90	}
91
92	bus->info.base_addr = crs.addr_bas;
93	bus->info.map_size = crs.addr_len;
94
95	*device_cookie = bus;
96	return B_OK;
97}
98
99
100static void
101uninit_device(void* device_cookie)
102{
103	ccp_acpi_sim_info* bus = (ccp_acpi_sim_info*)device_cookie;
104	free(bus);
105}
106
107
108static status_t
109register_device(device_node* parent)
110{
111	device_attr attrs[] = {
112		{B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {.string = "CCP ACPI"}},
113		{B_DEVICE_BUS, B_STRING_TYPE, {.string = "CCP"}},
114		{B_DEVICE_FIXED_CHILD, B_STRING_TYPE, {.string = CCP_DEVICE_MODULE_NAME}},
115		{}
116	};
117
118	return gDeviceManager->register_node(parent,
119		CCP_ACPI_DEVICE_MODULE_NAME, attrs, NULL, NULL);
120}
121
122
123static float
124supports_device(device_node* parent)
125{
126	const char* bus;
127
128	// make sure parent is a CCP ACPI device node
129	if (gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false)
130		< B_OK) {
131		return -1;
132	}
133
134	if (strcmp(bus, "acpi") != 0)
135		return 0.0f;
136
137	// check whether it's really a device
138	uint32 device_type;
139	if (gDeviceManager->get_attr_uint32(parent, ACPI_DEVICE_TYPE_ITEM,
140			&device_type, false) != B_OK
141		|| device_type != ACPI_TYPE_DEVICE) {
142		return 0.0;
143	}
144
145	// check whether it's a CCP device
146	const char *name;
147	if (gDeviceManager->get_attr_string(parent, ACPI_DEVICE_HID_ITEM, &name,
148		false) != B_OK) {
149		return 0.0;
150	}
151
152	if (strcmp(name, "AMDI0C00") == 0) {
153		TRACE("CCP device found! name %s\n", name);
154		return 0.6f;
155	}
156
157	return 0.0f;
158}
159
160
161//	#pragma mark -
162
163
164driver_module_info gCcpAcpiDevice = {
165	{
166		CCP_ACPI_DEVICE_MODULE_NAME,
167		0,
168		NULL
169	},
170
171	supports_device,
172	register_device,
173	init_device,
174	uninit_device,
175	NULL,	// register_child_devices,
176	NULL,	// rescan
177	NULL,	// device removed
178};
179
180
181