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