⛏️ index : haiku.git

/*
 * Copyright 2005-2008, Axel DΓΆrfler, axeld@pinc-software.de. All rights reserved.
 * Distributed under the terms of the MIT License.
 */


#include "accelerant_protos.h"
#include "accelerant.h"

#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <syslog.h>

#include <AutoDeleterOS.h>


//#define TRACE_ACCELERANT
#ifdef TRACE_ACCELERANT
extern "C" void _sPrintf(const char *format, ...);
#	define TRACE(x) _sPrintf x
#else
#	define TRACE(x) ;
#endif


struct accelerant_info *gInfo;


//	#pragma mark -


/*!	This is the common accelerant_info initializer. It is called by
	both, the first accelerant and all clones.
*/
static status_t
init_common(int device, bool isClone)
{
	// initialize global accelerant info structure

	gInfo = (accelerant_info *)malloc(sizeof(accelerant_info));
	MemoryDeleter infoDeleter(gInfo);
	if (gInfo == NULL)
		return B_NO_MEMORY;

	memset(gInfo, 0, sizeof(accelerant_info));

	gInfo->is_clone = isClone;
	gInfo->device = device;
	gInfo->current_mode = UINT16_MAX;

	// get basic info from driver

	area_id sharedArea;
	if (ioctl(device, VESA_GET_PRIVATE_DATA, &sharedArea, sizeof(area_id)) != 0)
		return B_ERROR;

	AreaDeleter sharedDeleter(clone_area("vesa shared info",
		(void **)&gInfo->shared_info, B_ANY_ADDRESS,
		B_READ_AREA | B_WRITE_AREA, sharedArea));
	status_t status = gInfo->shared_info_area = sharedDeleter.Get();
	if (status < B_OK)
		return status;

	gInfo->vesa_modes = (vesa_mode *)((uint8 *)gInfo->shared_info
		+ gInfo->shared_info->vesa_mode_offset);

	infoDeleter.Detach();
	sharedDeleter.Detach();
	return B_OK;
}


/*!	Cleans up everything done by a successful init_common(). */
static void
uninit_common(void)
{
	delete_area(gInfo->shared_info_area);
	gInfo->shared_info_area = -1;
	gInfo->shared_info = NULL;

	// close the file handle ONLY if we're the clone
	// (this is what Be tells us ;)
	if (gInfo->is_clone)
		close(gInfo->device);

	free(gInfo);
}


//	#pragma mark - public accelerant functions


/*!	Init primary accelerant */
status_t
vesa_init_accelerant(int device)
{
	TRACE(("vesa_init_accelerant()\n"));

	status_t status = init_common(device, false);
	if (status != B_OK)
		return status;

	status = create_mode_list();
	if (status != B_OK) {
		uninit_common();
		return status;
	}

	// Initialize current mode completely from the mode list
	vesa_propose_display_mode(&gInfo->shared_info->current_mode, NULL, NULL);
	return B_OK;
}


ssize_t
vesa_accelerant_clone_info_size(void)
{
	// clone info is device name, so return its maximum size
	return B_PATH_NAME_LENGTH;
}


void
vesa_get_accelerant_clone_info(void *info)
{
	ioctl(gInfo->device, VESA_GET_DEVICE_NAME, info, B_PATH_NAME_LENGTH);
}


status_t
vesa_clone_accelerant(void *info)
{
	TRACE(("vesa_clone_accelerant()\n"));

	// create full device name
	char path[MAXPATHLEN];
	strcpy(path, "/dev/");
	strcat(path, (const char *)info);

	int fd = open(path, B_READ_WRITE);
	if (fd < 0)
		return errno;

	status_t status = init_common(fd, true);
	if (status != B_OK)
		goto err1;

	// get read-only clone of supported display modes
	status = gInfo->mode_list_area = clone_area(
		"vesa cloned modes", (void **)&gInfo->mode_list,
		B_ANY_ADDRESS, B_READ_AREA, gInfo->shared_info->mode_list_area);
	if (status < B_OK)
		goto err2;

	return B_OK;

err2:
	uninit_common();
err1:
	close(fd);
	return status;
}


/*!	This function is called for both, the primary accelerant and all of
	its clones.
*/
void
vesa_uninit_accelerant(void)
{
	TRACE(("vesa_uninit_accelerant()\n"));

	// delete accelerant instance data
	delete_area(gInfo->mode_list_area);
	gInfo->mode_list = NULL;

	uninit_common();
}


status_t
vesa_get_accelerant_device_info(accelerant_device_info *info)
{
	info->version = B_ACCELERANT_VERSION;

	strcpy(info->name, "VESA driver");
	if (gInfo->shared_info->name[0] != '\0') {
		strlcpy(info->chipset, gInfo->shared_info->name, 32);
	} else {
		switch (gInfo->shared_info->bios_type) {
			case kIntelBiosType:
				strcpy(info->chipset, "Intel");
				break;
			case kNVidiaBiosType:
				strcpy(info->chipset, "nVidia");
				break;
			case kAtomBiosType1:
			case kAtomBiosType2:
				strcpy(info->chipset, "AMD/ATI Atombios");
				break;
			default:
				strcpy(info->chipset, "Generic VESA");
				break;
		}
	}
	strcpy(info->serial_no, "None");

	info->memory = gInfo->shared_info->vram_size;
#if 0
	info->dac_speed = ???
#endif

	return B_OK;
}


sem_id
vesa_accelerant_retrace_semaphore()
{
	return -1;
}