file: board.c
/*
* This file contains the "board" software module. It contains constant
* definitions and C functions that interface directly with the
* SoundLight boards.
*/
# define __KERNEL__
#endif
# define MODULE
#endif
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <asm/io.h>
/* local definitions */
#include "slh.h"
/* prevent symbols from this file from
* being accessed by any part of the
* kernel outside of this driver.
*/
EXPORT_NO_SYMBOLS;
/* macros to get high and low byte of address */
#define ADDR_HI( addr ) ( ((addr) >> 8) & 0xff )
#define ADDR_LO( addr ) ( (addr) & 0xff )
/* board RAM size */
#define SLH_RAM_SIZE 0xa00
/* first possible board port */
#define SLH_FIRST_PORT 0x100
/* board address for pumping */
#define SLH_PUMP_ADDR 0x000
/* board address for parameters */
#define SLH_PARMS_ADDR 0x3f0
/* board address for type */
#define SLH_BRD_TYPE_ADDR 0x3f9
/* board address of DMX send channels */
#define SLH_SND_CHAN_ADDR 0x400
/* board address of DMX receive channels */
#define SLH_RCV_CHAN_ADDR 0x800
/* test byte for board probing */
#define SLH_TEST_BYTE 0xaa
/* board type for 1512C */
#define SLH_TYPE_1512C 0x04
/* board type for 1512C */
#define SLH_TYPE_1512CC 0x05
/* board type for 1512A or 1512B/LC */
#define SLH_TYPE_1512ABLC 0x80
/* board type for 1512B */
#define SLH_TYPE_1512B 0x01
/* board port number */
static unsigned long slh_board_port;
/* board port number */
static unsigned char slh_board_parms[9];
int
slh_board_mod_init()
{
/* initialize the "board" software module
* (called when the slh driver is loaded).
*/
slh_board_port = 0;
slh_board_parms[0] = 60; /* start sync duration */
slh_board_parms[1] = 0; /* start byte */
slh_board_parms[2] = 0; /* end idle time */
slh_board_parms[3] = ADDR_LO(512); /* number of chans (lo byte) */
slh_board_parms[4] = ADDR_HI(512); /* number of chans (hi byte) */
slh_board_parms[5] = 0; /* send repeat */
slh_board_parms[6] = 0; /* inter-digit time */
slh_board_parms[7] = 0; /* not used */
slh_board_parms[8] = 0; /* card mode (read/write) */
return ( 0 );
}
void
slh_board_mod_cleanup()
{
/* cleanup the "board" software module
* (called when the slh driver is unloaded).
*/
/* stop the board (if running) */
slh_board_stop();
/* release the ISA ports */
release_region( slh_board_port, 4 );
slh_board_port = 0;
}
int
slh_board_find()
{
/* find the Soundlight boards (if any) in the system */
register int i;
unsigned char data;
slh_board_port = 0;
for ( i = 0; i < 4; i++ ) {
unsigned port = SLH_FIRST_PORT + (0x20 * i);
/* check if ports are registered to other apps */
if ( check_region(port, 4) < 0 ) {
continue;
}
/* write the test byte to the port */
outb( (unsigned char)0, port );
outb( (unsigned char)0, port + 1 );
outb( (unsigned char)SLH_TEST_BYTE, port + 2 );
/* read the test byte back from the port */
outb( (unsigned char)0, port );
outb( (unsigned char)0, port + 1 );
data = inb( port + 2 );
/* check if the test byte was retrieved */
if ( data == SLH_TEST_BYTE ) {
slh_board_port = port;
/* register the ports */
request_region( slh_board_port, 4, "slh" );
return ( port );
}
}
return ( -1 );
}
int
slh_board_pump( unsigned char *data, unsigned long length )
{
/* pump the firmware and parameters to the SoundLight board */
register unsigned long i;
register unsigned long addr;
register unsigned char test;
if ( slh_board_port == 0 ) {
return ( -1 );
}
/* stop repetitive channel timer (if running) */
slh_channel_timer_stop();
/* load the board firmware */
for ( addr = SLH_PUMP_ADDR, i = 0; i < length; i++, addr++, data++ ) {
/* write a firmware byte to the board */
outb( ADDR_LO(addr), slh_board_port );
outb( ADDR_HI(addr), slh_board_port + 1 );
outb( *data, slh_board_port + 2 );
/* read the firmware byte back from the board */
outb( ADDR_LO(addr), slh_board_port );
outb( ADDR_HI(addr), slh_board_port + 1 );
test = inb( slh_board_port + 2 );
/* verify that the firmware byte was written successfully */
if ( *data != test ) {
"Board pump check failed! data=0x%x, actual=0x%x\n",
(unsigned int)*data, (unsigned int)test );
return ( -1 );
}
}
/* zero the remaining board memory */
for ( ; i < SLH_RAM_SIZE; i++, addr++ ) {
outb( ADDR_LO(addr), slh_board_port );
outb( ADDR_HI(addr), slh_board_port + 1 );
outb( (unsigned char)0, slh_board_port + 2 );
}
/* load the board parameters */
slh_board_pump_parms();
/* start processor on board */
slh_board_start();
/* Wait 100us for the board to initialize. Measurements
* indicate that it takes the 1512B about 56us to init.
*/
udelay( 100 );
/* check the board type */
outb( ADDR_LO(SLH_BRD_TYPE_ADDR), slh_board_port );
outb( ADDR_HI(SLH_BRD_TYPE_ADDR), slh_board_port + 1 );
test = inb( slh_board_port + 2 );
if ( test != SLH_TYPE_1512B ) {
"Board type check failed! actual=0x%x\n", (unsigned int)test );
return ( -1 );
}
/* start repetitive channel timer */
slh_channel_timer_start();
return ( 0 );
}
int
slh_board_pump_parms()
{
/* pump parameters to SoundLight board */
register unsigned long i;
register unsigned long addr;
if ( slh_board_port == 0 ) {
return ( -1 );
}
addr = SLH_PARMS_ADDR;
for ( i = 0; i < sizeof(slh_board_parms); i++, addr++ ) {
outb( ADDR_LO(addr), slh_board_port );
outb( ADDR_HI(addr), slh_board_port + 1 );
outb( slh_board_parms[i], slh_board_port + 2 );
}
return ( 0 );
}
#if 0
int
slh_board_init_chans()
{
register unsigned long i;
register unsigned long addr;
if ( slh_board_port == 0 ) {
return ( -1 );
}
addr = SLH_SND_CHAN_ADDR;
for ( i = 0; i < NUM_DMX_CHANS; i++, addr++ ) {
outb( ADDR_LO(addr), slh_board_port );
outb( ADDR_HI(addr), slh_board_port + 1 );
outb( 0, slh_board_port + 2 );
}
return ( 0 );
}
#endif
int
slh_board_start()
{
/* start processor on Soundlight board */
if ( slh_board_port == 0 ) {
return ( -1 );
}
(void) inb( slh_board_port + 3 );
return ( 0 );
}
int
slh_board_stop()
{
/* stop processor on Soundlight board */
if ( slh_board_port == 0 ) {
return ( -1 );
}
outb( (unsigned char)0, slh_board_port );
return ( 0 );
}
void
slh_board_chan_set( unsigned long chan, unsigned long value )
{
/* set a DMX-512 channel to a specified value */
unsigned long addr;
if ( slh_board_port == 0 ) {
return;
}
/* channel must be 0 to 511 */
if ( chan >= 512 ) {
return;
}
/* calculate the board address of the DMX-512 channel */
addr = SLH_SND_CHAN_ADDR + chan;
/* set the channel value */
outb( ADDR_LO(addr), slh_board_port );
outb( ADDR_HI(addr), slh_board_port + 1 );
outb( value, slh_board_port + 2 );
return;
}
C++ to HTML Conversion by ctoohtml