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	*_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
74static status_t
75device_close(void* cookie)
76{
77	return B_OK;
78}
79
80
81static status_t
82device_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
98static status_t
99device_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
214static status_t
215device_read(void* /*cookie*/, off_t /*pos*/, void* /*buffer*/, size_t* _length)
216{
217	*_length = 0;
218	return B_NOT_ALLOWED;
219}
220
221
222static status_t
223device_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
231device_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