xref: /haiku/src/add-ons/kernel/drivers/graphics/vesa/device.cpp (revision 4a55cc230cf7566cadcbb23b1928eefff8aea9a2)
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 "device.h"
8 
9 #include <stdlib.h>
10 #include <string.h>
11 
12 #include <Drivers.h>
13 #include <graphic_driver.h>
14 #include <image.h>
15 #include <KernelExport.h>
16 #include <OS.h>
17 #include <PCI.h>
18 #include <SupportDefs.h>
19 
20 #include <vesa.h>
21 
22 #include "driver.h"
23 #include "utility.h"
24 #include "vesa_info.h"
25 #include "vesa_private.h"
26 #include "vga.h"
27 
28 
29 //#define TRACE_DEVICE
30 #ifdef TRACE_DEVICE
31 #	define TRACE(x) dprintf x
32 #else
33 #	define TRACE(x) ;
34 #endif
35 
36 
37 static status_t
38 device_open(const char* name, uint32 flags, void** _cookie)
39 {
40 	int id;
41 
42 	// find accessed device
43 	char* thisName;
44 
45 	// search for device name
46 	for (id = 0; (thisName = gDeviceNames[id]) != NULL; id++) {
47 		if (!strcmp(name, thisName))
48 			break;
49 	}
50 	if (thisName == NULL)
51 		return B_BAD_VALUE;
52 
53 	vesa_info* info = gDeviceInfo[id];
54 
55 	mutex_lock(&gLock);
56 
57 	status_t status = B_OK;
58 
59 	if (info->open_count == 0) {
60 		// this device has been opened for the first time, so
61 		// we allocate needed resources and initialize the structure
62 		if (status == B_OK)
63 			status = vesa_init(*info);
64 		if (status == B_OK)
65 			info->id = id;
66 	}
67 
68 	if (status == B_OK) {
69 		info->open_count++;
70 		*_cookie = info;
71 	}
72 
73 	mutex_unlock(&gLock);
74 	return status;
75 }
76 
77 
78 static status_t
79 device_close(void* cookie)
80 {
81 	return B_OK;
82 }
83 
84 
85 static status_t
86 device_free(void* cookie)
87 {
88 	struct vesa_info* info = (vesa_info*)cookie;
89 
90 	mutex_lock(&gLock);
91 
92 	if (info->open_count-- == 1) {
93 		// release info structure
94 		vesa_uninit(*info);
95 	}
96 
97 	mutex_unlock(&gLock);
98 	return B_OK;
99 }
100 
101 
102 static status_t
103 device_ioctl(void* cookie, uint32 msg, void* buffer, size_t bufferLength)
104 {
105 	struct vesa_info* info = (vesa_info*)cookie;
106 
107 	switch (msg) {
108 		case B_GET_ACCELERANT_SIGNATURE:
109 			dprintf(DEVICE_NAME ": acc: %s\n", VESA_ACCELERANT_NAME);
110 			if (user_strlcpy((char*)buffer, VESA_ACCELERANT_NAME,
111 					B_FILE_NAME_LENGTH) < B_OK)
112 				return B_BAD_ADDRESS;
113 
114 			return B_OK;
115 
116 		// needed to share data between kernel and accelerant
117 		case VESA_GET_PRIVATE_DATA:
118 			return user_memcpy(buffer, &info->shared_area, sizeof(area_id));
119 
120 		// needed for cloning
121 		case VESA_GET_DEVICE_NAME:
122 			if (user_strlcpy((char*)buffer, gDeviceNames[info->id],
123 					B_PATH_NAME_LENGTH) < B_OK)
124 				return B_BAD_ADDRESS;
125 
126 			return B_OK;
127 
128 		case VESA_SET_DISPLAY_MODE:
129 		{
130 			if (bufferLength != sizeof(uint32))
131 				return B_BAD_VALUE;
132 
133 			uint32 mode;
134 			if (user_memcpy(&mode, buffer, sizeof(uint32)) != B_OK)
135 				return B_BAD_ADDRESS;
136 
137 			return vesa_set_display_mode(*info, mode);
138 		}
139 
140 		case VESA_SET_CUSTOM_DISPLAY_MODE:
141 		{
142 			if (bufferLength != sizeof(display_mode))
143 				return B_BAD_VALUE;
144 
145 			if (info->shared_info->bios_type == kUnknownBiosType)
146 				return B_NOT_ALLOWED;
147 
148 			display_mode mode;
149 			if (user_memcpy(&mode, buffer, sizeof(display_mode)) != B_OK)
150 				return B_BAD_ADDRESS;
151 
152 			return vesa_set_custom_display_mode(*info, mode);
153 		}
154 
155 		case VESA_GET_DPMS_MODE:
156 		{
157 			if (bufferLength != sizeof(uint32))
158 				return B_BAD_VALUE;
159 
160 			uint32 mode;
161 			status_t status = vesa_get_dpms_mode(*info, mode);
162 			if (status != B_OK)
163 				return status;
164 
165 			return user_memcpy(buffer, &mode, sizeof(mode));
166 		}
167 
168 		case VESA_SET_DPMS_MODE:
169 		{
170 			if (bufferLength != sizeof(uint32))
171 				return B_BAD_VALUE;
172 
173 			uint32 mode;
174 			if (user_memcpy(&mode, buffer, sizeof(uint32)) != B_OK)
175 				return B_BAD_ADDRESS;
176 
177 			return vesa_set_dpms_mode(*info, mode);
178 		}
179 
180 		case VESA_SET_INDEXED_COLORS:
181 		{
182 			color_space space
183 				= (color_space)info->shared_info->current_mode.space;
184 			if (space != B_GRAY8 && space != B_CMAP8)
185 				return B_ERROR;
186 
187 			vesa_set_indexed_colors_args args;
188 			if (user_memcpy(&args, buffer, sizeof(args)) != B_OK)
189 				return B_BAD_ADDRESS;
190 
191 			status_t status = B_NOT_SUPPORTED;
192 			if (space != B_GRAY8) {
193 				status = vesa_set_indexed_colors(*info, args.first, args.colors,
194 					args.count);
195 			}
196 
197 			// Try VGA as a fallback
198 			if (status != B_OK && (info->vbe_capabilities
199 					& CAPABILITY_NOT_VGA_COMPATIBLE) == 0) {
200 				return vga_set_indexed_colors(args.first, args.colors,
201 					args.count);
202 			}
203 
204 			return status;
205 		}
206 
207 		case VGA_PLANAR_BLIT:
208 		{
209 			if (info->shared_info->current_mode.space != B_GRAY8
210 				|| (info->vbe_capabilities
211 					& CAPABILITY_NOT_VGA_COMPATIBLE) != 0)
212 				return B_NOT_SUPPORTED;
213 
214 			vga_planar_blit_args args;
215 			if (user_memcpy(&args, buffer, sizeof(args)) != B_OK)
216 				return B_BAD_ADDRESS;
217 
218 			return vga_planar_blit(info->shared_info, args.source,
219 				args.source_bytes_per_row, args.left, args.top,
220 				args.right, args.bottom);
221 		}
222 
223 		default:
224 			TRACE((DEVICE_NAME ": ioctl() unknown message %ld (length = %lu)\n",
225 				msg, bufferLength));
226 			break;
227 	}
228 
229 	return B_DEV_INVALID_IOCTL;
230 }
231 
232 
233 static status_t
234 device_read(void* /*cookie*/, off_t /*pos*/, void* /*buffer*/, size_t* _length)
235 {
236 	*_length = 0;
237 	return B_NOT_ALLOWED;
238 }
239 
240 
241 static status_t
242 device_write(void* /*cookie*/, off_t /*pos*/, const void* /*buffer*/,
243 	size_t* _length)
244 {
245 	*_length = 0;
246 	return B_NOT_ALLOWED;
247 }
248 
249 
250 device_hooks gDeviceHooks = {
251 	device_open,
252 	device_close,
253 	device_free,
254 	device_ioctl,
255 	device_read,
256 	device_write,
257 	NULL,
258 	NULL,
259 	NULL,
260 	NULL
261 };
262