xref: /haiku/src/add-ons/kernel/drivers/graphics/vesa/device.cpp (revision 820dca4df6c7bf955c46e8f6521b9408f50b2900)
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 	*_cookie = info;
55 
56 	mutex_lock(&gLock);
57 
58 	status_t status = B_OK;
59 
60 	if (info->open_count++ == 0) {
61 		// this device has been opened for the first time, so
62 		// we allocate needed resources and initialize the structure
63 		if (status == B_OK)
64 			status = vesa_init(*info);
65 		if (status == B_OK)
66 			info->id = id;
67 	}
68 
69 	mutex_unlock(&gLock);
70 	return status;
71 }
72 
73 
74 static status_t
75 device_close(void* cookie)
76 {
77 	return B_OK;
78 }
79 
80 
81 static status_t
82 device_free(void* cookie)
83 {
84 	struct vesa_info* info = (vesa_info*)cookie;
85 
86 	mutex_lock(&gLock);
87 
88 	if (info->open_count-- == 1) {
89 		// release info structure
90 		vesa_uninit(*info);
91 	}
92 
93 	mutex_unlock(&gLock);
94 	return B_OK;
95 }
96 
97 
98 static status_t
99 device_ioctl(void* cookie, uint32 msg, void* buffer, size_t bufferLength)
100 {
101 	struct vesa_info* info = (vesa_info*)cookie;
102 
103 	switch (msg) {
104 		case B_GET_ACCELERANT_SIGNATURE:
105 			dprintf(DEVICE_NAME ": acc: %s\n", VESA_ACCELERANT_NAME);
106 			if (user_strlcpy((char*)buffer, VESA_ACCELERANT_NAME,
107 					B_FILE_NAME_LENGTH) < B_OK)
108 				return B_BAD_ADDRESS;
109 
110 			return B_OK;
111 
112 		// needed to share data between kernel and accelerant
113 		case VESA_GET_PRIVATE_DATA:
114 			return user_memcpy(buffer, &info->shared_area, sizeof(area_id));
115 
116 		// needed for cloning
117 		case VESA_GET_DEVICE_NAME:
118 			if (user_strlcpy((char*)buffer, gDeviceNames[info->id],
119 					B_PATH_NAME_LENGTH) < B_OK)
120 				return B_BAD_ADDRESS;
121 
122 			return B_OK;
123 
124 		case VESA_SET_DISPLAY_MODE:
125 		{
126 			if (bufferLength != sizeof(uint32))
127 				return B_BAD_VALUE;
128 
129 			uint32 mode;
130 			if (user_memcpy(&mode, buffer, sizeof(uint32)) != B_OK)
131 				return B_BAD_ADDRESS;
132 
133 			return vesa_set_display_mode(*info, mode);
134 		}
135 
136 		case VESA_GET_DPMS_MODE:
137 		{
138 			if (bufferLength != sizeof(uint32))
139 				return B_BAD_VALUE;
140 
141 			uint32 mode;
142 			status_t status = vesa_get_dpms_mode(*info, mode);
143 			if (status != B_OK)
144 				return status;
145 
146 			return user_memcpy(buffer, &mode, sizeof(mode));
147 		}
148 
149 		case VESA_SET_DPMS_MODE:
150 		{
151 			if (bufferLength != sizeof(uint32))
152 				return B_BAD_VALUE;
153 
154 			uint32 mode;
155 			if (user_memcpy(&mode, buffer, sizeof(uint32)) != B_OK)
156 				return B_BAD_ADDRESS;
157 
158 			return vesa_set_dpms_mode(*info, mode);
159 		}
160 
161 		case VESA_SET_INDEXED_COLORS:
162 		{
163 			color_space space
164 				= (color_space)info->shared_info->current_mode.space;
165 			if (space != B_GRAY8 && space != B_CMAP8)
166 				return B_ERROR;
167 
168 			vesa_set_indexed_colors_args args;
169 			if (user_memcpy(&args, buffer, sizeof(args)) != B_OK)
170 				return B_BAD_ADDRESS;
171 
172 			status_t status = B_NOT_SUPPORTED;
173 			if (space != B_GRAY8) {
174 				status = vesa_set_indexed_colors(*info, args.first, args.colors,
175 					args.count);
176 			}
177 
178 			// Try VGA as a fallback
179 			if (status != B_OK && (info->vbe_capabilities
180 					& CAPABILITY_NOT_VGA_COMPATIBLE) == 0) {
181 				return vga_set_indexed_colors(args.first, args.colors,
182 					args.count);
183 			}
184 
185 			return status;
186 		}
187 
188 		case VGA_PLANAR_BLIT:
189 		{
190 			if (info->shared_info->current_mode.space != B_GRAY8
191 				|| (info->vbe_capabilities
192 					& CAPABILITY_NOT_VGA_COMPATIBLE) != 0)
193 				return B_NOT_SUPPORTED;
194 
195 			vga_planar_blit_args args;
196 			if (user_memcpy(&args, buffer, sizeof(args)) != B_OK)
197 				return B_BAD_ADDRESS;
198 
199 			return vga_planar_blit(info->shared_info, args.source,
200 				args.source_bytes_per_row, args.left, args.top,
201 				args.right, args.bottom);
202 		}
203 
204 		default:
205 			TRACE((DEVICE_NAME ": ioctl() unknown message %ld (length = %lu)\n",
206 				msg, bufferLength));
207 			break;
208 	}
209 
210 	return B_DEV_INVALID_IOCTL;
211 }
212 
213 
214 static status_t
215 device_read(void* /*cookie*/, off_t /*pos*/, void* /*buffer*/, size_t* _length)
216 {
217 	*_length = 0;
218 	return B_NOT_ALLOWED;
219 }
220 
221 
222 static status_t
223 device_write(void* /*cookie*/, off_t /*pos*/, const void* /*buffer*/,
224 	size_t* _length)
225 {
226 	*_length = 0;
227 	return B_NOT_ALLOWED;
228 }
229 
230 
231 device_hooks gDeviceHooks = {
232 	device_open,
233 	device_close,
234 	device_free,
235 	device_ioctl,
236 	device_read,
237 	device_write,
238 	NULL,
239 	NULL,
240 	NULL,
241 	NULL
242 };
243