#include "rtapi_ctype.h"
#include "rtapi.h"
#include "rtapi_app.h"
#include "hal.h"
#define FASTIO
#ifdef FASTIO
#define rtapi_inb inb
#define rtapi_outb outb
#include <asm/io.h>
#endif
MODULE_AUTHOR("John Kasunich");
MODULE_DESCRIPTION("Axiom AX5214H Driver for HAL");
MODULE_LICENSE("GPL");
static char *cfg = "";
RTAPI_MP_STRING(cfg, "config string");
typedef struct {
hal_bit_t *data;
union {
hal_bit_t *not;
hal_bit_t invert;
} io;
} io_pin_t;
typedef struct {
unsigned short base_addr;
unsigned char dir_bits;
unsigned char port1config;
unsigned char port2config;
io_pin_t port_1A[8];
io_pin_t port_1B[8];
io_pin_t port_1CL[4];
io_pin_t port_1CH[4];
io_pin_t port_2A[8];
io_pin_t port_2B[8];
io_pin_t port_2CL[4];
io_pin_t port_2CH[4];
} board_t;
static board_t *board_array;
static int comp_id;
static int num_boards;
static void read_board(void *arg, long period);
static void write_board(void *arg, long period);
static int pins_and_params(char *argv[]);
static unsigned short parse_board_addr(char *cp);
static int export_board(int boardnum, board_t * board);
static int export_port(int boardnum, int pin_num, io_pin_t *pin, int num_pins, int dir);
static int export_input_pin(int boardnum, int pinnum, io_pin_t *pin);
static int export_output_pin(int boardnum, int pinnum, io_pin_t *pin);
#define MAX_BOARDS 8
#define MAX_TOK ((MAX_BOARDS*2)+3)
int rtapi_app_main(void)
{
char *cp;
char *argv[MAX_TOK];
char name[HAL_NAME_LEN + 1];
int n, retval;
if ((cfg == 0) || (cfg[0] == '\0')) {
rtapi_print_msg(RTAPI_MSG_ERR, "AX5214H: ERROR: no config string\n");
return -1;
}
cp = cfg;
for (n = 0; n < MAX_TOK; n++) {
while ((*cp != '\0') && ( isspace(*cp) || ( *cp == '_') ))
cp++;
argv[n] = cp;
while ((*cp != '\0') && !( isspace(*cp) || ( *cp == '_') ))
cp++;
if (*cp != '\0') {
*cp = '\0';
cp++;
}
}
for (n = 0; n < MAX_TOK; n++) {
if (argv[n][0] == '\0') {
argv[n] = NULL;
}
}
retval = pins_and_params(argv);
if (retval != 0) {
return retval;
}
for (n = 0; n < num_boards; n++) {
rtapi_snprintf(name, sizeof(name), "ax5214h.%d.read", n);
retval = hal_export_funct(name, read_board, &(board_array[n]),
0, 0, comp_id);
if (retval != 0) {
rtapi_print_msg(RTAPI_MSG_ERR,
"AX5214H: ERROR: port %d read funct export failed\n", n);
hal_exit(comp_id);
return -1;
}
rtapi_snprintf(name, sizeof(name), "ax5214h.%d.write", n);
retval = hal_export_funct(name, write_board, &(board_array[n]),
0, 0, comp_id);
if (retval != 0) {
rtapi_print_msg(RTAPI_MSG_ERR,
"AX5214H: ERROR: port %d write funct export failed\n", n);
hal_exit(comp_id);
return -1;
}
}
rtapi_print_msg(RTAPI_MSG_INFO,
"AX5214H: installed driver for %d boards\n", num_boards);
hal_ready(comp_id);
return 0;
}
void rtapi_app_exit(void)
{
int n;
board_t *board;
for ( n = 0 ; n < num_boards ; n++ ) {
board = &(board_array[n]);
outb(0xff, board->base_addr+0);
outb(0xff, board->base_addr+1);
outb(0xff, board->base_addr+2);
outb(0xff, board->base_addr+3);
outb(0xff, board->base_addr+4);
outb(0xff, board->base_addr+5);
outb(0xff, board->base_addr+6);
outb(0xff, board->base_addr+7);
}
hal_exit(comp_id);
}
static void split_input(unsigned char data, io_pin_t *dest, int num)
{
int b;
unsigned char mask;
mask = 0x01;
for (b = 0 ; b < num ; b++ ) {
if ( data & mask ) {
*(dest->data) = 0;
*(dest->io.not) = 1;
} else {
*(dest->data) = 1;
*(dest->io.not) = 0;
}
mask <<= 1;
dest++;
}
}
static void read_board(void *arg, long period)
{
board_t *board;
unsigned char indata;
board = arg;
if ( (board->dir_bits & 0x01) == 0 ) {
indata = rtapi_inb(board->base_addr+0);
split_input(indata, &(board->port_1A[0]), 8);
}
if ( (board->dir_bits & 0x02) == 0 ) {
indata = rtapi_inb(board->base_addr+1);
split_input(indata, &(board->port_1B[0]), 8);
}
if ( (board->dir_bits & 0x0A) != 0x0A ) {
indata = rtapi_inb(board->base_addr+2);
if ( (board->dir_bits & 0x04) == 0 ) {
split_input(indata, &(board->port_1CL[0]), 4);
}
indata >>= 4;
if ( (board->dir_bits & 0x08) == 0 ) {
split_input(indata, &(board->port_1CH[0]), 4);
}
}
if ( (board->dir_bits & 0x10) == 0 ) {
indata = rtapi_inb(board->base_addr+4);
split_input(indata, &(board->port_2A[0]), 8);
}
if ( (board->dir_bits & 0x20) == 0 ) {
indata = rtapi_inb(board->base_addr+5);
split_input(indata, &(board->port_2B[0]), 8);
}
if ( (board->dir_bits & 0xA0) != 0xA0 ) {
indata = rtapi_inb(board->base_addr+6);
if ( (board->dir_bits & 0x40) == 0 ) {
split_input(indata, &(board->port_2CL[0]), 4);
}
indata >>= 4;
if ( (board->dir_bits & 0x80) == 0 ) {
split_input(indata, &(board->port_2CH[0]), 4);
}
}
}
unsigned char build_output(io_pin_t *src, int num)
{
int b;
unsigned char data, mask;
data = 0x00;
mask = 0x01;
for (b = 0; b < num; b++) {
if ( *(src->data) ) {
if ( !(src->io.invert) ) {
data |= mask;
}
} else {
if ( (src->io.invert) ) {
data |= mask;
}
}
mask <<= 1;
src++;
}
return data;
}
static void write_board(void *arg, long period)
{
board_t *board;
unsigned char outdata, tmp;
board = arg;
if ( (board->dir_bits & 0x01) == 0x01 ) {
outdata = build_output(&(board->port_1A[0]), 8);
rtapi_outb(~outdata, board->base_addr+0);
}
if ( (board->dir_bits & 0x02) == 0x02 ) {
outdata = build_output(&(board->port_1B[0]), 8);
rtapi_outb(~outdata, board->base_addr+1);
}
if ( (board->dir_bits & 0x0A) != 0x00 ) {
outdata = 0;
if ( (board->dir_bits & 0x04) == 0x04 ) {
tmp = build_output(&(board->port_1CL[0]), 4);
outdata = tmp;
}
if ( (board->dir_bits & 0x08) == 0x08 ) {
tmp = build_output(&(board->port_1CH[0]), 4);
outdata = outdata | (tmp << 4);
}
rtapi_outb(~outdata, board->base_addr+2);
}
if ( (board->dir_bits & 0x10) == 0x10 ) {
outdata = build_output(&(board->port_2A[0]), 8);
rtapi_outb(~outdata, board->base_addr+4);
}
if ( (board->dir_bits & 0x20) == 0x20 ) {
outdata = build_output(&(board->port_2B[0]), 8);
rtapi_outb(~outdata, board->base_addr+5);
}
if ( (board->dir_bits & 0xA0) != 0x00 ) {
outdata = 0;
if ( (board->dir_bits & 0x40) == 0x40 ) {
tmp = build_output(&(board->port_2CL[0]), 4);
outdata = tmp;
}
if ( (board->dir_bits & 0x80) == 0x80 ) {
tmp = build_output(&(board->port_2CH[0]), 4);
outdata = outdata | (tmp << 4);
}
rtapi_outb(~outdata, board->base_addr+6);
}
}
static int pins_and_params(char *argv[])
{
unsigned short board_addr[MAX_BOARDS];
unsigned char dir_bits[MAX_BOARDS], mask;
int n, m, retval;
for (n = 0; n < MAX_BOARDS; n++) {
board_addr[n] = 0;
dir_bits[n] = 0;
}
num_boards = 0;
n = 0;
while ((num_boards < MAX_BOARDS) && (argv[n] != 0)) {
board_addr[num_boards] = parse_board_addr(argv[n]);
if (board_addr[num_boards] == 0) {
rtapi_print_msg(RTAPI_MSG_ERR,
"AX5124H: ERROR: bad port address '%s'\n", argv[n]);
return -1;
}
n++;
if (argv[n] == 0) {
rtapi_print_msg(RTAPI_MSG_ERR,
"AX5124H: ERROR: no config info for port %s\n", argv[n-1]);
return -1;
}
dir_bits[num_boards] = 0;
mask = 0x01;
for ( m = 0 ; m < 8 ; m++ ) {
if ((argv[n][m] == 'i') || (argv[n][m] == 'I')) {
dir_bits[num_boards] &= ~mask;
} else if ((argv[n][m] == 'o') || (argv[n][m] == 'O')) {
dir_bits[num_boards] |= mask;
} else {
rtapi_print_msg(RTAPI_MSG_ERR,
"AX5124H: ERROR: bad config info for port %s: '%s'\n", argv[n-1], argv[n]);
return -1;
}
mask <<= 1;
}
n++;
num_boards++;
}
if (num_boards == 0) {
rtapi_print_msg(RTAPI_MSG_ERR,
"AX5214H: ERROR: no ports configured\n");
return -1;
}
comp_id = hal_init("hal_ax5214h");
if (comp_id < 0) {
rtapi_print_msg(RTAPI_MSG_ERR, "AX5214H: ERROR: hal_init() failed\n");
return -1;
}
board_array = hal_malloc(num_boards * sizeof(board_t));
if (board_array == 0) {
rtapi_print_msg(RTAPI_MSG_ERR,
"AX5214H: ERROR: hal_malloc() failed\n");
hal_exit(comp_id);
return -1;
}
for (n = 0; n < num_boards; n++) {
board_array[n].base_addr = board_addr[n];
board_array[n].dir_bits = dir_bits[n];
retval = export_board(n, &(board_array[n]));
if (retval != 0) {
rtapi_print_msg(RTAPI_MSG_ERR,
"AX5214H: ERROR: board %d (%04X) var export failed\n", n, board_addr[n]);
hal_exit(comp_id);
return -1;
}
}
return 0;
}
static unsigned short parse_board_addr(char *cp)
{
unsigned short result;
result = 0;
if (cp[0] == '0') {
if ((cp[1] == 'X') || (cp[1] == 'x')) {
cp += 2;
}
}
while (*cp != '\0') {
if ((*cp >= '0') && (*cp <= '9')) {
result <<= 4;
result += *cp - '0';
} else if ((*cp >= 'A') && (*cp <= 'F')) {
result <<= 4;
result += (*cp - 'A') + 10;
} else if ((*cp >= 'a') && (*cp <= 'f')) {
result <<= 4;
result += (*cp - 'a') + 10;
} else {
return 0;
}
cp++;
}
return result;
}
static int export_board(int boardnum, board_t * board)
{
int retval, msg, dir;
unsigned char config;
msg = rtapi_get_msg_level();
rtapi_set_msg_level(RTAPI_MSG_WARN);
retval = 0;
config = 0x80;
dir = board->dir_bits & 0x01;
retval += export_port ( boardnum, 0, &(board->port_1A[0]), 8, dir );
if ( dir == 0 ) {
config |= 0x10;
}
dir = board->dir_bits & 0x02;
retval += export_port ( boardnum, 8, &(board->port_1B[0]), 8, dir );
if ( dir == 0 ) {
config |= 0x02;
}
dir = board->dir_bits & 0x04;
retval += export_port ( boardnum, 16, &(board->port_1CL[0]), 4, dir );
if ( dir == 0 ) {
config |= 0x01;
}
dir = board->dir_bits & 0x08;
retval += export_port ( boardnum, 20, &(board->port_1CH[0]), 4, dir );
if ( dir == 0 ) {
config |= 0x08;
}
board->port1config = config;
config = 0x80;
dir = board->dir_bits & 0x10;
retval += export_port ( boardnum, 24, &(board->port_2A[0]), 8, dir );
if ( dir == 0 ) {
config |= 0x10;
}
dir = board->dir_bits & 0x20;
retval += export_port ( boardnum, 32, &(board->port_2B[0]), 8, dir );
if ( dir == 0 ) {
config |= 0x02;
}
dir = board->dir_bits & 0x40;
retval += export_port ( boardnum, 40, &(board->port_2CL[0]), 4, dir );
if ( dir == 0 ) {
config |= 0x01;
}
dir = board->dir_bits & 0x80;
retval += export_port ( boardnum, 44, &(board->port_2CH[0]), 4, dir );
if ( dir == 0 ) {
config |= 0x08;
}
board->port2config = config;
outb(board->port1config, board->base_addr+3);
outb(0xff, board->base_addr+0);
outb(0xff, board->base_addr+1);
outb(0xff, board->base_addr+2);
outb(board->port2config, board->base_addr+7);
outb(0xff, board->base_addr+4);
outb(0xff, board->base_addr+5);
outb(0xff, board->base_addr+6);
rtapi_set_msg_level(msg);
return retval;
}
static int export_port(int boardnum, int pin_num, io_pin_t *pin, int num_pins, int dir)
{
int n, retval;
retval = 0;
for ( n = 0 ; n < num_pins ; n++ ) {
if ( dir == 0 ) {
retval += export_input_pin(boardnum, pin_num, pin );
} else {
retval += export_output_pin(boardnum, pin_num, pin );
}
pin_num++;
pin++;
}
return retval;
}
static int export_input_pin(int boardnum, int pinnum, io_pin_t *pin)
{
int retval;
retval = hal_pin_bit_newf(HAL_OUT, &(pin->data), comp_id,
"ax5214h.%d.in-%02d", boardnum, pinnum);
if (retval != 0) {
return retval;
}
retval = hal_pin_bit_newf(HAL_OUT, &(pin->io.not), comp_id,
"ax5214h.%d.in-%02d-not", boardnum, pinnum);
*(pin->data) = 0;
*(pin->io.not) = 1;
return retval;
}
static int export_output_pin(int boardnum, int pinnum, io_pin_t *pin)
{
int retval;
retval = hal_pin_bit_newf(HAL_IN, &(pin->data), comp_id,
"ax5214h.%d.out-%02d", boardnum, pinnum);
if (retval != 0) {
return retval;
}
retval = hal_param_bit_newf(HAL_RW, &(pin->io.invert), comp_id,
"ax5214h.%d.out-%02d-invert", boardnum, pinnum);
*(pin->data) = 0;
pin->io.invert = 0;
return retval;
}