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