BeBox Zone Logo
 
About
Home
News
Forums
Registry
Tech Info
BeBox Overview
BeBooks
BeBox Peripherals
BeBox Bezel
BootROM
Clock Generation
Floppy Disk Drive
Geekport
I/O Board
Infrared Ports
ISA Bus
Joystick Ports
Keyboard/Mouse Controller
Main Processor Board
MIDI Ports
Memory Controller and PCI Bridge
Parallel Ports
PCI Bus
Processor Board Overview
Processor Bus
Processors
Real-Time Clock
Reset and Interrupts
Serial Ports
SCSI
Sound System
Voltage Regulation
History
Opinions
Images
Articles
FAQs
Links
Operating Systems
Software
Contact Us





















/* ++++++++++
	FILE:	a2d.c
	REVS:	$Revision: 1.35 $
	NAME:	herold
	DATE:	Wed Oct 18 15:54:56 PDT 1995
	Copyright (c) 1995 by Be Incorporated.  All Rights Reserved.

	The a2d and joystick drivers.
+++++ */

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define SUPPORT_REV3	1
#define DEBUG 1

#if DEBUG
#define ddprintf dprintf
#else
#define ddprintf 
#endif

/* -----
	private globals
----- */
	
static vshort	*geek_output_enable;
static vshort	*geek_a2d_data;
static vshort	*geek_a2d_control;
static vshort	*joy_mux;
static vuchar	*joy_button;

static long		open_device [8] = {0,0,0,0,0,0,0,0};	/* a2d 0-3 joy 4-7 */
static sem_id	a2d_hw = -1;					/* sem to access a2d h/w */
static bool		joy_mux_delay_needed = FALSE;	/* early i/o cards were slow */


/* ----------
	find_a2d - determines if a2d hardware is present, and set up globals
	to point to it.
----- */
static bool
find_a2d (void)
{
	area_info	a;
	area_id		id;
	int			version;

	version = io_card_version();
	if (version < 0)
		return FALSE;

	id = find_area ("isa_io");
	if (id < 0)
		return FALSE;
	if (get_area_info (id, &a) < 0)
		return FALSE;

	geek_output_enable = (vshort *) ((long)a.address + GEEK_OUTPUT_ENABLE);
	geek_a2d_data = (vshort *) ((long)a.address + GEEK_A2D_DATA);
	geek_a2d_control =  (vshort *) ((long) a.address + GEEK_A2D_CONTROL);
	joy_mux =  (vshort *) ((long) a.address + JOY_MUX);
	joy_button = (vuchar *) ((long) a.address + JOY_BUTTON);

	if (version < 5)
		joy_mux_delay_needed = TRUE;	/* early i/o cards were slow */

	return TRUE;
}

/* ----------
	force_deref - work around compiler optimizing away volatile references by passing them
	to this function.
----- */
static void force_deref (int x) {}
	


/* ----------
	init_hardware - determine if a2d present, initialize it.
----- */
status_t
init_hardware (void)
{
	if (!find_a2d())
		return B_ERROR;

	force_deref (*geek_a2d_data);	/* clear old interrupts w/read */
	__eieio();

#if SUPPORT_REV3
	/* see if mux bits are in separate location, or shared w/digital port 
	   output enable register. */

	*joy_mux = 0;
	__eieio();
	if ((B_LENDIAN_TO_HOST_INT16 (*joy_mux) & 0x0300) == 0) {
		__eieio();
		*joy_mux = B_HOST_TO_LENDIAN_INT16 (0x0300);
		__eieio();
		if ((B_LENDIAN_TO_HOST_INT16 (*joy_mux) & 0x0300) != 0x0300) {
			ddprintf ("init_hardware: mux shared w/output enable\n");
			joy_mux = geek_output_enable;
		}
	}
	__eieio();
#endif
	return B_NO_ERROR;
}
	
