xref: /haiku/src/add-ons/kernel/drivers/graphics/radeon_hd/device.cpp (revision d1f885b435e9892ac028f4be2b80536b9dd37413)
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