1/*
2 * Copyright 2006-2018, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Axel D��rfler, axeld@pinc-software.de
7 */
8
9
10#include "driver.h"
11#include "device.h"
12#include "intel_extreme.h"
13#include "utility.h"
14
15#include <OS.h>
16#include <KernelExport.h>
17#include <Drivers.h>
18#include <PCI.h>
19#include <SupportDefs.h>
20#include <graphic_driver.h>
21#include <image.h>
22
23#include <stdlib.h>
24#include <string.h>
25
26
27#define DEBUG_COMMANDS
28
29#define TRACE_DEVICE
30#ifdef TRACE_DEVICE
31#	define TRACE(x...) dprintf("intel_extreme: " x)
32#else
33#	define TRACE(x) ;
34#endif
35
36#define ERROR(x...) dprintf("intel_extreme: " x)
37#define CALLED(x...) TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
38
39
40/* device hooks prototypes */
41
42static status_t device_open(const char* name, uint32 flags, void** _cookie);
43static status_t device_close(void* data);
44static status_t device_free(void* data);
45static status_t device_ioctl(void* data, uint32 opcode, void* buffer,
46	size_t length);
47static status_t device_read(void* data, off_t offset, void* buffer,
48	size_t* length);
49static status_t device_write(void* data, off_t offset, const void* buffer,
50	size_t* length);
51
52
53device_hooks gDeviceHooks = {
54	device_open,
55	device_close,
56	device_free,
57	device_ioctl,
58	device_read,
59	device_write,
60	NULL,
61	NULL,
62	NULL,
63	NULL
64};
65
66
67#ifdef DEBUG_COMMANDS
68static int
69getset_register(int argc, char** argv)
70{
71	if (argc < 2 || argc > 3) {
72		kprintf("usage: %s <register> [set-to-value]\n", argv[0]);
73		return 0;
74	}
75
76	uint32 reg = parse_expression(argv[1]);
77	uint32 value = 0;
78	bool set = argc == 3;
79	if (set)
80		value = parse_expression(argv[2]);
81
82	kprintf("intel_extreme register %#" B_PRIx32 "\n", reg);
83
84	intel_info &info = *gDeviceInfo[0];
85	uint32 oldValue = read32(info, reg);
86
87	kprintf("  %svalue: %#" B_PRIx32 " (%" B_PRIu32 ")\n", set ? "old " : "",
88		oldValue, oldValue);
89
90	if (set) {
91		write32(info, reg, value);
92
93		value = read32(info, reg);
94		kprintf("  new value: %#" B_PRIx32 " (%" B_PRIu32 ")\n", value, value);
95	}
96
97	return 0;
98}
99
100
101static int
102dump_pipe_info(int argc, char** argv)
103{
104	int pipeOffset = 0;
105
106	if (argc > 2) {
107		kprintf("usage: %s [pipe index]\n", argv[0]);
108		return 0;
109	}
110
111	if (argc > 1) {
112		uint32 pipe = parse_expression(argv[1]);
113		if (pipe != 0)
114			pipeOffset = INTEL_DISPLAY_OFFSET; // Use pipe B if requested
115	}
116
117	intel_info &info = *gDeviceInfo[0];
118	uint32 value;
119
120	kprintf("intel_extreme pipe configuration:\n");
121
122	value = read32(info, INTEL_DISPLAY_A_HTOTAL + pipeOffset);
123	kprintf("  HTOTAL start %" B_PRIu32 " end %" B_PRIu32 "\n",
124		(value & 0xFFFF) + 1, (value >> 16) + 1);
125	value = read32(info, INTEL_DISPLAY_A_HBLANK + pipeOffset);
126	kprintf("  HBLANK start %" B_PRIu32 " end %" B_PRIu32 "\n",
127		(value & 0xFFFF) + 1, (value >> 16) + 1);
128	value = read32(info, INTEL_DISPLAY_A_HSYNC + pipeOffset);
129	kprintf("  HSYNC start %" B_PRIu32 " end %" B_PRIu32 "\n",
130		(value & 0xFFFF) + 1, (value >> 16) + 1);
131	value = read32(info, INTEL_DISPLAY_A_VTOTAL + pipeOffset);
132	kprintf("  VTOTAL start %" B_PRIu32 " end %" B_PRIu32 "\n",
133		(value & 0xFFFF) + 1, (value >> 16) + 1);
134	value = read32(info, INTEL_DISPLAY_A_VBLANK + pipeOffset);
135	kprintf("  VBLANK start %" B_PRIu32 " end %" B_PRIu32 "\n",
136		(value & 0xFFFF) + 1, (value >> 16) + 1);
137	value = read32(info, INTEL_DISPLAY_A_VSYNC + pipeOffset);
138	kprintf("  VSYNC start %" B_PRIu32 " end %" B_PRIu32 "\n",
139		(value & 0xFFFF) + 1, (value >> 16) + 1);
140	value = read32(info, INTEL_DISPLAY_A_PIPE_SIZE + pipeOffset);
141	kprintf("  SIZE %" B_PRIu32 "x%" B_PRIu32 "\n",
142		(value & 0xFFFF) + 1, (value >> 16) + 1);
143
144	if (info.pch_info != INTEL_PCH_NONE) {
145		kprintf("intel_extreme transcoder configuration:\n");
146
147		value = read32(info, INTEL_TRANSCODER_A_HTOTAL + pipeOffset);
148		kprintf("  HTOTAL start %" B_PRIu32 " end %" B_PRIu32 "\n",
149			(value & 0xFFFF) + 1, (value >> 16) + 1);
150		value = read32(info, INTEL_TRANSCODER_A_HBLANK + pipeOffset);
151		kprintf("  HBLANK start %" B_PRIu32 " end %" B_PRIu32 "\n",
152			(value & 0xFFFF) + 1, (value >> 16) + 1);
153		value = read32(info, INTEL_TRANSCODER_A_HSYNC + pipeOffset);
154		kprintf("  HSYNC start %" B_PRIu32 " end %" B_PRIu32 "\n",
155			(value & 0xFFFF) + 1, (value >> 16) + 1);
156		value = read32(info, INTEL_TRANSCODER_A_VTOTAL + pipeOffset);
157		kprintf("  VTOTAL start %" B_PRIu32 " end %" B_PRIu32 "\n",
158			(value & 0xFFFF) + 1, (value >> 16) + 1);
159		value = read32(info, INTEL_TRANSCODER_A_VBLANK + pipeOffset);
160		kprintf("  VBLANK start %" B_PRIu32 " end %" B_PRIu32 "\n",
161			(value & 0xFFFF) + 1, (value >> 16) + 1);
162		value = read32(info, INTEL_TRANSCODER_A_VSYNC + pipeOffset);
163		kprintf("  VSYNC start %" B_PRIu32 " end %" B_PRIu32 "\n",
164			(value & 0xFFFF) + 1, (value >> 16) + 1);
165		value = read32(info, INTEL_TRANSCODER_A_IMAGE_SIZE + pipeOffset);
166		kprintf("  SIZE %" B_PRIu32 "x%" B_PRIu32 "\n",
167			(value & 0xFFFF) + 1, (value >> 16) + 1);
168	}
169
170	kprintf("intel_extreme display plane configuration:\n");
171
172	value = read32(info, INTEL_DISPLAY_A_CONTROL + pipeOffset);
173	kprintf("  CONTROL: %" B_PRIx32 "\n", value);
174	value = read32(info, INTEL_DISPLAY_A_BASE + pipeOffset);
175	kprintf("  BASE: %" B_PRIx32 "\n", value);
176	value = read32(info, INTEL_DISPLAY_A_BYTES_PER_ROW + pipeOffset);
177	kprintf("  BYTES_PER_ROW: %" B_PRIx32 "\n", value);
178	value = read32(info, INTEL_DISPLAY_A_SURFACE + pipeOffset);
179	kprintf("  SURFACE: %" B_PRIx32 "\n", value);
180
181	return 0;
182}
183
184#endif	// DEBUG_COMMANDS
185
186
187//	#pragma mark - Device Hooks
188
189
190static status_t
191device_open(const char* name, uint32 /*flags*/, void** _cookie)
192{
193	CALLED();
194	int32 id;
195
196	// find accessed device
197	{
198		char* thisName;
199
200		// search for device name
201		for (id = 0; (thisName = gDeviceNames[id]) != NULL; id++) {
202			if (!strcmp(name, thisName))
203				break;
204		}
205		if (!thisName)
206			return B_BAD_VALUE;
207	}
208
209	intel_info* info = gDeviceInfo[id];
210
211	mutex_lock(&gLock);
212
213	if (info->open_count == 0) {
214		// This device hasn't been initialized yet, so we
215		// allocate needed resources and initialize the structure
216		info->init_status = intel_extreme_init(*info);
217		if (info->init_status == B_OK) {
218#ifdef DEBUG_COMMANDS
219			add_debugger_command("ie_reg", getset_register,
220				"dumps or sets the specified intel_extreme register");
221			add_debugger_command("ie_pipe", dump_pipe_info,
222				"show pipe configuration information");
223#endif
224		}
225	}
226
227	if (info->init_status == B_OK) {
228		info->open_count++;
229		*_cookie = info;
230	} else
231		ERROR("%s: initialization failed!\n", __func__);
232
233	mutex_unlock(&gLock);
234
235	return info->init_status;
236}
237
238
239static status_t
240device_close(void* /*data*/)
241{
242	CALLED();
243	return B_OK;
244}
245
246
247static status_t
248device_free(void* data)
249{
250	struct intel_info* info = (intel_info*)data;
251
252	mutex_lock(&gLock);
253
254	if (info->open_count-- == 1) {
255		// release info structure
256		info->init_status = B_NO_INIT;
257		intel_extreme_uninit(*info);
258
259#ifdef DEBUG_COMMANDS
260		remove_debugger_command("ie_reg", getset_register);
261		remove_debugger_command("ie_pipe", dump_pipe_info);
262#endif
263	}
264
265	mutex_unlock(&gLock);
266	return B_OK;
267}
268
269
270static status_t
271device_ioctl(void* data, uint32 op, void* buffer, size_t bufferLength)
272{
273	struct intel_info* info = (intel_info*)data;
274
275	switch (op) {
276		case B_GET_ACCELERANT_SIGNATURE:
277			TRACE("accelerant: %s\n", INTEL_ACCELERANT_NAME);
278			if (user_strlcpy((char*)buffer, INTEL_ACCELERANT_NAME,
279					bufferLength) < B_OK)
280				return B_BAD_ADDRESS;
281			return B_OK;
282
283		// needed to share data between kernel and accelerant
284		case INTEL_GET_PRIVATE_DATA:
285		{
286			intel_get_private_data data;
287			if (user_memcpy(&data, buffer, sizeof(intel_get_private_data)) < B_OK)
288				return B_BAD_ADDRESS;
289
290			if (data.magic == INTEL_PRIVATE_DATA_MAGIC) {
291				data.shared_info_area = info->shared_area;
292				return user_memcpy(buffer, &data,
293					sizeof(intel_get_private_data));
294			}
295			break;
296		}
297
298		// needed for cloning
299		case INTEL_GET_DEVICE_NAME:
300			if (user_strlcpy((char* )buffer, gDeviceNames[info->id],
301					bufferLength) < B_OK)
302				return B_BAD_ADDRESS;
303			return B_OK;
304
305		// graphics mem manager
306		case INTEL_ALLOCATE_GRAPHICS_MEMORY:
307		{
308			intel_allocate_graphics_memory allocMemory;
309			if (user_memcpy(&allocMemory, buffer,
310					sizeof(intel_allocate_graphics_memory)) < B_OK)
311				return B_BAD_ADDRESS;
312
313			if (allocMemory.magic != INTEL_PRIVATE_DATA_MAGIC)
314				return B_BAD_VALUE;
315
316			status_t status = intel_allocate_memory(*info, allocMemory.size,
317				allocMemory.alignment, allocMemory.flags,
318				&allocMemory.buffer_base);
319			if (status == B_OK) {
320				// copy result
321				if (user_memcpy(buffer, &allocMemory,
322						sizeof(intel_allocate_graphics_memory)) < B_OK)
323					return B_BAD_ADDRESS;
324			}
325			return status;
326		}
327
328		case INTEL_FREE_GRAPHICS_MEMORY:
329		{
330			intel_free_graphics_memory freeMemory;
331			if (user_memcpy(&freeMemory, buffer,
332					sizeof(intel_free_graphics_memory)) < B_OK)
333				return B_BAD_ADDRESS;
334
335			if (freeMemory.magic == INTEL_PRIVATE_DATA_MAGIC)
336				return intel_free_memory(*info, freeMemory.buffer_base);
337			break;
338		}
339
340		case INTEL_GET_BRIGHTNESS_LEGACY:
341		case INTEL_SET_BRIGHTNESS_LEGACY:
342		{
343			intel_brightness_legacy brightnessLegacy;
344			if (user_memcpy(&brightnessLegacy, buffer,
345					sizeof(brightnessLegacy)) < B_OK)
346				return B_BAD_ADDRESS;
347
348			if (brightnessLegacy.magic != INTEL_PRIVATE_DATA_MAGIC)
349				break;
350			if (op == INTEL_GET_BRIGHTNESS_LEGACY) {
351				brightnessLegacy.lpc = get_pci_config(info->pci, LEGACY_BACKLIGHT_BRIGHTNESS, 1);
352				// copy result
353				if (user_memcpy(buffer, &brightnessLegacy, sizeof(brightnessLegacy)) < B_OK)
354					return B_BAD_ADDRESS;
355			} else {
356				set_pci_config(info->pci, LEGACY_BACKLIGHT_BRIGHTNESS, 1, brightnessLegacy.lpc);
357			}
358			return B_OK;
359		}
360
361		default:
362			ERROR("ioctl() unknown message %" B_PRIu32 " (length = %"
363				B_PRIuSIZE ")\n", op, bufferLength);
364			break;
365	}
366
367	return B_DEV_INVALID_IOCTL;
368}
369
370
371static status_t
372device_read(void* /*data*/, off_t /*pos*/, void* /*buffer*/, size_t* _length)
373{
374	*_length = 0;
375	return B_NOT_ALLOWED;
376}
377
378
379static status_t
380device_write(void* /*data*/, off_t /*pos*/, const void* /*buffer*/,
381	size_t* _length)
382{
383	*_length = 0;
384	return B_NOT_ALLOWED;
385}
386
387