/* ----------
	init_driver - does one-time initialization of the a2d driver.
----- */
status_t
init_driver (void)
{
	if (!find_a2d())
		return B_ERROR;

	if ((a2d_hw = create_sem (1, "a2d hw access")) < 0)
		return B_ERROR;

	set_sem_owner(a2d_hw, B_SYSTEM_TEAM);

	return B_NO_ERROR;
}


/* ----------
	uninit_driver - does cleanup of a2d driver
----- */
void
uninit_driver (void)
{
	if (a2d_hw >= 0)
		delete_sem (a2d_hw);

	a2d_hw = -1;
}


/* ----------
	a2d_hw_read
----- */
static ushort
a2d_hw_read (short control_reg)
{
	ushort	data;
	vshort	*ctl = geek_a2d_control;

	acquire_sem(a2d_hw);

	/* setup, start conversion */
	*ctl = B_HOST_TO_LENDIAN_INT16 (control_reg);
	__eieio();

	/* wait till conversion done */
	while (!(B_LENDIAN_TO_HOST_INT16 (*ctl) & 0x0800)) {
		__eieio();
		spin (10);
	}
	__eieio();

	/* read 12 bit result */
	data = B_LENDIAN_TO_HOST_INT16 (*geek_a2d_data) & 0x0FFF;
	__eieio();
	
	release_sem (a2d_hw);

	return data;
}


/* ----------
	joy_close
----- */

static status_t
joy_close (short id)
{
	if ((id < 4) || (id >7))
		return B_ERROR;

	if (open_device[id] == 0)
		return B_ERROR;

	open_device[id] = 0;

	return B_NO_ERROR;
}


/* ----------
	joy_read
----- */

static status_t
joy_read (int id, void *buf)
{
	short		mux;
	joystick	j;
	uchar		buttons;
	static struct {
		char	button_1_mask;
		char	button_2_mask;
		char	mux_x;
		char	mux_y;
		short	a2d_select;
	} info[4] = {
		{ 0x01, 0x08, 0x00, 0x01, 0x002C },	/* joystick 1  (port a, primary) */
		{ 0x02, 0x04, 0x02, 0x03, 0x002C },	/* joystick 2  (port a, secondary) */
		{ 0x10, 0x80, 0x00, 0x01, 0x006C },	/* joystick 3  (port b, primary) */
		{ 0x20, 0x40, 0x02, 0x03, 0x006C }	/* joystick 4  (port b, secondary) */
	};

	if ((id < 4) || (id > 7))
		return B_ERROR;
	id -= 4;

	/* set joystick mux for x coordinate, read it */

	mux = B_LENDIAN_TO_HOST_INT16 (*joy_mux);
	__eieio();
	mux = (mux & 0xFCFF) + (info[id].mux_x << 8);
	*joy_mux = B_HOST_TO_LENDIAN_INT16 (mux);
	__eieio();
	if (joy_mux_delay_needed)		/* early i/o cards were slow */
		spin (100);
	j.horizontal = a2d_hw_read (info[id].a2d_select);

	/* set joystick mux for y coordinate, read it */

	mux = B_LENDIAN_TO_HOST_INT16 (*joy_mux);
	__eieio();
	mux = (mux & 0xFCFF) + (info[id].mux_y << 8);
	*joy_mux = B_HOST_TO_LENDIAN_INT16 (mux);
	__eieio();
	if (joy_mux_delay_needed)		/* early i/o cards were slow */
		spin (100);
	j.vertical = a2d_hw_read (info[id].a2d_select);

	buttons = *joy_button;
	j.timestamp = system_time();

	j.button1 = (buttons & info[id].button_1_mask) ? TRUE : FALSE;
	j.button2 = (buttons & info[id].button_2_mask) ? TRUE : FALSE;

	memcpy (buf, &j, sizeof (j));

	return 1;
}


/* ----------
	a2d_close
----- */

static status_t
a2d_close (short id)
{

	if ((id < 0) || (id > 3))
		return B_ERROR;

	if (open_device[id] == 0)
		return B_ERROR;

	open_device[id] = 0;

	return B_NO_ERROR;
}


/* ----------
	a2d_read
----- */

