1 /* 2 * Copyright 2006-2009, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Axel Dörfler, axeld@pinc-software.de 7 */ 8 9 10 #include "driver.h" 11 #include "device.h" 12 #include "radeon_hd.h" 13 #include "utility.h" 14 15 #include <OS.h> 16 #include <KernelExport.h> 17 #include <Drivers.h> 18 #include <PCI.h> 19 #include <SupportDefs.h> 20 #include <graphic_driver.h> 21 #include <image.h> 22 23 #include <stdlib.h> 24 #include <string.h> 25 26 27 //#define DEBUG_COMMANDS 28 29 #define TRACE_DEVICE 30 #ifdef TRACE_DEVICE 31 # define TRACE(x...) dprintf("radeon_hd: " x) 32 #else 33 # define TRACE(x...) ; 34 #endif 35 36 #define ERROR(x...) dprintf("radeon_hd: " x) 37 38 39 /* device hooks prototypes */ 40 41 static status_t device_open(const char* name, uint32 flags, void** _cookie); 42 static status_t device_close(void* data); 43 static status_t device_free(void* data); 44 static status_t device_ioctl(void* data, uint32 opcode, 45 void* buffer, size_t length); 46 static status_t device_read(void* data, off_t offset, 47 void* buffer, size_t* length); 48 static status_t device_write(void* data, off_t offset, 49 const void* buffer, size_t* length); 50 51 52 device_hooks gDeviceHooks = { 53 device_open, 54 device_close, 55 device_free, 56 device_ioctl, 57 device_read, 58 device_write, 59 NULL, 60 NULL, 61 NULL, 62 NULL 63 }; 64 65 66 #ifdef DEBUG_COMMANDS 67 static int 68 getset_register(int argc, char** argv) 69 { 70 if (argc < 2 || argc > 3) { 71 kprintf("usage: %s <register> [set-to-value]\n", argv[0]); 72 return 0; 73 } 74 75 uint32 reg = parse_expression(argv[1]); 76 uint32 value = 0; 77 bool set = argc == 3; 78 if (set) 79 value = parse_expression(argv[2]); 80 81 kprintf("radeon_hd register %#lx\n", reg); 82 83 radeon_info &info = *gDeviceInfo[0]; 84 uint32 oldValue = read32(info.registers + reg); 85 86 kprintf(" %svalue: %#lx (%lu)\n", set ? "old " : "", oldValue, oldValue); 87 88 if (set) { 89 write32(info.registers + reg, value); 90 91 value = read32(info.registers + reg); 92 kprintf(" new value: %#lx (%lu)\n", value, value); 93 } 94 95 return 0; 96 } 97 #endif // DEBUG_COMMANDS 98 99 100 // #pragma mark - Device Hooks 101 102 103 static status_t 104 device_open(const char* name, uint32 /*flags*/, void** _cookie) 105 { 106 TRACE("%s: open(name = %s)\n", __func__, name); 107 int32 id; 108 109 // find accessed device 110 { 111 char* thisName; 112 113 // search for device name 114 for (id = 0; (thisName = gDeviceNames[id]) != NULL; id++) { 115 if (!strcmp(name, thisName)) 116 break; 117 } 118 if (!thisName) 119 return B_BAD_VALUE; 120 } 121 122 radeon_info* info = gDeviceInfo[id]; 123 124 mutex_lock(&gLock); 125 126 if (info->open_count == 0) { 127 // This device hasn't been initialized yet, so we 128 // allocate needed resources and initialize the structure 129 info->init_status = radeon_hd_init(*info); 130 if (info->init_status == B_OK) { 131 #ifdef DEBUG_COMMANDS 132 add_debugger_command("radeonhd_reg", getset_register, 133 "dumps or sets the specified radeon_hd register"); 134 #endif 135 } 136 } 137 138 if (info->init_status == B_OK) { 139 info->open_count++; 140 *_cookie = info; 141 } else 142 ERROR("%s: initialization failed!\n", __func__); 143 144 mutex_unlock(&gLock); 145 146 return info->init_status; 147 } 148 149 150 static status_t 151 device_close(void* /*data*/) 152 { 153 TRACE("%s: close\n", __func__); 154 return B_OK; 155 } 156 157 158 static status_t 159 device_free(void* data) 160 { 161 struct radeon_info* info = (radeon_info*)data; 162 163 mutex_lock(&gLock); 164 165 if (info->open_count-- == 1) { 166 // release info structure 167 info->init_status = B_NO_INIT; 168 radeon_hd_uninit(*info); 169 170 #ifdef DEBUG_COMMANDS 171 remove_debugger_command("radeonhd_reg", getset_register); 172 #endif 173 } 174 175 mutex_unlock(&gLock); 176 return B_OK; 177 } 178 179 180 static status_t 181 device_ioctl(void* data, uint32 op, void* buffer, size_t bufferLength) 182 { 183 struct radeon_info* info = (radeon_info*)data; 184 185 switch (op) { 186 case B_GET_ACCELERANT_SIGNATURE: 187 TRACE("%s: accelerant: %s\n", __func__, RADEON_ACCELERANT_NAME); 188 if (user_strlcpy((char*)buffer, RADEON_ACCELERANT_NAME, 189 bufferLength) < B_OK) 190 return B_BAD_ADDRESS; 191 return B_OK; 192 193 // needed to share data between kernel and accelerant 194 case RADEON_GET_PRIVATE_DATA: 195 { 196 radeon_get_private_data data; 197 if (user_memcpy(&data, buffer, sizeof(radeon_get_private_data)) < B_OK) 198 return B_BAD_ADDRESS; 199 200 if (data.magic == RADEON_PRIVATE_DATA_MAGIC) { 201 data.shared_info_area = info->shared_area; 202 return user_memcpy(buffer, &data, 203 sizeof(radeon_get_private_data)); 204 } 205 break; 206 } 207 208 // needed for cloning 209 case RADEON_GET_DEVICE_NAME: 210 if (user_strlcpy((char*)buffer, gDeviceNames[info->id], 211 bufferLength) < B_OK) 212 return B_BAD_ADDRESS; 213 return B_OK; 214 215 default: 216 TRACE("%s: ioctl() unknown message %ld (length = %ld)\n", 217 __func__, op, bufferLength); 218 break; 219 } 220 221 return B_DEV_INVALID_IOCTL; 222 } 223 224 225 static status_t 226 device_read(void* /*data*/, off_t /*pos*/, 227 void* /*buffer*/, size_t *_length) 228 { 229 *_length = 0; 230 return B_NOT_ALLOWED; 231 } 232 233 234 static status_t 235 device_write(void* /*data*/, off_t /*pos*/, 236 const void* /*buffer*/, size_t* _length) 237 { 238 *_length = 0; 239 return B_NOT_ALLOWED; 240 } 241 242