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 41static status_t device_open(const char* name, uint32 flags, void** _cookie); 42static status_t device_close(void* data); 43static status_t device_free(void* data); 44static status_t device_ioctl(void* data, uint32 opcode, 45 void* buffer, size_t length); 46static status_t device_read(void* data, off_t offset, 47 void* buffer, size_t* length); 48static status_t device_write(void* data, off_t offset, 49 const void* buffer, size_t* length); 50 51 52device_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 67static int 68getset_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 103static status_t 104device_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 150static status_t 151device_close(void* /*data*/) 152{ 153 TRACE("%s: close\n", __func__); 154 return B_OK; 155} 156 157 158static status_t 159device_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 180static status_t 181device_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 %" B_PRIu32 " (length = %ld)\n", 217 __func__, op, bufferLength); 218 break; 219 } 220 221 return B_DEV_INVALID_IOCTL; 222} 223 224 225static status_t 226device_read(void* /*data*/, off_t /*pos*/, 227 void* /*buffer*/, size_t *_length) 228{ 229 *_length = 0; 230 return B_NOT_ALLOWED; 231} 232 233 234static status_t 235device_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