static status_t
a2d_read (int id, void *buf)
{
	short		val;
	static short control_reg[4] = {
		0x000C,		/* a/d 0, single ended, unipolar */
		0x004C,		/* a/d 1, single ended, unipolar */
		0x001C,		/* a/d 2, single ended, unipolar */
		0x005C		/* a/d 3, single ended, unipolar */
	};

	if ((id >3) || (id <0))
		return B_ERROR;

	val = a2d_hw_read (control_reg[id]);
	*(char *)buf = val >> 8;
	*((char *)buf + 1) = val;

	return 2;
}

/* -----
	generic function used for driver-kernel interface
----- */

static status_t
device_open (const char *name, uint32 flags, void** cookie)
{
	int	id;
	
	ddprintf("trying to open %s.\n",name);

	if (flags != O_RDONLY) {
		dprintf("%s is read only. Thanks, come again...\n", name);
		return B_ERROR;
	}

	id = name [strlen(name)-1] - '1';
	if (id < 0 || id > 3)
		return B_ERROR;

	/* distinguish open of a2d from joystick */
	id = (name[strlen(name) - 3] == 'd') ? id : id + 4;
	ddprintf("driver_open: id is %x.\n", id);

	if (atomic_or (&open_device[id], 1))
		return B_ERROR;						/*already opened ? */
		
	*cookie = (void*) id;		/* ! not really giving a cookie adress, just an id */
	return B_NO_ERROR;
}

/* -----
	device close
----- */

static status_t device_close(void* cookie)
{
	short 	id;

	id = (int) cookie;
	if (id < 4)
		return a2d_close(id);
	else
		return joy_close(id);
}


/* -----
	device read
----- */

static status_t
device_read (void* cookie, off_t position, void* buffer, size_t* num_bytes)
{
	short	id;

	id = (int) cookie;
	if (id < 4)
		return a2d_read(id, buffer);
	else
		return joy_read(id, buffer);
}


/* -----
	device write: read only!
----- */
static status_t 
device_write (void* cookie, off_t position, const void* buffer, size_t* num_bytes)
{
	return B_ERROR;
}


/* -----
	device control
----- */
static status_t
device_control (void* cookie, uint32 op, void* arg, size_t len)
{
	short id;

	id = (int) cookie;

	if ( (id > (-1)) && (id < 4)) {	/* hidden calls only for a2d */

		switch (op) {
		case 0xfeed0006:			/* hidden call: read channel 6 */
			return a2d_hw_read (0x003C);

		case 0xfeed0007:			/* hidden call: read channel 7 */
			return a2d_hw_read (0x007C);

		default:
			;
		}
	}
	return B_ERROR;
}

/* -----
	device_free - free my cookie!
----- */

static status_t 
device_free (void* cookie)
{
	/*no cookie was created, thanks come again */ 
	return B_NO_ERROR;
}


/* -----
	driver-related structures
----- */

device_hooks	a2d_devices[] = {
	device_open, 				/* -> open entry point */
	device_close, 				/* -> close entry point */
	device_free,				/* -> free cookies allocated */
	device_control, 			/* -> control entry point */
	device_read,				/* -> read entry point */
	device_write				/* -> write entry point */
};

static const char* a2d_device_names[] = {
	"beboxhw/geekport/a2d/a2d_1",
	"beboxhw/geekport/a2d/a2d_2",
	"beboxhw/geekport/a2d/a2d_3",
	"beboxhw/geekport/a2d/a2d_4",
	"joystick/joystick_1",
	"joystick/joystick_2",
	"joystick/joystick_3",
	"joystick/joystick_4",
	NULL
};

const char**
publish_devices()
{
	return a2d_device_names;
}

device_hooks* find_device(const char *name)
{
	return	a2d_devices;
}






 Questions? Comments? Contact Andrew Lampert (webmaster at bebox dot nu).


BeUnited
BeBits
LeBuzz Blog
BeOS Radio
BeDope

© 1998-2009 Andrew Lampert