/*
	Copyright (c) 2002, Thomas Kurschel
 
	Part of Radeon kernel driver
	DevFS interface
*/
 
#include "radeon_driver.h"
 
#include <OS.h>
#include <malloc.h>
#include <graphic_driver.h>
#include <stdio.h>
#include <string.h>
#include "AGP.h"
#include "mmio.h"
#include "version.h"
#include <driver_settings.h>
#include <stdlib.h> // for strtoXX
 
// tell the kernel what revision of the driver API we support
int32	api_version = 2;
 
 
static status_t open_hook(const char *name, uint32 flags, void **cookie);
static status_t close_hook(void *dev);
static status_t free_hook(void *dev);
static status_t read_hook(void *dev, off_t pos, void *buf, size_t *len);
static status_t write_hook(void *dev, off_t pos, const void *buf, size_t *len);
static status_t control_hook(void *dev, uint32 msg, void *buf, size_t len);
 
 
static device_hooks graphics_device_hooks = {
	open_hook,
	close_hook,
	free_hook,
	control_hook,
	read_hook,
	write_hook,
	NULL,
	NULL,
	NULL,
	NULL
};
 
radeon_settings def_settings = { // see comments in radeon.settings
	2,			 		// loginfo
	2,			 		// logflow
	2,			 		// logerror
	false,				// switchhead
	false,				// force_lcd
	true,				// dynamic_clocks
	true,				// force_pci
	false,				// unhide_fw
	false,				// acc_dma
	false,				// acc_mmio
	true,				// acc_wb
};
 
radeon_settings current_settings;
 
