xref: /haiku/src/add-ons/accelerants/vesa/accelerant.cpp (revision 5629675a326ecf2ff3fd23f154beb525c171048d)
1 /*
2  * Copyright 2005-2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
3  * Copyright 2016-207, Jessica Hamilton, jessica.l.hamilton@gmail.com.
4  * Distributed under the terms of the MIT License.
5  */
6 
7 
8 #include "accelerant_protos.h"
9 #include "accelerant.h"
10 
11 #include <stdlib.h>
12 #include <string.h>
13 #include <unistd.h>
14 #include <errno.h>
15 #include <syslog.h>
16 
17 
18 //#define TRACE_ACCELERANT
19 #ifdef TRACE_ACCELERANT
20 extern "C" void _sPrintf(const char *format, ...);
21 #	define TRACE(x) _sPrintf x
22 #else
23 #	define TRACE(x) ;
24 #endif
25 
26 
27 struct accelerant_info *gInfo;
28 
29 
30 class AreaCloner {
31 	public:
32 		AreaCloner();
33 		~AreaCloner();
34 
35 		area_id Clone(const char *name, void **_address, uint32 spec,
36 					uint32 protection, area_id sourceArea);
37 		status_t InitCheck() { return fArea < B_OK ? (status_t)fArea : B_OK; }
38 		void Keep();
39 
40 	private:
41 		area_id	fArea;
42 };
43 
44 
45 AreaCloner::AreaCloner()
46 	:
47 	fArea(-1)
48 {
49 }
50 
51 
52 AreaCloner::~AreaCloner()
53 {
54 	if (fArea >= B_OK)
55 		delete_area(fArea);
56 }
57 
58 
59 area_id
60 AreaCloner::Clone(const char *name, void **_address, uint32 spec,
61 	uint32 protection, area_id sourceArea)
62 {
63 	fArea = clone_area(name, _address, spec, protection, sourceArea);
64 	return fArea;
65 }
66 
67 
68 void
69 AreaCloner::Keep()
70 {
71 	fArea = -1;
72 }
73 
74 
75 //	#pragma mark -
76 
77 
78 /*!	This is the common accelerant_info initializer. It is called by
79 	both, the first accelerant and all clones.
80 */
81 static status_t
82 init_common(int device, bool isClone)
83 {
84 	// initialize global accelerant info structure
85 
86 	gInfo = (accelerant_info *)malloc(sizeof(accelerant_info));
87 	if (gInfo == NULL)
88 		return B_NO_MEMORY;
89 
90 	memset(gInfo, 0, sizeof(accelerant_info));
91 
92 	gInfo->is_clone = isClone;
93 	gInfo->device = device;
94 	gInfo->current_mode = UINT16_MAX;
95 
96 	// get basic info from driver
97 
98 	area_id sharedArea;
99 	if (ioctl(device, VESA_GET_PRIVATE_DATA, &sharedArea, sizeof(area_id))
100 			!= 0) {
101 		free(gInfo);
102 		return B_ERROR;
103 	}
104 
105 	AreaCloner sharedCloner;
106 	gInfo->shared_info_area = sharedCloner.Clone("vesa shared info",
107 		(void **)&gInfo->shared_info, B_ANY_ADDRESS,
108 		B_READ_AREA | B_WRITE_AREA, sharedArea);
109 	status_t status = sharedCloner.InitCheck();
110 	if (status < B_OK) {
111 		free(gInfo);
112 		return status;
113 	}
114 
115 	if (gInfo->shared_info->vesa_mode_count == 0)
116 		gInfo->vesa_modes = NULL;
117 	else
118 		gInfo->vesa_modes = (vesa_mode *)((uint8 *)gInfo->shared_info
119 			+ gInfo->shared_info->vesa_mode_offset);
120 
121 	sharedCloner.Keep();
122 	return B_OK;
123 }
124 
125 
126 /*!	Cleans up everything done by a successful init_common(). */
127 static void
128 uninit_common(void)
129 {
130 	delete_area(gInfo->shared_info_area);
131 	gInfo->shared_info_area = -1;
132 	gInfo->shared_info = NULL;
133 
134 	// close the file handle ONLY if we're the clone
135 	// (this is what Be tells us ;)
136 	if (gInfo->is_clone)
137 		close(gInfo->device);
138 
139 	free(gInfo);
140 }
141 
142 
143 //	#pragma mark - public accelerant functions
144 
145 
146 /*!	Init primary accelerant */
147 status_t
148 vesa_init_accelerant(int device)
149 {
150 	TRACE(("vesa_init_accelerant()\n"));
151 
152 	status_t status = init_common(device, false);
153 	if (status != B_OK)
154 		return status;
155 
156 	status = create_mode_list();
157 	if (status != B_OK) {
158 		uninit_common();
159 		return status;
160 	}
161 
162 	// Initialize current mode completely from the mode list
163 	vesa_propose_display_mode(&gInfo->shared_info->current_mode, NULL, NULL);
164 	return B_OK;
165 }
166 
167 
168 ssize_t
169 vesa_accelerant_clone_info_size(void)
170 {
171 	// clone info is device name, so return its maximum size
172 	return B_PATH_NAME_LENGTH;
173 }
174 
175 
176 void
177 vesa_get_accelerant_clone_info(void *info)
178 {
179 	ioctl(gInfo->device, VESA_GET_DEVICE_NAME, info, B_PATH_NAME_LENGTH);
180 }
181 
182 
183 status_t
184 vesa_clone_accelerant(void *info)
185 {
186 	TRACE(("vesa_clone_accelerant()\n"));
187 
188 	// create full device name
189 	char path[MAXPATHLEN];
190 	strcpy(path, "/dev/");
191 	strcat(path, (const char *)info);
192 
193 	int fd = open(path, B_READ_WRITE);
194 	if (fd < 0)
195 		return errno;
196 
197 	status_t status = init_common(fd, true);
198 	if (status != B_OK)
199 		goto err1;
200 
201 	// get read-only clone of supported display modes
202 	status = gInfo->mode_list_area = clone_area(
203 		"vesa cloned modes", (void **)&gInfo->mode_list,
204 		B_ANY_ADDRESS, B_READ_AREA, gInfo->shared_info->mode_list_area);
205 	if (status < B_OK)
206 		goto err2;
207 
208 	return B_OK;
209 
210 err2:
211 	uninit_common();
212 err1:
213 	close(fd);
214 	return status;
215 }
216 
217 
218 /*!	This function is called for both, the primary accelerant and all of
219 	its clones.
220 */
221 void
222 vesa_uninit_accelerant(void)
223 {
224 	TRACE(("vesa_uninit_accelerant()\n"));
225 
226 	// delete accelerant instance data
227 	delete_area(gInfo->mode_list_area);
228 	gInfo->mode_list = NULL;
229 
230 	uninit_common();
231 }
232 
233 
234 status_t
235 vesa_get_accelerant_device_info(accelerant_device_info *info)
236 {
237 	info->version = B_ACCELERANT_VERSION;
238 
239 	// TODO: provide some more insight here...
240 	if (gInfo->vesa_modes != NULL) {
241 		strcpy(info->name, "VESA driver");
242 		strcpy(info->chipset, "VESA");
243 	} else {
244 		strcpy(info->name, "Framebuffer");
245 		strcpy(info->chipset, "");
246 	}
247 
248 	strcpy(info->serial_no, "None");
249 
250 #if 0
251 	info->memory = ???
252 	info->dac_speed = ???
253 #endif
254 
255 	return B_OK;
256 }
257 
258 
259 sem_id
260 vesa_accelerant_retrace_semaphore()
261 {
262 	return -1;
263 }
264 
265