1 /* Author: 2 Rudolf Cornelissen 4/2003-1/2006 3 */ 4 5 #define MODULE_BIT 0x00008000 6 7 #include "nm_std.h" 8 9 static status_t test_ram(void); 10 static status_t nmxxxx_general_powerup (void); 11 static status_t nm_general_bios_to_powergraphics(void); 12 13 static void nm_dump_configuration_space (void) 14 { 15 #define DUMP_CFG(reg, type) if (si->ps.card_type >= type) do { \ 16 uint32 value = CFGR(reg); \ 17 MSG(("configuration_space 0x%02x %20s 0x%08x\n", \ 18 NMCFG_##reg, #reg, value)); \ 19 } while (0) 20 DUMP_CFG (DEVID, 0); 21 DUMP_CFG (DEVCTRL, 0); 22 DUMP_CFG (CLASS, 0); 23 DUMP_CFG (HEADER, 0); 24 DUMP_CFG (BASE1FB, 0); 25 DUMP_CFG (BASE2REG1,0); 26 DUMP_CFG (BASE3REG2,0); 27 DUMP_CFG (BASE4, 0); 28 DUMP_CFG (BASE5, 0); 29 DUMP_CFG (BASE6, 0); 30 DUMP_CFG (BASE7, 0); 31 DUMP_CFG (SUBSYSID1,0); 32 DUMP_CFG (ROMBASE, 0); 33 DUMP_CFG (CAPPTR, 0); 34 DUMP_CFG (CFG_1, 0); 35 DUMP_CFG (INTERRUPT,0); 36 DUMP_CFG (CFG_3, 0); 37 DUMP_CFG (CFG_4, 0); 38 DUMP_CFG (CFG_5, 0); 39 DUMP_CFG (CFG_6, 0); 40 DUMP_CFG (CFG_7, 0); 41 DUMP_CFG (CFG_8, 0); 42 DUMP_CFG (CFG_9, 0); 43 DUMP_CFG (CFG_10, 0); 44 DUMP_CFG (CFG_11, 0); 45 DUMP_CFG (CFG_12, 0); 46 DUMP_CFG (CFG_13, 0); 47 DUMP_CFG (CFG_14, 0); 48 DUMP_CFG (CFG_15, 0); 49 DUMP_CFG (CFG_16, 0); 50 DUMP_CFG (CFG_17, 0); 51 DUMP_CFG (CFG_18, 0); 52 DUMP_CFG (CFG_19, 0); 53 DUMP_CFG (CFG_20, 0); 54 DUMP_CFG (CFG_21, 0); 55 DUMP_CFG (CFG_22, 0); 56 DUMP_CFG (CFG_23, 0); 57 DUMP_CFG (CFG_24, 0); 58 DUMP_CFG (CFG_25, 0); 59 DUMP_CFG (CFG_26, 0); 60 DUMP_CFG (CFG_27, 0); 61 DUMP_CFG (CFG_28, 0); 62 DUMP_CFG (CFG_29, 0); 63 DUMP_CFG (CFG_30, 0); 64 DUMP_CFG (CFG_31, 0); 65 DUMP_CFG (CFG_32, 0); 66 DUMP_CFG (CFG_33, 0); 67 DUMP_CFG (CFG_34, 0); 68 DUMP_CFG (CFG_35, 0); 69 DUMP_CFG (CFG_36, 0); 70 DUMP_CFG (CFG_37, 0); 71 DUMP_CFG (CFG_38, 0); 72 DUMP_CFG (CFG_39, 0); 73 DUMP_CFG (CFG_40, 0); 74 DUMP_CFG (CFG_41, 0); 75 DUMP_CFG (CFG_42, 0); 76 DUMP_CFG (CFG_43, 0); 77 DUMP_CFG (CFG_44, 0); 78 DUMP_CFG (CFG_45, 0); 79 DUMP_CFG (CFG_46, 0); 80 DUMP_CFG (CFG_47, 0); 81 DUMP_CFG (CFG_48, 0); 82 DUMP_CFG (CFG_49, 0); 83 DUMP_CFG (CFG_50, 0); 84 #undef DUMP_CFG 85 } 86 87 status_t nm_general_powerup() 88 { 89 status_t status; 90 91 LOG(1,("POWERUP: Haiku Neomagic Accelerant 0.14 running.\n")); 92 93 /* log VBLANK INT usability status */ 94 if (si->ps.int_assigned) 95 LOG(4,("POWERUP: Usable INT assigned to HW; Vblank semaphore enabled\n")); 96 else 97 LOG(4,("POWERUP: No (usable) INT assigned to HW; Vblank semaphore disabled\n")); 98 99 /* WARNING: 100 * _adi.name_ and _adi.chipset_ can contain 31 readable characters max.!!! */ 101 102 /* detect card type and power it up */ 103 switch(CFGR(DEVID)) 104 { 105 case 0x000110c8: //NM2070 ISA 106 si->ps.card_type = NM2070; 107 sprintf(si->adi.name, "Neomagic MagicGraph 128"); 108 sprintf(si->adi.chipset, "NM2070 (ISA)"); 109 break; 110 case 0x000210c8: //NM2090 ISA 111 si->ps.card_type = NM2090; 112 sprintf(si->adi.name, "Neomagic MagicGraph 128V"); 113 sprintf(si->adi.chipset, "NM2090 (ISA)"); 114 break; 115 case 0x000310c8: //NM2093 ISA 116 si->ps.card_type = NM2093; 117 sprintf(si->adi.name, "Neomagic MagicGraph 128ZV"); 118 sprintf(si->adi.chipset, "NM2093 (ISA)"); 119 break; 120 case 0x008310c8: //NM2097 PCI 121 si->ps.card_type = NM2097; 122 sprintf(si->adi.name, "Neomagic MagicGraph 128ZV+"); 123 sprintf(si->adi.chipset, "NM2097 (PCI)"); 124 break; 125 case 0x000410c8: //NM2160 PCI 126 si->ps.card_type = NM2160; 127 sprintf(si->adi.name, "Neomagic MagicGraph 128XD"); 128 sprintf(si->adi.chipset, "NM2160 (PCI)"); 129 break; 130 case 0x000510c8: //NM2200 131 si->ps.card_type = NM2200; 132 sprintf(si->adi.name, "Neomagic MagicMedia 256AV"); 133 sprintf(si->adi.chipset, "NM2200"); 134 break; 135 case 0x002510c8: //NM2230 136 si->ps.card_type = NM2230; 137 sprintf(si->adi.name, "Neomagic MagicMedia 256AV+"); 138 sprintf(si->adi.chipset, "NM2230"); 139 break; 140 case 0x000610c8: //NM2360 141 si->ps.card_type = NM2360; 142 sprintf(si->adi.name, "Neomagic MagicMedia 256ZX"); 143 sprintf(si->adi.chipset, "NM2360"); 144 break; 145 case 0x001610c8: //NM2380 146 si->ps.card_type = NM2380; 147 sprintf(si->adi.name, "Neomagic MagicMedia 256XL+"); 148 sprintf(si->adi.chipset, "NM2380"); 149 break; 150 default: 151 LOG(8,("POWERUP: Failed to detect valid card 0x%08x\n",CFGR(DEVID))); 152 return B_ERROR; 153 } 154 155 /* power up the card */ 156 status = nmxxxx_general_powerup(); 157 158 /* override memory detection if requested by user */ 159 if (si->settings.memory != 0) 160 si->ps.memory_size = si->settings.memory; 161 162 return status; 163 } 164 165 static status_t test_ram(void) 166 { 167 uint32 value, offset; 168 status_t result = B_OK; 169 170 /* make sure we don't corrupt the hardware cursor by using fbc.frame_buffer. */ 171 if (si->fbc.frame_buffer == NULL) 172 { 173 LOG(8,("INIT: test_ram detected NULL pointer.\n")); 174 return B_ERROR; 175 } 176 177 for (offset = 0, value = 0x55aa55aa; offset < 256; offset++) 178 { 179 /* write testpattern to cardRAM */ 180 ((uint32 *)si->fbc.frame_buffer)[offset] = value; 181 /* toggle testpattern */ 182 value = 0xffffffff - value; 183 } 184 185 for (offset = 0, value = 0x55aa55aa; offset < 256; offset++) 186 { 187 /* readback and verify testpattern from cardRAM */ 188 if (((uint32 *)si->fbc.frame_buffer)[offset] != value) result = B_ERROR; 189 /* toggle testpattern */ 190 value = 0xffffffff - value; 191 } 192 return result; 193 } 194 195 /* NOTE: 196 * This routine *has* to be done *after* SetDispplayMode has been executed, 197 * or test results will not be representative! 198 * (CAS latency is dependant on nm setup on some (DRAM) boards) */ 199 status_t nm_set_cas_latency() 200 { 201 /* check current RAM access to see if we need to change anything */ 202 if (test_ram() == B_OK) 203 { 204 LOG(4,("INIT: RAM access OK.\n")); 205 return B_OK; 206 } 207 208 /* check if we read PINS at starttime so we have valid registersettings at our disposal */ 209 LOG(4,("INIT: RAM access errors; not fixable: missing coldstart specs.\n")); 210 return B_ERROR; 211 } 212 213 void nm_unlock() 214 { 215 /* unlock cards GRAPHICS registers (any other value than 0x26 should lock it again) */ 216 ISAGRPHW(GRPHXLOCK, 0x26); 217 } 218 219 static status_t nmxxxx_general_powerup() 220 { 221 uint8 temp; 222 // status_t result; 223 224 LOG(4, ("INIT: powerup\n")); 225 LOG(4, ("INIT: Detected %s (%s)\n", si->adi.name, si->adi.chipset)); 226 if (si->settings.logmask & 0x80000000) nm_dump_configuration_space(); 227 228 /* set ISA registermapping to VGA colormode */ 229 temp = (ISARB(MISCR) | 0x01); 230 /* we need to wait a bit or the card will mess-up it's register values.. */ 231 snooze(10); 232 ISAWB(MISCW, temp); 233 234 /* unlock cards GRAPHICS registers (any other value than 0x26 should lock it again) */ 235 ISAGRPHW(GRPHXLOCK, 0x26); 236 237 /* unlock cards CRTC registers */ 238 //don't touch: most cards get into trouble on this! 239 // ISAGRPHW(GENLOCK, 0x00); 240 241 /* initialize the shared_info struct */ 242 set_specs(); 243 /* log the struct settings */ 244 dump_specs(); 245 246 /* activate PCI access: b7 = framebuffer, b6 = registers */ 247 ISAGRPHW(IFACECTRL2, 0xc0); 248 249 /* disable VGA-mode cursor (just to be sure) */ 250 ISACRTCW(VGACURCTRL, 0x00); 251 252 /* if the user doesn't want a coldstart OR the BIOS pins info could not be found warmstart */ 253 /*if (si->settings.usebios || (result != B_OK)) */return nm_general_bios_to_powergraphics(); 254 255 /*power up the PLLs,LUT,DAC*/ 256 LOG(2,("INIT: powerup\n")); 257 258 /* turn off both displays and the hardcursor (also disables transfers) */ 259 nm_crtc_dpms(false, false, false); 260 nm_crtc_cursor_hide(); 261 262 /* setup sequencer clocking mode */ 263 ISASEQW(CLKMODE, 0x21); 264 265 //fixme: setup coldstart capability... 266 267 /* turn on display */ 268 nm_crtc_dpms(true, true, true); 269 270 return B_OK; 271 } 272 273 status_t nm_general_output_select() 274 { 275 /* log currently selected output */ 276 switch (nm_general_output_read() & 0x03) 277 { 278 case 0x01: 279 LOG(2, ("INIT: external CRT only mode active\n")); 280 break; 281 case 0x02: 282 LOG(2, ("INIT: internal LCD only mode active\n")); 283 break; 284 case 0x03: 285 LOG(2, ("INIT: simultaneous LCD/CRT mode active\n")); 286 break; 287 } 288 return B_OK; 289 } 290 291 uint8 nm_general_output_read() 292 { 293 uint8 size_outputs; 294 295 /* read panelsize and currently active outputs */ 296 size_outputs = ISAGRPHR(PANELCTRL1); 297 298 /* update noted currently active outputs if prudent: 299 * - tracks active output devices, even if the keyboard shortcut is used because 300 * using that key will take the selected output devices out of DPMS sleep mode 301 * if programmed via these bits; 302 * - when the shortcut key is not used, and DPMS was in a power-saving mode while 303 * programmed via these bits, an output device will (still) be shut-off. */ 304 if (si->ps.card_type < NM2200) 305 { 306 /* both output devices do DPMS via these bits. 307 * if one of the bits is on we have a valid setting if no power-saving mode 308 * is active, or the keyboard shortcut key for selecting output devices has 309 * been used during power-saving mode. */ 310 if (size_outputs & 0x03) si->ps.outputs = (size_outputs & 0x03); 311 } 312 else 313 { 314 /* check if any power-saving mode active */ 315 if (!(ISASEQR(CLKMODE) & 0x20)) 316 { 317 /* screen is on: 318 * we can 'safely' copy both output devices settings... */ 319 if (size_outputs & 0x03) 320 { 321 si->ps.outputs = (size_outputs & 0x03); 322 } 323 else 324 { 325 /* ... unless no output is active, as this is illegal then */ 326 si->ps.outputs = 0x02; 327 328 LOG(4, ("INIT: illegal outputmode detected, assuming internal mode!\n")); 329 } 330 } 331 else 332 { 333 /* screen is off: 334 * only the internal panel does DPMS via these bits, so the external setting 335 * can always be copied */ 336 si->ps.outputs &= 0xfe; 337 si->ps.outputs |= (size_outputs & 0x01); 338 /* if the panel is on, we can note that (the shortcut key has been used) */ 339 if (size_outputs & 0x02) si->ps.outputs |= 0x02; 340 } 341 } 342 343 return ((size_outputs & 0xfc) | (si->ps.outputs & 0x03)); 344 } 345 346 /* basic change of card state from VGA to powergraphics -> should work from BIOS init state*/ 347 static 348 status_t nm_general_bios_to_powergraphics() 349 { 350 uint8 temp; 351 352 LOG(2, ("INIT: Skipping card coldstart!\n")); 353 354 /* turn off display */ 355 nm_crtc_dpms(false, false, false); 356 357 /* set card to 'enhanced' mode: (only VGA standard registers used for NeoMagic cards) */ 358 /* (keep) card enabled, set plain normal memory usage, no old VGA 'tricks' ... */ 359 ISACRTCW(MODECTL, 0xc3); 360 /* ... plain sequential memory use, more than 64Kb RAM installed, 361 * switch to graphics mode ... */ 362 ISASEQW(MEMMODE, 0x0e); 363 /* ... disable bitplane tweaking ... */ 364 /* note: 365 * NeoMagic cards have custom b4-b7 use in this register! */ 366 ISAGRPHW(ENSETRESET, 0x80); 367 /* ... no logical function tweaking with display data, no data rotation ... */ 368 ISAGRPHW(DATAROTATE, 0x00); 369 /* ... reset read map select to plane 0 ... */ 370 ISAGRPHW(READMAPSEL, 0x00); 371 /* ... set standard mode ... */ 372 ISAGRPHW(MODE, 0x00); 373 /* ... ISA framebuffer mapping is 64Kb window, switch to graphics mode (again), 374 * select standard adressing ... */ 375 ISAGRPHW(MISC, 0x05); 376 /* ... disable bit masking ... */ 377 ISAGRPHW(BITMASK, 0xff); 378 /* ... attributes are in color, switch to graphics mode (again) ... */ 379 ISAATBW(MODECTL, 0x01); 380 /* ... set overscan color to black ... */ 381 ISAATBW(OSCANCOLOR, 0x00); 382 /* ... enable all color planes ... */ 383 ISAATBW(COLPLANE_EN, 0x0f); 384 /* ... reset horizontal pixelpanning ... */ 385 ISAATBW(HORPIXPAN, 0x00); 386 /* ... reset colorpalette groupselect bits ... */ 387 ISAATBW(COLSEL, 0x00); 388 /* ... do unknown standard VGA register ... */ 389 /* note: 390 * NeoMagic cards have custom b6 use in this register! */ 391 ISAATBW(0x16, 0x01); 392 /* ... and enable all four byteplanes. */ 393 ISASEQW(MAPMASK, 0x0f); 394 395 /* setup sequencer clocking mode */ 396 ISASEQW(CLKMODE, 0x21); 397 398 /* enable memory above 256Kb: set b4 (disables adress wraparound at 256Kb boundary) */ 399 ISAGRPHW(FBSTADDE, 0x10); 400 401 /* this register has influence on the CRTC framebuffer offset, so reset! */ 402 //fixme: investigate further... 403 ISAGRPHW(0x15, 0x00); 404 405 /* enable fast PCI write bursts (b4-5) */ 406 temp = ((ISAGRPHR(IFACECTRL1) & 0x0f) | 0x30); 407 /* we need to wait a bit or the card will mess-up it's register values.. */ 408 snooze(10); 409 ISAGRPHW(IFACECTRL1, temp); 410 411 /* this speeds up RAM writes according to XFree driver */ 412 // fixme: don't touch until more is known: part of RAM or CORE PLL??? 413 // ISAGRPHW(SPEED, 0xc0); 414 415 /* turn on display */ 416 nm_crtc_dpms(true, true, true); 417 418 return B_OK; 419 } 420 421 /* Check if mode virtual_size adheres to the cards _maximum_ contraints, and modify 422 * virtual_size to the nearest valid maximum for the mode on the card if not so. 423 * Then: check if virtual_width adheres to the cards _multiple_ constraints, and 424 * create mode slopspace if not so. 425 * We use acc multiple constraints here if we expect we can use acceleration, because 426 * acc constraints are worse than CRTC constraints. 427 * 428 * Mode slopspace is reflected in fbc->bytes_per_row BTW. */ 429 status_t nm_general_validate_pic_size (display_mode *target, uint32 *bytes_per_row, bool *acc_mode) 430 { 431 /* Note: 432 * This routine assumes that the CRTC memory pitch granularity is 'smaller than', 433 * or 'equals' the acceleration engine memory pitch granularity! */ 434 435 uint32 video_pitch = 0; 436 uint32 crtc_mask; 437 uint8 depth = 8; 438 439 /* determine pixel multiple based on CRTC memory pitch constraints. 440 * (Note: Don't mix this up with CRTC timing contraints! Those are 441 * multiples of 8 for horizontal, 1 for vertical timing.) 442 * 443 * CRTC pitch constraints are 'officially' the same for all Neomagic cards */ 444 switch (si->ps.card_type) 445 { 446 case NM2070: 447 switch (target->space) 448 { 449 case B_CMAP8: crtc_mask = 0x07; depth = 8; break; 450 /* Note for NM2070 only: 451 * The following depths have bandwidth trouble (pixel noise) with the 452 * 'official' crtc_masks (used as defaults below). Masks of 0x1f are 453 * needed (confirmed 15 and 16 bit spaces) to minimize this. */ 454 //fixme: doublecheck for NM2090 and NM2093: correct code if needed! 455 case B_RGB15: crtc_mask = 0x1f; depth = 16; break; 456 case B_RGB16: crtc_mask = 0x1f; depth = 16; break; 457 case B_RGB24: crtc_mask = 0x1f; depth = 24; break; 458 default: 459 LOG(8,("INIT: unsupported colorspace: 0x%08x\n", target->space)); 460 return B_ERROR; 461 } 462 break; 463 default: 464 switch (target->space) 465 { 466 case B_CMAP8: crtc_mask = 0x07; depth = 8; break; 467 case B_RGB15: crtc_mask = 0x03; depth = 16; break; 468 case B_RGB16: crtc_mask = 0x03; depth = 16; break; 469 case B_RGB24: crtc_mask = 0x07; depth = 24; break; 470 default: 471 LOG(8,("INIT: unsupported colorspace: 0x%08x\n", target->space)); 472 return B_ERROR; 473 } 474 break; 475 } 476 477 /* check if we can setup this mode with acceleration: */ 478 *acc_mode = true; 479 480 /* pre-NM2200 cards don't support accelerated 24bit modes */ 481 if ((si->ps.card_type < NM2200) && (target->space == B_RGB24)) *acc_mode = false; 482 483 /* virtual_width */ 484 if (si->ps.card_type == NM2070) 485 { 486 /* confirmed NM2070 */ 487 if (target->virtual_width > 1024) *acc_mode = false; 488 } 489 else 490 { 491 /* confirmed for all cards */ 492 if (target->virtual_width > 1600) *acc_mode = false; 493 } 494 495 /* virtual_height (confirmed NM2070, NM2097, NM2160 and NM2200 */ 496 if (target->virtual_height > 1024) *acc_mode = false; 497 498 /* now check virtual_size based on CRTC constraints and modify if needed */ 499 //fixme: checkout cardspecs here!! (NM2160 can do 8192 _bytes_ at least (in theory)) 500 { 501 /* virtual_width */ 502 switch(target->space) 503 { 504 case B_CMAP8: 505 if (target->virtual_width > 16368) 506 target->virtual_width = 16368; 507 break; 508 case B_RGB15_LITTLE: 509 case B_RGB16_LITTLE: 510 if (target->virtual_width > 8184) 511 target->virtual_width = 8184; 512 break; 513 case B_RGB24_LITTLE: 514 if (target->virtual_width > 5456) 515 target->virtual_width = 5456; 516 break; 517 } 518 519 /* virtual_height: The only constraint here is the cards memory size which is 520 * checked later on in ProposeMode: virtual_height is adjusted then if needed. 521 * 'Limiting here' to the variable size that's at least available (uint16). */ 522 if (target->virtual_height > 65535) target->virtual_height = 65535; 523 } 524 525 /* OK, now we know that virtual_width is valid, and it's needing no slopspace if 526 * it was confined above, so we can finally calculate safely if we need slopspace 527 * for this mode... */ 528 if (*acc_mode) 529 { 530 if (si->ps.card_type == NM2070) 531 { 532 uint32 acc_mask = 0; 533 534 /* determine pixel multiple based on 2D engine constraints */ 535 switch (target->space) 536 { 537 case B_CMAP8: acc_mask = 0x07; break; 538 /* Note: 539 * The following depths have actual acc_masks of 0x03. 0x1f is used 540 * because on lower acc_masks more bandwidth trouble arises. 541 * (pixel noise) */ 542 //fixme: doublecheck for NM2090 and NM2093: correct code if needed! 543 case B_RGB15: acc_mask = 0x1f; break; 544 case B_RGB16: acc_mask = 0x1f; break; 545 } 546 video_pitch = ((target->virtual_width + acc_mask) & ~acc_mask); 547 } 548 else 549 { 550 /* Note: 551 * We prefer unaccelerated modes above accelerated ones here if not enough 552 * RAM exists and the mode can be closer matched to the requested one if 553 * unaccelerated. We do this because of the large amount of slopspace 554 * sometimes needed here to keep a mode accelerated. */ 555 556 uint32 mem_avail, bytes_X_height; 557 558 /* calculate amount of available memory */ 559 mem_avail = (si->ps.memory_size * 1024); 560 if (si->settings.hardcursor) mem_avail -= si->ps.curmem_size; 561 /* helper */ 562 bytes_X_height = (depth >> 3) * target->virtual_height; 563 564 /* Accelerated modes work with a table, there are very few fixed settings.. */ 565 if (target->virtual_width == 640) video_pitch = 640; 566 else 567 if (target->virtual_width <= 800) 568 { 569 if (((800 * bytes_X_height) > mem_avail) && 570 (target->virtual_width < (800 - crtc_mask))) 571 *acc_mode = false; 572 else 573 video_pitch = 800; 574 } 575 else 576 if (target->virtual_width <= 1024) 577 { 578 if (((1024 * bytes_X_height) > mem_avail) && 579 (target->virtual_width < (1024 - crtc_mask))) 580 *acc_mode = false; 581 else 582 video_pitch = 1024; 583 } 584 else 585 if (target->virtual_width <= 1152) 586 { 587 if (((1152 * bytes_X_height) > mem_avail) && 588 (target->virtual_width < (1152 - crtc_mask))) 589 *acc_mode = false; 590 else 591 video_pitch = 1152; 592 } 593 else 594 if (target->virtual_width <= 1280) 595 { 596 if (((1280 * bytes_X_height) > mem_avail) && 597 (target->virtual_width < (1280 - crtc_mask))) 598 *acc_mode = false; 599 else 600 video_pitch = 1280; 601 } 602 else 603 if (target->virtual_width <= 1600) 604 { 605 if (((1600 * bytes_X_height) > mem_avail) && 606 (target->virtual_width < (1600 - crtc_mask))) 607 *acc_mode = false; 608 else 609 video_pitch = 1600; 610 } 611 } 612 } 613 if (!*acc_mode) 614 video_pitch = ((target->virtual_width + crtc_mask) & ~crtc_mask); 615 616 LOG(2,("INIT: memory pitch will be set to %d pixels for colorspace 0x%08x\n", 617 video_pitch, target->space)); 618 if (target->virtual_width != video_pitch) 619 LOG(2,("INIT: effective mode slopspace is %d pixels\n", 620 (video_pitch - target->virtual_width))); 621 622 /* now calculate bytes_per_row for this mode */ 623 *bytes_per_row = video_pitch * (depth >> 3); 624 625 return B_OK; 626 } 627