1 /* 2 Copyright 1999, Be Incorporated. All Rights Reserved. 3 This file may be used under the terms of the Be Sample Code License. 4 5 Other authors: 6 Mark Watson, 7 Rudolf Cornelissen 10/2002-1/2016. 8 */ 9 10 #define MODULE_BIT 0x00800000 11 12 #include <string.h> 13 #include <unistd.h> 14 #include "acc_std.h" 15 16 static status_t init_common(int the_fd); 17 18 /* Initialization code shared between primary and cloned accelerants */ 19 static status_t init_common(int the_fd) { 20 status_t result; 21 nv_get_private_data gpd; 22 23 // LOG not available from here to next LOG: NULL si 24 25 /* memorize the file descriptor */ 26 fd = the_fd; 27 /* set the magic number so the driver knows we're for real */ 28 gpd.magic = NV_PRIVATE_DATA_MAGIC; 29 /* contact driver and get a pointer to the registers and shared data */ 30 result = ioctl(fd, NV_GET_PRIVATE_DATA, &gpd, sizeof(gpd)); 31 if (result != B_OK) 32 goto error0; 33 34 /* clone the shared area for our use */ 35 shared_info_area = clone_area(DRIVER_PREFIX " shared", (void **)&si, B_ANY_ADDRESS, 36 B_READ_AREA | B_WRITE_AREA, gpd.shared_info_area); 37 if (shared_info_area < 0) { 38 result = shared_info_area; 39 goto error0; 40 } 41 // LOG is now available, si !NULL 42 LOG(4,("init_common: logmask 0x%08x, memory %dMB, hardcursor %d, usebios %d, switchhead %d, force_pci %d\n", 43 si->settings.logmask, si->settings.memory, si->settings.hardcursor, si->settings.usebios, si->settings.switchhead, si->settings.force_pci)); 44 LOG(4,("init_common: dumprom %d, unhide_fw %d, pgm_panel %d, dma_acc %d, tv_output %d, vga_on_tv %d\n", 45 si->settings.dumprom, si->settings.unhide_fw, si->settings.pgm_panel, si->settings.dma_acc, si->settings.tv_output, si->settings.vga_on_tv)); 46 LOG(4,("init_common: force_sync %d, gpu_clk %dMhz, ram_clk %dMhz, force_ws %d, block_acc %d, check_edid %d\n", 47 si->settings.force_sync, si->settings.gpu_clk, si->settings.ram_clk, si->settings.force_ws, si->settings.block_acc, si->settings.check_edid)); 48 49 /*Check for R4.5.0 and if it is running, use work around*/ 50 { 51 if (si->use_clone_bugfix) 52 { 53 /*check for R4.5.0 bug and attempt to work around*/ 54 LOG(2,("InitACC: Found R4.5.0 bug - attempting to work around\n")); 55 regs = si->clone_bugfix_regs; 56 } 57 else 58 { 59 /* clone the memory mapped registers for our use - does not work on <4.5.2 (but is better this way)*/ 60 regs_area = clone_area(DRIVER_PREFIX " regs", (void **)®s, B_ANY_ADDRESS, 61 B_READ_AREA | B_WRITE_AREA, si->regs_area); 62 if (regs_area < 0) { 63 result = regs_area; 64 goto error1; 65 } 66 } 67 } 68 69 /* all done */ 70 goto error0; 71 72 error1: 73 delete_area(shared_info_area); 74 error0: 75 return result; 76 } 77 78 /* Clean up code shared between primary and cloned accelrants */ 79 static void uninit_common(void) { 80 /* release the memory mapped registers */ 81 delete_area(regs_area); 82 /* a little cheap paranoia */ 83 regs = 0; 84 /* release our copy of the shared info from the kernel driver */ 85 delete_area(shared_info_area); 86 /* more cheap paranoia */ 87 si = 0; 88 } 89 90 /* 91 Initialize the accelerant. the_fd is the file handle of the device (in 92 /dev/graphics) that has been opened by the app_server (or some test harness). 93 We need to determine if the kernel driver and the accelerant are compatible. 94 If they are, get the accelerant ready to handle other hook functions and 95 report success or failure. 96 */ 97 status_t INIT_ACCELERANT(int the_fd) 98 { 99 status_t result; 100 int pointer_reservation; //mem reserved for pointer 101 int cnt; //used for iteration through the overlay buffers 102 103 if (0) { 104 time_t now = time (NULL); 105 // LOG not available from here to next LOG: NULL si 106 MSG(("INIT_ACCELERANT: %s", ctime (&now))); 107 } 108 109 /* note that we're the primary accelerant (accelerantIsClone is global) */ 110 accelerantIsClone = 0; 111 112 /* do the initialization common to both the primary and the clones */ 113 result = init_common(the_fd); 114 115 /* bail out if the common initialization failed */ 116 if (result != B_OK) 117 goto error0; 118 // LOG now available: !NULL si 119 120 /* ensure that INIT_ACCELERANT is executed just once (copies should be clones) */ 121 if (si->accelerant_in_use) 122 { 123 result = B_NOT_ALLOWED; 124 goto error1; 125 } 126 127 /* call the device specific init code */ 128 result = nv_general_powerup(); 129 130 /* bail out if it failed */ 131 if (result != B_OK) 132 goto error1; 133 134 /* 135 Now would be a good time to figure out what video modes your card supports. 136 We'll place the list of modes in another shared area so all of the copies 137 of the driver can see them. The primary copy of the accelerant (ie the one 138 initialized with this routine) will own the "one true copy" of the list. 139 Everybody else get's a read-only clone. 140 */ 141 result = create_mode_list(); 142 if (result != B_OK) 143 goto error1; 144 145 /* 146 Put the cursor at the start of the frame buffer. 147 Nvidia cursor is 32x32 16 color? takes up 4096 bytes of RAM. 148 */ 149 /* Initialize the rest of the cursor information while we're here */ 150 si->cursor.width = 16; 151 si->cursor.height = 16; 152 si->cursor.hot_x = 0; 153 si->cursor.hot_y = 0; 154 si->cursor.x = 0; 155 si->cursor.y = 0; 156 si->cursor.dh_right = false; 157 158 /* 159 Put the frame buffer immediately following the cursor data. We store this 160 info in a frame_buffer_config structure to make it convienient to return 161 to the app_server later. 162 */ 163 pointer_reservation = 0; 164 /* Nvidia hardcursor needs 2kB space */ 165 if (si->settings.hardcursor) pointer_reservation = 2048; 166 167 si->fbc.frame_buffer = (void *)((char *)si->framebuffer+pointer_reservation); 168 si->fbc.frame_buffer_dma = (void *)((char *)si->framebuffer_pci+pointer_reservation); 169 170 /* count of issued parameters or commands */ 171 si->engine.last_idle = si->engine.count = 0; 172 /* no 3D clones are currently loaded */ 173 si->engine.threeD.clones = 0; 174 /* tell 3D add-ons that they should reload their rendering states and surfaces */ 175 si->engine.threeD.reload = 0xffffffff; 176 INIT_BEN(si->engine.lock); 177 178 INIT_BEN(si->overlay.lock); 179 for (cnt = 0; cnt < MAXBUFFERS; cnt++) 180 { 181 /* make sure overlay buffers are 'marked' as being free */ 182 si->overlay.myBuffer[cnt].buffer = NULL; 183 si->overlay.myBuffer[cnt].buffer_dma = NULL; 184 } 185 186 /* make sure overlay unit is 'marked' as being free */ 187 si->overlay.myToken = NULL; 188 189 /* note that overlay is not in use (for nv_bes_move_overlay()) */ 190 si->overlay.active = false; 191 192 /* initialise various cursor stuff */ 193 head1_cursor_init(); 194 if (si->ps.secondary_head) head2_cursor_init(); 195 196 /* ensure cursor state */ 197 head1_cursor_hide(); 198 if (si->ps.secondary_head) head2_cursor_hide(); 199 200 /* ensure DPMS state */ 201 si->dpms_flags = B_DPMS_ON; 202 203 /* ensure TVout state: 204 * TVencoder is on head to be assigned primary, no dualhead switch mode active. */ 205 //fixme: actually check on what CRTC TVout was active during boot (if any)... 206 si->dm.flags = TV_PRIMARY; 207 208 /* make sure a possible 3D add-on will block rendering and re-initialize itself. 209 * note: update in _this_ order only */ 210 /* SET_DISPLAY_MODE will reset this flag when it's done. */ 211 si->engine.threeD.mode_changing = true; 212 /* every 3D add-on will reset this bit-flag when it's done. */ 213 si->engine.threeD.newmode = 0xffffffff; 214 215 /* we did not detect the Haiku ScreenPrefs app yet */ 216 si->haiku_prefs_used = false; 217 si->Haiku_switch_head = false; 218 219 /* a winner! */ 220 result = B_OK; 221 /* ensure that INIT_ACCELERANT won't be executed again (copies should be clones) */ 222 si->accelerant_in_use = true; 223 goto error0; 224 225 error1: 226 /* 227 Initialization failed after init_common() succeeded, so we need to clean 228 up before quiting. 229 */ 230 uninit_common(); 231 232 error0: 233 return result; 234 } 235 236 /* 237 Return the number of bytes required to hold the information required 238 to clone the device. 239 */ 240 ssize_t ACCELERANT_CLONE_INFO_SIZE(void) { 241 /* 242 Since we're passing the name of the device as the only required 243 info, return the size of the name buffer 244 */ 245 return B_OS_NAME_LENGTH; // apsed, was MAX_NV_DEVICE_NAME_LENGTH; 246 } 247 248 249 /* 250 Return the info required to clone the device. void *data points to 251 a buffer at least ACCELERANT_CLONE_INFO_SIZE() bytes in length. 252 */ 253 void GET_ACCELERANT_CLONE_INFO(void *data) { 254 nv_device_name dn; 255 status_t result; 256 257 /* call the kernel driver to get the device name */ 258 dn.magic = NV_PRIVATE_DATA_MAGIC; 259 /* store the returned info directly into the passed buffer */ 260 dn.name = (char *)data; 261 result = ioctl(fd, NV_DEVICE_NAME, &dn, sizeof(dn)); 262 } 263 264 /* 265 Initialize a copy of the accelerant as a clone. void *data points to 266 a copy of the data returned by GET_ACCELERANT_CLONE_INFO(). 267 */ 268 status_t CLONE_ACCELERANT(void *data) 269 { 270 status_t result; 271 char path[MAXPATHLEN]; 272 273 /* the data is the device name */ 274 /* Note: the R4 graphics driver kit is in error here (missing trailing '/') */ 275 strcpy(path, "/dev/"); 276 strcat(path, (const char *)data); 277 /* open the device, the permissions aren't important */ 278 fd = open(path, B_READ_WRITE); 279 if (fd < 0) 280 { 281 /* we can't use LOG because we didn't get the shared_info struct.. */ 282 char fname[64]; 283 FILE *myhand = NULL; 284 285 sprintf (fname, "/boot/home/" DRIVER_PREFIX ".accelerant.0.log"); 286 myhand=fopen(fname,"a+"); 287 fprintf(myhand, "CLONE_ACCELERANT: couldn't open kerneldriver %s! Aborting.\n", path); 288 fclose(myhand); 289 290 /* abort with resultcode from open attempt on kerneldriver */ 291 result = fd; 292 goto error0; 293 } 294 295 /* note that we're a clone accelerant */ 296 accelerantIsClone = 1; 297 298 /* call the shared initialization code */ 299 result = init_common(fd); 300 301 /* bail out if the common initialization failed */ 302 if (result != B_OK) goto error1; 303 304 /* ensure that INIT_ACCELERANT is executed first (i.e. primary accelerant exists) */ 305 if (!(si->accelerant_in_use)) 306 { 307 result = B_NOT_ALLOWED; 308 goto error2; 309 } 310 311 /* setup CRTC and DAC functions access */ 312 //fixme: setup_virtualized_heads is a problem for clones: needs to be run 313 //for each clone if the mode is changed! 314 if (si->ps.secondary_head) 315 setup_virtualized_heads(si->crtc_switch_mode); 316 else 317 setup_virtualized_heads(si->ps.crtc2_prim); 318 319 /* get shared area for display modes */ 320 result = my_mode_list_area = clone_area( 321 DRIVER_PREFIX " cloned display_modes", 322 (void **)&my_mode_list, 323 B_ANY_ADDRESS, 324 B_READ_AREA, 325 si->mode_area 326 ); 327 if (result < B_OK) goto error2; 328 329 /* all done */ 330 LOG(4,("CLONE_ACCELERANT: cloning was succesfull.\n")); 331 332 result = B_OK; 333 goto error0; 334 335 error2: 336 /* free up the areas we cloned */ 337 uninit_common(); 338 error1: 339 /* close the device we opened */ 340 close(fd); 341 error0: 342 return result; 343 } 344 345 void UNINIT_ACCELERANT(void) 346 { 347 if (accelerantIsClone) 348 { 349 LOG(4,("UNINIT_ACCELERANT: shutting down clone accelerant.\n")); 350 } 351 else 352 { 353 LOG(4,("UNINIT_ACCELERANT: shutting down primary accelerant.\n")); 354 355 /* delete benaphores ONLY if we are the primary accelerant */ 356 DELETE_BEN(si->engine.lock); 357 DELETE_BEN(si->overlay.lock); 358 359 /* ensure that INIT_ACCELERANT can be executed again */ 360 si->accelerant_in_use = false; 361 } 362 363 /* free our mode list area */ 364 delete_area(my_mode_list_area); 365 /* paranoia */ 366 my_mode_list = 0; 367 /* release our cloned data */ 368 uninit_common(); 369 /* close the file handle ONLY if we're the clone */ 370 if (accelerantIsClone) close(fd); 371 } 372