1/*
2 * Copyright 2007, Haiku.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Eric Petit <eric.petit@lapsus.org>
7 *		Michael Pfeiffer <laplace@users.sourceforge.net>
8 */
9
10
11#include "driver.h"
12
13#include <KernelExport.h>
14#include <PCI.h>
15#include <OS.h>
16#include <graphic_driver.h>
17
18#include <stdlib.h>
19#include <stdio.h>
20#include <string.h>
21
22
23#define get_pci(o, s) (*gPciBus->read_pci_config)(pcii->bus, pcii->device, pcii->function, (o), (s))
24#define set_pci(o, s, v) (*gPciBus->write_pci_config)(pcii->bus, pcii->device, pcii->function, (o), (s), (v))
25
26
27static void
28PrintCapabilities(uint32 c)
29{
30	TRACE("capabilities:\n");
31	if (c & SVGA_CAP_RECT_FILL)			TRACE("RECT_FILL\n");
32	if (c & SVGA_CAP_RECT_COPY)			TRACE("RECT_COPY\n");
33	if (c & SVGA_CAP_RECT_PAT_FILL)		TRACE("RECT_PAT_FILL\n");
34	if (c & SVGA_CAP_LEGACY_OFFSCREEN)	TRACE("LEGACY_OFFSCREEN\n");
35	if (c & SVGA_CAP_RASTER_OP)			TRACE("RASTER_OP\n");
36	if (c & SVGA_CAP_CURSOR)			TRACE("CURSOR\n");
37	if (c & SVGA_CAP_CURSOR_BYPASS)		TRACE("CURSOR_BYPASS\n");
38	if (c & SVGA_CAP_CURSOR_BYPASS_2)	TRACE("CURSOR_BYPASS_2\n");
39	if (c & SVGA_CAP_8BIT_EMULATION)	TRACE("8BIT_EMULATION\n");
40	if (c & SVGA_CAP_ALPHA_CURSOR)		TRACE("ALPHA_CURSOR\n");
41	if (c & SVGA_CAP_GLYPH)				TRACE("GLYPH\n");
42	if (c & SVGA_CAP_GLYPH_CLIPPING)	TRACE("GLYPH_CLIPPING\n");
43	if (c & SVGA_CAP_OFFSCREEN_1)		TRACE("OFFSCREEN_1\n");
44	if (c & SVGA_CAP_ALPHA_BLEND)		TRACE("ALPHA_BLEND\n");
45	if (c & SVGA_CAP_3D)				TRACE("3D\n");
46	if (c & SVGA_CAP_EXTENDED_FIFO)		TRACE("EXTENDED_FIFO\n");
47}
48
49
50static status_t
51CheckCapabilities()
52{
53	SharedInfo *si = gPd->si;
54	uint32 id;
55
56	/* Needed to read/write registers */
57	si->indexPort = gPd->pcii.u.h0.base_registers[0] + SVGA_INDEX_PORT;
58	si->valuePort = gPd->pcii.u.h0.base_registers[0] + SVGA_VALUE_PORT;
59	TRACE("index port: %d, value port: %d\n",
60		si->indexPort, si->valuePort);
61
62	/* This should be SVGA II according to the PCI device_id,
63	 * but just in case... */
64	WriteReg(SVGA_REG_ID, SVGA_ID_2);
65	if ((id = ReadReg(SVGA_REG_ID)) != SVGA_ID_2) {
66		TRACE("SVGA_REG_ID is %ld, not %d\n", id, SVGA_REG_ID);
67		return B_ERROR;
68	}
69	TRACE("SVGA_REG_ID OK\n");
70
71	/* Grab some info */
72	si->maxWidth = ReadReg(SVGA_REG_MAX_WIDTH);
73	si->maxHeight = ReadReg(SVGA_REG_MAX_HEIGHT);
74	TRACE("max resolution: %ldx%ld\n", si->maxWidth, si->maxHeight);
75	si->fbDma = (void *)ReadReg(SVGA_REG_FB_START);
76	si->fbSize = ReadReg(SVGA_REG_VRAM_SIZE);
77	TRACE("frame buffer: %p, size %ld\n", si->fbDma, si->fbSize);
78	si->fifoDma = (void *)ReadReg(SVGA_REG_MEM_START);
79	si->fifoSize = ReadReg(SVGA_REG_MEM_SIZE) & ~3;
80	TRACE("fifo: %p, size %ld\n", si->fifoDma, si->fifoSize);
81	si->capabilities = ReadReg(SVGA_REG_CAPABILITIES);
82	PrintCapabilities(si->capabilities);
83	si->fifoMin = (si->capabilities & SVGA_CAP_EXTENDED_FIFO) ?
84		ReadReg(SVGA_REG_MEM_REGS) : 4;
85
86	return B_OK;
87}
88
89
90static status_t
91MapDevice()
92{
93	SharedInfo *si = gPd->si;
94	int writeCombined = 1;
95
96	/* Map the frame buffer */
97	si->fbArea = map_physical_memory("VMware frame buffer",
98		(addr_t)si->fbDma, si->fbSize, B_ANY_KERNEL_BLOCK_ADDRESS|B_MTR_WC,
99		B_READ_AREA|B_WRITE_AREA, (void **)&si->fb);
100	if (si->fbArea < 0) {
101		/* Try again without write combining */
102		writeCombined = 0;
103		si->fbArea = map_physical_memory("VMware frame buffer",
104			(addr_t)si->fbDma, si->fbSize, B_ANY_KERNEL_BLOCK_ADDRESS,
105			B_READ_AREA|B_WRITE_AREA, (void **)&si->fb);
106	}
107	if (si->fbArea < 0) {
108		TRACE("failed to map frame buffer\n");
109		return si->fbArea;
110	}
111	TRACE("frame buffer mapped: %p->%p, area %ld, size %ld, write "
112		"combined: %d\n", si->fbDma, si->fb, si->fbArea,
113		si->fbSize, writeCombined);
114
115	/* Map the fifo */
116	si->fifoArea = map_physical_memory("VMware fifo",
117		(addr_t)si->fifoDma, si->fifoSize, B_ANY_KERNEL_BLOCK_ADDRESS,
118		B_READ_AREA|B_WRITE_AREA, (void **)&si->fifo);
119	if (si->fifoArea < 0) {
120		TRACE("failed to map fifo\n");
121		delete_area(si->fbArea);
122		return si->fifoArea;
123	}
124	TRACE("fifo mapped: %p->%p, area %ld, size %ld\n", si->fifoDma,
125		si->fifo, si->fifoArea, si->fifoSize);
126
127	return B_OK;
128}
129
130
131static void
132UnmapDevice()
133{
134	SharedInfo *si = gPd->si;
135	pci_info *pcii = &gPd->pcii;
136	uint32 tmpUlong;
137
138	/* Disable memory mapped IO */
139	tmpUlong = get_pci(PCI_command, 2);
140	tmpUlong &= ~PCI_command_memory;
141	set_pci(PCI_command, 2, tmpUlong);
142
143	/* Delete the areas */
144	if (si->fifoArea >= 0)
145		delete_area(si->fifoArea);
146	if (si->fbArea >= 0)
147		delete_area(si->fbArea);
148	si->fifoArea = si->fbArea = -1;
149	si->fb = si->fifo = NULL;
150}
151
152
153static status_t
154CreateShared()
155{
156	gPd->sharedArea = create_area("VMware shared", (void **)&gPd->si,
157		B_ANY_KERNEL_ADDRESS, ROUND_TO_PAGE_SIZE(sizeof(SharedInfo)),
158		B_FULL_LOCK, 0);
159	if (gPd->sharedArea < B_OK) {
160		TRACE("failed to create shared area\n");
161		return gPd->sharedArea;
162	}
163	TRACE("shared area created\n");
164
165	memset(gPd->si, 0, sizeof(SharedInfo));
166	return B_OK;
167}
168
169
170static void
171FreeShared()
172{
173	delete_area(gPd->sharedArea);
174	gPd->sharedArea = -1;
175	gPd->si = NULL;
176}
177
178
179static status_t
180OpenHook(const char *name, uint32 flags, void **cookie)
181{
182	status_t ret = B_OK;
183	pci_info *pcii = &gPd->pcii;
184	uint32 tmpUlong;
185
186	TRACE("OpenHook (%s, %ld)\n", name, flags);
187	ACQUIRE_BEN(gPd->kernel);
188
189	if (gPd->isOpen)
190		goto markAsOpen;
191
192	/* Enable memory mapped IO and VGA I/O */
193	tmpUlong = get_pci(PCI_command, 2);
194	tmpUlong |= PCI_command_memory;
195	tmpUlong |= PCI_command_io;
196	set_pci(PCI_command, 2, tmpUlong);
197
198	if ((ret = CreateShared()) != B_OK)
199		goto done;
200	if ((ret = CheckCapabilities()) != B_OK)
201		goto freeShared;
202	if ((ret = MapDevice()) != B_OK)
203		goto freeShared;
204
205markAsOpen:
206	gPd->isOpen++;
207	*cookie = gPd;
208	goto done;
209
210freeShared:
211	FreeShared();
212
213done:
214	RELEASE_BEN(gPd->kernel);
215	TRACE("OpenHook: %ld\n", ret);
216	return ret;
217}
218
219
220/*--------------------------------------------------------------------*/
221/* ReadHook, WriteHook, CloseHook: do nothing */
222
223static status_t
224ReadHook(void *dev, off_t pos, void *buf, size_t *len)
225{
226	*len = 0;
227	return B_NOT_ALLOWED;
228}
229static status_t
230WriteHook(void *dev, off_t pos, const void *buf, size_t *len)
231{
232	*len = 0;
233	return B_NOT_ALLOWED;
234}
235static status_t
236CloseHook(void *dev)
237{
238	return B_OK;
239}
240
241
242/*--------------------------------------------------------------------*/
243/* FreeHook: closes down the device */
244
245static status_t
246FreeHook(void *dev)
247{
248	TRACE("FreeHook\n");
249	ACQUIRE_BEN(gPd->kernel);
250
251	if (gPd->isOpen < 2) {
252		UnmapDevice();
253		FreeShared();
254	}
255	gPd->isOpen--;
256
257	RELEASE_BEN(gPd->kernel);
258	TRACE("FreeHook ends\n");
259	return B_OK;
260}
261
262
263static void
264UpdateCursor(SharedInfo *si)
265{
266	WriteReg(SVGA_REG_CURSOR_ID, CURSOR_ID);
267	WriteReg(SVGA_REG_CURSOR_X, si->cursorX);
268	WriteReg(SVGA_REG_CURSOR_Y, si->cursorY);
269	WriteReg(SVGA_REG_CURSOR_ON, si->cursorShow ? SVGA_CURSOR_ON_SHOW :
270				SVGA_CURSOR_ON_HIDE);
271}
272
273
274/*--------------------------------------------------------------------*/
275/* ControlHook: responds the the ioctl from the accelerant */
276
277static status_t
278ControlHook(void *dev, uint32 msg, void *buf, size_t len)
279{
280	SharedInfo *si = gPd->si;
281
282	switch (msg) {
283		case B_GET_ACCELERANT_SIGNATURE:
284			strcpy((char *)buf, "vmware.accelerant");
285			return B_OK;
286
287		case VMWARE_GET_PRIVATE_DATA:
288			*((area_id *)buf) = gPd->sharedArea;
289			return B_OK;
290
291		case VMWARE_FIFO_START:
292			WriteReg(SVGA_REG_ENABLE, 1);
293			WriteReg(SVGA_REG_CONFIG_DONE, 1);
294			return B_OK;
295
296		case VMWARE_FIFO_STOP:
297			WriteReg(SVGA_REG_CONFIG_DONE, 0);
298			WriteReg(SVGA_REG_ENABLE, 0);
299			return B_OK;
300
301		case VMWARE_FIFO_SYNC:
302			WriteReg(SVGA_REG_SYNC, 1);
303			while (ReadReg(SVGA_REG_BUSY));
304			return B_OK;
305
306		case VMWARE_SET_MODE:
307		{
308			display_mode *dm = buf;
309			WriteReg(SVGA_REG_WIDTH, dm->virtual_width);
310			WriteReg(SVGA_REG_HEIGHT, dm->virtual_height);
311			WriteReg(SVGA_REG_BITS_PER_PIXEL, BppForSpace(dm->space));
312			si->fbOffset = ReadReg(SVGA_REG_FB_OFFSET);
313			si->bytesPerRow = ReadReg(SVGA_REG_BYTES_PER_LINE);
314			ReadReg(SVGA_REG_DEPTH);
315			ReadReg(SVGA_REG_PSEUDOCOLOR);
316			ReadReg(SVGA_REG_RED_MASK);
317			ReadReg(SVGA_REG_GREEN_MASK);
318			ReadReg(SVGA_REG_BLUE_MASK);
319			return B_OK;
320		}
321
322		case VMWARE_SET_PALETTE:
323		{
324			uint8 *color = (uint8 *)buf;
325			uint32 i;
326			if (ReadReg(SVGA_REG_PSEUDOCOLOR) != 1)
327				return B_ERROR;
328
329			for (i = 0; i < 256; i++) {
330				WriteReg(SVGA_PALETTE_BASE + 3 * i, *color++);
331				WriteReg(SVGA_PALETTE_BASE + 3 * i + 1, *color++);
332				WriteReg(SVGA_PALETTE_BASE + 3 * i + 2, *color++);
333			}
334			return B_OK;
335		}
336
337		case VMWARE_MOVE_CURSOR:
338		{
339			uint16 *pos = buf;
340			si->cursorX = pos[0];
341			si->cursorY = pos[1];
342			UpdateCursor(si);
343			return B_OK;
344		}
345
346		case VMWARE_SHOW_CURSOR:
347		{
348			si->cursorShow = *((bool *)buf);
349			UpdateCursor(si);
350			return B_OK;
351		}
352
353		case VMWARE_GET_DEVICE_NAME:
354			dprintf("device: VMWARE_GET_DEVICE_NAME %s\n", gPd->names[0]);
355#ifdef HAIKU_TARGET_PLATFORM_HAIKU
356			if (user_strlcpy((char *)buf, gPd->names[0],
357					B_PATH_NAME_LENGTH) < B_OK)
358				return B_BAD_ADDRESS;
359#else
360			strlcpy((char *)buf, gPd->names[0], B_PATH_NAME_LENGTH);
361#endif
362			return B_OK;
363
364	}
365
366	TRACE("ioctl: %ld, %p, %ld\n", msg, buf, len);
367	return B_DEV_INVALID_IOCTL;
368}
369
370
371device_hooks gGraphicsDeviceHooks =
372{
373	OpenHook,
374	CloseHook,
375	FreeHook,
376	ControlHook,
377	ReadHook,
378	WriteHook,
379	NULL,
380	NULL,
381	NULL,
382	NULL
383};
384
385