xref: /haiku/src/add-ons/accelerants/vesa/accelerant.cpp (revision 5e7964b0a929555415798dea3373db9ac4611caa)
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 	gInfo->current_mode = UINT16_MAX;
94 
95 	// get basic info from driver
96 
97 	area_id sharedArea;
98 	if (ioctl(device, VESA_GET_PRIVATE_DATA, &sharedArea, sizeof(area_id))
99 			!= 0) {
100 		free(gInfo);
101 		return B_ERROR;
102 	}
103 
104 	AreaCloner sharedCloner;
105 	gInfo->shared_info_area = sharedCloner.Clone("vesa shared info",
106 		(void **)&gInfo->shared_info, B_ANY_ADDRESS,
107 		B_READ_AREA | B_WRITE_AREA, sharedArea);
108 	status_t status = sharedCloner.InitCheck();
109 	if (status < B_OK) {
110 		free(gInfo);
111 		return status;
112 	}
113 
114 	gInfo->vesa_modes = (vesa_mode *)((uint8 *)gInfo->shared_info
115 		+ gInfo->shared_info->vesa_mode_offset);
116 
117 	sharedCloner.Keep();
118 	return B_OK;
119 }
120 
121 
122 /*!	Cleans up everything done by a successful init_common(). */
123 static void
124 uninit_common(void)
125 {
126 	delete_area(gInfo->shared_info_area);
127 	gInfo->shared_info_area = -1;
128 	gInfo->shared_info = NULL;
129 
130 	// close the file handle ONLY if we're the clone
131 	// (this is what Be tells us ;)
132 	if (gInfo->is_clone)
133 		close(gInfo->device);
134 
135 	free(gInfo);
136 }
137 
138 
139 //	#pragma mark - public accelerant functions
140 
141 
142 /*!	Init primary accelerant */
143 status_t
144 vesa_init_accelerant(int device)
145 {
146 	TRACE(("vesa_init_accelerant()\n"));
147 
148 	status_t status = init_common(device, false);
149 	if (status != B_OK)
150 		return status;
151 
152 	status = create_mode_list();
153 	if (status != B_OK) {
154 		uninit_common();
155 		return status;
156 	}
157 
158 	// Initialize current mode completely from the mode list
159 	vesa_propose_display_mode(&gInfo->shared_info->current_mode, NULL, NULL);
160 	return B_OK;
161 }
162 
163 
164 ssize_t
165 vesa_accelerant_clone_info_size(void)
166 {
167 	// clone info is device name, so return its maximum size
168 	return B_PATH_NAME_LENGTH;
169 }
170 
171 
172 void
173 vesa_get_accelerant_clone_info(void *info)
174 {
175 	ioctl(gInfo->device, VESA_GET_DEVICE_NAME, info, B_PATH_NAME_LENGTH);
176 }
177 
178 
179 status_t
180 vesa_clone_accelerant(void *info)
181 {
182 	TRACE(("vesa_clone_accelerant()\n"));
183 
184 	// create full device name
185 	char path[MAXPATHLEN];
186 	strcpy(path, "/dev/");
187 	strcat(path, (const char *)info);
188 
189 	int fd = open(path, B_READ_WRITE);
190 	if (fd < 0)
191 		return errno;
192 
193 	status_t status = init_common(fd, true);
194 	if (status != B_OK)
195 		goto err1;
196 
197 	// get read-only clone of supported display modes
198 	status = gInfo->mode_list_area = clone_area(
199 		"vesa cloned modes", (void **)&gInfo->mode_list,
200 		B_ANY_ADDRESS, B_READ_AREA, gInfo->shared_info->mode_list_area);
201 	if (status < B_OK)
202 		goto err2;
203 
204 	return B_OK;
205 
206 err2:
207 	uninit_common();
208 err1:
209 	close(fd);
210 	return status;
211 }
212 
213 
214 /*!	This function is called for both, the primary accelerant and all of
215 	its clones.
216 */
217 void
218 vesa_uninit_accelerant(void)
219 {
220 	TRACE(("vesa_uninit_accelerant()\n"));
221 
222 	// delete accelerant instance data
223 	delete_area(gInfo->mode_list_area);
224 	gInfo->mode_list = NULL;
225 
226 	uninit_common();
227 }
228 
229 
230 status_t
231 vesa_get_accelerant_device_info(accelerant_device_info *info)
232 {
233 	info->version = B_ACCELERANT_VERSION;
234 	strcpy(info->name, "VESA Driver");
235 	strcpy(info->chipset, "VESA");
236 		// ToDo: provide some more insight here...
237 	strcpy(info->serial_no, "None");
238 
239 #if 0
240 	info->memory = ???
241 	info->dac_speed = ???
242 #endif
243 
244 	return B_OK;
245 }
246 
247 
248 sem_id
249 vesa_accelerant_retrace_semaphore()
250 {
251 	return -1;
252 }
253 
254