xref: /haiku/src/add-ons/kernel/drivers/graphics/framebuffer/framebuffer.cpp (revision 4c8e85b316c35a9161f5a1c50ad70bc91c83a76f)
1 /*
2  * Copyright 2005-2009, Axel Dörfler, axeld@pinc-software.de.
3  * Copyright 2016, Jessica Hamilton, jessica.l.hamilton@gmail.com.
4  * Distributed under the terms of the MIT License.
5  */
6 
7 
8 #include "framebuffer_private.h"
9 #include "vesa.h"
10 
11 #include <string.h>
12 
13 #include <drivers/bios.h>
14 
15 #include <boot_item.h>
16 #include <frame_buffer_console.h>
17 #include <util/kernel_cpp.h>
18 #include <vm/vm.h>
19 
20 #include "driver.h"
21 #include "utility.h"
22 #include "vesa_info.h"
23 
24 
25 static status_t
26 find_graphics_card(addr_t frameBuffer, addr_t& base, size_t& size)
27 {
28 	// TODO: when we port this over to the new driver API, this mechanism can be
29 	// used to find the right device_node
30 	pci_module_info* pci;
31 	if (get_module(B_PCI_MODULE_NAME, (module_info**)&pci) != B_OK)
32 		return B_ERROR;
33 
34 	pci_info info;
35 	for (int32 index = 0; pci->get_nth_pci_info(index, &info) == B_OK; index++) {
36 		if (info.class_base != PCI_display)
37 			continue;
38 
39 		// check PCI BARs
40 		for (uint32 i = 0; i < 6; i++) {
41 			if (info.u.h0.base_registers[i] <= frameBuffer
42 				&& info.u.h0.base_registers[i] + info.u.h0.base_register_sizes[i]
43 					> frameBuffer) {
44 				// found it!
45 				base = info.u.h0.base_registers[i];
46 				size = info.u.h0.base_register_sizes[i];
47 
48 				put_module(B_PCI_MODULE_NAME);
49 				return B_OK;
50 			}
51 		}
52 	}
53 
54 	put_module(B_PCI_MODULE_NAME);
55 	return B_ENTRY_NOT_FOUND;
56 }
57 
58 
59 static uint32
60 get_color_space_for_depth(uint32 depth)
61 {
62 	switch (depth) {
63 		case 1:
64 			return B_GRAY1;
65 		case 4:
66 			return B_GRAY8;
67 				// the app_server is smart enough to translate this to VGA mode
68 		case 8:
69 			return B_CMAP8;
70 		case 15:
71 			return B_RGB15;
72 		case 16:
73 			return B_RGB16;
74 		case 24:
75 			return B_RGB24;
76 		case 32:
77 			return B_RGB32;
78 	}
79 
80 	return 0;
81 }
82 
83 
84 /*!	Remaps the frame buffer if necessary; if we've already mapped the complete
85 	frame buffer, there is no need to map it again.
86 */
87 static status_t
88 remap_frame_buffer(framebuffer_info& info, addr_t physicalBase, uint32 width,
89 	uint32 height, int8 depth, uint32 bytesPerRow, bool initializing)
90 {
91 	vesa_shared_info& sharedInfo = *info.shared_info;
92 	addr_t frameBuffer = info.frame_buffer;
93 
94 	if (!info.complete_frame_buffer_mapped) {
95 		addr_t base = physicalBase;
96 		size_t size = bytesPerRow * height;
97 		bool remap = !initializing;
98 
99 		if (info.physical_frame_buffer_size != 0) {
100 			// we can map the complete frame buffer
101 			base = info.physical_frame_buffer;
102 			size = info.physical_frame_buffer_size;
103 			remap = true;
104 		}
105 
106 		if (remap) {
107 			area_id area = map_physical_memory("framebuffer buffer", base,
108 				size, B_ANY_KERNEL_ADDRESS, B_READ_AREA | B_WRITE_AREA,
109 				(void**)&frameBuffer);
110 			if (area < 0)
111 				return area;
112 
113 			if (initializing) {
114 				// We need to manually update the kernel's frame buffer address,
115 				// since this frame buffer remapping has not been issued by the
116 				// app_server (which would otherwise take care of this)
117 				frame_buffer_update(frameBuffer, width, height, depth,
118 					bytesPerRow);
119 			}
120 
121 			delete_area(info.shared_info->frame_buffer_area);
122 
123 			info.frame_buffer = frameBuffer;
124 			sharedInfo.frame_buffer_area = area;
125 
126 			// Turn on write combining for the area
127 			vm_set_area_memory_type(area, base, B_MTR_WC);
128 
129 			if (info.physical_frame_buffer_size != 0)
130 				info.complete_frame_buffer_mapped = true;
131 		}
132 	}
133 
134 	if (info.complete_frame_buffer_mapped)
135 		frameBuffer += physicalBase - info.physical_frame_buffer;
136 
137 	// Update shared frame buffer information
138 	sharedInfo.frame_buffer = (uint8*)frameBuffer;
139 	sharedInfo.physical_frame_buffer = (uint8*)physicalBase;
140 	sharedInfo.bytes_per_row = bytesPerRow;
141 
142 	return B_OK;
143 }
144 
145 
146 //	#pragma mark -
147 
148 
149 status_t
150 framebuffer_init(framebuffer_info& info)
151 {
152 	frame_buffer_boot_info* bufferInfo
153 		= (frame_buffer_boot_info*)get_boot_item(FRAME_BUFFER_BOOT_INFO, NULL);
154 	if (bufferInfo == NULL)
155 		return B_ERROR;
156 
157 	info.complete_frame_buffer_mapped = false;
158 
159 	// Find out which PCI device we belong to, so that we know its frame buffer
160 	// size
161 	find_graphics_card(bufferInfo->physical_frame_buffer,
162 		info.physical_frame_buffer, info.physical_frame_buffer_size);
163 
164 	size_t sharedSize = (sizeof(vesa_shared_info) + 7) & ~7;
165 
166 	info.shared_area = create_area("framebuffer shared info",
167 		(void**)&info.shared_info, B_ANY_KERNEL_ADDRESS,
168 		ROUND_TO_PAGE_SIZE(sharedSize), B_FULL_LOCK,
169 		B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_CLONEABLE_AREA);
170 	if (info.shared_area < 0)
171 		return info.shared_area;
172 
173 	vesa_shared_info& sharedInfo = *info.shared_info;
174 
175 	memset(&sharedInfo, 0, sizeof(vesa_shared_info));
176 
177 	sharedInfo.frame_buffer_area = bufferInfo->area;
178 
179 	remap_frame_buffer(info, bufferInfo->physical_frame_buffer,
180 		bufferInfo->width, bufferInfo->height, bufferInfo->depth,
181 		bufferInfo->bytes_per_row, true);
182 		// Does not matter if this fails - the frame buffer was already mapped
183 		// before.
184 
185 	sharedInfo.current_mode.virtual_width = bufferInfo->width;
186 	sharedInfo.current_mode.virtual_height = bufferInfo->height;
187 	sharedInfo.current_mode.space = get_color_space_for_depth(
188 		bufferInfo->depth);
189 
190 	dprintf(DEVICE_NAME ": framebuffer_init() completed successfully!\n");
191 	return B_OK;
192 }
193 
194 
195 void
196 framebuffer_uninit(framebuffer_info& info)
197 {
198 	dprintf(DEVICE_NAME": framebuffer_uninit()\n");
199 
200 	delete_area(info.shared_info->frame_buffer_area);
201 	delete_area(info.shared_area);
202 }
203