1/*
2	Copyright (c) 2002, Thomas Kurschel
3
4	Part of Radeon kernel driver
5	DevFS interface
6*/
7
8#include "radeon_driver.h"
9
10#include <OS.h>
11#include <malloc.h>
12#include <graphic_driver.h>
13#include <stdio.h>
14#include <string.h>
15#include "AGP.h"
16#include "mmio.h"
17#include "version.h"
18#include <driver_settings.h>
19#include <stdlib.h> // for strtoXX
20
21// tell the kernel what revision of the driver API we support
22int32	api_version = 2;
23
24
25static status_t open_hook(const char *name, uint32 flags, void **cookie);
26static status_t close_hook(void *dev);
27static status_t free_hook(void *dev);
28static status_t read_hook(void *dev, off_t pos, void *buf, size_t *len);
29static status_t write_hook(void *dev, off_t pos, const void *buf, size_t *len);
30static status_t control_hook(void *dev, uint32 msg, void *buf, size_t len);
31
32
33static device_hooks graphics_device_hooks = {
34	open_hook,
35	close_hook,
36	free_hook,
37	control_hook,
38	read_hook,
39	write_hook,
40	NULL,
41	NULL,
42	NULL,
43	NULL
44};
45
46radeon_settings def_settings = { // see comments in radeon.settings
47	2,			 		// loginfo
48	2,			 		// logflow
49	2,			 		// logerror
50	false,				// switchhead
51	false,				// force_lcd
52	true,				// dynamic_clocks
53	true,				// force_pci
54	false,				// unhide_fw
55	false,				// acc_dma
56	false,				// acc_mmio
57	true,				// acc_wb
58};
59
60radeon_settings current_settings;
61
62static void
63GetDriverSettings(void)
64{
65	void *settings_handle = NULL;
66
67	SHOW_FLOW0( 1, "" );
68
69	// init settings to defaults;
70	current_settings = def_settings;
71
72	// get driver/accelerant settings, apsed
73	settings_handle  = load_driver_settings ("radeon.settings");
74	if (settings_handle != NULL) {
75		const char *item;
76		char       *end;
77		uint32      value;
78
79		item = get_driver_parameter (settings_handle, "loginfo", "2", "2");
80		value = strtoul (item, &end, 0);
81		if (*end == '\0' && value <= 4) {
82			current_settings.loginfo = value;
83			SHOW_INFO( 1, "Log Info Level now %ld/4", value );
84		}
85
86		item = get_driver_parameter (settings_handle, "logflow", "2", "2");
87		value = strtoul (item, &end, 0);
88		if (*end == '\0' && value <= 4) {
89			current_settings.logflow = value;
90			SHOW_INFO( 1, "Log Flow Level now %ld/4", value );
91		}
92
93		item = get_driver_parameter (settings_handle, "logerror", "2", "2");
94		value = strtoul (item, &end, 0);
95		if (*end == '\0' && value <= 4) {
96			current_settings.logerror = value;
97			SHOW_INFO( 1, "Log Error Level now %ld/4", value );
98		}
99
100		current_settings.switchhead = get_driver_boolean_parameter (settings_handle, "switchhead", false, false);
101		current_settings.force_lcd = get_driver_boolean_parameter (settings_handle, "force_lcd", false, false);
102		current_settings.dynamic_clocks = get_driver_boolean_parameter (settings_handle, "dynamic_clocks", true, true);
103		current_settings.force_pci = get_driver_boolean_parameter (settings_handle, "force_pci", true, true);
104		current_settings.unhide_fastwrites = get_driver_boolean_parameter (settings_handle, "unhide_fw", false, false);
105		current_settings.force_acc_dma = get_driver_boolean_parameter (settings_handle, "force_acc_dma", false, false);
106		current_settings.force_acc_mmio = get_driver_boolean_parameter (settings_handle, "force_acc_mmio", false, false);
107		current_settings.acc_writeback = get_driver_boolean_parameter (settings_handle, "acc_writeback", false, false);
108
109		if ( current_settings.switchhead != def_settings.switchhead )
110			SHOW_INFO0( 1, "Switch Head = True" );
111		if ( current_settings.force_lcd != def_settings.force_lcd )
112			SHOW_INFO0( 1, "Force LCD ON" );
113		if ( current_settings.dynamic_clocks != def_settings.dynamic_clocks )
114			SHOW_INFO0( 1, "Mobility Power Saving Disabled (Dynamic Clocks)" );
115		if ( current_settings.force_pci != def_settings.force_pci )
116			SHOW_INFO0( 1, "Force PCI = True" );
117		if ( current_settings.unhide_fastwrites != def_settings.unhide_fastwrites )
118			SHOW_INFO0( 1, "use Fastwrites ON" );
119		if ( current_settings.force_acc_dma != def_settings.force_acc_dma )
120			SHOW_INFO0( 1, "DMA ACC Enabled" );
121		if ( current_settings.force_acc_mmio != def_settings.force_acc_mmio )
122			SHOW_INFO0( 1, "DMA ACC Disabled" );
123		if ( current_settings.acc_writeback != def_settings.acc_writeback )
124			SHOW_INFO0( 1, "DMA WriteBack Disabled" );
125
126		unload_driver_settings (settings_handle);
127	}
128}
129
130
131//	#pragma mark - driver API
132
133
134status_t
135init_hardware(void)
136{
137	SHOW_INFO0(0, RADEON_DRIVER_VERSION);
138	if (Radeon_CardDetect() == B_OK)
139		return B_OK;
140
141	return B_ERROR;
142}
143
144
145status_t
146init_driver(void)
147{
148	SHOW_FLOW0(3, "");
149
150	if (get_module(B_PCI_MODULE_NAME, (module_info **)&pci_bus) != B_OK)
151		return B_ERROR;
152
153	/* get a handle for the agp bus if it exists */
154	get_module(B_AGP_GART_MODULE_NAME, (module_info **)&sAGP);
155
156	/* driver private data */
157	devices = (radeon_devices *)calloc(1, sizeof(radeon_devices));
158	if (devices == NULL) {
159		put_module(B_PCI_MODULE_NAME);
160		if (sAGP != NULL)
161			put_module(B_AGP_GART_MODULE_NAME);
162		return B_ERROR;
163	}
164
165	(void)INIT_BEN(devices->kernel, "Radeon Kernel");
166
167	GetDriverSettings();
168	Radeon_ProbeDevices();
169	return B_OK;
170}
171
172
173void
174uninit_driver(void)
175{
176	SHOW_FLOW0(3, "");
177	DELETE_BEN(devices->kernel);
178
179	free(devices);
180	devices = NULL;
181
182	put_module(B_PCI_MODULE_NAME);
183	if (sAGP)
184		put_module(B_AGP_GART_MODULE_NAME);
185}
186
187
188const char **
189publish_devices(void)
190{
191	return (const char **)devices->device_names;
192}
193
194
195device_hooks *
196find_device(const char *name)
197{
198	uint32 index;
199
200	// probably, we could always return standard hooks
201	for (index = 0; devices->device_names[index]; ++index) {
202		if (strcmp(name, devices->device_names[index]) == 0)
203			return &graphics_device_hooks;
204	}
205
206	return NULL;
207}
208
209
210//	#pragma mark - device API
211
212
213static status_t
214open_hook(const char *name, uint32 flags, void **cookie)
215{
216	int32 index = 0;
217	device_info *di;
218	status_t result = B_OK;
219
220	SHOW_FLOW( 3, "name=%s, flags=%ld, cookie=0x%08lx", name, flags, (uint32)cookie );
221
222	// find device info
223	while (devices->device_names[index]
224		&& strcmp(name, devices->device_names[index]) != 0) {
225		index++;
226	}
227
228	di = &(devices->di[index / 2]);
229
230	ACQUIRE_BEN(devices->kernel);
231
232	if (!di->is_open)
233		result = Radeon_FirstOpen(di);
234
235	if (result == B_OK) {
236		di->is_open++;
237		*cookie = di;
238	}
239
240	RELEASE_BEN(devices->kernel);
241
242	SHOW_FLOW(3, "returning 0x%08lx", result);
243	return result;
244}
245
246
247static status_t
248read_hook(void *dev, off_t pos, void *buf, size_t *len)
249{
250	*len = 0;
251	return B_NOT_ALLOWED;
252}
253
254
255// public function: write to device (denied)
256static status_t
257write_hook(void *dev, off_t pos, const void *buf, size_t *len)
258{
259	*len = 0;
260	return B_NOT_ALLOWED;
261}
262
263
264static status_t
265close_hook(void *dev)
266{
267	return B_NO_ERROR;
268}
269
270
271static status_t
272free_hook(void *dev)
273{
274	device_info *di = (device_info *)dev;
275
276	SHOW_FLOW0( 0, "" );
277
278	ACQUIRE_BEN( devices->kernel );
279
280	mem_freetag( di->memmgr[mt_local], dev );
281
282	if( di->memmgr[mt_PCI] )
283		mem_freetag( di->memmgr[mt_PCI], dev );
284
285	if( di->memmgr[mt_AGP] )
286		mem_freetag( di->memmgr[mt_AGP], dev );
287
288	if( di->is_open == 1 )
289		Radeon_LastClose( di );
290
291	di->is_open--;
292	RELEASE_BEN( devices->kernel );
293
294	return B_OK;
295}
296
297
298static status_t
299control_hook(void *dev, uint32 msg, void *buf, size_t len)
300{
301	device_info *di = (device_info *)dev;
302	status_t result = B_DEV_INVALID_IOCTL;
303
304	switch (msg) {
305		// needed by app_server to load accelerant
306		case B_GET_ACCELERANT_SIGNATURE: {
307			char *sig = (char *)buf;
308			strcpy(sig, "radeon.accelerant");
309			result = B_OK;
310		} break;
311
312		// needed to share data between kernel and accelerant
313		case RADEON_GET_PRIVATE_DATA: {
314			radeon_get_private_data *gpd = (radeon_get_private_data *)buf;
315
316			if (gpd->magic == RADEON_PRIVATE_DATA_MAGIC) {
317				gpd->shared_info_area = di->shared_area;
318				gpd->virtual_card_area = di->virtual_card_area;
319				result = B_OK;
320			}
321		} break;
322
323		// needed for cloning
324		case RADEON_DEVICE_NAME: {
325			radeon_device_name *dn = (radeon_device_name *)buf;
326
327			if( dn->magic == RADEON_PRIVATE_DATA_MAGIC ) {
328				strncpy( dn->name, di->name, MAX_RADEON_DEVICE_NAME_LENGTH );
329				result = B_OK;
330			}
331		} break;
332
333		// graphics mem manager
334		case RADEON_ALLOC_MEM: {
335			radeon_alloc_mem *am = (radeon_alloc_mem *)buf;
336			memory_type_e memory_type;
337
338			if( am->magic != RADEON_PRIVATE_DATA_MAGIC )
339				break;
340
341			if( am->memory_type > mt_last )
342				break;
343
344			memory_type = am->memory_type == mt_nonlocal ? di->si->nonlocal_type : am->memory_type;
345
346			result = mem_alloc( di->memmgr[memory_type], am->size, am->global ? 0 : dev, &am->handle, &am->offset );
347		} break;
348
349		case RADEON_FREE_MEM: {
350			radeon_free_mem *fm = (radeon_free_mem *)buf;
351			memory_type_e memory_type;
352
353			if( fm->magic != RADEON_PRIVATE_DATA_MAGIC )
354				break;
355
356			if( fm->memory_type > mt_last )
357				break;
358
359			memory_type = fm->memory_type == mt_nonlocal ? di->si->nonlocal_type : fm->memory_type;
360
361			result = mem_free( di->memmgr[memory_type], fm->handle, fm->global ? 0 : dev );
362		} break;
363
364		case RADEON_WAITFORIDLE: {
365			radeon_wait_for_idle *wfi = (radeon_wait_for_idle *)buf;
366
367			if( wfi->magic != RADEON_PRIVATE_DATA_MAGIC )
368				break;
369
370			Radeon_WaitForIdle( di, true, wfi->keep_lock );
371			result = B_OK;
372		} break;
373
374		case RADEON_WAITFORFIFO: {
375			radeon_wait_for_fifo *wff = (radeon_wait_for_fifo *)buf;
376
377			if( wff->magic != RADEON_PRIVATE_DATA_MAGIC )
378				break;
379
380			Radeon_WaitForFifo( di, wff->entries );
381			result = B_OK;
382		} break;
383
384		case RADEON_RESETENGINE: {
385			radeon_no_arg *na = (radeon_no_arg *)buf;
386
387			if( na->magic != RADEON_PRIVATE_DATA_MAGIC )
388				break;
389
390			ACQUIRE_BEN( di->si->cp.lock );
391			Radeon_ResetEngine( di );
392			RELEASE_BEN( di->si->cp.lock );
393
394			result = B_OK;
395		} break;
396
397		case RADEON_VIPREAD: {
398			radeon_vip_read *vr = (radeon_vip_read *)buf;
399
400			if( vr->magic != RADEON_PRIVATE_DATA_MAGIC )
401				break;
402
403			result = Radeon_VIPRead( di, vr->channel, vr->address, &vr->data,
404				vr->lock ) ? B_OK : B_ERROR;
405		} break;
406
407		case RADEON_VIPWRITE: {
408			radeon_vip_write *vw = (radeon_vip_write *)buf;
409
410			if( vw->magic != RADEON_PRIVATE_DATA_MAGIC )
411				break;
412
413			result = Radeon_VIPWrite( di, vw->channel, vw->address, vw->data,
414				vw->lock ) ? B_OK : B_ERROR;
415		} break;
416
417		case RADEON_VIPFIFOREAD: {
418			radeon_vip_fifo_read *vr = (radeon_vip_fifo_read *)buf;
419
420			if( vr->magic != RADEON_PRIVATE_DATA_MAGIC )
421				break;
422
423			result = Radeon_VIPFifoRead( di, vr->channel, vr->address, vr->count, vr->data,
424				vr->lock ) ? B_OK : B_ERROR;
425		} break;
426
427		case RADEON_VIPFIFOWRITE: {
428			radeon_vip_fifo_write *vw = (radeon_vip_fifo_write *)buf;
429
430			if( vw->magic != RADEON_PRIVATE_DATA_MAGIC )
431				break;
432
433			result = Radeon_VIPFifoWrite( di, vw->channel, vw->address, vw->count, vw->data,
434				vw->lock ) ? B_OK : B_ERROR;
435		} break;
436
437		case RADEON_FINDVIPDEVICE: {
438			radeon_find_vip_device *fvd = (radeon_find_vip_device *)buf;
439
440			if( fvd->magic != RADEON_PRIVATE_DATA_MAGIC )
441				break;
442
443			fvd->channel = Radeon_FindVIPDevice( di, fvd->device_id );
444			result = B_OK;
445		} break;
446
447
448		case RADEON_VIPRESET: {
449			radeon_vip_reset *fvd = (radeon_vip_reset *)buf;
450
451			if( fvd->magic != RADEON_PRIVATE_DATA_MAGIC )
452				break;
453
454			Radeon_VIPReset( di, fvd->lock );
455			result = B_OK;
456		} break;
457
458		case RADEON_WAIT_FOR_CAP_IRQ: {
459			radeon_wait_for_cap_irq *wvc = (radeon_wait_for_cap_irq *)buf;
460
461			if( wvc->magic != RADEON_PRIVATE_DATA_MAGIC )
462				break;
463
464			// restrict wait time to 1 sec to get not stuck here in kernel
465			result = acquire_sem_etc( di->cap_sem, 1, B_RELATIVE_TIMEOUT,
466				min( wvc->timeout, 1000000 ));
467
468			if( result == B_OK ) {
469				cpu_status prev_irq_state = disable_interrupts();
470				acquire_spinlock( &di->cap_spinlock );
471
472				wvc->timestamp = di->cap_timestamp;
473				wvc->int_status = di->cap_int_status;
474				wvc->counter = di->cap_counter;
475
476				release_spinlock( &di->cap_spinlock );
477				restore_interrupts( prev_irq_state );
478			}
479		} break;
480
481		case RADEON_DMACOPY: {
482			radeon_dma_copy *dc = (radeon_dma_copy *)buf;
483
484			if( dc->magic != RADEON_PRIVATE_DATA_MAGIC )
485				break;
486
487			result = Radeon_DMACopy( di, dc->src, dc->target, dc->size, dc->lock_mem, dc->contiguous );
488		} break;
489
490#ifdef ENABLE_LOGGING
491#ifdef LOG_INCLUDE_STARTUP
492		// interface to log data
493		case RADEON_GET_LOG_SIZE:
494			*(uint32 *)buf = log_getsize( di->si->log );
495			result = B_OK;
496			break;
497
498		case RADEON_GET_LOG_DATA:
499			log_getcopy( di->si->log, buf, ((uint32 *)buf)[0] );
500			result = B_OK;
501			break;
502#endif
503#endif
504	}
505
506	if( result == B_DEV_INVALID_IOCTL )
507		SHOW_ERROR( 3, "Invalid ioctl call: code=0x%lx", msg );
508
509	return result;
510}
511