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
37static status_t
38device_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
78static status_t
79device_close(void* cookie)
80{
81	return B_OK;
82}
83
84
85static status_t
86device_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
102static status_t
103device_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
233static status_t
234device_read(void* /*cookie*/, off_t /*pos*/, void* /*buffer*/, size_t* _length)
235{
236	*_length = 0;
237	return B_NOT_ALLOWED;
238}
239
240
241static status_t
242device_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
250device_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