Files
epics-base/src/drv/ansi/drvAb.c
1995-08-17 14:45:57 +00:00

1830 lines
54 KiB
C
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* drvAb.c - Driver Support Routines for Allen Bradley */
/*
* Interface to the Allen-Bradley Remote Serial IO
*
* Author: Bob Dalesio
* Date: 6-21-88
* Major Revision March 1995. Bob Dalesio and Marty Kraimer
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
* Notes:
* 1. This driver uses Asynchronous Communications to the AB scanner
* The manual description for this type of interface is
* misleading in the area of interrupt handling.
* 2. We are using double slot addressing
* The database uses card numbers 0-11 to address slots 1-12
* It is possible to use 1 slot and 1/2 slot addressing.
* For 1 slot addressing assign card=slot*2
* For 1/2 slot addressing assign card = slot*4
* 3. The binary io is memory mapped and the analog io is handled through
* block transfers of whole cards of data.
* 4. The driver spawns a task for each 6008 card in VME and scans cards as
* the database claims they exist - there is no way to poll the hardware
* to determine what is present.
* 4. A flag is used to limit the requests to the analog input modules. This
* assures that only one request is outstanding at any time.
*
* Modification Log:
* -----------------
* .19 08-01-89 lrd changed sc_queue and bt_queue to always set
* length to 0 for compatibility with PLC-5
* communication
* .26 10-17-89 cbf added logic to see if the scanner was using the
* dual port when we had it locked. it is!
* ****************************************************************************
* * Many of the above were needed to work around problems in the *
* * 6008-SV firmware. These problems have been reported to Allen- *
* * Bradley and fixes are promised. The PROMs we are presently using *
* * are both labeled "91332-501". U63 chksum = A7A1. U64 chksum = 912B *
* * (Series A, Revision C.) *
* ****************************************************************************
* .27 12-11-89 cbf new PROMs implemented which allow output image
* table to be preserved during SYSTEM RESET.
* This driver is still compatible with the old
* firmware also.
* A piece of code was added to store the firmware
* revision level in array ab_firmware_info.
* .28 12-11-89 cbf With the new firmware, the scanner no longer
* uses the dual port when we have it locked so
* the tests for this condition have been removed.
* .29 01-23-90 cbf In the previous rev of this driver we made an
* attempt to build a scan list automatically by
* waiting until the periodic scan task had asked
* for data from each needed adapter.
* This scheme caused problems with the
* the initialization of BOs and AOs, because they
* were not initially in the scan list and so
* could not be read at initialization.
* In this rev, that code has been removed and the
* scan list is always built to include all
* eight possible adapters. This has some
* performance implications because each
* non-existant adapter which appears in the scan
* list adds an extra 12 ms to each I/O scan time
* for the 6008SV. The decreased performance does
* not appear to be very significant, however.
* The 6008SV front panel "SER" LED blinks if not
* all adapters in the scan list are responding.
* With this rev of the driver, the light will
* therefore be blinking.
****************************************************************************
** Allen-Bradley has given us a new firmware revision.
** This revision allows the reset of the scanner without using the
** sysReset on the VME backplane. It also maintains the output image table
** for the binary outputs. This reset is used to recover from a scanner
** fault, where the 6008 firmware deadends - ab_reset provides this
** function. *
*****************************************************************************
* .41 05-16-91 lrd have the ab_scan_task driver analog outputs
* periodically as well as on change
* .56 06-30-93 mrk After 3 attempts to queue request reinitialize
* .64 09-16-93 mrk ab_reset: all links; only reset scanner.
* ???????????? ??? fix scaling on IXE 4-20 Milli amp
* .65 04-04-94 lrd return the value for overrange and underrange
* .66 04-04-94 lrd put the binary change of state into the AB scan task
* .67 04-04-94 lrd support N serial cards
* - put all link and adapter information into structure
* - allocate structures as needed
* .68 09-29-94 lrd removed historical comments of no current significance
* .69 10-20-94 lrd moved all I/O board specific stuff up to the device layer
*/
#include <vxWorks.h>
#include <vxLib.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sysLib.h>
#include <semLib.h>
#include <vme.h>
#include <rebootLib.h>
#include <logLib.h>
#include <tickLib.h>
#include <task_params.h>
#include <dbDefs.h>
#include <dbScan.h>
#include <drvSup.h>
#include <taskwd.h>
#include <module_types.h>
#include <devLib.h>
#include <drvAb.h>
#define maxCmdTrys 3
#define AB_INT_LEVEL 5
#define MAX_AB_ADAPTERS 8
#define MAX_GROUPS_PER_ADAPTER 8
#define MAX_CARDS_PER_ADAPTER 16
/*Definitions for dual ported memory on scanner interface card*/
/* Command Word */
#define AUTO_CONF 0x10
#define SCAN_LIST 0x11
#define SET_UP 0x13
#define SET_MODE 0x20
#define LINK_STATUS 0x21
#define AB_READ 0x01
#define AB_WRITE 0x02
/* osw - operating status word definitions */
#define PROGRAM_MODE 0x01 /* program/reset mode */
#define TEST_MODE 0x02 /* test/reset mode */
#define RUN_MODE 0x04 /* run mode */
#define DEBUG_MODE 0x08 /* we are debugging */
#define UNSOLICITED_BT 0x10 /* detected block xfer we didn't want */
#define BTS_QUEUED 0x20 /* block xfers queued */
#define ADAPTER_FAULT 0x40 /* at least one faulted adapter list */
#define ADAP_FLT_CHNG 0x80 /* Adapter status change*/
/* Confirmation Status Word */
#define SCANNER_POWERUP 0x90 /* power up status */
#define BT_ACCEPTED 0x2f /* block trans accepted by scanner */
#define BT_QUEUE_FULL 0x14 /* Queue Full*/
#define BT_TIMEOUT 0x23 /* block transfer timeout */
/* these are used for the SET_UP command */
#define DEF_RATE 0x01 /* default baud rate 57.6K */
#define FAST_RATE 0x02 /* 115.2 KB */
#define NO_CHANGE 0xff /* no change */
#define DEBUG 0x01 /* debug - turn off watchdog timer */
#define AB_INT_ENABLE 0x00 /* interrupt enabled */
#define AB_SYSFAIL_DISABLE 0x01 /* disable VMEbus SYSFAIL signal */
/* DUAL PORTED MEMORY AREA DEFINITION */
/* mail box definition */
typedef volatile struct dp_mbox{
unsigned short conf_stat; /* confirmation status word */
unsigned short command; /* command word */
unsigned short address; /* module address */
unsigned short bt_tag; /* block transfer tag number */
unsigned short resv[9]; /* 18 bytes reserved */
unsigned char dummy;
unsigned char fl_lock; /* semaphore word byte */
unsigned short data_len; /* length of data sent/returned */
unsigned short msg[64]; /*mail box message */
}dp_mbox;
/* entire region with the mailbox */
typedef volatile struct ab_region {
unsigned short oit[64]; /* output image table */
unsigned short iit[64]; /* input image table */
unsigned short osw; /* operating status word */
dp_mbox mail; /* dual port mail box */
unsigned short gda[1872-66]; /* unused part gen data area */
unsigned short sys_fail_set1; /* 1st byte to recover from SYSFAIL */
unsigned short sys_fail_set2; /* 2nd byte to recover from SYSFAIL */
unsigned char vmeid[60]; /* scanner id */
unsigned short sc_intr; /* to interrupt the scanner */
unsigned short sc_pad; /* last word in scanner shared mem */
}ab_region;
typedef struct {
abStatus btStatus;
unsigned short cmd;
unsigned short *pmsg;
unsigned short msg_len;
}btInfo;
typedef enum {
stateInit,stateInitBTwait,stateCountdown,stateBT,stateBTwait
}scanState;
typedef struct {
scanState state;
unsigned short update_rate;
unsigned short *pread_msg;
unsigned short *pwrite_msg;
unsigned short read_msg_len;
unsigned short write_msg_len;
unsigned short state_cnt; /* number of consecutive time in state*/
unsigned short down_cnt; /* down_counter for scanning */
unsigned short bt_to; /* data transfer timed out */
unsigned short bt_fail; /*block transfer bad status*/
unsigned short init_ctr; /* number times the card initialized*/
}scanInfo;
typedef struct {
unsigned short link;
unsigned short adapter;
unsigned short card;
cardType type;
const char *card_name;
abNumBits nBits;
BOOL needsUpdate;
BOOL active;
abStatus status;
SEM_ID card_sem;
btInfo *pbtInfo;
scanInfo *pscanInfo;
void *userPvt;
void (*callback)(void *pcard); /*user's callback routine*/
void (*bocallback)(void *pcard); /*user's callback routine*/
unsigned long diprev;
}ab_card;
typedef struct{
unsigned short adapter;
BOOL adapter_online;
BOOL adapter_status_change;
ab_card **papcard; /*pointer to array of pointers*/
SEM_ID adapter_sem; /* request talk to scanner*/
}ab_adapter;
typedef struct {
void *base_address;
unsigned short baud_rate;
unsigned short int_vector;
unsigned short int_level;
unsigned short autoconfig;
unsigned short scan_list_len;
unsigned char scan_list[64];
} ab_config;
typedef struct {
unsigned short list_len;
unsigned short status[32];
unsigned char list[64];
}ab_link_status;
typedef struct{
unsigned short link;
unsigned short ab_disable;
SEM_ID request_sem; /* request talk to scanner*/
SEM_ID ab_cmd_sem; /* transfer complete semaphore */
SEM_ID ab_data_sem; /* transfer complete semaphore */
int abScanId; /* id of the Allen-Bradley scan task */
int abDoneId; /* id of the Allen-Bradley done task */
unsigned short sclock_to; /* Timeout trying to lock mailbox*/
unsigned short sccmd_to; /* command timeout on semTake*/
unsigned short sc_fail; /* Scanner Command Failure*/
unsigned short intr_cnt; /* interrupt counter*/
unsigned short intrSec; /* interrupts per second */
unsigned short bt_cnt; /* Block Transfer counter*/
unsigned short btSec; /* block transfers per second*/
ab_config *pconfig;
char firmware_info[96]; /* NOTE: available only temporarily */
ab_region *vme_addr; /* ptr to the memory of interface */
ab_adapter **papadapter;
ab_link_status *plink_status;
BOOL initialCallback;
BOOL initialized;
}ab_link;
/*Local variables and function prototypes*/
LOCAL ab_link **pab_links=NULL;
LOCAL unsigned int max_ab_6008s = 2;
/* forward references */
LOCAL void *abCalloc(size_t nobj,size_t size);
LOCAL ab_link *allocLink(unsigned short link);
LOCAL void ab_intr(int link);
LOCAL int sc_lock(ab_link *plink);
LOCAL int sc_waitcmd(ab_link *plink);
LOCAL void sc_conferr(ab_link *plink);
LOCAL void sc_unlock(ab_link *plink);
LOCAL void uctrans (unsigned char *from,unsigned char *to,unsigned short n);
LOCAL void ustrans (unsigned short *from,unsigned short *to,
unsigned short nwords);
LOCAL void di_read(ab_card *pcard,unsigned long *pvalue);
LOCAL void do_read(ab_card *pcard,unsigned long *pvalue);
LOCAL void do_write(ab_card *pcard,unsigned long value);
LOCAL abStatus bt_queue(unsigned short command,ab_card *pcard,
unsigned short *pmsg, unsigned short msg_len);
LOCAL int link_status(ab_link *plink);
LOCAL int ab_reboot_hook(int boot_type);
LOCAL void config_init(ab_link *plink);
LOCAL int ab_driver_init();
LOCAL int link_init(ab_link *plink);
LOCAL void abScanTask(ab_link *plink);
LOCAL void abDoneTask(ab_link *plink);
LOCAL void read_ab_adapter(ab_link *plink, ab_adapter *padapter);
LOCAL void ab_reset_task(ab_link *plink);
LOCAL long ab_io_report(int level);
/*Global variables */
unsigned int ab_debug=0;
LOCAL char *statusMessage[] = {
"Success","New Card","Card Conflict","No Card",
"Card not initialized","block transfer queued",
"Card Busy","Timeout","Adapter Down","Failure"};
char **abStatusMessage = statusMessage;
LOCAL char *numBitsMessage[] = {
"nbits_Not_defined"," 8_Bit","16_Bit","32_Bit"};
char **abNumBitsMessage = numBitsMessage;
/*End Global variables*/
/*Beginning of DSET routines */
LOCAL long report();
LOCAL long init();
struct {
long number;
DRVSUPFUN report;
DRVSUPFUN init;
} drvAb={
2,
report,
init
};
LOCAL long report(int level)
{
return(ab_io_report(level));
}
LOCAL long init()
{
return(ab_driver_init());
}
LOCAL void *abCalloc(size_t nobj,size_t size)
{
void *p;
p=calloc(nobj,size);
if(p) return(p);
logMsg("drvAb: calloc failure\n",0,0,0,0,0,0);
taskSuspend(0);
return(NULL);
}
LOCAL ab_link *allocLink(unsigned short link)
{
ab_link *plink;
if(pab_links[link]) return(pab_links[link]);
plink = abCalloc(1,sizeof(ab_link));
plink->ab_disable = TRUE;
plink->papadapter = abCalloc(MAX_AB_ADAPTERS,sizeof(ab_adapter *));
plink->plink_status = abCalloc(1,sizeof(ab_link_status));
plink->link = link;
config_init(plink);
pab_links[link] = plink;
return(plink);
}
/*
* AB_INTR
*
* The Allen-Bradley protocol requires that an interrupt be received when
* a block transfer request is given to the scanner board through the dual
* ported memory and then another when the command is complete.
* dual-ported memory lock is controlled in a much different fashion than it is.
*/
LOCAL void ab_intr(int link)
{
ab_link *plink;
ab_region *p6008;
dp_mbox *pmb;
if(!pab_links) return; /*Called before init complete*/
plink = pab_links[link];
if(!plink) return; /*Called before init complete*/
p6008 = plink->vme_addr;
if(!p6008) return;
pmb = &p6008->mail;
if((pmb->fl_lock&0x80)==0) {/*Should NEVER be True*/
logMsg("drvAb: Interrupt but fl_lock not locked\n", 0,0,0,0,0,0);
}
if(p6008->osw & UNSOLICITED_BT){
if (ab_debug != 0)
logMsg("link %x, unsolicited_block xfer\n",plink->link,0,0,0,0,0);
/* scanner depends on us to clear some bits */
p6008->osw = 0;
}
plink->intr_cnt++;
if((pmb->command==AB_WRITE || pmb->command==AB_READ)
&& (pmb->conf_stat != BT_ACCEPTED) && (pmb->conf_stat != BT_QUEUE_FULL)) {
semGive(plink->ab_data_sem);
} else {
semGive(plink->ab_cmd_sem);
}
}
/*Routines for communication with scanner*/
LOCAL int sc_lock(ab_link *plink)
{
ab_region *p6008 = plink->vme_addr;
dp_mbox *pmb = &p6008->mail;
unsigned short lock_stat = 0;
int i;
if(ab_debug>3)printf("sc_lock\n");
semTake(plink->request_sem,WAIT_FOREVER);
/* try to to lock the dual port memory */
for(i=0; i<vxTicksPerSecond*6; i++) {
if ((lock_stat = sysBusTas ((char *)&pmb->fl_lock)) == TRUE) break;
taskDelay(1);
}
if(lock_stat == FALSE) {
if(ab_debug)
printf("drvAb: link %x sc_lock failure\n", plink->link);
plink->sclock_to += 1;
pmb->fl_lock = 0; /*Unlock to attempt to recover. May not work*/
semGive(plink->request_sem);
return (ERROR);
}
return(0);
}
LOCAL int sc_waitcmd(ab_link *plink)
{
ab_region *p6008 = plink->vme_addr;
dp_mbox *pmb = &p6008->mail;
unsigned short savecmd;
int status;
int ntry;
if(ab_debug>3)printf("sc_waitcmd\n");
savecmd = pmb->command;
pmb->conf_stat = 0x000f;
ntry = 0;
p6008->sc_intr = 1; /*Wake up scanner*/
status = semTake(plink->ab_cmd_sem,vxTicksPerSecond);
if(status!=OK) {
plink->sccmd_to++;
if(ab_debug) printf(
"drvAb: sc_waitcmd timeout link %hu command %4x\n",
plink->link,savecmd);
sc_unlock(plink);
return(ERROR);
}
if(pmb->command != savecmd){
plink->sc_fail++;
if(ab_debug) printf(
"drvAb: bad cmd response. link %hu sent %4x received %4x\n",
plink->link,savecmd,pmb->command);
sc_unlock(plink);
return(ERROR);
}
return(0);
}
LOCAL void sc_conferr(ab_link *plink)
{
ab_region *p6008 = plink->vme_addr;
dp_mbox *pmb = &p6008->mail;
if(ab_debug>3)printf("sc_conferr\n");
plink->sc_fail++;
if(ab_debug) printf("drvAb: link %hu conf_stat error %4x\n",
plink->link,pmb->conf_stat);
sc_unlock(plink);
return;
}
LOCAL void sc_unlock(ab_link *plink)
{
ab_region *p6008 = plink->vme_addr;
dp_mbox *pmb = &p6008->mail;
if(ab_debug>3)printf("sc_unlock\n");
pmb->fl_lock = 0;
semGive(plink->request_sem);
}
/*Routines to transfer data to/from mailbox*/
/* Unsigned character transfer*/
LOCAL void uctrans (unsigned char *from,unsigned char *to,unsigned short n)
{
int i;
for (i=0;i<n;i++)
*to++ = *from++;
}
/* Unsigned short transfer*/
LOCAL void ustrans (unsigned short *from,unsigned short *to,
unsigned short nwords)
{
int i;
for (i=0;i<nwords;i++)
*to++ = *from++;
}
/* read the values from the hardware into the local word */
LOCAL void di_read(ab_card *pcard,unsigned long *pvalue)
{
unsigned short link = pcard->link;
unsigned short adapter = pcard->adapter;
unsigned short card = pcard->card;
unsigned short group,slot;
unsigned short rack_offset;
unsigned short *pimage;
unsigned long value;
rack_offset = (adapter * MAX_GROUPS_PER_ADAPTER);
group = card/2; slot = card - group*2;
pimage = &(pab_links[link]->vme_addr->iit[rack_offset + group]);
if (pcard->nBits == abBit8) {
value = *pimage;
if(slot==1) value >>= 8;
value &= 0x00ff;
*pvalue = value;
}else if(pcard->nBits == abBit16){
*pvalue = *pimage;
} else if (pcard->nBits == abBit32) {
value = *(pimage+1);
value <<= 16;
value += *pimage;
*pvalue = value;
}
}
/* read the values from the hardware into the local word */
LOCAL void do_read(ab_card *pcard,unsigned long *pvalue)
{
unsigned short link = pcard->link;
unsigned short adapter = pcard->adapter;
unsigned short card = pcard->card;
unsigned short group,slot;
unsigned short rack_offset;
unsigned short *pimage;
unsigned long value;
rack_offset = (adapter * MAX_GROUPS_PER_ADAPTER);
group = card/2; slot = card - group*2;
pimage = &(pab_links[link]->vme_addr->oit[rack_offset + group]);
if (pcard->nBits == abBit8) {
value = *pimage;
if(slot==1) value >>= 8;
value &= 0x00ff;
*pvalue = value;
}else if(pcard->nBits == abBit16){
*pvalue = *pimage;
} else if (pcard->nBits == abBit32) {
value = *(pimage+1);
value <<= 16;
value += *pimage;
*pvalue = value;
}
}
/* write the values to the hardware from the local word */
LOCAL void do_write(ab_card *pcard,unsigned long value)
{
unsigned short link = pcard->link;
unsigned short adapter = pcard->adapter;
unsigned short card = pcard->card;
unsigned short group,slot;
unsigned short rack_offset;
unsigned short *pimage;
rack_offset = (adapter * MAX_GROUPS_PER_ADAPTER);
group = card/2; slot = card - group*2;
pimage = &(pab_links[link]->vme_addr->oit[rack_offset + group]);
if (pcard->nBits == abBit8) {
if(slot==0) {
*pimage = (*pimage & 0xff00) | ((unsigned short)value & 0x00ff);
} else {
value <<= 8;
*pimage = (*pimage & 0x00ff) | ((unsigned short)value & 0xff00);
}
}else if(pcard->nBits == abBit16){
*pimage = (unsigned short)value;
} else if (pcard->nBits == abBit32) {
*pimage = (unsigned short)value;
*(pimage+1) = (unsigned short)(value >> 16);
}
}
LOCAL abStatus bt_queue(unsigned short command,ab_card *pcard,
unsigned short *pmsg, unsigned short msg_len)
{
ab_link *plink = pab_links[pcard->link];
ab_adapter *padapter = plink->papadapter[pcard->adapter];
btInfo *pbtInfo = pcard->pbtInfo;
ab_region *p6008 = plink->vme_addr;
dp_mbox *pmb = &p6008->mail;
unsigned short *pmb_msg = &pmb->msg[0];
int status;
if(!padapter->adapter_online) return(abAdapterDown);
pbtInfo->cmd = command;
pbtInfo->pmsg = pmsg;
pbtInfo->msg_len = msg_len;
status = sc_lock(plink);
if(status) return(abFailure);
pmb->command = command;
pmb->address = (padapter->adapter << 4) + pcard->card;
pmb->data_len = msg_len;
if(pbtInfo->cmd==AB_WRITE) ustrans(pmsg,pmb_msg,msg_len);
status = sc_waitcmd(plink);
if(status) return(abFailure);
status = pmb->conf_stat;
if(status != BT_ACCEPTED){
sc_conferr(plink);
if (status == BT_QUEUE_FULL){
printf("drvAb: BT_QUEUE_FULL link %hu\n",plink->link);
taskDelay(vxTicksPerSecond/10);
}
return(abFailure);
}
pbtInfo->btStatus = abBtqueued;
sc_unlock(plink);
return(abBtqueued);
}
/*
* LINK_STATUS
*
* Fetches the status of the adapters on the specified link
* The ab_adapter_status table is used to determine hardware communication
* errors and convey them to the database
*/
LOCAL int link_status(ab_link *plink)
{
short i;
ab_adapter *padapter;
dp_mbox *pmb;
ab_link_status *plink_status = plink->plink_status;
int status;
int ntry;
/* initialize the pointer to the dual ported memory */
pmb = (dp_mbox *)(&plink->vme_addr->mail);
/* get the link status */
for(ntry=0; ntry<maxCmdTrys; ntry++) {
status = sc_lock(plink);
if(status) continue;
pmb->command = LINK_STATUS;
pmb->data_len = 0;
status = sc_waitcmd(plink);
if(status) continue;
if(pmb->conf_stat != 0) {
sc_conferr(plink);
continue;
}
plink_status->list_len = pmb->data_len;
ustrans(pmb->msg,plink_status->status,32);
uctrans((unsigned char *)(pmb->msg+32),plink_status->list,64);
sc_unlock(plink);
break;
}
if(ntry>=maxCmdTrys) {
if(ab_debug)printf("abDrv: link_status failed link %hu\n",plink->link);
return(ERROR);
}
/* check each adapter on this link */
for (i = 0; i< AB_MAX_ADAPTERS; i++){
padapter = plink->papadapter[i];
if(!padapter) continue;
/* good status */
if (plink_status->status[i*4] & 0x70){
if (!padapter->adapter_online) {
printf("link %d adapter %d change bad to good\n",
plink->link,i);
padapter->adapter_status_change=TRUE;
}
padapter->adapter_online = TRUE;
}else { /* bad status */
if (padapter->adapter_online){
printf("link %d adapter %d change good to bad\n",
plink->link,i);
padapter->adapter_status_change=TRUE;
}
padapter->adapter_online = FALSE;
}
}
return(0);
}
/* ab_reboot_hook - routine to call when IOC is rebooted with a control-x */
LOCAL int ab_reboot_hook(int boot_type)
{
short i;
ab_link *plink;
/* Stop communication to the Allen-Bradley Scanner Cards */
/* delete the scan task stops analog input communication */
for (i=0; i<max_ab_6008s; i++) {
plink = pab_links[i];
if(plink) {
pab_links[i]->ab_disable = 1;
taskDelete(pab_links[i]->abScanId);
}
}
/* this seems to be necessary for the AB card to stop talking */
printf("\nReboot: drvAb delay to clear interrupts off backplane\n");
taskDelay(vxTicksPerSecond*2);
return(0);
}
LOCAL void config_init(ab_link *plink)
{
ab_config *pconfig = plink->pconfig;
int i;
ab_region *p6008;
if(!pconfig) plink->pconfig = pconfig = abCalloc(1,sizeof(ab_config));
p6008 = (ab_region *)AB_BASE_ADDR;
p6008 += plink->link;
pconfig->base_address = (void *)p6008;
pconfig->baud_rate = DEF_RATE;
pconfig->autoconfig = FALSE;
pconfig->int_vector = AB_VEC_BASE + plink->link;
pconfig->int_level = AB_INT_LEVEL;
pconfig->scan_list_len = 8;
for(i=0; i< AB_MAX_ADAPTERS; i++) pconfig->scan_list[i] = (i<<2);
}
int abConfigNlinks(int nlinks)
{
if(pab_links) {
printf("abConfigNlinks Illegal call. Must be first abDrv related call");
return(-1);
}
max_ab_6008s = nlinks;
pab_links = abCalloc(max_ab_6008s,sizeof(ab_link *));
return(0);
}
int abConfigVme(int link, int base, int vector, int level)
{
ab_link *plink;
ab_config *pconfig;
if(link<0 || link>=max_ab_6008s) return(-1);
if(!pab_links) pab_links = abCalloc(max_ab_6008s,sizeof(ab_link *));
plink = pab_links[link];
if(!plink) plink = allocLink(link);
pconfig = plink->pconfig;
pconfig->base_address = (void *)base;
pconfig->int_vector = vector;
pconfig->int_level = level;
return(0);
}
int abConfigBaud(int link, int baud)
{
ab_link *plink;
ab_config *pconfig;
if(link<0 || link>=max_ab_6008s) return(-1);
if(!pab_links) pab_links = abCalloc(max_ab_6008s,sizeof(ab_link *));
plink = pab_links[link];
if(!plink) plink = allocLink(link);
pconfig = plink->pconfig;
if(baud = 0) pconfig->baud_rate = DEF_RATE;
else pconfig->baud_rate = FAST_RATE;
return(0);
}
int abConfigAuto(int link)
{
ab_link *plink;
ab_config *pconfig;
if(link<0 || link>=max_ab_6008s) return(-1);
if(!pab_links) pab_links = abCalloc(max_ab_6008s,sizeof(ab_link *));
plink = pab_links[link];
if(!plink) plink = allocLink(link);
pconfig = plink->pconfig;
pconfig->autoconfig = TRUE;
return(0);
}
int abConfigScanList(int link, int scan_list_len, char *scan_list)
{
ab_link *plink;
ab_config *pconfig;
if(link<0 || link>=max_ab_6008s) return(-1);
if(!pab_links) pab_links = abCalloc(max_ab_6008s,sizeof(ab_link *));
plink = pab_links[link];
if(!plink) plink = allocLink(link);
pconfig = plink->pconfig;
pconfig->scan_list_len = scan_list_len;
memset(pconfig->scan_list,'\0',64);
memcpy(pconfig->scan_list,scan_list,scan_list_len);
return(0);
}
int abConfigScanListAscii(int link, char *filename,int setRackSize)
{
FILE *fp;
char *scan_list;
char buf[80];
unsigned rack,group,size;
int nItemsRead,nCharsRead,scan_list_len;
scan_list = abCalloc(64,sizeof(char));
fp = fopen(filename,"r");
scan_list_len = 0;
while(fgets(buf,80,fp)) {
if(buf[0] == '#') continue;
nItemsRead = sscanf(buf,"%u %u %n",&rack,&group,&nCharsRead);
if(nItemsRead!=2) {
printf("abConfigScanListAscii: Illegal line %d %s\n",
scan_list_len,buf);
fclose(fp);
return(0);
}
if(!setRackSize) {
size = 0x00;
} else if(strstr(&buf[nCharsRead],"1/4")) {
size = 0x00;
} else if(strstr(&buf[nCharsRead],"1/2")) {
size = 0x40;
} else if(strstr(&buf[nCharsRead],"3/4")) {
size = 0x80;
} else if(strstr(&buf[nCharsRead],"Full")) {
size = 0xc0;
} else {
printf("abConfigScanListAscii: Illegal line %d %s\n",
scan_list_len,buf);
fclose(fp);
return(0);
}
scan_list[scan_list_len] = size | (rack<<2) | group;
scan_list_len++;
}
fclose(fp);
return(abConfigScanList(link,scan_list_len,scan_list));
}
LOCAL int ab_driver_init()
{
unsigned short cok;
unsigned short link;
ab_link *plink;
ab_region *p6008;
ab_config *pconfig;
int vxstatus;
long status;
int got_one;
char task_name[50];
if(!pab_links) pab_links = abCalloc(max_ab_6008s,sizeof(ab_link *));
/* check if any of the cards are there */
got_one = 0;
for (link = 0; link < max_ab_6008s; link++,p6008++){
plink = pab_links[link];
if(plink) {
p6008 = plink->pconfig->base_address;
} else {
p6008 = (void *)AB_BASE_ADDR;
p6008 += link;
}
status = devRegisterAddress("drvAb",atVMEA24,(void *)p6008,
sizeof(ab_region),(void **)&p6008);
if(status) {
errMessage(status,"drvAb");
return(status);
}
if (vxMemProbe((char *)p6008,READ,1,(char *)&cok)==ERROR) {
continue;
}
got_one = 1;
if(!plink) plink = allocLink(link);
plink->vme_addr = p6008; /* set AB card address */
pconfig = plink->pconfig;
if(!(plink->request_sem = semBCreate(SEM_Q_FIFO,SEM_EMPTY))){
printf("AB_DRIVER_INIT: semBcreate failed");
taskSuspend(0);
}
if(!(plink->ab_cmd_sem = semBCreate(SEM_Q_FIFO,SEM_EMPTY))){
printf("AB_DRIVER_INIT: semBcreate failed");
taskSuspend(0);
}
if(!(plink->ab_data_sem = semBCreate(SEM_Q_FIFO,SEM_EMPTY))){
printf("AB_DRIVER_INIT: semBcreate failed");
taskSuspend(0);
}
status = devConnectInterrupt(intVME,pconfig->int_vector,
ab_intr,(void *)(int)link);
if(status) {
errMessage(status,"drvAb");
return(status);
}
status = devEnableInterruptLevel(intVME,pconfig->int_level);
if(status) {
errMessage(status,"drvAb");
taskSuspend(0);
}
/* initialize the serial link */
if(link_init(plink)) {
/*No use proceeding*/
continue;
}
plink->initialized = TRUE;
sprintf(task_name,"%s%2.2d",ABSCAN_NAME,link);
vxstatus = taskSpawn(task_name,ABSCAN_PRI,ABSCAN_OPT,
ABSCAN_STACK,(FUNCPTR)abScanTask,(int)plink,
0,0,0,0,0,0,0,0,0);
if(vxstatus < 0){
printf("AB_DRIVER_INIT: failed taskSpawn");
taskSuspend(0);
}
plink->abScanId = vxstatus;
taskwdInsert(plink->abScanId,NULL,NULL);
sprintf(task_name,"%s%2.2d",ABDONE_NAME,link);
vxstatus = taskSpawn(task_name,ABDONE_PRI,ABDONE_OPT,
ABDONE_STACK,(FUNCPTR)abDoneTask,(int)plink,
0,0,0,0,0,0,0,0,0);
if(vxstatus < 0){
printf("AB_DRIVER_INIT: failed taskSpawn");
taskSuspend(0);
}
plink->abDoneId = vxstatus;
taskwdInsert(plink->abDoneId,NULL,NULL);
plink->ab_disable = FALSE;
}
/* put in hook for disabling communication for a reboot */
if (got_one) rebootHookAdd(ab_reboot_hook);
return(0);
}
/*
* link_init
*
* establish the communication link with the AB scanner
*/
LOCAL int link_init(ab_link *plink)
{
ab_region *p6008 = plink->vme_addr;
dp_mbox *pmb = &p6008->mail;
ab_config *pconfig=plink->pconfig;
int status;
int ntry;
/* the scanner comes up with the dual ported memory locked */
pmb->fl_lock = 0; /* so unlock it */
/*clear request semaphore*/
semGive(plink->request_sem);
if(pmb->conf_stat != SCANNER_POWERUP){
/* This link must already be initialized. We're done */
if (ab_debug){
printf("Link %x already initialized\n", plink->link);
}
return(0);
}
if(ab_debug) printf("drvAb: link %x, powerup...\n",plink->link);
/* on initialization the scanner puts its firmware revision info*/
/* into the general data are of the dual-port. We save it here. */
/* (The most current revision is Series A, Revision D.) */
strcpy(plink->firmware_info,(char *)&pmb->msg[0]);
/* setup scanner */
/* Wake up scanner for the first time*/
p6008->sc_intr = 1; /*Wake up scanner*/
taskDelay(1); /*Give it time to initialize*/
for(ntry=0; ntry<maxCmdTrys; ntry++) {
status = sc_lock(plink);
if(status) continue;
pmb->command = SET_UP;
pmb->data_len = 4;
pmb->msg[0] = (pconfig->baud_rate<<8) | 0;
pmb->msg[1] = (DEBUG<<8) | pconfig->int_level;
pmb->msg[2] = (pconfig->int_vector<<8) | AB_INT_ENABLE;
pmb->msg[3] = (AB_SYSFAIL_DISABLE<<8) | 0;
status = sc_waitcmd(plink);
if(status) continue;
if(pmb->conf_stat != 0) {
sc_conferr(plink);
continue;
}
break;
}
if(ntry>=maxCmdTrys) {
printf("abDrv: SET_UP failed link %hu\n",plink->link);
return(ERROR);
}
sc_unlock(plink);
/* Once scanner has been placed in RUN_MODE, putting it back into
* PROGRAM_MODE will disable binary outputs until it is placed back in
* RUN_MODE. Some scanner commands, such as SCAN_LIST, can only be
* performed in PROGRAM_MODE. These commands should only be issued*
* immediately after initialization.
* Re-booting an IOC (without powering it down) is the presently
* the only way of getting it into PROGRAM_MODE
* without disabling binary outputs */
/* initialize scan list for each link present */
/* A promised firmware change will allow us to RESET
the scanner over the vmeBus. For now, the only way
to get the scanner into prog-mode without having
the BO's glitch is with the vmeBus SYSRESET signal,
which occurs when the RESET switch on the VME chassis
is used. Until the f/w change is made, changing the
scanner from run mode to program mode (to modify the
scan list, for instance) will cause the BO's to turn
off until the scanner is returned to run mode. It's
not nice, but for now we'll have to assume that all
adapters are needed and put them all in the scan list. */
/* set scan list*/
if(pconfig->autoconfig) for(ntry=0; ntry<maxCmdTrys; ntry++) {
status = sc_lock(plink);
if(status) continue;
pmb->command = AUTO_CONF;
pmb->data_len = 0;
status = sc_waitcmd(plink);
if(status) continue;
if(pmb->conf_stat != 0) {
sc_conferr(plink);
continue;
}
break;
}else for(ntry=0; ntry<maxCmdTrys; ntry++) {
status = sc_lock(plink);
if(status) continue;
pmb->command = SCAN_LIST;
pmb->data_len = pconfig->scan_list_len;
uctrans(pconfig->scan_list,(unsigned char *)pmb->msg,
pconfig->scan_list_len);
status = sc_waitcmd(plink);
if(status) continue;
if(pmb->conf_stat != 0) {
sc_conferr(plink);
continue;
}
break;
}
if(ntry>=maxCmdTrys) {
printf("abDrv: AUTO_CONFIG or SCAN_LIST failed link %hu\n",plink->link);
return(ERROR);
}
sc_unlock(plink);
/* place the scanner into run mode */
for(ntry=0; ntry<maxCmdTrys; ntry++) {
status = sc_lock(plink);
if(status) continue;
pmb->command = SET_MODE;
pmb->msg[0] = (RUN_MODE<<8);
status = sc_waitcmd(plink);
if(status) continue;
if(pmb->conf_stat != 0) {
sc_conferr(plink);
continue;
}
break;
}
if(ntry>=maxCmdTrys) {
printf("abDrv: SET_MODE failed link %hu\n",plink->link);
return(ERROR);
}
sc_unlock(plink);
return(0);
}
/*
* abScanTask
*
* Scans the AB IO according to the AB configuration table.
* Entries are made in the AB configuration table when an IO
* interface is attempted from the database scan tasks.
* The sleep time assures that there is at least 1/10 second between the passes.
* The time through the scan loop seems to be minimal so there are no provisions
* for excluding the scan time from the sleep time.
*/
LOCAL void abScanTask(ab_link *plink)
{
unsigned short adapter;
ab_adapter *padapter;
unsigned int pass = 0;
BOOL madeInitialCallback = FALSE;
unsigned long tickNow,tickBeg,tickDiff;
tickBeg = tickGet();
while(TRUE){
/* run every 1/10 second */
taskDelay(vxTicksPerSecond/10);
if(plink->ab_disable) continue;
/* Every second perform a link check to see if any adapters */
/* have changed state. (Don't want to queue up requests if*/
/* they're off) */
if((pass % 10) == 0){
if (link_status(plink) != 0){
if(ab_debug) printf("%x link_stat error\n",plink->link);
}
}
if(!madeInitialCallback && interruptAccept)
plink->initialCallback = TRUE;
pass++;
/*recompute intrSec and btSec about every 10 seconds*/
if((pass %100) == 0) {
tickNow = tickGet();
if(tickNow > tickBeg){/*skip overflows*/
tickDiff = tickNow - tickBeg;
/*round to nearest counts/sec */
plink->intrSec=((plink->intr_cnt*vxTicksPerSecond)+5)/tickDiff;
plink->btSec=((plink->bt_cnt*vxTicksPerSecond)+5)/tickDiff;
}
tickBeg = tickNow;
plink->intr_cnt = 0;
plink->bt_cnt = 0;
}
for (adapter = 0; adapter < AB_MAX_ADAPTERS; adapter++){
padapter = plink->papadapter[adapter];
if(!padapter) continue;
read_ab_adapter(plink,padapter);
padapter->adapter_status_change = FALSE;
}
if(plink->initialCallback) {
plink->initialCallback = FALSE;
madeInitialCallback = TRUE;
}
}
}
LOCAL void read_ab_adapter(ab_link *plink, ab_adapter *padapter)
{
unsigned short card;
unsigned long value;
ab_card *pcard;
scanInfo *pscanInfo;
btInfo *pbtInfo;
abStatus btStatus=0;
/* each card */
for (card = 0; card < AB_MAX_CARDS; card++){
pcard = padapter->papcard[card];
if (!pcard) continue;
if(!pcard->active) continue;
if(pcard->type==typeBt) continue;
if(pcard->type==typeBi || pcard->type==typeBo || pcard->type==typeBiBo){
if(pcard->type==typeBi || pcard->type==typeBiBo) {
di_read(pcard,&value);
if ((value != pcard->diprev)||padapter->adapter_status_change){
pcard->diprev = value;
if(pcard->callback) (*pcard->callback)((void *)pcard);
}
}
if(pcard->type==typeBo || pcard->type==typeBiBo) {
if(padapter->adapter_status_change) {
if(pcard->bocallback) (*pcard->bocallback)((void *)pcard);
}
}
if(plink->initialCallback) {
if(pcard->callback) (*pcard->callback)((void *)pcard);
if(pcard->bocallback) (*pcard->bocallback)((void *)pcard);
}
continue;
}
/*If we get here card is typeAi or typeAo*/
pscanInfo = pcard->pscanInfo;
if(!pscanInfo) continue;
pbtInfo = pcard->pbtInfo;
if(!pbtInfo) continue;
if(padapter->adapter_status_change){
if(!padapter->adapter_online) {
pcard->status = abNotInitialized;
if(pcard->callback) (*pcard->callback)((void *)pcard);
continue;
}
pscanInfo->state = stateInit;
}
if(!padapter->adapter_online) continue;
switch(pscanInfo->state) {
case stateInit:
if(pcard->status !=abNotInitialized) {
pcard->status = abNotInitialized;
if(pcard->callback) (*pcard->callback)((void *)pcard);
}
if(pcard->type==typeAo) {
btStatus = bt_queue(AB_READ,pcard,pscanInfo->pread_msg,
pscanInfo->read_msg_len);
}else {
btStatus = bt_queue(AB_WRITE,pcard,pscanInfo->pwrite_msg,
pscanInfo->write_msg_len);
}
if(btStatus==abBtqueued) {
pscanInfo->state_cnt = 0;
pscanInfo->state = stateInitBTwait;
pscanInfo->init_ctr++;
} else {
pscanInfo->bt_fail++;
pscanInfo->state_cnt++;
}
break;
case stateInitBTwait:
if(pbtInfo->btStatus==abBtqueued) {
pscanInfo->state_cnt++;
if(pscanInfo->state_cnt < 15) break;
}
if(pbtInfo->btStatus!=abSuccess) {
if(btStatus==abTimeout) pscanInfo->bt_to++;
else pscanInfo->bt_fail++;
pscanInfo->state_cnt = 0;
pscanInfo->state = stateInit;
break;
}
pscanInfo->state_cnt = 0;
pscanInfo->state = stateBT;
if(pcard->type==typeAi) {
pcard->needsUpdate = TRUE;
} else {
/*Give device support time to set output words*/
pscanInfo->down_cnt = pscanInfo->update_rate;
}
/*break left out on purpose*/
repeat_countdown:
case stateCountdown:
if(pcard->needsUpdate) pscanInfo->down_cnt = 0;
if(pscanInfo->down_cnt>0) pscanInfo->down_cnt--;
if(pscanInfo->down_cnt>0) continue;
pscanInfo->state_cnt = 0;
pscanInfo->state = stateBT;
/*break left out on purpose*/
case stateBT:
if(pcard->type==typeAi) {
btStatus = bt_queue(AB_READ,pcard,pscanInfo->pread_msg,
pscanInfo->read_msg_len);
}else {
btStatus = bt_queue(AB_WRITE,pcard,pscanInfo->pwrite_msg,
pscanInfo->write_msg_len);
}
if(btStatus!=abBtqueued) {
pscanInfo->state_cnt++;
/*After 15 trys reinitialize*/
if(pscanInfo->state_cnt > 15) {
pcard->status = abFailure;
pscanInfo->bt_fail++;
pscanInfo->state_cnt = 0;
pscanInfo->state = stateInit;
}
break;
}
pscanInfo->state_cnt = 0;
pscanInfo->state = stateBTwait;
break;
case stateBTwait:
if(pbtInfo->btStatus==abBtqueued) {
pscanInfo->state_cnt++;
if(pscanInfo->state_cnt < 30) break;
}
if(pbtInfo->btStatus!=abSuccess) {
pcard->status = abFailure;
if(btStatus==abTimeout) pscanInfo->bt_to++;
else pscanInfo->bt_fail++;
pscanInfo->state_cnt = 0;
pscanInfo->state = stateInit;
break;
}
pcard->status = abSuccess;
pscanInfo->state_cnt = 0;
pscanInfo->down_cnt = pscanInfo->update_rate;
pscanInfo->state = stateCountdown;
if(pcard->callback) (*pcard->callback)((void *)pcard);
goto repeat_countdown;
}
}
}
LOCAL void abDoneTask(ab_link *plink)
{
unsigned short adapter;
unsigned short card;
ab_adapter *padapter; /* adapter data structure */
ab_card *pcard; /* card data structure */
btInfo *pbtInfo;
dp_mbox *pmb = &plink->vme_addr->mail;
unsigned short *pmb_msg = &pmb->msg[0];
while(TRUE) {
semTake(plink->ab_data_sem,WAIT_FOREVER);
/* Must check all data returned by hardware interface*/
card = pmb->address & 0x0f;
adapter = (pmb->address & 0x70) >> 4;
if(card >= MAX_CARDS_PER_ADAPTER || adapter>=MAX_AB_ADAPTERS) {
if(ab_debug)
printf("drvAb: scanner returned bad address %4x\n",
pmb->address);
pmb->fl_lock = 0;
continue;
}
padapter = plink->papadapter[adapter];
if(!padapter) {
if(ab_debug)
printf("abDrv:abDoneTask padapter=NULL adapter=%d\n",
adapter);
pmb->fl_lock = 0;
continue;
}
pcard = padapter->papcard[card];
if(!pcard) {
if(ab_debug)
printf("abDrv: abDoneTask pcard=NULL card=%d adapter=%d\n",
card,adapter);
pmb->fl_lock = 0;
continue;
}
plink->bt_cnt++;
pbtInfo = pcard->pbtInfo;
/* block transfer failure */
if (pmb->conf_stat != 0){
if (pmb->conf_stat == BT_TIMEOUT) {
pbtInfo->btStatus = abTimeout;
}else{
pbtInfo->btStatus = abFailure;
}
}else{
/* successful */
pbtInfo->btStatus = abSuccess;
/* was it the response to a read command */
if (pbtInfo->cmd == AB_READ){
ustrans(pmb_msg,pbtInfo->pmsg,pbtInfo->msg_len);
}
}
pmb->fl_lock = 0;
if(pcard->type==typeBt) {
pcard->active = FALSE;
pcard->status = pbtInfo->btStatus;
if(pcard->callback) (*pcard->callback)((void *)pcard);
}
}
}
LOCAL void ab_reset_task(ab_link *plink)
{
unsigned short link,adapter,card,ab_reset_wait;
ab_adapter *padapter;
ab_region *pab_region=0;
ab_card *pcard;
btInfo *pbtInfo;
link = plink->link;
pab_region = plink->vme_addr;
plink->ab_disable = 1;
printf("Disabled AB Scanner Task\n");
taskDelay(vxTicksPerSecond*2);
/* Signal the Scanner to Reset */
pab_region->sys_fail_set2 = 0xa0a0;
pab_region->sys_fail_set1 = 0x0080;
printf("Card %d Reset\n",link);
/*mark all block transfer cards for initialization*/
for(adapter = 0; adapter < AB_MAX_ADAPTERS; adapter++){
padapter = plink->papadapter[adapter];
if(!padapter) continue;
for (card = 0; card < AB_MAX_CARDS; card++){
pcard = padapter->papcard[card];
if(!pcard) continue;
pbtInfo = pcard->pbtInfo;
if(pcard->type==typeAo || pcard->type==typeAi)
pcard->needsUpdate = TRUE;
}
}
ab_reset_wait = 0;
while((pab_region->mail.conf_stat != SCANNER_POWERUP)
&& (ab_reset_wait < 600)){
taskDelay(1);
ab_reset_wait++;
}
if (ab_reset_wait < 600)
printf("Link %d Power Up After %d Ticks\n",link,ab_reset_wait);
else
printf("Link %d Failed to Reinitialize After %d Ticks\n",
link,ab_reset_wait);
link_init(plink);
/* enable the scanner */
plink->ab_disable = 0;
}
int ab_reset_link(int link)
{
ab_link *plink;
if(link>=max_ab_6008s) return(0);
plink = pab_links[link];
if(!plink) return(0);
taskSpawn("ab_reset",38,0,8000,(FUNCPTR)ab_reset_task,(int)plink,
0,0,0,0,0,0,0,0,0);
return(0);
}
int ab_reset(void)
{
int link;
for(link=0; link<max_ab_6008s; link++) ab_reset_link(link);
return(0);
}
LOCAL char *activeMessage[2] = {"notScanning","Scanning"};
LOCAL long ab_io_report(int level)
{
ab_link *plink;
ab_adapter *padapter;
ab_card *pcard;
scanInfo *pscanInfo;
unsigned short link, adapter, card;
int i;
unsigned long divalue,dovalue;
/* link data */
for (link = 0; link < max_ab_6008s; link++){
plink = pab_links[link];
if(!plink) continue;
if(!plink->initialized) {
printf("AB-6008SV link %hu not initialized\n",link);
continue;
}
printf("AB-6008SV link: %hu osw %4.4x vme: %p\n",
link,plink->vme_addr->osw,plink->vme_addr);
if(plink->firmware_info[0]) printf(" %s\n",plink->firmware_info);
printf(" Mailbox lock timeouts %hu\n",plink->sclock_to);
printf(" Command timeouts %hu\n", plink->sccmd_to);
printf(" Command Failure %hu\n", plink->sc_fail);
printf(" Interrupts per second %hu\n", plink->intrSec);
printf(" Block Transfers per second %hu\n", plink->btSec);
if(level>2) {
ab_link_status *plink_status = plink->plink_status;
printf(" Adapter Status Words");
for(i=0; i<32; i++) {
if((i%8)==0) printf("\n ");
printf("%4.4x ",plink_status->status[i]);
}
printf("\n scan list");
for(i=0; i<plink_status->list_len; i++) {
if((i%16)==0) printf("\n ");
printf("%2.2x ",plink_status->list[i]);
}
printf("\n");
}
/* adapter information */
for (adapter = 0; adapter < AB_MAX_ADAPTERS; adapter++){
padapter = plink->papadapter[adapter];
if (!padapter) continue;
if (padapter->adapter_online)
printf(" Adapter %hu ONLINE\n",adapter);
else
printf(" Adapter %hu OFFLINE\n",adapter);
/* card information */
for (card = 0; card < AB_MAX_CARDS; card++){
pcard = padapter->papcard[card];
if(!pcard) continue;
pscanInfo = pcard->pscanInfo;
switch (pcard->type){
case (typeBi):
di_read(pcard,&divalue);
printf(" CARD %hu: BI %s %s 0x%x\n",
card,abNumBitsMessage[pcard->nBits],
activeMessage[pcard->active],divalue);
break;
case (typeBo):
do_read(pcard,&dovalue);
printf(" CARD %hu: BO %s %s 0x%x\n",
card,abNumBitsMessage[pcard->nBits],
activeMessage[pcard->active],dovalue);
break;
case (typeBiBo):
di_read(pcard,&divalue);
do_read(pcard,&dovalue);
printf(" CARD %hu: BIBO %s %s in 0x%x out 0x%x\n",
card,abNumBitsMessage[pcard->nBits],
activeMessage[pcard->active],divalue,dovalue);
break;
case (typeAi):
case (typeAo):
if(pcard->type==typeAi)
printf(" CARD %hu: AI ",card);
else
printf(" CARD %hu: AO ",card);
if(!pscanInfo || pscanInfo->state==stateInit)
printf(" NOT INITIALIZED ");
printf(" %s %s",activeMessage[pcard->active],
pcard->card_name);
/* error reporting */
if(!pscanInfo) {
printf("\n");
break;
}
if (pscanInfo->bt_to)
printf(" bt timeout: %hu",pscanInfo->bt_to);
if (pscanInfo->bt_fail)
printf(" bt fail: %hu",pscanInfo->bt_fail);
if (pscanInfo->init_ctr)
printf(" initialized %hu times",pscanInfo->init_ctr);
printf("\n");
if (level > 0){
if(pcard->type==typeAo || level>1) {
printf("\tWrite");
for (i=0; i<pscanInfo->write_msg_len; i++) {
if((i%10)==0) printf("\n\t");
printf("%4.4x ",pscanInfo->pwrite_msg[i]);
}
printf("\n");
}
if(pcard->type==typeAi || level>1) {
printf("\tRead");
for (i=0; i<pscanInfo->read_msg_len; i++) {
if((i%10)==0) printf("\n\t");
printf("%4.4x ",pscanInfo->pread_msg[i]);
}
printf("\n");
}
}
break;
default:
continue;
}
}
}
}
return(0);
}
LOCAL abStatus registerCard(
unsigned short link,unsigned short adapter, unsigned short card,
cardType type, const char *card_name, void (*callback)(void *drvPvt),
void **pdrvPvt)
{
ab_adapter *padapter;
ab_card *pcard = NULL;
ab_link *plink;
ab_card **ppcard = (ab_card **)pdrvPvt;
if(link>=max_ab_6008s) {
if(ab_debug>0)
printf("abDrv(registerCard) bad link %hu\n",link);
return(abNoCard);
}
if(adapter>=MAX_AB_ADAPTERS) {
if(ab_debug>0)
printf("abDrv(registerCard) bad adapter %hu\n",adapter);
return(abNoCard);
}
if(card>=MAX_CARDS_PER_ADAPTER) {
if(ab_debug>0)
printf("abDrv(registerCard) bad card %hu\n",card);
return(abNoCard);
}
plink = pab_links[link];
if(!plink || !plink->initialized) {
if(ab_debug>0)
printf("abDrv(registerCard) link %hu not initialized\n",link);
return(abNoCard);
}
padapter = plink->papadapter[adapter];
if(padapter) pcard = padapter->papcard[card];
if(pcard) {
if(strcmp(pcard->card_name,card_name)!=0) return(abCardConflict);
if(pcard->type==type) {
*ppcard = pcard;
return(abSuccess);
}
if(type==typeBi || type==typeBo) {
if(pcard->type==typeBo || pcard->type==typeBi
|| pcard->type==typeBiBo) {
if(!pcard->callback && type==typeBi )
pcard->callback = callback;
if(!pcard->bocallback && type==typeBo )
pcard->bocallback = callback;
pcard->type = typeBiBo;
*ppcard = pcard;
return(abSuccess);
}
}
return(abCardConflict);
}
/*New Card*/
pcard = abCalloc(1,sizeof(ab_card));
pcard->link = link;
pcard->adapter = adapter;
pcard->card = card;
pcard->type = type;
pcard->card_name = card_name;
if(!(pcard->card_sem = semBCreate(SEM_Q_FIFO,SEM_FULL))){
printf("abDrv register card: semBcreate failed");
taskSuspend(0);
}
if(type==typeBo) pcard->bocallback = callback;
else pcard->callback = callback;
if(type==typeAi || type ==typeAo || type == typeBt)
pcard->pbtInfo = abCalloc(1,sizeof(btInfo));
*ppcard = pcard;
if(!padapter) {
padapter = abCalloc(1,sizeof(ab_adapter));
padapter->papcard = abCalloc(MAX_CARDS_PER_ADAPTER,sizeof(ab_card *));
if(!(padapter->adapter_sem = semBCreate(SEM_Q_FIFO,SEM_FULL))){
printf("abDrv: abRegister: semBcreate failed");
taskSuspend(0);
}
padapter->adapter = adapter;
}
padapter->papcard[card] = pcard;
if(!plink->papadapter[adapter]) plink->papadapter[adapter] = padapter;
link_status(plink);
return(abNewCard);
}
LOCAL void getLocation(void *drvPvt,unsigned short *link,
unsigned short *adapter,unsigned short *card)
{
ab_card *pcard = drvPvt;
*link = pcard->link;
*adapter = pcard->adapter;
*card = pcard->card;
return;
}
LOCAL abStatus setNbits(void *drvPvt, abNumBits nBits)
{
ab_card *pcard = drvPvt;
if(pcard->nBits == abBitNotdefined) {
pcard->nBits = nBits;
pcard->active = TRUE;
return(abSuccess);
}
if(pcard->nBits == nBits) return(abSuccess);
return(abFailure);
}
LOCAL void setUserPvt(void *drvPvt,void *userPvt)
{
ab_card *pcard = drvPvt;
pcard->userPvt = userPvt;
return;
}
LOCAL void *getUserPvt(void *drvPvt)
{
ab_card *pcard = drvPvt;
return(pcard->userPvt);
}
LOCAL abStatus getStatus(void *drvPvt)
{
ab_card *pcard = drvPvt;
unsigned short link = pcard->link;
unsigned short adapter = pcard->adapter;
ab_adapter *padapter = pab_links[link]->papadapter[adapter];
if(!padapter->adapter_online) return(abAdapterDown);
return(pcard->status);
}
LOCAL abStatus startScan(void *drvPvt, unsigned short update_rate,
unsigned short *pwrite_msg, unsigned short write_msg_len,
unsigned short *pread_msg, unsigned short read_msg_len)
{
ab_card *pcard = drvPvt;
scanInfo *pscanInfo;
pscanInfo = pcard->pscanInfo;
if(!pscanInfo) pcard->pscanInfo = pscanInfo = abCalloc(1,sizeof(scanInfo));
pscanInfo->update_rate = update_rate;
pscanInfo->pwrite_msg = pwrite_msg;
pscanInfo->write_msg_len = write_msg_len;
pscanInfo->pread_msg = pread_msg;
pscanInfo->read_msg_len = read_msg_len;
pscanInfo->state = stateInit;
pcard->active = TRUE;
pcard->status = abNotInitialized;
return(abSuccess);
}
LOCAL abStatus updateAo(void *drvPvt)
{
ab_card *pcard = drvPvt;
pcard->needsUpdate = TRUE;
return(getStatus(drvPvt));
}
LOCAL abStatus updateBo(void *drvPvt,unsigned long value,unsigned long mask)
{
ab_card *pcard = drvPvt;
unsigned long imagevalue;
semTake(pcard->card_sem,WAIT_FOREVER);
do_read(pcard,&imagevalue);
imagevalue = (imagevalue & ~mask) | (value & mask);
do_write(pcard,imagevalue);
semGive(pcard->card_sem);
if(pcard->bocallback) (*pcard->bocallback)((void *)pcard);
return(getStatus(drvPvt));
}
LOCAL abStatus readBo(void *drvPvt,unsigned long *pvalue,unsigned long mask)
{
ab_card *pcard = drvPvt;
unsigned long value;
do_read(pcard,&value);
*pvalue = value & mask;
return(getStatus(drvPvt));
}
LOCAL abStatus readBi(void *drvPvt,unsigned long *pvalue,unsigned long mask)
{
ab_card *pcard = drvPvt;
unsigned long value;
di_read(pcard,&value);
*pvalue = value & mask;
return(getStatus(drvPvt));
}
LOCAL abStatus btRead(void *drvPvt,unsigned short *pread_msg, unsigned short read_msg_len)
{
ab_card *pcard = drvPvt;
int btStatus;
if(pcard->active) return(abBusy);
pcard->active = TRUE;
btStatus=bt_queue(AB_READ,pcard,pread_msg,read_msg_len);
if(btStatus!=abBtqueued) pcard->active = FALSE;
return(btStatus);
}
LOCAL abStatus btWrite(void *drvPvt,unsigned short *pwrite_msg, unsigned short write_msg_len)
{
ab_card *pcard = drvPvt;
int btStatus;
if(pcard->active) return(abBusy);
pcard->active = TRUE;
btStatus=bt_queue(AB_WRITE,pcard,pwrite_msg,write_msg_len);
if(btStatus!=abBtqueued) pcard->active = FALSE;
return(btStatus);
}
LOCAL abStatus adapterStatus(unsigned short link,unsigned short adapter)
{
ab_adapter *padapter;
ab_link *plink;
if(link>=max_ab_6008s) return(abFailure);
if(adapter>=MAX_AB_ADAPTERS) return(abFailure);
plink = pab_links[link];
if(!plink || !plink->initialized) return(abFailure);
padapter = plink->papadapter[adapter];
if(!padapter->adapter_online) return(abAdapterDown);
return(abSuccess);
}
LOCAL abStatus cardStatus(
unsigned short link,unsigned short adapter,unsigned short card)
{
ab_adapter *padapter;
ab_link *plink;
ab_card *pcard;
if(link>=max_ab_6008s) return(abFailure);
if(adapter>=MAX_AB_ADAPTERS) return(abFailure);
if(card>=MAX_CARDS_PER_ADAPTER) return(abFailure);
plink = pab_links[link];
if(!plink || !plink->initialized) return(abFailure);
padapter = plink->papadapter[adapter];
if(!padapter->adapter_online) return(abAdapterDown);
pcard = padapter->papcard[card];
if(!pcard) return(abNoCard);
if(!padapter->adapter_online) return(abAdapterDown);
return(pcard->status);
}
LOCAL abDrv abDrvTable= {
registerCard,getLocation,setNbits,setUserPvt,getUserPvt,
getStatus,startScan,updateAo,updateBo,readBo,readBi,btRead,btWrite,
adapterStatus,cardStatus
};
abDrv *pabDrv = &abDrvTable;
/*Time how long it takes to issue link_status */
int ab_time_link_status(int link)
{
ab_link *plink = pab_links[link];
int startTicks;
int stopTicks;
int pass;
double tdiff;
if(!plink) return(-1);
startTicks = tickGet();
for (pass=0; pass<100; pass++) link_status(plink);
stopTicks = tickGet();
tdiff = (stopTicks - startTicks)/60.0;
printf("pass/sec %f\n",(float)pass/tdiff);
return(0);
}