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 94 // get basic info from driver 95 96 area_id sharedArea; 97 if (ioctl(device, VESA_GET_PRIVATE_DATA, &sharedArea, sizeof(area_id)) 98 != 0) { 99 free(gInfo); 100 return B_ERROR; 101 } 102 103 AreaCloner sharedCloner; 104 gInfo->shared_info_area = sharedCloner.Clone("vesa shared info", 105 (void **)&gInfo->shared_info, B_ANY_ADDRESS, 106 B_READ_AREA | B_WRITE_AREA, sharedArea); 107 status_t status = sharedCloner.InitCheck(); 108 if (status < B_OK) { 109 free(gInfo); 110 return status; 111 } 112 113 gInfo->vesa_modes = (vesa_mode *)((uint8 *)gInfo->shared_info 114 + gInfo->shared_info->vesa_mode_offset); 115 116 sharedCloner.Keep(); 117 return B_OK; 118 } 119 120 121 /*! Cleans up everything done by a successful init_common(). */ 122 static void 123 uninit_common(void) 124 { 125 delete_area(gInfo->shared_info_area); 126 gInfo->shared_info_area = -1; 127 gInfo->shared_info = NULL; 128 129 // close the file handle ONLY if we're the clone 130 // (this is what Be tells us ;) 131 if (gInfo->is_clone) 132 close(gInfo->device); 133 134 free(gInfo); 135 } 136 137 138 // #pragma mark - public accelerant functions 139 140 141 /*! Init primary accelerant */ 142 status_t 143 vesa_init_accelerant(int device) 144 { 145 TRACE(("vesa_init_accelerant()\n")); 146 147 status_t status = init_common(device, false); 148 if (status != B_OK) 149 return status; 150 151 status = create_mode_list(); 152 if (status != B_OK) { 153 uninit_common(); 154 return status; 155 } 156 157 // Initialize current mode completely from the mode list 158 vesa_propose_display_mode(&gInfo->shared_info->current_mode, NULL, NULL); 159 return B_OK; 160 } 161 162 163 ssize_t 164 vesa_accelerant_clone_info_size(void) 165 { 166 // clone info is device name, so return its maximum size 167 return B_PATH_NAME_LENGTH; 168 } 169 170 171 void 172 vesa_get_accelerant_clone_info(void *info) 173 { 174 ioctl(gInfo->device, VESA_GET_DEVICE_NAME, info, B_PATH_NAME_LENGTH); 175 } 176 177 178 status_t 179 vesa_clone_accelerant(void *info) 180 { 181 TRACE(("vesa_clone_accelerant()\n")); 182 183 // create full device name 184 char path[MAXPATHLEN]; 185 strcpy(path, "/dev/"); 186 strcat(path, (const char *)info); 187 188 int fd = open(path, B_READ_WRITE); 189 if (fd < 0) 190 return errno; 191 192 status_t status = init_common(fd, true); 193 if (status != B_OK) 194 goto err1; 195 196 // get read-only clone of supported display modes 197 status = gInfo->mode_list_area = clone_area( 198 "vesa cloned modes", (void **)&gInfo->mode_list, 199 B_ANY_ADDRESS, B_READ_AREA, gInfo->shared_info->mode_list_area); 200 if (status < B_OK) 201 goto err2; 202 203 return B_OK; 204 205 err2: 206 uninit_common(); 207 err1: 208 close(fd); 209 return status; 210 } 211 212 213 /*! This function is called for both, the primary accelerant and all of 214 its clones. 215 */ 216 void 217 vesa_uninit_accelerant(void) 218 { 219 TRACE(("vesa_uninit_accelerant()\n")); 220 221 // delete accelerant instance data 222 delete_area(gInfo->mode_list_area); 223 gInfo->mode_list = NULL; 224 225 uninit_common(); 226 } 227 228 229 status_t 230 vesa_get_accelerant_device_info(accelerant_device_info *info) 231 { 232 info->version = B_ACCELERANT_VERSION; 233 strcpy(info->name, "VESA Driver"); 234 strcpy(info->chipset, "VESA"); 235 // ToDo: provide some more insight here... 236 strcpy(info->serial_no, "None"); 237 238 #if 0 239 info->memory = ??? 240 info->dac_speed = ??? 241 #endif 242 243 return B_OK; 244 } 245 246 247 sem_id 248 vesa_accelerant_retrace_semaphore() 249 { 250 return -1; 251 } 252 253