xref: /haiku/src/add-ons/kernel/drivers/display/display_adapter.cpp (revision 52c4471a3024d2eb81fe88e2c3982b9f8daa5e56)
1 #include "display_adapter.h"
2 
3 
4 typedef struct acpi_ns_device_info {
5 	device_node *node;
6 	acpi_handle acpi_device;
7 } displayadapter_device_info;
8 
9 
10 device_manager_info *gDeviceManager = NULL;
11 acpi_module_info *gAcpi = NULL;
12 
13 
14 /*
15 
16 TODO: ACPI Spec 5 Appendix B: Implement:
17 _DOS Method to control display output switching
18 (  _DOD Method to retrieve information about child output devices
19 	- You can already do this by listing child devices )
20 _ROM Method to retrieve the ROM image for this device
21 _GPD Method for determining which VGA device will post
22 _SPD Method for controlling which VGA device will post
23 _VPO Method for determining the post options
24 
25 Display cycling notifications
26 
27 */
28 
29 
30 //	#pragma mark - device module API
31 
32 
33 static status_t
34 displayadapter_init_device(void *_cookie, void **cookie)
35 {
36 	device_node *node = (device_node *)_cookie;
37 	displayadapter_device_info *device;
38 //	device_node *parent;
39 
40 //	acpi_objects arguments;
41 //	acpi_object_type argument;
42 
43 	const char *path;
44 	dprintf("%s: start.\n", __func__);
45 
46 
47 	device = (displayadapter_device_info *)calloc(1, sizeof(*device));
48 	if (device == NULL)
49 		return B_NO_MEMORY;
50 
51 	device->node = node;
52 	if (gDeviceManager->get_attr_string(node, ACPI_DEVICE_PATH_ITEM, &path,
53 			false) != B_OK
54 		|| gAcpi->get_handle(NULL, path, &device->acpi_device) != B_OK) {
55 		dprintf("%s: failed to get acpi node.\n", __func__);
56 		free(device);
57 		return B_ERROR;
58 	}
59 /*
60 	argument.object_type = ACPI_TYPE_INTEGER;
61 	argument.integer.integer = BIOS_DISPLAY_SWITCH | BIOS_BRIGHTNESS_CONTROL;
62 	arguments.count = 1;
63 	arguments.pointer = &argument;
64 	if (gAcpi->evaluate_object(&device->acpi_device, "_DOS", &arguments, NULL,
65 			0) != B_OK)
66 		dprintf("%s: failed to set _DOS %s\n", __func__, path);
67 
68 	dprintf("%s: done.\n", __func__);
69 */
70 	*cookie = device;
71 	return B_OK;
72 }
73 
74 
75 static void
76 displayadapter_uninit_device(void *_cookie)
77 {
78 	displayadapter_device_info *device = (displayadapter_device_info *)_cookie;
79 	free(device);
80 }
81 
82 
83 static status_t
84 displayadapter_open(void *_cookie, const char *path, int flags, void** cookie)
85 {
86 	displayadapter_device_info *device = (displayadapter_device_info *)_cookie;
87 	*cookie = device;
88 	return B_OK;
89 }
90 
91 
92 static status_t
93 displayadapter_read(void* _cookie, off_t position, void *buf, size_t* num_bytes)
94 {
95 	return B_ERROR;
96 }
97 
98 
99 static status_t
100 displayadapter_write(void* cookie, off_t position, const void* buffer,
101 	size_t* num_bytes)
102 {
103 	return B_ERROR;
104 }
105 
106 
107 static status_t
108 displayadapter_control(void* _cookie, uint32 op, void* arg, size_t len)
109 {
110 //	displayadapter_device_info* device = (displayadapter_device_info*)_cookie;
111 
112 	return B_ERROR;
113 }
114 
115 
116 static status_t
117 displayadapter_close(void* cookie)
118 {
119 	return B_OK;
120 }
121 
122 
123 static status_t
124 displayadapter_free(void* cookie)
125 {
126 	return B_OK;
127 }
128 
129 
130 //	#pragma mark - driver module API
131 
132 
133 static float
134 displayadapter_support(device_node *parent)
135 {
136 	acpi_handle handle, method;
137 //	acpi_object_type dosType;
138 
139 	const char *bus;
140 	const char *path;
141 	uint32 device_type;
142 
143 	// make sure parent is really the ACPI bus manager
144 	if (gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false))
145 		return -1;
146 
147 	if (strcmp(bus, "acpi"))
148 		return 0.0;
149 
150 	if (gDeviceManager->get_attr_string(parent, ACPI_DEVICE_PATH_ITEM, &path,
151 			false) != B_OK)
152 		return 0.0;
153 
154 	// check whether it's really a device
155 	if (gDeviceManager->get_attr_uint32(parent, ACPI_DEVICE_TYPE_ITEM,
156 			&device_type, false) != B_OK
157 		|| device_type != ACPI_TYPE_DEVICE) {
158 		return 0.0;
159 	}
160 
161 
162 	if (gAcpi->get_handle(NULL, path, &handle) != B_OK)
163 		return 0.0;
164 
165 	if (gAcpi->get_handle(handle, "_DOD", &method) != B_OK ||
166 		gAcpi->get_handle(handle, "_DOS", &method) != B_OK) {// ||
167 //		sAcpi->get_type(method, &dosType) != B_OK ||
168 //		dosType != ACPI_TYPE_METHOD) {
169 		return 0.0;
170 	}
171 
172 	dprintf("%s: found at bus: %s path: %s\n", __func__, bus, path);
173 	return 0.6;
174 }
175 
176 
177 static status_t
178 register_displays(const char *parentName, device_node *node)
179 {
180 	acpi_handle acpiHandle;
181 	const char *path;
182 	device_node *parent = gDeviceManager->get_parent_node(node);
183 	if (gDeviceManager->get_attr_string(parent, ACPI_DEVICE_PATH_ITEM, &path,
184 			false) != B_OK
185 		|| gAcpi->get_handle(NULL, path, &acpiHandle) != B_OK) {
186 		dprintf("%s: failed to get acpi node.\n", __func__);
187 		gDeviceManager->put_node(parent);
188 		return B_ERROR;
189 	}
190 
191 	//get list of ids from _DOD
192 	acpi_object_type *pkgData = (acpi_object_type *)malloc(128);
193 	if (pkgData == NULL)
194 		return B_ERROR;
195 
196 	status_t status = gAcpi->evaluate_object(acpiHandle, "_DOD", NULL, pkgData,
197 		128);
198 	if (status != B_OK || pkgData->object_type != ACPI_TYPE_PACKAGE) {
199 		dprintf("%s: fail. %ld %lu\n", __func__, status, pkgData->object_type);
200 		free(pkgData);
201 		return status;
202 	}
203 
204 	acpi_object_type *displayIDs = pkgData->package.objects;
205 	for (uint32 i = 0; i < pkgData->package.count; i++) {
206 		dprintf("Display ID = %lld\n", displayIDs[i].integer.integer);
207 	}
208 
209 	acpi_object_type result;
210 	acpi_handle child = NULL;
211 	while (gAcpi->get_next_object(ACPI_TYPE_DEVICE, acpiHandle, &child)
212 		== B_OK) {
213 		char name[5] = {0};
214 		//TODO: HARDCODED type.
215 		if(gAcpi->get_name(child, 1, name, 5) == B_OK)
216 			dprintf("name: %s\n", name);
217 		if (gAcpi->evaluate_object(child, "_ADR", NULL, &result, sizeof(result))
218 			!= B_OK)
219 			continue;
220 
221 		dprintf("Child _adr %llu\n", result.integer.integer);
222 		uint32 i;
223 		for (i = 0; i < pkgData->package.count; i++)
224 			if (displayIDs[i].integer.integer == result.integer.integer) break;
225 
226 		if (i == pkgData->package.count) continue;
227 
228 		device_attr attrs[] = {
229 			{ B_DEVICE_PRETTY_NAME, B_STRING_TYPE, { .string = name }},
230 			{ B_DEVICE_FLAGS, B_UINT32_TYPE, { .ui32 = B_KEEP_DRIVER_LOADED }},
231 			{ NULL }
232 
233 		};
234 
235 		device_node* deviceNode;
236 		gDeviceManager->register_node(node, DISPLAY_DEVICE_MODULE_NAME, attrs,
237 				NULL, &deviceNode);
238 
239 		char deviceName[128];
240 		snprintf(deviceName, sizeof(deviceName), "%s/%s", parentName, name);
241 		gDeviceManager->publish_device(parent, deviceName,
242 			DISPLAY_DEVICE_MODULE_NAME);
243 
244 	}
245 	gDeviceManager->put_node(parent);
246 	free(pkgData);
247 	return B_OK;
248 }
249 
250 
251 static status_t
252 displayadapter_register_device(device_node *node)
253 {
254 	device_attr attrs[] = {
255 		{ B_DEVICE_PRETTY_NAME, B_STRING_TYPE, { .string = "Display Adapter" }},
256 		{ B_DEVICE_FLAGS, B_UINT32_TYPE, {
257 			.ui32 = B_KEEP_DRIVER_LOADED | B_FIND_MULTIPLE_CHILDREN }},
258 		{ NULL }
259 	};
260 
261 	return gDeviceManager->register_node(node, DISPLAYADAPTER_MODULE_NAME,
262 		attrs, NULL, NULL);
263 }
264 
265 
266 static status_t
267 displayadapter_init_driver(device_node *node, void **_driverCookie)
268 {
269 	*_driverCookie = node;
270 	return B_OK;
271 }
272 
273 
274 static void
275 displayadapter_uninit_driver(void *driverCookie)
276 {
277 }
278 
279 
280 static status_t
281 displayadapter_register_child_devices(void *_cookie)
282 {
283 	device_node *node = (device_node*)_cookie;
284 
285 	int path_id = gDeviceManager->create_id(DISPLAYADAPTER_PATHID_GENERATOR);
286 	if (path_id < 0) {
287 		dprintf("displayadapter_register_child_devices: error creating path\n");
288 		return B_ERROR;
289 	}
290 
291 	char name[128];
292 	snprintf(name, sizeof(name), DISPLAYADAPTER_BASENAME, path_id);
293 	status_t status = gDeviceManager->publish_device(node, name,
294 		DISPLAYADAPTER_DEVICE_MODULE_NAME);
295 
296 	if (status == B_OK)
297 		register_displays(name, node);
298 
299 	return status;
300 }
301 
302 
303 module_dependency module_dependencies[] = {
304 	{ B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&gDeviceManager },
305 	{ B_ACPI_MODULE_NAME, (module_info **)&gAcpi},
306 	{}
307 };
308 
309 
310 driver_module_info displayadapter_driver_module = {
311 	{
312 		DISPLAYADAPTER_MODULE_NAME,
313 		0,
314 		NULL
315 	},
316 
317 	displayadapter_support,
318 	displayadapter_register_device,
319 	displayadapter_init_driver,
320 	displayadapter_uninit_driver,
321 	displayadapter_register_child_devices,
322 	NULL,	// rescan
323 	NULL,	// removed
324 };
325 
326 
327 device_module_info displayadapter_device_module = {
328 	{
329 		DISPLAYADAPTER_DEVICE_MODULE_NAME,
330 		0,
331 		NULL
332 	},
333 
334 	displayadapter_init_device,
335 	displayadapter_uninit_device,
336 	NULL,
337 
338 	displayadapter_open,
339 	displayadapter_close,
340 	displayadapter_free,
341 	displayadapter_read,
342 	displayadapter_write,
343 	NULL,
344 	displayadapter_control,
345 
346 	NULL,
347 	NULL
348 };
349 
350 
351 module_info *modules[] = {
352 	(module_info *)&display_device_module,
353 	(module_info *)&displayadapter_device_module,
354 	(module_info *)&displayadapter_driver_module,
355 	NULL
356 };
357