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