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