xref: /haiku/src/add-ons/kernel/drivers/graphics/vesa/device.cpp (revision 52f7c9389475e19fc21487b38064b4390eeb6fea)
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 			display_mode mode;
146 			if (user_memcpy(&mode, buffer, sizeof(display_mode)) != B_OK)
147 				return B_BAD_ADDRESS;
148 
149 			return vesa_set_custom_display_mode(*info, mode);
150 		}
151 
152 		case VESA_GET_DPMS_MODE:
153 		{
154 			if (bufferLength != sizeof(uint32))
155 				return B_BAD_VALUE;
156 
157 			uint32 mode;
158 			status_t status = vesa_get_dpms_mode(*info, mode);
159 			if (status != B_OK)
160 				return status;
161 
162 			return user_memcpy(buffer, &mode, sizeof(mode));
163 		}
164 
165 		case VESA_SET_DPMS_MODE:
166 		{
167 			if (bufferLength != sizeof(uint32))
168 				return B_BAD_VALUE;
169 
170 			uint32 mode;
171 			if (user_memcpy(&mode, buffer, sizeof(uint32)) != B_OK)
172 				return B_BAD_ADDRESS;
173 
174 			return vesa_set_dpms_mode(*info, mode);
175 		}
176 
177 		case VESA_SET_INDEXED_COLORS:
178 		{
179 			color_space space
180 				= (color_space)info->shared_info->current_mode.space;
181 			if (space != B_GRAY8 && space != B_CMAP8)
182 				return B_ERROR;
183 
184 			vesa_set_indexed_colors_args args;
185 			if (user_memcpy(&args, buffer, sizeof(args)) != B_OK)
186 				return B_BAD_ADDRESS;
187 
188 			status_t status = B_NOT_SUPPORTED;
189 			if (space != B_GRAY8) {
190 				status = vesa_set_indexed_colors(*info, args.first, args.colors,
191 					args.count);
192 			}
193 
194 			// Try VGA as a fallback
195 			if (status != B_OK && (info->vbe_capabilities
196 					& CAPABILITY_NOT_VGA_COMPATIBLE) == 0) {
197 				return vga_set_indexed_colors(args.first, args.colors,
198 					args.count);
199 			}
200 
201 			return status;
202 		}
203 
204 		case VGA_PLANAR_BLIT:
205 		{
206 			if (info->shared_info->current_mode.space != B_GRAY8
207 				|| (info->vbe_capabilities
208 					& CAPABILITY_NOT_VGA_COMPATIBLE) != 0)
209 				return B_NOT_SUPPORTED;
210 
211 			vga_planar_blit_args args;
212 			if (user_memcpy(&args, buffer, sizeof(args)) != B_OK)
213 				return B_BAD_ADDRESS;
214 
215 			return vga_planar_blit(info->shared_info, args.source,
216 				args.source_bytes_per_row, args.left, args.top,
217 				args.right, args.bottom);
218 		}
219 
220 		default:
221 			TRACE((DEVICE_NAME ": ioctl() unknown message %ld (length = %lu)\n",
222 				msg, bufferLength));
223 			break;
224 	}
225 
226 	return B_DEV_INVALID_IOCTL;
227 }
228 
229 
230 static status_t
231 device_read(void* /*cookie*/, off_t /*pos*/, void* /*buffer*/, size_t* _length)
232 {
233 	*_length = 0;
234 	return B_NOT_ALLOWED;
235 }
236 
237 
238 static status_t
239 device_write(void* /*cookie*/, off_t /*pos*/, const void* /*buffer*/,
240 	size_t* _length)
241 {
242 	*_length = 0;
243 	return B_NOT_ALLOWED;
244 }
245 
246 
247 device_hooks gDeviceHooks = {
248 	device_open,
249 	device_close,
250 	device_free,
251 	device_ioctl,
252 	device_read,
253 	device_write,
254 	NULL,
255 	NULL,
256 	NULL,
257 	NULL
258 };
259