xref: /haiku/src/add-ons/kernel/drivers/graphics/radeon/driver.c (revision aff60bb217827097c13d643275fdf1f1c66e7f17)
1 /*
2 	Copyright (c) 2002, Thomas Kurschel
3 
4 
5 	Part of Radeon kernel driver
6 
7 	DevFS interface
8 */
9 
10 #include "radeon_driver.h"
11 
12 #include <OS.h>
13 #include <malloc.h>
14 #include <graphic_driver.h>
15 #include <stdio.h>
16 #include <string.h>
17 #include "mmio.h"
18 #include "version.h"
19 
20 // tell the kernel what revision of the driver API we support
21 int32	api_version = 2;
22 
23 
24 static status_t open_hook( const char *name, uint32 flags, void **cookie );
25 static status_t close_hook( void *dev );
26 static status_t free_hook( void *dev );
27 static status_t read_hook( void *dev, off_t pos, void *buf, size_t *len );
28 static status_t write_hook( void *dev, off_t pos, const void *buf, size_t *len );
29 static status_t control_hook( void *dev, uint32 msg, void *buf, size_t len );
30 
31 
32 static device_hooks graphics_device_hooks = {
33 	open_hook,
34 	close_hook,
35 	free_hook,
36 	control_hook,
37 	read_hook,
38 	write_hook,
39 	NULL,
40 	NULL,
41 	NULL,
42 	NULL
43 };
44 
45 
46 // public function: check whether there is *any* supported hardware
47 status_t init_hardware( void )
48 {
49 	SHOW_INFO0( 0, RADEON_DRIVER_VERSION );
50 	if( Radeon_CardDetect() == B_OK )
51 		return B_OK;
52 	else
53 		return B_ERROR;
54 }
55 
56 
57 // public function: init driver
58 status_t init_driver( void )
59 {
60 	SHOW_FLOW0( 3, "" );
61 
62 	if( get_module(B_PCI_MODULE_NAME, (module_info **)&pci_bus) != B_OK )
63 		return B_ERROR;
64 
65 	/* driver private data */
66 	devices = (radeon_devices *)calloc( 1, sizeof( radeon_devices ));
67 	if( devices == NULL ) {
68 		put_module(B_PCI_MODULE_NAME);
69 		return B_ERROR;
70 	}
71 
72 	(void)INIT_BEN( devices->kernel, "Radeon Kernel" );
73 
74 	Radeon_ProbeDevices();
75 	return B_OK;
76 }
77 
78 
79 // public function: uninit driver
80 void uninit_driver( void )
81 {
82 	SHOW_FLOW0( 3, "" );
83 	DELETE_BEN( devices->kernel );
84 
85 	free( devices );
86 	devices = NULL;
87 
88 	put_module( B_PCI_MODULE_NAME );
89 }
90 
91 
92 // public function: return list of device names
93 const char **publish_devices( void )
94 {
95 	return (const char **)devices->device_names;
96 }
97 
98 
99 // public function: find hooks for specific device given its name
100 device_hooks *find_device( const char *name )
101 {
102 	uint32 index;
103 
104 	// probably, we could always return standard hooks
105 	for( index = 0; devices->device_names[index]; ++index ) {
106 		if( strcmp( name, devices->device_names[index] ) == 0 )
107 			return &graphics_device_hooks;
108 	}
109 
110 	return NULL;
111 }
112 
113 
114 // public function: open device
115 static status_t open_hook( const char *name, uint32 flags, void **cookie )
116 {
117 	int32 index = 0;
118 	device_info *di;
119 	status_t	result = B_OK;
120 
121 	SHOW_FLOW( 3, "name=%s, flags=%ld, cookie=0x%08lx", name, flags, (uint32)cookie );
122 
123 	// find device info
124 	while( devices->device_names[index] &&
125 		strcmp(name, devices->device_names[index] ) != 0 )
126 		index++;
127 
128 	di = &(devices->di[index/2]);
129 
130 	ACQUIRE_BEN( devices->kernel );
131 
132 	if( !di->is_open )
133 		result = Radeon_FirstOpen( di );
134 
135 	if( result == B_OK ) {
136 		di->is_open++;
137 		*cookie = di;
138 	}
139 
140 	RELEASE_BEN( devices->kernel );
141 
142 	SHOW_FLOW( 3, "returning 0x%08lx", result );
143 	return result;
144 }
145 
146 
147 // public function: read from device (denied)
148 static status_t read_hook( void *dev, off_t pos, void *buf, size_t *len )
149 {
150 	*len = 0;
151 	return B_NOT_ALLOWED;
152 }
153 
154 
155 // public function: write to device (denied)
156 static status_t write_hook( void *dev, off_t pos, const void *buf, size_t *len )
157 {
158 	*len = 0;
159 	return B_NOT_ALLOWED;
160 }
161 
162 
163 // public function: close device (ignored, wait for free_hook instead)
164 static status_t close_hook( void *dev )
165 {
166 	return B_NO_ERROR;
167 }
168 
169 
170 // public function: free device
171 static status_t free_hook( void *dev )
172 {
173 	device_info *di = (device_info *)dev;
174 
175 	SHOW_FLOW0( 0, "" );
176 
177 	ACQUIRE_BEN( devices->kernel );
178 
179 	mem_freetag( di->memmgr[mt_local], dev );
180 
181 	if( di->memmgr[mt_PCI] )
182 		mem_freetag( di->memmgr[mt_PCI], dev );
183 
184 	if( di->memmgr[mt_AGP] )
185 		mem_freetag( di->memmgr[mt_AGP], dev );
186 
187 	if( di->is_open == 1 )
188 		Radeon_LastClose( di );
189 
190 	di->is_open--;
191 	RELEASE_BEN( devices->kernel );
192 
193 	return B_OK;
194 }
195 
196 
197 // public function: ioctl
198 static status_t control_hook( void *dev, uint32 msg, void *buf, size_t len )
199 {
200 	device_info *di = (device_info *)dev;
201 	status_t result = B_DEV_INVALID_IOCTL;
202 
203 	switch (msg) {
204 		// needed by app_server to load accelerant
205 		case B_GET_ACCELERANT_SIGNATURE: {
206 			char *sig = (char *)buf;
207 			strcpy(sig, "radeon.accelerant");
208 			result = B_OK;
209 		} break;
210 
211 		// needed to share data between kernel and accelerant
212 		case RADEON_GET_PRIVATE_DATA: {
213 			radeon_get_private_data *gpd = (radeon_get_private_data *)buf;
214 
215 			if (gpd->magic == RADEON_PRIVATE_DATA_MAGIC) {
216 				gpd->shared_info_area = di->shared_area;
217 				gpd->virtual_card_area = di->virtual_card_area;
218 				result = B_OK;
219 			}
220 		} break;
221 
222 		// needed for cloning
223 		case RADEON_DEVICE_NAME: {
224 			radeon_device_name *dn = (radeon_device_name *)buf;
225 
226 			if( dn->magic == RADEON_PRIVATE_DATA_MAGIC ) {
227 				strncpy( dn->name, di->name, MAX_RADEON_DEVICE_NAME_LENGTH );
228 				result = B_OK;
229 			}
230 		} break;
231 
232 		// graphics mem manager
233 		case RADEON_ALLOC_MEM: {
234 			radeon_alloc_mem *am = (radeon_alloc_mem *)buf;
235 			memory_type_e memory_type;
236 
237 			if( am->magic != RADEON_PRIVATE_DATA_MAGIC )
238 				break;
239 
240 			if( am->memory_type > mt_last )
241 				break;
242 
243 			memory_type = am->memory_type == mt_nonlocal ? di->si->nonlocal_type : am->memory_type;
244 
245 			result = mem_alloc( di->memmgr[memory_type], am->size, am->global ? 0 : dev, &am->handle, &am->offset );
246 		} break;
247 
248 		case RADEON_FREE_MEM: {
249 			radeon_free_mem *fm = (radeon_free_mem *)buf;
250 			memory_type_e memory_type;
251 
252 			if( fm->magic != RADEON_PRIVATE_DATA_MAGIC )
253 				break;
254 
255 			if( fm->memory_type > mt_last )
256 				break;
257 
258 			memory_type = fm->memory_type == mt_nonlocal ? di->si->nonlocal_type : fm->memory_type;
259 
260 			result = mem_free( di->memmgr[memory_type], fm->handle, fm->global ? 0 : dev );
261 		} break;
262 
263 		case RADEON_WAITFORIDLE: {
264 			radeon_wait_for_idle *wfi = (radeon_wait_for_idle *)buf;
265 
266 			if( wfi->magic != RADEON_PRIVATE_DATA_MAGIC )
267 				break;
268 
269 			Radeon_WaitForIdle( di, true, wfi->keep_lock );
270 			result = B_OK;
271 		} break;
272 
273 		case RADEON_RESETENGINE: {
274 			radeon_no_arg *na = (radeon_no_arg *)buf;
275 
276 			if( na->magic != RADEON_PRIVATE_DATA_MAGIC )
277 				break;
278 
279 			ACQUIRE_BEN( di->si->cp.lock );
280 			Radeon_ResetEngine( di );
281 			RELEASE_BEN( di->si->cp.lock );
282 
283 			result = B_OK;
284 		} break;
285 
286 		case RADEON_VIPREAD: {
287 			radeon_vip_read *vr = (radeon_vip_read *)buf;
288 
289 			if( vr->magic != RADEON_PRIVATE_DATA_MAGIC )
290 				break;
291 
292 			result = Radeon_VIPRead( di, vr->channel, vr->address, &vr->data,
293 				vr->lock ) ? B_OK : B_ERROR;
294 		} break;
295 
296 		case RADEON_VIPWRITE: {
297 			radeon_vip_write *vw = (radeon_vip_write *)buf;
298 
299 			if( vw->magic != RADEON_PRIVATE_DATA_MAGIC )
300 				break;
301 
302 			result = Radeon_VIPWrite( di, vw->channel, vw->address, vw->data,
303 				vw->lock ) ? B_OK : B_ERROR;
304 		} break;
305 
306 		case RADEON_FINDVIPDEVICE: {
307 			radeon_find_vip_device *fvd = (radeon_find_vip_device *)buf;
308 
309 			if( fvd->magic != RADEON_PRIVATE_DATA_MAGIC )
310 				break;
311 
312 			fvd->channel = Radeon_FindVIPDevice( di, fvd->device_id );
313 			result = B_OK;
314 		} break;
315 
316 		case RADEON_WAIT_FOR_CAP_IRQ: {
317 			radeon_wait_for_cap_irq *wvc = (radeon_wait_for_cap_irq *)buf;
318 
319 			if( wvc->magic != RADEON_PRIVATE_DATA_MAGIC )
320 				break;
321 
322 			// restrict wait time to 1 sec to get not stuck here in kernel
323 			result = acquire_sem_etc( di->cap_sem, 1, B_RELATIVE_TIMEOUT,
324 				min( wvc->timeout, 1000000 ));
325 
326 			if( result == B_OK ) {
327 				cpu_status prev_irq_state = disable_interrupts();
328 				acquire_spinlock( &di->cap_spinlock );
329 
330 				wvc->timestamp = di->cap_timestamp;
331 				wvc->int_status = di->cap_int_status;
332 				wvc->counter = di->cap_counter;
333 
334 				release_spinlock( &di->cap_spinlock );
335 				restore_interrupts( prev_irq_state );
336 			}
337 		} break;
338 
339 		case RADEON_DMACOPY: {
340 			radeon_dma_copy *dc = (radeon_dma_copy *)buf;
341 
342 			if( dc->magic != RADEON_PRIVATE_DATA_MAGIC )
343 				break;
344 
345 			result = Radeon_DMACopy( di, dc->src, dc->target, dc->size, dc->lock_mem, dc->contiguous );
346 		} break;
347 
348 #ifdef ENABLE_LOGGING
349 #ifdef LOG_INCLUDE_STARTUP
350 		// interface to log data
351 		case RADEON_GET_LOG_SIZE:
352 			*(uint32 *)buf = log_getsize( di->si->log );
353 			result = B_OK;
354 			break;
355 
356 		case RADEON_GET_LOG_DATA:
357 			log_getcopy( di->si->log, buf, ((uint32 *)buf)[0] );
358 			result = B_OK;
359 			break;
360 #endif
361 #endif
362 	}
363 
364 	if( result == B_DEV_INVALID_IOCTL )
365 		SHOW_ERROR( 3, "Invalid ioctl call: code=0x%lx", msg );
366 
367 	return result;
368 }
369