1 /* 2 * Copyright 2005-2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved. 3 * Copyright 2016-207, Jessica Hamilton, jessica.l.hamilton@gmail.com. 4 * Distributed under the terms of the MIT License. 5 */ 6 7 8 #include "accelerant_protos.h" 9 #include "accelerant.h" 10 11 #include <stdlib.h> 12 #include <string.h> 13 #include <unistd.h> 14 #include <errno.h> 15 #include <syslog.h> 16 17 18 //#define TRACE_ACCELERANT 19 #ifdef TRACE_ACCELERANT 20 extern "C" void _sPrintf(const char *format, ...); 21 # define TRACE(x) _sPrintf x 22 #else 23 # define TRACE(x) ; 24 #endif 25 26 27 struct accelerant_info *gInfo; 28 29 30 class AreaCloner { 31 public: 32 AreaCloner(); 33 ~AreaCloner(); 34 35 area_id Clone(const char *name, void **_address, uint32 spec, 36 uint32 protection, area_id sourceArea); 37 status_t InitCheck() { return fArea < B_OK ? (status_t)fArea : B_OK; } 38 void Keep(); 39 40 private: 41 area_id fArea; 42 }; 43 44 45 AreaCloner::AreaCloner() 46 : 47 fArea(-1) 48 { 49 } 50 51 52 AreaCloner::~AreaCloner() 53 { 54 if (fArea >= B_OK) 55 delete_area(fArea); 56 } 57 58 59 area_id 60 AreaCloner::Clone(const char *name, void **_address, uint32 spec, 61 uint32 protection, area_id sourceArea) 62 { 63 fArea = clone_area(name, _address, spec, protection, sourceArea); 64 return fArea; 65 } 66 67 68 void 69 AreaCloner::Keep() 70 { 71 fArea = -1; 72 } 73 74 75 // #pragma mark - 76 77 78 /*! This is the common accelerant_info initializer. It is called by 79 both, the first accelerant and all clones. 80 */ 81 static status_t 82 init_common(int device, bool isClone) 83 { 84 // initialize global accelerant info structure 85 86 gInfo = (accelerant_info *)malloc(sizeof(accelerant_info)); 87 if (gInfo == NULL) 88 return B_NO_MEMORY; 89 90 memset(gInfo, 0, sizeof(accelerant_info)); 91 92 gInfo->is_clone = isClone; 93 gInfo->device = device; 94 gInfo->current_mode = UINT16_MAX; 95 96 // get basic info from driver 97 98 area_id sharedArea; 99 if (ioctl(device, VESA_GET_PRIVATE_DATA, &sharedArea, sizeof(area_id)) 100 != 0) { 101 free(gInfo); 102 return B_ERROR; 103 } 104 105 AreaCloner sharedCloner; 106 gInfo->shared_info_area = sharedCloner.Clone("vesa shared info", 107 (void **)&gInfo->shared_info, B_ANY_ADDRESS, 108 B_READ_AREA | B_WRITE_AREA, sharedArea); 109 status_t status = sharedCloner.InitCheck(); 110 if (status < B_OK) { 111 free(gInfo); 112 return status; 113 } 114 115 if (gInfo->shared_info->vesa_mode_count == 0) 116 gInfo->vesa_modes = NULL; 117 else 118 gInfo->vesa_modes = (vesa_mode *)((uint8 *)gInfo->shared_info 119 + gInfo->shared_info->vesa_mode_offset); 120 121 sharedCloner.Keep(); 122 return B_OK; 123 } 124 125 126 /*! Cleans up everything done by a successful init_common(). */ 127 static void 128 uninit_common(void) 129 { 130 delete_area(gInfo->shared_info_area); 131 gInfo->shared_info_area = -1; 132 gInfo->shared_info = NULL; 133 134 // close the file handle ONLY if we're the clone 135 // (this is what Be tells us ;) 136 if (gInfo->is_clone) 137 close(gInfo->device); 138 139 free(gInfo); 140 } 141 142 143 // #pragma mark - public accelerant functions 144 145 146 /*! Init primary accelerant */ 147 status_t 148 vesa_init_accelerant(int device) 149 { 150 TRACE(("vesa_init_accelerant()\n")); 151 152 status_t status = init_common(device, false); 153 if (status != B_OK) 154 return status; 155 156 status = create_mode_list(); 157 if (status != B_OK) { 158 uninit_common(); 159 return status; 160 } 161 162 // Initialize current mode completely from the mode list 163 vesa_propose_display_mode(&gInfo->shared_info->current_mode, NULL, NULL); 164 return B_OK; 165 } 166 167 168 ssize_t 169 vesa_accelerant_clone_info_size(void) 170 { 171 // clone info is device name, so return its maximum size 172 return B_PATH_NAME_LENGTH; 173 } 174 175 176 void 177 vesa_get_accelerant_clone_info(void *info) 178 { 179 ioctl(gInfo->device, VESA_GET_DEVICE_NAME, info, B_PATH_NAME_LENGTH); 180 } 181 182 183 status_t 184 vesa_clone_accelerant(void *info) 185 { 186 TRACE(("vesa_clone_accelerant()\n")); 187 188 // create full device name 189 char path[MAXPATHLEN]; 190 strcpy(path, "/dev/"); 191 strcat(path, (const char *)info); 192 193 int fd = open(path, B_READ_WRITE); 194 if (fd < 0) 195 return errno; 196 197 status_t status = init_common(fd, true); 198 if (status != B_OK) 199 goto err1; 200 201 // get read-only clone of supported display modes 202 status = gInfo->mode_list_area = clone_area( 203 "vesa cloned modes", (void **)&gInfo->mode_list, 204 B_ANY_ADDRESS, B_READ_AREA, gInfo->shared_info->mode_list_area); 205 if (status < B_OK) 206 goto err2; 207 208 return B_OK; 209 210 err2: 211 uninit_common(); 212 err1: 213 close(fd); 214 return status; 215 } 216 217 218 /*! This function is called for both, the primary accelerant and all of 219 its clones. 220 */ 221 void 222 vesa_uninit_accelerant(void) 223 { 224 TRACE(("vesa_uninit_accelerant()\n")); 225 226 // delete accelerant instance data 227 delete_area(gInfo->mode_list_area); 228 gInfo->mode_list = NULL; 229 230 uninit_common(); 231 } 232 233 234 status_t 235 vesa_get_accelerant_device_info(accelerant_device_info *info) 236 { 237 info->version = B_ACCELERANT_VERSION; 238 strcpy(info->name, "VESA Driver"); 239 strcpy(info->chipset, "VESA"); 240 // ToDo: provide some more insight here... 241 strcpy(info->serial_no, "None"); 242 243 #if 0 244 info->memory = ??? 245 info->dac_speed = ??? 246 #endif 247 248 return B_OK; 249 } 250 251 252 sem_id 253 vesa_accelerant_retrace_semaphore() 254 { 255 return -1; 256 } 257 258