1/*
2 * Copyright 2005-2009, Axel D��rfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include "vesa_private.h"
8#include "vesa.h"
9
10#include <boot_item.h>
11#include <driver_settings.h>
12#include <frame_buffer_console.h>
13#include <util/kernel_cpp.h>
14#include <vm/vm.h>
15
16#include "driver.h"
17#include "utility.h"
18#include "vesa_info.h"
19
20
21#define LINEAR_ADDRESS(segment, offset) \
22	        (((addr_t)(segment) << 4) + (addr_t)(offset))
23#define SEGMENTED_TO_LINEAR(segmented) \
24	        LINEAR_ADDRESS((addr_t)(segmented) >> 16, (addr_t)(segmented) & 0xffff)
25
26
27bios_module_info* sBIOSModule;
28
29
30/*!	Loads the BIOS module and sets up a state for it. The BIOS module is only
31	loaded when we need it, as it is quite a large module.
32*/
33status_t
34vbe_call_prepare(bios_state** state)
35{
36	status_t status;
37
38	status = get_module(B_BIOS_MODULE_NAME, (module_info**)&sBIOSModule);
39	if (status != B_OK) {
40		dprintf(DEVICE_NAME ": failed to get BIOS module: %s\n",
41			strerror(status));
42		return status;
43	}
44
45	status = sBIOSModule->prepare(state);
46	if (status != B_OK) {
47		dprintf(DEVICE_NAME ": failed to prepare BIOS state: %s\n",
48			strerror(status));
49		put_module(B_BIOS_MODULE_NAME);
50	}
51
52	return status;
53}
54
55
56void
57vbe_call_finish(bios_state* state)
58{
59	sBIOSModule->finish(state);
60	put_module(B_BIOS_MODULE_NAME);
61}
62
63
64static status_t
65find_graphics_card(addr_t frameBuffer, addr_t& base, size_t& size)
66{
67	// TODO: when we port this over to the new driver API, this mechanism can be
68	// used to find the right device_node
69	pci_module_info* pci;
70	if (get_module(B_PCI_MODULE_NAME, (module_info**)&pci) != B_OK)
71		return B_ERROR;
72
73	pci_info info;
74	for (int32 index = 0; pci->get_nth_pci_info(index, &info) == B_OK; index++) {
75		if (info.class_base != PCI_display)
76			continue;
77
78		// check PCI BARs
79		for (uint32 i = 0; i < 6; i++) {
80			if (info.u.h0.base_registers[i] <= frameBuffer
81				&& info.u.h0.base_registers[i] + info.u.h0.base_register_sizes[i]
82					> frameBuffer) {
83				// found it!
84				base = info.u.h0.base_registers[i];
85				size = info.u.h0.base_register_sizes[i];
86
87				put_module(B_PCI_MODULE_NAME);
88				return B_OK;
89			}
90		}
91	}
92
93	put_module(B_PCI_MODULE_NAME);
94	return B_ENTRY_NOT_FOUND;
95}
96
97
98uint32
99get_color_space_for_depth(uint32 depth)
100{
101	switch (depth) {
102		case 1:
103			return B_GRAY1;
104		case 4:
105			return B_GRAY8;
106				// the app_server is smart enough to translate this to VGA mode
107		case 8:
108			return B_CMAP8;
109		case 15:
110			return B_RGB15;
111		case 16:
112			return B_RGB16;
113		case 24:
114			return B_RGB24;
115		case 32:
116			return B_RGB32;
117	}
118
119	return 0;
120}
121
122
123status_t
124vbe_get_mode_info(bios_state* state, uint16 mode, struct vbe_mode_info* modeInfo)
125{
126	void* vbeModeInfo = sBIOSModule->allocate_mem(state,
127		sizeof(struct vbe_mode_info));
128	if (vbeModeInfo == NULL)
129		return B_NO_MEMORY;
130	memset(vbeModeInfo, 0, sizeof(vbe_mode_info));
131
132	uint32 physicalAddress = sBIOSModule->physical_address(state, vbeModeInfo);
133	bios_regs regs = {};
134	regs.eax = 0x4f01;
135	regs.ecx = mode;
136	regs.es  = physicalAddress >> 4;
137	regs.edi = physicalAddress - (regs.es << 4);
138
139	status_t status = sBIOSModule->interrupt(state, 0x10, &regs);
140	if (status != B_OK) {
141		dprintf(DEVICE_NAME ": vbe_get_mode_info(%u): BIOS failed: %s\n", mode,
142			strerror(status));
143		return status;
144	}
145
146	if ((regs.eax & 0xffff) != 0x4f) {
147		dprintf(DEVICE_NAME ": vbe_get_mode_info(%u): BIOS returned "
148			"0x%04" B_PRIx32 "\n", mode, regs.eax & 0xffff);
149		return B_ENTRY_NOT_FOUND;
150	}
151
152	memcpy(modeInfo, vbeModeInfo, sizeof(struct vbe_mode_info));
153	return B_OK;
154}
155
156
157status_t
158vbe_set_mode(bios_state* state, uint16 mode)
159{
160	bios_regs regs = {};
161	regs.eax = 0x4f02;
162	regs.ebx = (mode & SET_MODE_MASK) | SET_MODE_LINEAR_BUFFER;
163
164	status_t status = sBIOSModule->interrupt(state, 0x10, &regs);
165	if (status != B_OK) {
166		dprintf(DEVICE_NAME ": vbe_set_mode(%u): BIOS failed: %s\n", mode,
167			strerror(status));
168		return status;
169	}
170
171	if ((regs.eax & 0xffff) != 0x4f) {
172		dprintf(DEVICE_NAME ": vbe_set_mode(%u): BIOS returned 0x%04" B_PRIx32
173			"\n", mode, regs.eax & 0xffff);
174		return B_ERROR;
175	}
176
177	return B_OK;
178}
179
180
181static uint32
182vbe_to_system_dpms(uint8 vbeMode)
183{
184	uint32 mode = 0;
185	if ((vbeMode & (DPMS_OFF | DPMS_REDUCED_ON)) != 0)
186		mode |= B_DPMS_OFF;
187	if ((vbeMode & DPMS_STANDBY) != 0)
188		mode |= B_DPMS_STAND_BY;
189	if ((vbeMode & DPMS_SUSPEND) != 0)
190		mode |= B_DPMS_SUSPEND;
191
192	return mode;
193}
194
195
196static status_t
197vbe_get_dpms_capabilities(bios_state* state, uint32& vbeMode, uint32& mode)
198{
199	// we always return a valid mode
200	vbeMode = 0;
201	mode = B_DPMS_ON;
202
203	bios_regs regs = {};
204	regs.eax = 0x4f10;
205	regs.ebx = 0;
206	regs.esi = 0;
207	regs.edi = 0;
208
209	status_t status = sBIOSModule->interrupt(state, 0x10, &regs);
210	if (status != B_OK) {
211		dprintf(DEVICE_NAME ": vbe_get_dpms_capabilities(): BIOS failed: %s\n",
212			strerror(status));
213		return status;
214	}
215
216	if ((regs.eax & 0xffff) != 0x4f) {
217		dprintf(DEVICE_NAME ": vbe_get_dpms_capabilities(): BIOS returned "
218			"0x%04" B_PRIx32 "\n", regs.eax & 0xffff);
219		return B_ERROR;
220	}
221
222	vbeMode = regs.ebx >> 8;
223	mode = vbe_to_system_dpms(vbeMode);
224	return status;
225}
226
227
228status_t
229vbe_set_bits_per_gun(bios_state* state, vesa_info& info, uint8 bits)
230{
231	info.bits_per_gun = 6;
232
233	bios_regs regs = {};
234	regs.eax = 0x4f08;
235	regs.ebx = (bits << 8) | 1;
236
237	status_t status = sBIOSModule->interrupt(state, 0x10, &regs);
238	if (status != B_OK) {
239		dprintf(DEVICE_NAME ": vbe_set_bits_per_gun(): BIOS failed: %s\n",
240			strerror(status));
241		return status;
242	}
243
244	if ((regs.eax & 0xffff) != 0x4f) {
245		dprintf(DEVICE_NAME ": vbe_set_bits_per_gun(): BIOS returned "
246			"0x%04" B_PRIx32 "\n", regs.eax & 0xffff);
247		return B_ERROR;
248	}
249
250	info.bits_per_gun = regs.ebx >> 8;
251	return B_OK;
252}
253
254
255// We used to read the existing mode set by the bootsplash to avoid setting the same mode
256// when entering app_server, but this has been disabled. So now there is always a modeset
257// done when app_server starts.
258#if 0
259static status_t
260vbe_get_vesa_info(bios_state* state, vesa_info& info)
261{
262	vbe_info_block* infoHeader = (vbe_info_block*)sBIOSModule->allocate_mem(state, 256);
263	phys_addr_t physicalAddress = sBIOSModule->physical_address(state, infoHeader);
264
265	bios_regs regs = {};
266	regs.eax = 0x4f00;
267	regs.es  = physicalAddress >> 4;
268	regs.edi = physicalAddress - (regs.es << 4);
269
270	status_t status = sBIOSModule->interrupt(state, 0x10, &regs);
271	if (status != B_OK) {
272		dprintf(DEVICE_NAME ": vbe_get_vesa_info(): BIOS failed: %s\n",
273			strerror(status));
274		return status;
275	}
276
277	if ((regs.eax & 0xffff) != 0x4f) {
278		dprintf(DEVICE_NAME ": vbe_get_vesa_info(): BIOS returned "
279			"0x%04" B_PRIx32 "\n", regs.eax & 0xffff);
280		return B_ERROR;
281	}
282
283	info.shared_info->vram_size = infoHeader->total_memory * 65536;
284	strlcpy(info.shared_info->name, (char*)sBIOSModule->virtual_address(state,
285			SEGMENTED_TO_LINEAR(infoHeader->oem_string)), 32);
286
287	return status;
288}
289#endif
290
291
292/*!	Remaps the frame buffer if necessary; if we've already mapped the complete
293	frame buffer, there is no need to map it again.
294*/
295status_t
296remap_frame_buffer(vesa_info& info, addr_t physicalBase, uint32 width,
297	uint32 height, int8 depth, uint32 bytesPerRow, bool initializing)
298{
299	vesa_shared_info& sharedInfo = *info.shared_info;
300	addr_t frameBuffer = info.frame_buffer;
301
302	if (!info.complete_frame_buffer_mapped) {
303		addr_t base = physicalBase;
304		size_t size = bytesPerRow * height;
305		bool remap = !initializing;
306
307		if (info.physical_frame_buffer_size != 0) {
308			// we can map the complete frame buffer
309			base = info.physical_frame_buffer;
310			size = info.physical_frame_buffer_size;
311			remap = true;
312		}
313
314		if (remap) {
315			area_id area = map_physical_memory("vesa frame buffer", base,
316				size, B_ANY_KERNEL_ADDRESS, B_READ_AREA | B_WRITE_AREA,
317				(void**)&frameBuffer);
318			if (area < 0)
319				return area;
320
321			if (initializing) {
322				// We need to manually update the kernel's frame buffer address,
323				// since this frame buffer remapping has not been issued by the
324				// app_server (which would otherwise take care of this)
325				frame_buffer_update(frameBuffer, width, height, depth,
326					bytesPerRow);
327			}
328
329			delete_area(info.shared_info->frame_buffer_area);
330
331			info.frame_buffer = frameBuffer;
332			sharedInfo.frame_buffer_area = area;
333
334			// Turn on write combining for the area
335			vm_set_area_memory_type(area, base, B_MTR_WC);
336
337			if (info.physical_frame_buffer_size != 0)
338				info.complete_frame_buffer_mapped = true;
339		}
340	}
341
342	if (info.complete_frame_buffer_mapped)
343		frameBuffer += physicalBase - info.physical_frame_buffer;
344
345	// Update shared frame buffer information
346	sharedInfo.frame_buffer = (uint8*)frameBuffer;
347	sharedInfo.physical_frame_buffer = (uint8*)physicalBase;
348	sharedInfo.bytes_per_row = bytesPerRow;
349
350	return B_OK;
351}
352
353
354//	#pragma mark -
355
356
357status_t
358vesa_init(vesa_info& info)
359{
360	frame_buffer_boot_info* bufferInfo
361		= (frame_buffer_boot_info*)get_boot_item(FRAME_BUFFER_BOOT_INFO, NULL);
362	if (bufferInfo == NULL)
363		return B_ERROR;
364
365	info.vbe_capabilities = bufferInfo->vesa_capabilities;
366	info.complete_frame_buffer_mapped = false;
367
368	// Find out which PCI device we belong to, so that we know its frame buffer
369	// size
370	find_graphics_card(bufferInfo->physical_frame_buffer,
371		info.physical_frame_buffer, info.physical_frame_buffer_size);
372
373	size_t modesSize = 0;
374	vesa_mode* modes = (vesa_mode*)get_boot_item(VESA_MODES_BOOT_INFO,
375		&modesSize);
376	info.modes = modes;
377
378	size_t sharedSize = (sizeof(vesa_shared_info) + 7) & ~7;
379
380	info.shared_area = create_area("vesa shared info",
381		(void**)&info.shared_info, B_ANY_KERNEL_ADDRESS,
382		ROUND_TO_PAGE_SIZE(sharedSize + modesSize), B_FULL_LOCK,
383		B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_CLONEABLE_AREA);
384	if (info.shared_area < 0)
385		return info.shared_area;
386
387	vesa_shared_info& sharedInfo = *info.shared_info;
388
389	memset(&sharedInfo, 0, sizeof(vesa_shared_info));
390
391	if (modes != NULL) {
392		sharedInfo.vesa_mode_offset = sharedSize;
393		sharedInfo.vesa_mode_count = modesSize / sizeof(vesa_mode);
394
395		memcpy((uint8*)&sharedInfo + sharedSize, modes, modesSize);
396	}
397
398	sharedInfo.frame_buffer_area = bufferInfo->area;
399
400	remap_frame_buffer(info, bufferInfo->physical_frame_buffer,
401		bufferInfo->width, bufferInfo->height, bufferInfo->depth,
402		bufferInfo->bytes_per_row, true);
403		// Does not matter if this fails - the frame buffer was already mapped
404		// before.
405
406	sharedInfo.current_mode.virtual_width = bufferInfo->width;
407	sharedInfo.current_mode.virtual_height = bufferInfo->height;
408	sharedInfo.current_mode.space = get_color_space_for_depth(
409		bufferInfo->depth);
410
411	edid1_info* edidInfo = (edid1_info*)get_boot_item(VESA_EDID_BOOT_INFO,
412		NULL);
413	if (edidInfo != NULL) {
414		sharedInfo.has_edid = true;
415		memcpy(&sharedInfo.edid_info, edidInfo, sizeof(edid1_info));
416	}
417
418	bios_state* state;
419	status_t status = vbe_call_prepare(&state);
420	if (status != B_OK)
421		return status;
422
423	void* settings = load_driver_settings("vesa");
424	bool patchingAllowed = false;
425	if (settings != NULL) {
426		patchingAllowed = get_driver_boolean_parameter(settings, "bios_patching",
427			patchingAllowed, true);
428		unload_driver_settings(settings);
429	}
430
431	if (patchingAllowed)
432		vesa_identify_bios(state, &sharedInfo);
433	else
434		sharedInfo.bios_type = kUnknownBiosType;
435
436	vbe_get_dpms_capabilities(state, info.vbe_dpms_capabilities,
437		sharedInfo.dpms_capabilities);
438	if (bufferInfo->depth <= 8)
439		vbe_set_bits_per_gun(state, info, 8);
440
441	vbe_call_finish(state);
442
443	dprintf(DEVICE_NAME ": vesa_init() completed successfully!\n");
444	return B_OK;
445}
446
447
448void
449vesa_uninit(vesa_info& info)
450{
451	dprintf(DEVICE_NAME": vesa_uninit()\n");
452
453	delete_area(info.shared_info->frame_buffer_area);
454	delete_area(info.shared_area);
455}
456
457
458status_t
459vesa_set_display_mode(vesa_info& info, uint32 mode)
460{
461	if (mode >= info.shared_info->vesa_mode_count)
462		return B_ENTRY_NOT_FOUND;
463
464	// Prepare BIOS environment
465	bios_state* state;
466	status_t status = vbe_call_prepare(&state);
467	if (status != B_OK)
468		return status;
469
470	// Get mode information
471	struct vbe_mode_info modeInfo;
472	status = vbe_get_mode_info(state, info.modes[mode].mode, &modeInfo);
473	if (status != B_OK) {
474		dprintf(DEVICE_NAME": vesa_set_display_mode(): cannot get mode info\n");
475		goto out;
476	}
477
478	// Set mode
479	status = vbe_set_mode(state, info.modes[mode].mode);
480	if (status != B_OK) {
481		dprintf(DEVICE_NAME": vesa_set_display_mode(): cannot set mode\n");
482		goto out;
483	}
484
485	if (info.modes[mode].bits_per_pixel <= 8)
486		vbe_set_bits_per_gun(state, info, 8);
487
488	// Map new frame buffer if necessary
489
490	status = remap_frame_buffer(info, modeInfo.physical_base, modeInfo.width,
491		modeInfo.height, modeInfo.bits_per_pixel, modeInfo.bytes_per_row,
492		false);
493	if (status == B_OK) {
494		// Update shared frame buffer information
495		info.shared_info->current_mode.virtual_width = modeInfo.width;
496		info.shared_info->current_mode.virtual_height = modeInfo.height;
497		info.shared_info->current_mode.space = get_color_space_for_depth(
498			modeInfo.bits_per_pixel);
499	}
500
501out:
502	vbe_call_finish(state);
503	return status;
504}
505
506
507status_t
508vesa_get_dpms_mode(vesa_info& info, uint32& mode)
509{
510	mode = B_DPMS_ON;
511		// we always return a valid mode
512
513	// Prepare BIOS environment
514	bios_state* state;
515	status_t status = vbe_call_prepare(&state);
516	if (status != B_OK)
517		return status;
518
519	bios_regs regs = {};
520	regs.eax = 0x4f10;
521	regs.ebx = 2;
522	regs.esi = 0;
523	regs.edi = 0;
524
525	status = sBIOSModule->interrupt(state, 0x10, &regs);
526	if (status != B_OK) {
527		dprintf(DEVICE_NAME ": vesa_get_dpms_mode(): BIOS failed: %s\n",
528			strerror(status));
529		goto out;
530	}
531
532	if ((regs.eax & 0xffff) != 0x4f) {
533		dprintf(DEVICE_NAME ": vesa_get_dpms_mode(): BIOS returned "
534			"0x%" B_PRIx32 "\n", regs.eax & 0xffff);
535		status = B_ERROR;
536		goto out;
537	}
538
539	mode = vbe_to_system_dpms(regs.ebx >> 8);
540
541out:
542	vbe_call_finish(state);
543	return status;
544}
545
546
547status_t
548vesa_set_dpms_mode(vesa_info& info, uint32 mode)
549{
550	// Only let supported modes through
551	mode &= info.shared_info->dpms_capabilities;
552
553	uint8 vbeMode = 0;
554	if ((mode & B_DPMS_OFF) != 0)
555		vbeMode |= DPMS_OFF | DPMS_REDUCED_ON;
556	if ((mode & B_DPMS_STAND_BY) != 0)
557		vbeMode |= DPMS_STANDBY;
558	if ((mode & B_DPMS_SUSPEND) != 0)
559		vbeMode |= DPMS_SUSPEND;
560
561	vbeMode &= info.vbe_dpms_capabilities;
562
563	// Prepare BIOS environment
564	bios_state* state;
565	status_t status = vbe_call_prepare(&state);
566	if (status != B_OK)
567		return status;
568
569	bios_regs regs = {};
570	regs.eax = 0x4f10;
571	regs.ebx = (vbeMode << 8) | 1;
572	regs.esi = 0;
573	regs.edi = 0;
574
575	status = sBIOSModule->interrupt(state, 0x10, &regs);
576	if (status != B_OK) {
577		dprintf(DEVICE_NAME ": vesa_set_dpms_mode(): BIOS failed: %s\n",
578			strerror(status));
579		goto out;
580	}
581
582	if ((regs.eax & 0xffff) != 0x4f) {
583		dprintf(DEVICE_NAME ": vesa_set_dpms_mode(): BIOS returned "
584			"0x%04" B_PRIx32 "\n", regs.eax & 0xffff);
585		status = B_ERROR;
586		goto out;
587	}
588
589out:
590	vbe_call_finish(state);
591	return status;
592}
593
594
595status_t
596vesa_set_indexed_colors(vesa_info& info, uint8 first, uint8* colors,
597	uint16 count)
598{
599	bios_regs regs = {};
600	uint32 shift, physicalAddress;
601
602	if (first + count > 256)
603		count = 256 - first;
604
605	// Prepare BIOS environment
606	bios_state* state;
607	status_t status = vbe_call_prepare(&state);
608	if (status != B_OK)
609		return status;
610
611	uint8* palette = (uint8*)sBIOSModule->allocate_mem(state, 256 * 4);
612	if (palette == NULL) {
613		status = B_NO_MEMORY;
614		goto out;
615	}
616
617	shift = 8 - info.bits_per_gun;
618
619	// convert colors to VESA palette
620	for (int32 i = first; i < count; i++) {
621		uint8 color[3];
622		if (user_memcpy(color, &colors[i * 3], 3) < B_OK) {
623			status = B_BAD_ADDRESS;
624			goto out;
625		}
626
627		// order is BGR-
628		palette[i * 4 + 0] = color[2] >> shift;
629		palette[i * 4 + 1] = color[1] >> shift;
630		palette[i * 4 + 2] = color[0] >> shift;
631		palette[i * 4 + 3] = 0;
632	}
633
634	// set palette
635	physicalAddress = sBIOSModule->physical_address(state, palette);
636	regs.eax = 0x4f09;
637	regs.ebx = 0;
638	regs.ecx = count;
639	regs.edx = first;
640	regs.es  = physicalAddress >> 4;
641	regs.edi = physicalAddress - (regs.es << 4);
642
643	status = sBIOSModule->interrupt(state, 0x10, &regs);
644	if (status != B_OK) {
645		dprintf(DEVICE_NAME ": vesa_set_indexed_colors(): BIOS failed: %s\n",
646			strerror(status));
647		goto out;
648	}
649
650	if ((regs.eax & 0xffff) != 0x4f) {
651		dprintf(DEVICE_NAME ": vesa_set_indexed_colors(): BIOS returned "
652			"0x%04" B_PRIx32 "\n", regs.eax & 0xffff);
653		status = B_ERROR;
654	}
655
656out:
657	vbe_call_finish(state);
658	return status;
659}
660