static void
GetDriverSettings(void)
{
	void *settings_handle = NULL;
 
	SHOW_FLOW0( 1, "" );
	
	// init settings to defaults;
	current_settings = def_settings;
	
	// get driver/accelerant settings, apsed
	settings_handle  = load_driver_settings ("radeon.settings");
	if (settings_handle != NULL) {
		const char *item;
		char       *end;
		uint32      value;
 
		item = get_driver_parameter (settings_handle, "loginfo", "2", "2");
		value = strtoul (item, &end, 0);
		if (*end == '\0' && value <= 4) {
			current_settings.loginfo = value;
			SHOW_INFO( 1, "Log Info Level now %ld/4", value );
		}
		
		item = get_driver_parameter (settings_handle, "logflow", "2", "2");
		value = strtoul (item, &end, 0);
		if (*end == '\0' && value <= 4) {
			current_settings.logflow = value;
			SHOW_INFO( 1, "Log Flow Level now %ld/4", value );
		}
 
		item = get_driver_parameter (settings_handle, "logerror", "2", "2");
		value = strtoul (item, &end, 0);
		if (*end == '\0' && value <= 4) {
			current_settings.logerror = value;
			SHOW_INFO( 1, "Log Error Level now %ld/4", value );
		}
		
		current_settings.switchhead = get_driver_boolean_parameter (settings_handle, "switchhead", false, false);
		current_settings.force_lcd = get_driver_boolean_parameter (settings_handle, "force_lcd", false, false);
		current_settings.dynamic_clocks = get_driver_boolean_parameter (settings_handle, "dynamic_clocks", true, true);
		current_settings.force_pci = get_driver_boolean_parameter (settings_handle, "force_pci", true, true);
		current_settings.unhide_fastwrites = get_driver_boolean_parameter (settings_handle, "unhide_fw", false, false);
		current_settings.force_acc_dma = get_driver_boolean_parameter (settings_handle, "force_acc_dma", false, false);
		current_settings.force_acc_mmio = get_driver_boolean_parameter (settings_handle, "force_acc_mmio", false, false);
		current_settings.acc_writeback = get_driver_boolean_parameter (settings_handle, "acc_writeback", false, false);
 
		if ( current_settings.switchhead != def_settings.switchhead )
			SHOW_INFO0( 1, "Switch Head = True" );
		if ( current_settings.force_lcd != def_settings.force_lcd )
			SHOW_INFO0( 1, "Force LCD ON" );
		if ( current_settings.dynamic_clocks != def_settings.dynamic_clocks )
			SHOW_INFO0( 1, "Mobility Power Saving Disabled (Dynamic Clocks)" );
		if ( current_settings.force_pci != def_settings.force_pci )
			SHOW_INFO0( 1, "Force PCI = True" );
		if ( current_settings.unhide_fastwrites != def_settings.unhide_fastwrites )
			SHOW_INFO0( 1, "use Fastwrites ON" );
		if ( current_settings.force_acc_dma != def_settings.force_acc_dma )
			SHOW_INFO0( 1, "DMA ACC Enabled" );
		if ( current_settings.force_acc_mmio != def_settings.force_acc_mmio )
			SHOW_INFO0( 1, "DMA ACC Disabled" );
		if ( current_settings.acc_writeback != def_settings.acc_writeback )
			SHOW_INFO0( 1, "DMA WriteBack Disabled" );
			
		unload_driver_settings (settings_handle);
	}
}
 
 
//	#pragma mark - driver API
 
 
status_t
init_hardware(void)
{
	SHOW_INFO0(0, RADEON_DRIVER_VERSION);
	if (Radeon_CardDetect() == B_OK)
		return B_OK;
 
	return B_ERROR;
}
 
 
status_t
init_driver(void)
{
	SHOW_FLOW0(3, "");
 
	if (get_module(B_PCI_MODULE_NAME, (module_info **)&pci_bus) != B_OK)
		return B_ERROR;
 
	/* get a handle for the agp bus if it exists */
	get_module(B_AGP_GART_MODULE_NAME, (module_info **)&sAGP);
 
	/* driver private data */
	devices = (radeon_devices *)calloc(1, sizeof(radeon_devices));
	if (devices == NULL) {
		put_module(B_PCI_MODULE_NAME);
		if (sAGP != NULL)
			put_module(B_AGP_GART_MODULE_NAME);
		return B_ERROR;
	}
 
	(void)INIT_BEN(devices->kernel, "Radeon Kernel");
 
	GetDriverSettings();
	Radeon_ProbeDevices();
	return B_OK;
}
 
 
void
uninit_driver(void)
{
	SHOW_FLOW0(3, "");
	DELETE_BEN(devices->kernel);
 
	free(devices);
	devices = NULL;
 
	put_module(B_PCI_MODULE_NAME);
	if (sAGP) 
		put_module(B_AGP_GART_MODULE_NAME);
}
 
 
const char **
publish_devices(void)
{
	return (const char **)devices->device_names;
}
 
 
device_hooks *
find_device(const char *name)
{
	uint32 index;
 
	// probably, we could always return standard hooks 
	for (index = 0; devices->device_names[index]; ++index) {
		if (strcmp(name, devices->device_names[index]) == 0)
			return &graphics_device_hooks;
	}
 
	return NULL;
}
 
 
//	#pragma mark - device API
 
 
static status_t
open_hook(const char *name, uint32 flags, void **cookie)
{
	int32 index = 0;
	device_info *di;
	status_t result = B_OK;
 
	SHOW_FLOW( 3, "name=%s, flags=%ld, cookie=0x%08lx", name, flags, (uint32)cookie );
 
	// find device info
	while (devices->device_names[index]
		&& strcmp(name, devices->device_names[index]) != 0) {
		index++;
	}
 
	di = &(devices->di[index / 2]);
 
	ACQUIRE_BEN(devices->kernel);
 
	if (!di->is_open)
		result = Radeon_FirstOpen(di);
 
	if (result == B_OK) {
		di->is_open++;
		*cookie = di;
	}
 
	RELEASE_BEN(devices->kernel);
 
	SHOW_FLOW(3, "returning 0x%08lx", result);
	return result;
}
 
 
static status_t
read_hook(void *dev, off_t pos, void *buf, size_t *len)
{
	*len = 0;
	return B_NOT_ALLOWED;
}
 
 
// public function: write to device (denied)
static status_t
write_hook(void *dev, off_t pos, const void *buf, size_t *len)
{
	*len = 0;
	return B_NOT_ALLOWED;
}
 
 
static status_t
close_hook(void *dev)
{
	return B_NO_ERROR;
}
 
 
static status_t
free_hook(void *dev)
{
	device_info *di = (device_info *)dev;
 
	SHOW_FLOW0( 0, "" );
 
	ACQUIRE_BEN( devices->kernel );
 
	mem_freetag( di->memmgr[mt_local], dev );
	
	if( di->memmgr[mt_PCI] )
		mem_freetag( di->memmgr[mt_PCI], dev );
 
	if( di->memmgr[mt_AGP] )
		mem_freetag( di->memmgr[mt_AGP], dev );
	
	if( di->is_open == 1 )
		Radeon_LastClose( di );
 
	di->is_open--;
	RELEASE_BEN( devices->kernel );
 
	return B_OK;
}
 
 
static status_t
control_hook(void *dev, uint32 msg, void *buf, size_t len)
{
	device_info *di = (device_info *)dev;
	status_t result = B_DEV_INVALID_IOCTL;
 
	switch (msg) {
		// needed by app_server to load accelerant
		case B_GET_ACCELERANT_SIGNATURE: {
			char *sig = (char *)buf;
			strcpy(sig, "radeon.accelerant");
			result = B_OK;
		} break;
 
		// needed to share data between kernel and accelerant		
		case RADEON_GET_PRIVATE_DATA: {
			radeon_get_private_data *gpd = (radeon_get_private_data *)buf;
			
			if (gpd->magic == RADEON_PRIVATE_DATA_MAGIC) {
				gpd->shared_info_area = di->shared_area;
				gpd->virtual_card_area = di->virtual_card_area;
				result = B_OK;
			}
		} break;
 
		// needed for cloning
		case RADEON_DEVICE_NAME: {
			radeon_device_name *dn = (radeon_device_name *)buf;
			
			if( dn->magic == RADEON_PRIVATE_DATA_MAGIC ) {
				strncpy( dn->name, di->name, MAX_RADEON_DEVICE_NAME_LENGTH );
				result = B_OK;
			}
		} break;
		
		// graphics mem manager
		case RADEON_ALLOC_MEM: {
			radeon_alloc_mem *am = (radeon_alloc_mem *)buf;
			memory_type_e memory_type;
			
			if( am->magic != RADEON_PRIVATE_DATA_MAGIC )
				break;
				
			if( am->memory_type > mt_last )
				break;
 
			memory_type = am->memory_type == mt_nonlocal ? di->si->nonlocal_type : am->memory_type;
			
			result = mem_alloc( di->memmgr[memory_type], am->size, am->global ? 0 : dev, &am->handle, &am->offset );
		} break;
		
		case RADEON_FREE_MEM: {
			radeon_free_mem *fm = (radeon_free_mem *)buf;
			memory_type_e memory_type;
		
			if( fm->magic != RADEON_PRIVATE_DATA_MAGIC )
				break;
				
			if( fm->memory_type > mt_last )
				break;	
				
			memory_type = fm->memory_type == mt_nonlocal ? di->si->nonlocal_type : fm->memory_type;
				
			result = mem_free( di->memmgr[memory_type], fm->handle, fm->global ? 0 : dev );
		} break;
		
		case RADEON_WAITFORIDLE: {
			radeon_wait_for_idle *wfi = (radeon_wait_for_idle *)buf;
			
			if( wfi->magic != RADEON_PRIVATE_DATA_MAGIC )
				break;
				
			Radeon_WaitForIdle( di, true, wfi->keep_lock );
			result = B_OK;
		} break;
		
		case RADEON_WAITFORFIFO: {
			radeon_wait_for_fifo *wff = (radeon_wait_for_fifo *)buf;
			
			if( wff->magic != RADEON_PRIVATE_DATA_MAGIC )
				break;
				
			Radeon_WaitForFifo( di, wff->entries );
			result = B_OK;
		} break;
		
		case RADEON_RESETENGINE: {
			radeon_no_arg *na = (radeon_no_arg *)buf;
			
			if( na->magic != RADEON_PRIVATE_DATA_MAGIC )
				break;
				
			ACQUIRE_BEN( di->si->cp.lock );
			Radeon_ResetEngine( di );
			RELEASE_BEN( di->si->cp.lock );
			
			result = B_OK;
		} break;
		
		case RADEON_VIPREAD: {
			radeon_vip_read *vr = (radeon_vip_read *)buf;
			
			if( vr->magic != RADEON_PRIVATE_DATA_MAGIC )
				break;
				
			result = Radeon_VIPRead( di, vr->channel, vr->address, &vr->data,
				vr->lock ) ? B_OK : B_ERROR;
		} break;
		
		case RADEON_VIPWRITE: {
			radeon_vip_write *vw = (radeon_vip_write *)buf;
			
			if( vw->magic != RADEON_PRIVATE_DATA_MAGIC )
				break;
				
			result = Radeon_VIPWrite( di, vw->channel, vw->address, vw->data,
				vw->lock ) ? B_OK : B_ERROR;
		} break;
		
		case RADEON_VIPFIFOREAD: {
			radeon_vip_fifo_read *vr = (radeon_vip_fifo_read *)buf;
			
			if( vr->magic != RADEON_PRIVATE_DATA_MAGIC )
				break;
				
			result = Radeon_VIPFifoRead( di, vr->channel, vr->address, vr->count, vr->data,
				vr->lock ) ? B_OK : B_ERROR;
		} break;
		
		case RADEON_VIPFIFOWRITE: {
			radeon_vip_fifo_write *vw = (radeon_vip_fifo_write *)buf;
			
			if( vw->magic != RADEON_PRIVATE_DATA_MAGIC )
				break;
				
			result = Radeon_VIPFifoWrite( di, vw->channel, vw->address, vw->count, vw->data,
				vw->lock ) ? B_OK : B_ERROR;
		} break;
		
		case RADEON_FINDVIPDEVICE: {
			radeon_find_vip_device *fvd = (radeon_find_vip_device *)buf;
			
			if( fvd->magic != RADEON_PRIVATE_DATA_MAGIC )
				break;
 
			fvd->channel = Radeon_FindVIPDevice( di, fvd->device_id );
			result = B_OK;
		} break;
		
		
		case RADEON_VIPRESET: {
			radeon_vip_reset *fvd = (radeon_vip_reset *)buf;
 
			if( fvd->magic != RADEON_PRIVATE_DATA_MAGIC )
				break;
			
			Radeon_VIPReset( di, fvd->lock );
			result = B_OK;
		} break;
		
		case RADEON_WAIT_FOR_CAP_IRQ: {
			radeon_wait_for_cap_irq *wvc = (radeon_wait_for_cap_irq *)buf;
			
			if( wvc->magic != RADEON_PRIVATE_DATA_MAGIC )
				break;
				
			// restrict wait time to 1 sec to get not stuck here in kernel
			result = acquire_sem_etc( di->cap_sem, 1, B_RELATIVE_TIMEOUT, 
				min( wvc->timeout, 1000000 ));
	
			if( result == B_OK ) {
				cpu_status prev_irq_state = disable_interrupts();
				acquire_spinlock( &di->cap_spinlock );
				
				wvc->timestamp = di->cap_timestamp;
				wvc->int_status = di->cap_int_status;
				wvc->counter = di->cap_counter;
				
				release_spinlock( &di->cap_spinlock );
				restore_interrupts( prev_irq_state );
			}
		} break;
		
		case RADEON_DMACOPY: {
			radeon_dma_copy *dc = (radeon_dma_copy *)buf;
			
			if( dc->magic != RADEON_PRIVATE_DATA_MAGIC )
				break;
				
			result = Radeon_DMACopy( di, dc->src, dc->target, dc->size, dc->lock_mem, dc->contiguous );
		} break;
					
#ifdef ENABLE_LOGGING
#ifdef LOG_INCLUDE_STARTUP
		// interface to log data
		case RADEON_GET_LOG_SIZE:
			*(uint32 *)buf = log_getsize( di->si->log );
			result = B_OK;
			break;
			
		case RADEON_GET_LOG_DATA:
			log_getcopy( di->si->log, buf, ((uint32 *)buf)[0] );
			result = B_OK;
			break;
#endif
#endif
	}
	
	if( result == B_DEV_INVALID_IOCTL )
		SHOW_ERROR( 3, "Invalid ioctl call: code=0x%lx", msg );
		
	return result;
}

↑ V576 Incorrect format. Consider checking the fourth actual argument of the 'dprintf' function. The memsize type argument is expected.

↑ V576 Incorrect format. Consider checking the fourth actual argument of the 'dprintf' function. The memsize type argument is expected.

↑ V576 Incorrect format. Consider checking the fifth actual argument of the 'dprintf' function. The memsize type argument is expected.

↑ V576 Incorrect format. Consider checking the sixth actual argument of the 'dprintf' function. The memsize type argument is expected.

↑ V576 Incorrect format. Consider checking the fourth actual argument of the 'dprintf' function. The memsize type argument is expected.

↑ V576 Incorrect format. Consider checking the fourth actual argument of the 'dprintf' function. The memsize type argument is expected.

↑ V576 Incorrect format. Consider checking the fourth actual argument of the 'dprintf' function. The memsize type argument is expected.