diff --git a/src/drv/drvEpvxi.c b/src/drv/drvEpvxi.c new file mode 100644 index 000000000..61a07616d --- /dev/null +++ b/src/drv/drvEpvxi.c @@ -0,0 +1,2398 @@ +/* + * routines for the VXI device support and resource management + * + * + * + * + * Author: Jeff Hill + * Date: 11-89 + * + * 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 + * + * Modification Log: + * ----------------- + * .01 joh 02-14-90 formal release + * .02 joh 04-04-90 as requested KLUDGED dynamic address so they + * dont have to specify model number in DCT + * .03 joh 04-04-90 as requested KLUDGED dynamic address so they + * dont have to specify model number in DCT + * .04 joh 07-26-90 changed from ttl trig 7 to ecl trig 0 + * .05 joh 07-27-90 added support for multiple slot0 cards + * .06 joh 08-08-91 delinting + * .07 joh 09-05-91 converted to v5 vxWorks + * .08 joh 12-05-91 split vxi_driver.c into vxi_driver.c and + * vxi_resman.c + * .09 joh 01-29-91 added MXI support & removed KLUDGE + * + * To do + * ----- + * .01 Should this module prevent two triggers from driving + * the same front panel connector at once? + * .02 The resource manager sets up a default front + * panel trigger routing. Perhaps this should + * be left to the application + * + * + * RM unfinished items + * ------------------- + * 1. does not handle multiple dc in one slot + * 2. does not handle blocked address devices + * 3. does not configure std and ext addr spaces + * 4. Assigning the hierachy from within a DC res man + * needs to be revisited + * + * + * NOTES + * .01 this software was tested with Rev D of the NI MXI bus extenders + * -the INTX stuff does not work properly on this rev + * -hopefully Rev E will solve the problem + * + * + */ + +/* + * Code Portions + * + * local + * vxi_find_slot0 Find the slot 0 module if present + * vxi_find_offset find a free space for n devices + * vxi_find_slot given a VXI modules addr find its slot + * vxi_self_test resrc manager self test functions + * vxi_init_ignore_list init list of interrupt handlers to ignore + * vxi_vec_inuse check to see if vector is in use + * vxi_configure_hierarchies setup commander servant hierarchies + * vxi_self_test test for dev self test passed + * vxi_find_slot0 find (and open) slot zero devices + * vxi_find_slot what slot is that LA in + * open_slot0_device open slot zero devices + * nicpu030_slot0_test is it a NICPU030 slot zero module + * nivxi_cpu030_set_modid set modid on the NICPU030 + * nivxi_cpu030_clr_all_modid clear all modid lines on the NICPU030 + * set_reg_modid set modid on a reg based slot0 device + * clr_all_reg_modid clr all modid on a reg based slot0 dev + * vxi_find_sc_devices find all SC devices and open them + * vxi_find_dc_devices find all DC devices and open them + * vxi_init_ignore_list find addresses of default int handlers + * vxi_vec_inuse test for int vector in use + * vxi_find_offset find LA for a DC device to assume + * mxi_map mat the addresses on a MXI bus extender + * vxi_find_mxi_devices search for and open mxi bus repeaters + * map_mxi_inward map from a VXI crate towards the RM + * + * for use by IOC core + * epvxiResman entry for a VXI resource manager which + * also sets up the MXI bus + * vxi_io_report call io device specific report routines + * for all registered devices and print + * information about device's configuration + * epvxiDeviceList print info useful when debugging drivers + * vxi_init compatibility + * + * for use by vxi drivers + * epvxiLookupLA find LA given search pattern + * epvxiUniqueDriverID obtain a unique id each call + * epvxiOpen register a drivers use of a device + * epvxiClose disconnect from a device + * epvxiPConfig fetch a driver config block given a LA + * epvxiRouteTriggerECL route ECL trig to/from front pannel + * epvxiRouteTriggerTTL route TTL trig to/from front pannel + * + */ + +#include +#include +#ifdef V5_vxWorks +# include <68k/iv.h> +#else +#include +#endif +#include + +#define SRCepvxiLib /* allocate externals here */ +#include + +#define NICPU030 + +#define VXI_HP_MODEL_E1404 0x110 +#define VXI_HP_MODEL_E1404_SLOT0 0x10 + +/* + * so setting ECL triggers does not mess with the + * RM's address windows + */ +#define MXI_CONTROL_CONSTANT 0x4000 +#define INTX_INT_OUT_ENABLE 0x7f00 +#define INTX_INT_IN_ENABLE 0x7f7f + +#define abort(A) taskSuspend(0) + +#define VXIMSGINTLEVEL 1 + +#define BELL 7 + +#define UKN_SLOT (-1) +#define UKN_CRATE (-1) + +/* + * bits for the device type and a pointer + * to its configuration registers if + * available (The national Instruments + * cpu030 does not conform with vxi + * standard by not making these registers + * available to programs running on it). + */ +struct slot_zero_device{ + char present:1; + char reg:1; + char msg:1; + char nicpu030:1; + struct vxi_csr *pcsr; + void (*set_modid)(); + void (*clear_modid)(); +}; +LOCAL struct slot_zero_device vxislot0[10]; + +LOCAL char *ignore_list[] = {"_excStub","_excIntStub"}; +LOCAL void *ignore_addr_list[NELEMENTS(ignore_list)]; +LOCAL unsigned char last_la; + +#define SETMODID(SLOT, CRATE) \ +(*vxislot0[CRATE].set_modid)(CRATE, SLOT) + +#define CLRMODID(CRATE) \ +(*vxislot0[CRATE].clear_modid)(CRATE); + +/* forward references */ +int vxi_find_slot0(); +int vxi_find_offset(); +int vxi_find_slot(); +int vxi_self_test(); +int vxi_init_ignore_list(); +int vxi_vec_inuse(); +int mxi_map(); +int map_mxi_inward(); +int open_vxi_device(); +int vxi_begin_normal_operation(); +int vxi_allocate_int_lines(); +void nicpu030_slot0_test(); +void vxi_find_sc_devices(); +void vxi_find_dc_devices(); +void set_reg_modid(); +void clr_all_reg_modid(); +void nivxi_cpu030_set_modid(); +void nivxi_cpu030_clr_all_modid(); +void open_slot0_device(); +void vxi_configure_hierarchies(); +void vxi_find_mxi_devices(); +void vxi_unmap_mxi_devices(); + + +/* + * + * vxi_init() + * + * for compatibility with past releases + * + * + */ +vxi_init() +{ + int status; + + status = epvxiResman(); + if(status>=0){ + return OK; + } + else{ + return ERROR; + } +} + + +/* + * epvxiResman() + * + * perform vxi resource management functions + * + * + */ +int +epvxiResman() +{ + unsigned crate; + unsigned nd; + unsigned lla; + unsigned hla; + int status; + + /* + * find out where the VXI LA space is on this processor + */ + status = sysBusToLocalAdrs( + VME_AM_USR_SHORT_IO, + VXIBASEADDR, + &epvxi_local_base); + if(status != OK){ + printf("Addressing error in vxi driver\n"); + return ERROR; + } + + /* + * clip the EPICS logical address range + */ + last_la = min(VXIDYNAMICADDR-1, EPICS_VXI_LA_COUNT-1); + last_la = min(last_la, NELEMENTS(epvxiLibDeviceList)-1); + + /* + * perform this step if you want to reassign LA to DC + * devices after a soft reboot + */ +# ifdef RESET_DC_DEVICES + vxi_reset_dc(); +# endif + + if(vxi_init_ignore_list()==ERROR) + return ERROR; + + /* + * close any MXI devices which have open windows but + * have not been encountered by this execution + * of the resource manager. + * + * This makes the MXI/VXI configure correctly after + * a control x (soft) reboot. + */ + vxi_unmap_mxi_devices(); + + /* + * locate SC, DC, and MXI devices + */ + mxi_map(VXI_RESMAN_LA, &nd, &lla, &hla); + if(!nd){ + return OK; + } + + vxi_self_test(); + + vxi_configure_hierarchies( + VXI_RESMAN_LA, + last_la); + + vxi_allocate_int_lines(); + + vxi_begin_normal_operation(); +/* + * + * Triggers used to be hard routed here there + */ +#ifdef MAP_TRIGGERS + /* + * install a default trigger routing + */ +# define DEFAULT_TRIG_ENABLE_MAP 1 +# define DEFAULT_TRIG_IO_MAP 0 + for(crate=0; cratedir.w.dd.mxi.la_window = 0; + } +} + + + +/* + * + * vxi_find_mxi_devices() + * + */ +LOCAL void +vxi_find_mxi_devices(base_la, pnd, plla, phla) +unsigned base_la; +unsigned *pnd; +unsigned *plla; +unsigned *phla; +{ + struct vxi_csr *pmxi; + unsigned addr; + + for(addr=0; addr<=last_la; addr++){ + + /* + * only configure devices seen before + */ + if(!epvxiLibDeviceList[addr]){ + continue; + } + + /* + * skip mxi devices seen before + */ + if(epvxiLibDeviceList[addr]->mxi_dev){ + continue; + } + + pmxi = VXIBASE(addr); + + if(!VXIMXI(pmxi)){ + continue; + } + + /* + * this is a MXI device + */ + epvxiLibDeviceList[addr]->mxi_dev = TRUE; + + /* + * open the address window outward for all device + */ + pmxi->dir.w.dd.mxi.control = + MXI_UPPER_LOWER_BOUNDS; + pmxi->dir.w.dd.mxi.la_window = + VXIADDRMASK | VXIADDRMASK<dir.w.dd.mxi.la_window = + *plla<dir.w.dd.mxi.INTX_interrupt = + INTX_INT_IN_ENABLE; + } + } + else{ + logMsg( "VXI resman: VXI to MXI(%d) is empty\n", + addr); + pmxi->dir.w.dd.mxi.la_window = + 0 | 0<mxi_dev = TRUE; + + /* + * open the address window inward for all device + */ + pmxi_new->dir.w.dd.mxi.control = + MXI_UPPER_LOWER_BOUNDS; + pmxi_new->dir.w.dd.mxi.la_window = + 1 | 1<dir.w.dd.mxi.INTX_interrupt = + INTX_INT_OUT_ENABLE; + } + + if(*pnd){ + logMsg( "VXI resman: MXI to VXI(%d) %d-%d\n", + addr, + *plla, + *phla); + pmxi_new->dir.w.dd.mxi.la_window = + *plla | (*phla+1)<dir.w.dd.mxi.la_window = + 0 | 0<make = VXIMAKE(pdevice); + plac->model = VXIMODEL(pdevice); + plac->class = VXICLASS(pdevice); + epvxiLibDeviceList[la] = plac; + + if(vxi_vec_inuse(la)){ + logMsg( "WARNING: SC VXI device at allocated int vec=%x\n", + la); + logMsg( "WARNING: VXI device placed off line %c(la=%d)\n", + BELL, + la); + pdevice->dir.w.control = VXISAFECONTROL; + } + else{ + if(VXISLOT0MODELTEST(plac->model)){ + /* + * This takes care of MXI devices + * that show up after the slot 0 device + * search has completed + */ + plac->slot0_dev = TRUE; + open_slot0_device(la); + } + } + + { + unsigned slot, crate; + + status = vxi_find_slot(pdevice, &slot, &crate); + if(status==OK){ + plac->slot = slot; + plac->crate = crate; + } + else{ + logMsg( "slot could not be found for LA %d\n", + la); + plac->slot = 0xff; + plac->crate = 0xff; + } + } + + return OK; +} + + +/* + * + * + * VXI_FIND_SC_DEVICES + * + */ +LOCAL void +vxi_find_sc_devices(pnew_device_found, plow_la, phigh_la) +unsigned *pnew_device_found; +unsigned *plow_la; +unsigned *phigh_la; +{ + register unsigned addr; + register status; + + /* + * Locate the slots of all SC devices + */ + *plow_la = last_la; + *phigh_la = 0; + *pnew_device_found = FALSE; + for(addr=0; addr<=last_la; addr++){ + + /* + * dont configure devices seen before + */ + if(epvxiLibDeviceList[addr]){ + continue; + } + + status = open_vxi_device(addr); + if(status < 0){ + continue; + } + + *pnew_device_found = TRUE; + *plow_la = min(*plow_la, addr); + *phigh_la = max(*phigh_la, addr); + + } +} + + +/* + * + * + * VXI_FIND_DC_DEVICES + * + */ +LOCAL void +vxi_find_dc_devices(base_la, pnew_device_found, plow_la, phigh_la) +unsigned base_la; +unsigned *pnew_device_found; +unsigned *plow_la; +unsigned *phigh_la; +{ + short id; + register status; + unsigned offset; + struct vxi_csr *pcsr; + int crate; + int slot; + + *pnew_device_found = FALSE; + *phigh_la = 0; + *plow_la = last_la; + + /* + * dont move DC devices if SC device at address 0xff + */ + for(crate=0; cratedir.w.addr = offset; + status = open_vxi_device(offset); + if(status<0){ + logMsg("VXI resman: DC dev failed to DC\n"); + logMsg("VXI resman: DC VXI device ignored\n"); + continue; + } + *plow_la = min(*plow_la, offset); + *phigh_la = max(*phigh_la, offset); + *pnew_device_found = TRUE; + epvxiLibDeviceList[offset]->crate = crate; + } + CLRMODID(crate); + } +} + + +/* + * + * + * VXI_FIND_SLOT0 + * Find the slot 0 module if present + * (assume that it is a static address) + * + */ +LOCAL int +vxi_find_slot0() +{ + register int status; + register unsigned addr; + struct vxi_csr *pcsr; + short id; + +# ifdef NICPU030 + nicpu030_slot0_test(); +# endif + + for(addr=0; addr<=last_la; addr++){ + + /* + * only add slot zero devices we have not + * seen before + */ + if(epvxiLibDeviceList[addr]){ + continue; + } + + pcsr = VXIBASE(addr); + + status = vxMemProbe( pcsr, + READ, + sizeof(id), + &id); + if(status<0){ + continue; + } + + /* + * Is it a slot 0 card ? + */ + if(!VXISLOT0MODEL(pcsr)){ + continue; + } + + open_slot0_device(addr); + + } + if(vxislot0[0].present){ + return OK; + } + else{ + return ERROR; + } +} + + +/* + * + * open slot 0 device + * + * + */ +LOCAL void +open_slot0_device(la) +unsigned la; +{ + unsigned index; + struct vxi_csr *pcsr; + int status; + + pcsr = VXIBASE(la); + + if( VXICLASS(pcsr) != VXI_REGISTER_DEVICE && + !VXIMXI(pcsr)){ + + logMsg("Only register based slot 0 devices\n"); + logMsg("currently supported\n"); + return; + } + + for(index=0; index < NELEMENTS(vxislot0); index++){ + if(vxislot0[index].pcsr == pcsr){ + return; + } + if(!vxislot0[index].present){ + break; + } + } + if(index>=NELEMENTS(vxislot0)){ + logMsg( + "VXI Slot0s After %d'th ignored\n", + NELEMENTS(vxislot0)); + return; + } + + vxislot0[index].present = TRUE; + vxislot0[index].reg = TRUE; + vxislot0[index].pcsr = pcsr; + vxislot0[index].set_modid = set_reg_modid; + vxislot0[index].clear_modid = clr_all_reg_modid; + + if(!epvxiLibDeviceList[la]){ + status = open_vxi_device(la); + if(status!=OK){ + logMsg("slot 0 card ignored\n"); + vxislot0[index].present = FALSE; + return; + } + } + + /* + * if this happenens the card is wacko + */ + if( epvxiLibDeviceList[la]->slot != 0 && + epvxiLibDeviceList[la]->slot != UKN_SLOT){ + + logMsg( "VXI slot 0 found in slot %d\n", + epvxiLibDeviceList[la]->slot); + logMsg("VXI la %d hardware failure\n", la); + logMsg("slot 0 card ignored\n"); + vxislot0[index].present = FALSE; + return; + } + + /* + * hpE1404 specific stuff + */ + if( VXIMAKE(pcsr) == VXI_MAKE_HP){ + if( VXIMODEL(pcsr) == VXI_HP_MODEL_E1404 || + VXIMODEL(pcsr) == VXI_HP_MODEL_E1404_SLOT0){ + hpE1404Init(la); + } + } + + logMsg( "VXI resman: slot zero found at LA=%d crate=%d\n", + la, + epvxiLibDeviceList[la]->crate); +} + + + + + +/* + * + * NICPU030_SLOT0_TEST() + * check to see if this code is running on a + * national instruments cpu030 installed in + * slot zero. + * + */ +#ifdef NICPU030 +LOCAL void +nicpu030_slot0_test() +{ + int i; + int status; + short model; + UTINY type; + + if(vxislot0[0].present){ + return; + } + + for(i=0; i= count){ + *poffset = ((int)addr)-(count-1); + return OK; + } + } + + return ERROR; +} + + + +/* + * + * VXI_FIND_SLOT + * given a VXI module's addr find its slot + * + */ +int +vxi_find_slot(pcsr, pslot, pcrate) +struct vxi_csr *pcsr; +unsigned *pslot; +unsigned *pcrate; +{ + register unsigned char slot; + register unsigned char crate; + register status; + + status = ERROR; + + for(crate=0; cratedir.r.status)){ + *pslot = slot; + *pcrate = crate; + status = OK; + break; + } + } + CLRMODID(crate); + + if(status == OK) + break; + } + + return status; +} + + +/* + * + * VXI_RESET_DC + * force all dynamic devices back to address 0xff + * (In case this is a ctrl X restart) + * + * not tested with at5vxi modules + */ +#ifdef JUNKYARD +LOCAL int +vxi_reset_dc() +{ + register unsigned addr; + unsigned slot; + unsigned crate; + short id; + register status; + struct vxi_csr_w *pcr; + struct vxi_csr_r *psr; + + for(addr=0; addraddr = VXIDYNAMICADDR; + } + + return OK; +} +#endif + + +/* + * + * VXI_DC_TEST + * determine if a VXI module in the static address range is dynamic + * + */ +#ifdef JUNKYARD +LOCAL int +vxi_dc_test(current_addr) +unsigned current_addr; +{ + register unsigned addr; + unsigned slot; + unsigned crate; + short id; + register status; + struct vxi_csr_w *pcr; + struct vxi_csr_r *psr; + + static unsigned open_addr; + unsigned dynamic; + + for(addr=0; addraddr = open_addr; + + psr = (struct vxi_csr_r *) VXIBASE(open_addr); + pcr = (struct vxi_csr_w *) psr; + + status = vxMemProbe( psr, + READ, + sizeof(id), + &id); + + if(status==OK){ + dynamic = TRUE; + pcr->addr = current_addr; + } + else + dynamic = FALSE; + + status = vxMemProbe( VXIBASE(current_addr), + READ, + sizeof(id), + &id); + if(status == ERROR) + abort(); + + + return dynamic; +} +#endif + + +/* + * + * VXI_CONFIGURE_HIERARCHIES + * + */ +LOCAL void +vxi_configure_hierarchies(commander_la, servant_area) +unsigned commander_la; +unsigned servant_area; +{ + int status; + struct vxi_csr *pcsr; + unsigned long response; + VXIDI **ppvxidi; + VXIDI *pvxidi; + unsigned sla; + unsigned last_sla; + unsigned area; + + last_sla = servant_area+commander_la; + + if(last_sla >= NELEMENTS(epvxiLibDeviceList)){ + logMsg( "vxi resman: Clipping servant area (la=%d)\n", + commander_la); + last_sla = NELEMENTS(epvxiLibDeviceList)-1; + } + + sla = commander_la+1; + ppvxidi = &epvxiLibDeviceList[sla]; + for( ; + sla<=last_sla; + sla += area+1, ppvxidi += area+1){ + + pvxidi = *ppvxidi; + area = 0; + + if(!pvxidi){ + continue; + } + + pvxidi->commander_la = commander_la; + + if(!pvxidi->st_passed){ + continue; + } + + pcsr = VXIBASE(sla); + + if(VXICLASS(pcsr) != VXI_MESSAGE_DEVICE){ + continue; + } + + if(commander_la != VXI_RESMAN_LA){ + status = epvxiCmdQuery( + commander_la, + (unsigned long)MBC_GRANT_DEVICE | sla, + &response); + if(status<0){ + logMsg( "vxi resman: gd failed (la=%d)\n", + sla); + } + else{ + logMsg( "vxi resman: gd resp %x\n", + response); + } + } + if(VXICMDR(pcsr)){ + status = epvxiCmdQuery( + sla, + (unsigned long)MBC_READ_SERVANT_AREA, + &response); + if(status<0){ + logMsg( "vxi resman: rsa failed (la=%d)\n", + sla); + } + else{ + area = response & MBR_READ_SERVANT_AREA_MASK; + + logMsg( "The servant area was %d (la=%d)\n", + area, + sla); + + vxi_configure_hierarchies( + sla, + area); + } + } + } +} + + +/* + * + * VXI_BEGIN_NORMAL_OPERATION + * + */ +LOCAL int +vxi_begin_normal_operation() +{ + int status; + unsigned la; + VXIDI **ppvxidi; + VXIDI *pvxidi; + struct vxi_csr *pcsr; + + for( la=0, ppvxidi = epvxiLibDeviceList; + ppvxidi < epvxiLibDeviceList+NELEMENTS(epvxiLibDeviceList); + ppvxidi++, la++){ + + unsigned cmdr; + unsigned long cmd; + unsigned long resp; + + pvxidi = *ppvxidi; + + if(!pvxidi){ + continue; + } + + pcsr = VXIBASE(la); + + if(!pvxidi->st_passed){ + continue; + } + + if(VXICLASS(pcsr) != VXI_MESSAGE_DEVICE){ + continue; + } + + cmdr = VXICMDR(pcsr); + + cmd = MBC_BEGIN_NORMAL_OPERATION; +/* + * this will send the begin nml op command to servants which + * have a commander + * + * more work needs to be done here if this situation occurs + * see below + */ + if(cmdr){ + cmd |= MBC_TOP_LEVEL_CMDR; + } + status = epvxiCmdQuery(la, cmd, &resp); + if(status<0){ + logMsg( + "vxi resman: beg nml op cmd failed (la=%d) (reason=%d)\n", + la, + status); + } + else if( + MBR_STATUS(resp)!=MBR_STATUS_SUCCESS || + MBR_BNO_STATE(resp)!=MBR_BNO_STATE_NO){ + logMsg( + "vxi resman: beg nml op cmd failed (la=%d) (status=%x) (state=%x)\n", + la, + MBR_STATUS(resp), + MBR_BNO_STATE(resp)); + } + else{ + pvxidi->msg_dev_online = TRUE; + } + + /* + * Dont send begin normal operation cmd + * to servants who have a commander + */ +/* + * apparently this is not a good enough test + * for CMDR since some devices are rejecting this cmd + */ +#if 0 + if(cmdr){ + unsigned long sa=0; + + logMsg("Found a msg based cmdr\n"); + + status = epvxiCmdQuery( + la, + (unsigned long)MBC_READ_SERVANT_AREA, + &sa); + if(status<0){ + logMsg("vxi resman: rsa failed\n"); + } + else{ + sa = sa & MBR_READ_SERVANT_AREA_MASK; + logMsg( "The servant area was %d\n", + sa); + la += sa; + } + } +#endif + } +} + + +/* + * + * VXI_SELF_TEST + * check self test bits and place in safe state if failed + * print message about failed devices + * + */ +LOCAL int +vxi_self_test() +{ + unsigned la; + short wd; + int status; + struct vxi_csr *pcsr; + VXIDI **ppvxidi; + + for( la=0, ppvxidi = epvxiLibDeviceList; + ppvxidi < epvxiLibDeviceList+NELEMENTS(epvxiLibDeviceList); + ppvxidi++, la++){ + + if(!*ppvxidi){ + continue; + } + + pcsr = VXIBASE(la); + + wd = pcsr->dir.r.status; + + if(VXIPASSEDSTATUS(wd)){ + (*ppvxidi)->st_passed = TRUE; + } + else{ + unsigned slot, crate; + + logMsg("VXI device self test failed\n"); + logMsg( "\tmake %x\t model %x\n", + pcsr->dir.r.make, + pcsr->dir.r.model); + logMsg("\taddr %x\n",la); + status = vxi_find_slot(pcsr, &slot, &crate); + if(status == OK) + logMsg("\tslot %d crate %d\n\n", + slot, + crate); + pcsr->dir.w.control = VXISAFECONTROL; + } + } + + return OK; +} + + +/* + * + * VXI_INIT_IGNORE_LIST + * init list of interrupt handlers to ignore + * + */ +LOCAL int +vxi_init_ignore_list() +{ + + int i; + char type; + int status; + + for(i=0; islot, + pmxidi->crate, + pmxidi->class); + printf("\t"); + if(pmxidi->mxi_dev){ + printf("mxi, "); + } + if(pmxidi->msg_dev_online){ + printf("msg online, "); + } + printf("driver ID %d, ", pmxidi->driverID); + printf("cmdr la %d, ", pmxidi->commander_la); + printf("make %d, ", pmxidi->make); + printf("model %d, ", pmxidi->model); + printf("pio_report_func %x, ", pmxidi->pio_report_func); + printf("\n"); + } + i++; + ppmxidi++; + } +} + + +/* + * + * vxiUniqueDriverID() + * + * return a non zero unique id for a VXI driver + */ +int +vxiUniqueDriverID() +{ + if(epvxiNextDriverID NELEMENTS(epvxiLibDeviceList)){ + return VXI_BAD_LA; + } + + if(vxiDriverID == UNINITIALIZED_DRIVER_ID){ + return VXI_NOT_OWNER; + } + + pvxidi = epvxiLibDeviceList[la]; + + if(pvxidi){ + if(pvxidi->driverID == vxiDriverID){ + return VXI_DEVICE_OPEN; + } + else if(pvxidi->driverID != NO_DRIVER_ATTACHED_ID){ + return VXI_NOT_OWNER; + } + } + else{ + return VXI_UKN_DEVICE; + } + + if(!pvxidi->st_passed){ + return VXI_SELF_TEST_FAILED; + } + + if(driverConfigSize){ + pconfig = (void *)calloc(1,driverConfigSize); + if(!pconfig){ + return VXI_NO_MEMORY; + } + pvxidi->pDriverConfig = pconfig; + } + else{ + pvxidi->pDriverConfig = NULL; + } + + pvxidi->pio_report_func = pio_report_func; + + pvxidi->driverID = vxiDriverID; + + return VXI_SUCCESS; +} + + +/* + * + * vxiClose() + * + * 1) Unregister a driver's ownership of a device + * 2) Free driver's configuration block if one is allocated + */ +int +vxiClose(la, vxiDriverID) +unsigned la; +int vxiDriverID; +{ + VXIDI *pvxidi; + + if(la > NELEMENTS(epvxiLibDeviceList)){ + return VXI_BAD_LA; + } + + pvxidi = epvxiLibDeviceList[la]; + + if(pvxidi){ + if(pvxidi->driverID == vxiDriverID){ + free(pvxidi); + return VXI_SUCCESS; + } + return VXI_NOT_OWNER; + } + + return VXI_NOT_OPEN; +} + + +/* + * + * epvxiLookupLA() + * + */ +int +epvxiLookupLA(pdsp, pfunc, parg) +epvxiDeviceSearchPattern *pdsp; +void (*pfunc)(); +void *parg; +{ + VXIDI *plac; + unsigned i; + + for(i=0; i<=last_la; i++){ + long flags; + + flags = pdsp->flags; + plac = epvxiLibDeviceList[i]; + + /* + * skip devices not present + */ + if(!plac){ + continue; + } + + if(flags & VXI_DSP_make){ + if(plac->make != pdsp->make){ + continue; + } + } + + if(flags & VXI_DSP_model){ + if(plac->model != pdsp->model){ + continue; + } + } + + if(flags & VXI_DSP_class){ + if(plac->class != pdsp->class){ + continue; + } + } + + if(flags & VXI_DSP_slot){ + if(plac->slot != pdsp->slot){ + continue; + } + } + + if(flags & VXI_DSP_slot_zero_la){ + if(VXI_PA_TO_LA(vxislot0[plac->crate].pcsr) + != pdsp->slot_zero_la){ + continue; + } + } + + if(flags & VXI_DSP_commander_la){ + if(plac->commander_la != pdsp->commander_la){ + continue; + } + } + + (*pfunc)(i, parg); + + } + + return VXI_SUCCESS; +} + + +/* + * epvxiRouteTriggerECL() + */ +int +epvxiRouteTriggerECL(la, enable_map, io_map) +unsigned la; /* slot zero device logical address */ +unsigned enable_map; /* bits 0-5 correspond to trig 0-5 */ + /* a 1 enables a trigger */ + /* a 0 disables a trigger */ +unsigned io_map; /* bits 0-5 correspond to trig 0-5 */ + /* a 1 sources the front panel */ + /* a 0 sources the back plane */ +{ + struct vxi_csr *pcsr; + char mask; + int status; + + mask = (1<= 0){ + return VXI_SUCCESS; + } + } + } + + pcsr = VXIBASE(la); + + if(VXIMXI(pcsr)){ + int ctrl = MXI_CONTROL_CONSTANT; + + if(enable_map & (1<<0)){ + ctrl |= MXI_ECL0_ENABLE; + } + if(io_map & (1<<0)){ + ctrl |= MXI_ECL0_BP_TO_FP; + } + else{ + ctrl |= MXI_ECL0_FP_TO_BP; + } + + + if(enable_map & (1<<1)){ + ctrl |= MXI_ECL1_ENABLE; + } + if(io_map & (1<<1)){ + ctrl |= MXI_ECL1_BP_TO_FP; + } + else{ + ctrl |= MXI_ECL1_FP_TO_BP; + } + + pcsr->dir.w.dd.mxi.control = ctrl; + + return VXI_SUCCESS; + } + + /* + * HP MODEL E1404 trigger routing + */ + if(VXIMAKE(pcsr)==VXI_MAKE_HP){ + if( VXIMODEL(pcsr)==VXI_HP_MODEL_E1404 || + VXIMODEL(pcsr)==VXI_HP_MODEL_E1404_SLOT0){ + return hpE1404RouteTriggerECL( + la, + enable_map, + io_map); + } + } + + logMsg("failed to map ECL trigger for (la=%d)\n", la); + + return VXI_UKN_DEVICE; +} + + +/* + * vxiRouteTriggerTTL() + * + */ +int +vxiRouteTriggerTTL(la, enable_map, io_map) +unsigned la; /* slot zero device logical address */ +unsigned enable_map; /* bits 0-5 correspond to trig 0-5 */ + /* a 1 enables a trigger */ + /* a 0 disables a trigger */ +unsigned io_map; /* bits 0-5 correspond to trig 0-5 */ + /* a 1 sources the front panel */ + /* a 0 sources the back plane */ +{ + struct vxi_csr *pcsr; + unsigned mask; + int status; + + mask = (1<= 0){ + return VXI_SUCCESS; + } + } + } + + pcsr = VXIBASE(la); + + if(VXIMXI(pcsr)){ + short tmp; + + tmp = (enable_map<<8) | ~io_map; + pcsr->dir.w.dd.mxi.trigger_config = tmp; + + return VXI_SUCCESS; + } + + /* + * HP MODEL E1404 trigger routing + */ + if(VXIMAKE(pcsr)==VXI_MAKE_HP){ + if( VXIMODEL(pcsr)==VXI_HP_MODEL_E1404 || + VXIMODEL(pcsr)==VXI_HP_MODEL_E1404_SLOT0){ + return hpE1404RouteTriggerTTL( + la, + enable_map, + io_map); + } + } + + logMsg("failed to map TTL trigger for (la=%d)\n", la); + + return VXI_UKN_DEVICE; +} + + + + +/* + * + * VXI_IO_REPORT + * + * call io report routines for all registered devices + * + */ +int +vxi_io_report(level) +unsigned level; +{ + register int i; + register unsigned la; + register status; + unsigned slot; + unsigned crate; + short id; + struct vxi_csr *pcsr; + VXIDI *plac; + + /* Get local address from VME address. */ + /* in case the resource manager has not been called */ + if(!epvxi_local_base){ + status = sysBusToLocalAdrs( + VME_AM_USR_SHORT_IO, + VXIBASEADDR, + &epvxi_local_base); + if(status != OK){ + logMsg("VXI addressing error\n"); + return ERROR; + } + } + + printf("<< VXI logical address table >>\n"); + + for(la=0; la<=last_la; la++){ + char *pmake; + int make; + + pcsr = VXIBASE(la); + status = vxMemProbe( pcsr, + READ, + sizeof(id), + &id); + if(status != OK){ + continue; + } + + status = vxi_find_slot(pcsr, &slot, &crate); + if(status == ERROR){ + printf("VXI: slot could not be found\n"); + slot = UKN_SLOT; + crate = UKN_CRATE; + } + + make = VXIMAKE(pcsr); + pmake = NULL; + for(i=0; idir.r.status)){ + printf("\t---- Self Test Failed ----\n"); + continue; + } + + /* + * call their io report routine if they supply one + */ + plac = epvxiLibDeviceList[la]; + if(plac){ + if(plac->pio_report_func){ + (*plac->pio_report_func)(la, level); + } + } + + if(level == 0){ + continue; + } + + printf("\taddress %8x\n", + (int) VXIBASE(la)); + + printf( "\t%s device", + vxi_device_class_names[VXICLASS(pcsr)]); + switch(VXICLASS(pcsr)){ + case VXI_MEMORY_DEVICE: + break; + + case VXI_EXTENDED_DEVICE: + if(VXIMXI(pcsr)){ + mxi_io_report(pcsr, level); + } + break; + + case VXI_MESSAGE_DEVICE: + { + unsigned long resp; + + if(VXICMDR(pcsr)){ + printf(", cmdr"); + } + if(VXIFHS(pcsr)){ + printf(", fh"); + } + if(VXISHM(pcsr)){ + printf(", shm"); + } + if(VXIMBINT(pcsr)){ + printf(", interrupter"); + } + if(VXIVMEBM(pcsr)){ + printf(", VME bus master"); + } + if(VXISIGREG(pcsr)){ + printf(", has signal reg"); + } + printf("\n"); + /* + * all message based devices are required to + * implement this command query + */ + status = epvxiCmdQuery( + la, + (unsigned long)MBC_READ_PROTOCOL, + &resp); + if(status>=0){ + printf("\tprotocols("); + if(MBR_REV_12(resp)){ + printf("Rev 1.2 device, "); + } + if(MBR_RP_LW(resp)){ + printf("long word serial, "); + } + if(MBR_RP_ELW(resp)){ + printf("extended long word serial, "); + } + if(MBR_RP_I(resp)){ + printf("VXI instr, "); + } + if(MBR_RP_I4(resp)){ + printf("488 instr, "); + } + if(MBR_RP_TRG(resp)){ + printf("sft trig, "); + } + if(MBR_RP_PH(resp)){ + printf("prog int hdlr, "); + } + if(MBR_RP_PI(resp)){ + printf("prog interrupter, "); + } + if(MBR_RP_EG(resp)){ + printf("evnt gen, "); + } + if(MBR_RP_RG(resp)){ + printf("resp gen, "); + } + printf(")"); + } + break; + } + case VXI_REGISTER_DEVICE: + break; + + } + printf("\n"); + + + } + return OK; +} + + +/* + * + * mxi_io_report() + * + * + */ +LOCAL int +mxi_io_report(pmxi, level) +struct vxi_csr *pmxi; +int level; +{ + unsigned la; + unsigned ha; + + printf(", MXI sub class"); + + if(pmxi->dir.w.dd.mxi.control & MXI_UPPER_LOWER_BOUNDS){ + la = VXIADDRMASK & + pmxi->dir.w.dd.mxi.la_window; + ha = VXIADDRMASK & + (pmxi->dir.w.dd.mxi.la_window>>NVXIADDRBITS); + } + else{ + la = VXIADDRMASK & + pmxi->dir.w.dd.mxi.la_window; + ha = la + (MXI_LA_WINDOW_SIZE_MASK & + (pmxi->dir.w.dd.mxi.la_window>>NVXIADDRBITS)); + } + printf(", LA window %x-%x", + la, + ha); + +} + + +/* + * + * vxi_allocate_int_lines() + * + * + */ +LOCAL int +vxi_allocate_int_lines() +{ + int status; + struct vxi_csr *pcsr; + VXIDI **ppvxidi; + VXIDI *pvxidi; + unsigned la; + unsigned long resp; + unsigned long cmd; + unsigned line_count; + + for( la=0, ppvxidi = epvxiLibDeviceList; + ppvxidi < epvxiLibDeviceList+NELEMENTS(epvxiLibDeviceList); + ppvxidi++, la++){ + + pvxidi = *ppvxidi; + + if(!pvxidi){ + continue; + } + + pcsr = VXIBASE(la); + + if(VXICLASS(pcsr) != VXI_MESSAGE_DEVICE){ + continue; + } + + /* + * find out if this is a programmable interrupter + */ + status = epvxiCmdQuery( + la, + (unsigned long)MBC_READ_PROTOCOL, + &resp); + if(status<0){ + logMsg( "Device rejected READ_PROTOCOL (la=%d)\n", + la); + continue; + } + if(!MBR_RP_PI(resp)){ + continue; + } + + logMsg("Programming interrupter (la=%d)\n", la); + + cmd = MBC_READ_INTERRUPTERS; + status = epvxiCmdQuery( + la, + cmd, + &resp); + if(status<0){ + logMsg( "Device rejected READ_INTERRUPTERS (la=%d)\n", + la); + continue; + } + line_count = resp&MBR_READ_INTERRUPTERS_MASK; + while(line_count--){ + cmd = MBC_ASSIGN_INTERRUPTER_LINE | + (line_count+1)<<4 | + VXIMSGINTLEVEL; + sysIntEnable(VXIMSGINTLEVEL); + status = epvxiCmdQuery( + la, + cmd, + &resp); + if(status<0){ + logMsg( "Device rejected ASSIGN_INT(la=%d)\n", + la); + continue; + } + if(MBR_STATUS(resp) != MBR_STATUS_SUCCESS){ + logMsg( "ASSIGN_INT failed (la=%d)\n", + la); + continue; + } + } + } +} + + diff --git a/src/drv/drvEpvxiMsg.c b/src/drv/drvEpvxiMsg.c new file mode 100644 index 000000000..e0320c8a6 --- /dev/null +++ b/src/drv/drvEpvxiMsg.c @@ -0,0 +1,1422 @@ +/* + * epvxiMsgLib.c + * + * driver for VXI message based devices + * + * Author: Jeff Hill + * Date: 042792 + * + * 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 + * + * Modification Log: + * ----------------- + * .01 joh 042792 first release + * + * Improvements + * ------------ + * .01 joh 051992 Some work on fast handshake exists in this file. + * If a card with fast handshake is found to exist + * then this code will be tested and uncommented. + * .02 joh 052292 Allways append a NULL even if at the end of + * the buffer in vxi_read() + * .03 joh 060292 Added debug mode + * + */ + +#include +#include +#include +#include + +#define LOCAL + +enum msgDeviceSyncType { + syncInt, + syncSignal, + syncPoll, +}; + +typedef +struct epvxiMessageDeviceInfo{ + unsigned err:1; /* error pending */ + unsigned trace:1; /* debug trace on */ + unsigned long timeout; /* in ticks */ + enum msgDeviceSyncType syncType; + SEM_ID syncSem; + FAST_LOCK lck; +}VXIMDI; + +#define VXIMSGSYNCDELAY 1 + +#define DEFAULTMSGTMO sysClkRateGet()*10; /* 10 sec */ +#define MAXIMUMTMO (0xffffff) + +LOCAL +int msgCommanderLA = (-1); + +LOCAL +char vxiMsgSignalInit; + +LOCAL +unsigned long vxiMsgLibDriverId = UNINITIALIZED_DRIVER_ID; + +#define VXI_HP_MODEL_E1404_SLOT0 0x010 +#define VXI_HP_MODEL_E1404_MSG 0x111 +#define VXI_HP_MODEL_E1404 0x110 + +#define abort(A) taskSuspend(0) + +/* + * local functions + */ +void set_la(); +void vxiMsgInt(); +void vxiHP1404SignalInt(); +void cpu030SignalInt(); +void signalHandler(); +int epvxiReadSlowHandshake(); +int epvxiReadFastHandshake(); +int vxiMsgClose(); +int vxiMsgOpen(); +int vxiMsgSignalSetup(); +int vxiCPU030MsgSignalSetup(); +int vxiHP1404MsgSignalSetup(); +int vxiAttemptAsyncModeControl(); +int vxiMsgSync(); +int fetch_protocol_error(); + + + + +/* + * + * vxi_msg_test() + * + */ +vxi_msg_test(la) +unsigned la; +{ + char buf[512]; + unsigned long count; + int status; + + status = epvxiWrite(la, "*IDN?", (unsigned long)5, &count); + if(status != VXI_SUCCESS){ + return status; + } + status = epvxiRead(la, buf, (unsigned long)sizeof(buf)-1, &count); + if(status != VXI_SUCCESS){ + return status; + } + + buf[count] = NULL; + printf("%s %d\n", buf,count); + + status = epvxiWrite(la, "*TST?", (unsigned long)5, &count); + if(status != VXI_SUCCESS){ + return status; + } + status = epvxiRead(la, buf, (unsigned long)sizeof(buf)-1, &count); + if(status != VXI_SUCCESS){ + return status; + } + + buf[count] = NULL; + printf("%s %d\n", buf, count); + + return VXI_SUCCESS; +} + + +/* + * + * vxi_msg_print_id + * + */ +vxi_msg_print_id(la) +unsigned la; +{ + char buf[32]; + unsigned long count; + char *pcmd = "*IDN?"; + int status; + + status = epvxiWrite(la, pcmd, (unsigned long) strlen(pcmd), &count); + if(status != VXI_SUCCESS){ + return status; + } + status = epvxiRead(la, buf, (unsigned long)sizeof(buf)-1, &count); + if(status != VXI_SUCCESS){ + return status; + } + + buf[count] = NULL; + printf(" %s ", buf); + + return VXI_SUCCESS; +} + + +/* + * + * vxi_msg_test_protocol_error + * + */ +int +vxi_msg_test_protocol_error(la) +unsigned la; +{ + unsigned long resp; + int i; + int status; + + for(i=0;i<1000;i++){ + status = epvxiCmd(la, MBC_READ_PROTOCOL); + if(status<0){ + return status; + } + } + return VXI_SUCCESS; +} + + +/* + * epvxiCmd() + * + * deliver a command to a msg based device + * + */ +int +epvxiCmd(la, cmd) +unsigned la; +unsigned long cmd; +{ + struct vxi_csr *pcsr; + VXIMDI *pvximdi; + int status; + +# ifdef DEBUG + logMsg("cmd to be sent %4x (la=%d)\n", cmd, la); +# endif + + pvximdi = epvxiPConfig(la, vxiMsgLibDriverId, VXIMDI *); + if(!pvximdi){ + status = vxiMsgOpen(la); + if(status != VXI_SUCCESS){ + return status; + } + pvximdi = (VXIMDI *) epvxiLibDeviceList[la]->pDriverConfig; + } + + pcsr = VXIBASE(la); + + FASTLOCK(&pvximdi->lck); + + status = vxiMsgSync( + la, + VXIWRITEREADYMASK, + VXIWRITEREADYMASK, + cmd == MBC_CLEAR); + if(status>=0){ + pcsr->dir.w.dd.msg.dlow = cmd; + } + + FASTUNLOCK(&pvximdi->lck); + + if(status == VXI_PROTOCOL_ERROR){ + return fetch_protocol_error(la); + } + + if(pvximdi->trace){ + printf( "VXI Trace: (la=%3d) Cmd -> %x\n", + la, + cmd); + } + + return status; +} + + + +/* + * epvxiQuery() + * + * query the response to a command + * + */ +int +epvxiQuery(la, presp) +unsigned la; +unsigned long *presp; +{ + struct vxi_csr *pcsr; + VXIMDI *pvximdi; + int status; + + pvximdi = epvxiPConfig(la, vxiMsgLibDriverId, VXIMDI *); + if(!pvximdi){ + status = vxiMsgOpen(la); + if(status != VXI_SUCCESS){ + return status; + } + pvximdi = (VXIMDI *) epvxiLibDeviceList[la]->pDriverConfig; + } + + pcsr = VXIBASE(la); + + FASTLOCK(&pvximdi->lck); + + status = vxiMsgSync( + la, + VXIREADREADYMASK, + VXIREADREADYMASK, + FALSE); + if(status<=0){ + *presp = pcsr->dir.r.dd.msg.dlow; + } + + FASTUNLOCK(&pvximdi->lck); + +# ifdef DEBUG + logMsg("resp returned %4x (la=%d)\n", *presp, la); +# endif + + if(status == VXI_PROTOCOL_ERROR){ + return fetch_protocol_error(la); + } + + if(pvximdi->trace){ + printf( "VXI Trace: (la=%3d) Query -> %x\n", + la, + *presp); + } + + return status; +} + + +/* + * epvxiCmdQuery() + */ +int +epvxiCmdQuery(la, cmd, presp) +unsigned la; +unsigned long cmd; +unsigned long *presp; +{ + int status; + + status = epvxiCmd(la, cmd); + if(status<0){ + return status; + } + status = epvxiQuery(la, presp); + return status; +} + + +/* + * epvxiRead() + * + * Read a string using fast handshake mode + * or call a routine to do a slow handshake + * if that is all that is supported. + */ +int +epvxiRead(la, pbuf, count, pread_count) +unsigned la; +char *pbuf; +unsigned long count; +unsigned long *pread_count; +{ + VXIMDI *pvximdi; + int status; + + pvximdi = epvxiPConfig(la, vxiMsgLibDriverId, VXIMDI *); + if(!pvximdi){ + status = vxiMsgOpen(la); + if(status != VXI_SUCCESS){ + return status; + } + pvximdi = (VXIMDI *) epvxiLibDeviceList[la]->pDriverConfig; + } + + /* + * does the device support fast handshake + */ +# ifdef FASTHANDSHAKE + if(VXIFHS(pcsr)){ + status = epvxiReadFastHandshake( + la, + pbuf, + count, + pread_count); + } + else{ +# endif + status = epvxiReadSlowHandshake( + la, + pbuf, + count, + pread_count); +# ifdef FASTHANDSHAKE + } +# endif + + if(pvximdi->trace){ + printf( "VXI Trace: (la=%3d) Read -> %*s\n", + la, + count, + pbuf); + } + + return status; +} + + +#ifdef FASTHANDSHAKE +/* + * epvxiReadFastHandshake() + * + * Read a string using fast handshake mode + * or call a routine to do a slow handshake + * if that is all that is supported. + * + * This function will be tested and installed + * if a card with fast handshake s found to exist + * + */ +LOCAL int +epvxiReadFastHandshake(la, pbuf, count, pread_count) +unsigned la; +char *pbuf; +unsigned long count; +unsigned long *pread_count; +{ + struct vxi_csr *pcsr; + VXIMDI *pvximdi; + short resp; + int fhm; + short cmd; + int status; + int i; + + pvximdi = epvxiPConfig(la, vxiMsgLibDriverId, VXIMDI *); + if(!pvximdi){ + status = vxiMsgOpen(la); + if(status != VXI_SUCCESS){ + return status; + } + pvximdi = (VXIMDI *) epvxiLibDeviceList[la]->pDriverConfig; + } + + pcsr = VXIBASE(la); + + FASTLOCK(&pvximdi->lck); + fhm = FALSE; + /* + * always leave room to write a NULL termination + */ + for(i=0; i<(count-1); i++){ + + while(TRUE){ + /* + * wait for fast handshake mode + */ + if(!fhm){ + status = vxiMsgSync( + la, + VXIFHSMMASK, + 0, + FALSE); + if(status<0){ + *pread_count = i; + goto exit; + } + fhm = TRUE; + } + + cmd = MBC_BR; + status = vxMemProbe( + &pcsr->dir.r.dd.msg.dlow, + WRITE, + sizeof(pcsr->dir.r.dd.msg.dlow), + &cmd); + if(status == OK){ + break; + } + fhm = FALSE; + } + + while(TRUE){ + /* + * wait for fast handshake mode + */ + if(!fhm){ + status = vxiMsgSync( + la, + VXIFHSMMASK, + 0, + FALSE); + if(status<0){ + *pread_count = i; + goto exit; + } + fhm = TRUE; + } + + status = vxMemProbe( + &pcsr->dir.r.dd.msg.dlow, + READ, + sizeof(pcsr->dir.r.dd.msg.dlow), + &resp); + if(status == OK){ + break; + } + fhm = FALSE; + } + + *pbuf = resp; + pbuf++; + if(resp & MBC_END){ + *pread_count = i+1; + break; + } + } + status = VXI_SUCCESS; +exit: + FASTUNLOCK(&pvximdi->lck); + + if(status == VXI_PROTOCOL_ERROR){ + return fetch_protocol_error(la); + } + + *pbuf = NULL; + + return status; +} +#endif + + +/* + * epvxiReadSlowHandshake() + */ +LOCAL int +epvxiReadSlowHandshake(la, pbuf, count, pread_count) +unsigned la; +char *pbuf; +unsigned long count; +unsigned long *pread_count; +{ + VXIMDI *pvximdi; + struct vxi_csr *pcsr; + short resp; + int status; + int i; + + pvximdi = epvxiPConfig(la, vxiMsgLibDriverId, VXIMDI *); + if(!pvximdi){ + status = vxiMsgOpen(la); + if(status != VXI_SUCCESS){ + return status; + } + pvximdi = (VXIMDI *) epvxiLibDeviceList[la]->pDriverConfig; + } + + pcsr = VXIBASE(la); + + FASTLOCK(&pvximdi->lck); + /* + * always leave room to write a NULL termination + */ + for(i=0; i<(count-1); i++){ + + /* + * wait for handshake + */ + status = vxiMsgSync( + la, + VXIWRITEREADYMASK|VXIDORMASK, + VXIWRITEREADYMASK|VXIDORMASK, + FALSE); + if(status<0){ + *pread_count = i; + goto exit; + } + + pcsr->dir.w.dd.msg.dlow = MBC_BR; + + /* + * wait for handshake + */ + status = vxiMsgSync( + la, + VXIREADREADYMASK, + VXIREADREADYMASK, + FALSE); + if(status<0){ + *pread_count = i; + goto exit; + } + + resp = pcsr->dir.r.dd.msg.dlow; + + *pbuf = resp; + pbuf++; + if(resp & MBC_END){ + int cnt; + + cnt = i+1; + *pread_count= cnt; + break; + } + } + + status = VXI_SUCCESS; + +exit: + FASTUNLOCK(&pvximdi->lck); + + if(status == VXI_PROTOCOL_ERROR){ + return fetch_protocol_error(la); + } + + /* + * append the NULL + */ + *pbuf = NULL; + + return status; +} + + +/* + * epvxiWrite() + */ +int +epvxiWrite(la, pbuf, count, pwrite_count) +unsigned la; +char *pbuf; +unsigned long count; +unsigned long *pwrite_count; +{ + VXIMDI *pvximdi; + struct vxi_csr *pcsr; + int i; + short cmd; + int status; + char *pstr; + + pvximdi = epvxiPConfig(la, vxiMsgLibDriverId, VXIMDI *); + if(!pvximdi){ + status = vxiMsgOpen(la); + if(status != VXI_SUCCESS){ + return status; + } + pvximdi = (VXIMDI *) epvxiLibDeviceList[la]->pDriverConfig; + } + + pcsr = VXIBASE(la); + + FASTLOCK(&pvximdi->lck); + pstr = pbuf; + for(i=0; idir.r.dd.msg.dlow = cmd; + pstr++; + } + *pwrite_count = i; + status = VXI_SUCCESS; +exit: + FASTUNLOCK(&pvximdi->lck); + + if(status == VXI_PROTOCOL_ERROR){ + return fetch_protocol_error(la); + } + + if(pvximdi->trace){ + printf( "VXI Trace: (la=%3d) Write -> %*s\n", + la, + count, + pbuf); + } + + return status; +} + + +/* + * + * epvxiSetTimeout() + * + * change the message based transfer timeout + * (timeout is in milli sec) + * + */ +int +epvxiSetTimeout(la, timeout) +unsigned la; +unsigned long timeout; +{ + VXIMDI *pvximdi; + int status; + + pvximdi = epvxiPConfig(la, vxiMsgLibDriverId, VXIMDI *); + if(!pvximdi){ + status = vxiMsgOpen(la); + if(status != VXI_SUCCESS){ + return status; + } + pvximdi = (VXIMDI *) epvxiLibDeviceList[la]->pDriverConfig; + } + + /* + * order of operations significant here + */ + if(timeout > MAXIMUMTMO){ + return VXI_TIMEOUT_TO_LARGE; + } + + pvximdi->timeout = (timeout * sysClkRateGet())/1000; + + return VXI_SUCCESS; +} + + +/* + * + * epvxiSetTraceEnable() + * + * turn trace mode on or off + * + */ +int +epvxiSetTraceEnable(la, enable) +unsigned la; +int enable; +{ + VXIMDI *pvximdi; + int status; + + pvximdi = epvxiPConfig(la, vxiMsgLibDriverId, VXIMDI *); + if(!pvximdi){ + status = vxiMsgOpen(la); + if(status != VXI_SUCCESS){ + return status; + } + pvximdi = (VXIMDI *) epvxiLibDeviceList[la]->pDriverConfig; + } + + + pvximdi->trace = enable?TRUE:FALSE; + + return VXI_SUCCESS; +} + + +/* + * + * vxiMsgClose() + * + * + */ +LOCAL int +vxiMsgClose(la) +unsigned la; +{ + int status; + VXIMDI *pvximdi; + + pvximdi = epvxiPConfig(la, vxiMsgLibDriverId, VXIMDI *); + if(!pvximdi){ + return VXI_NOT_OPEN; + } + + status = semDelete(pvximdi->syncSem); + if(status<0){ + logMsg( "%s: vxiMsgClose(): bad sem id\n", + __FILE__); + } + status = vxiClose(la, vxiMsgLibDriverId); + if(status<0){ + logMsg( "%s: vxiMsgClose(): close failed\n", + __FILE__); + } + FASTLOCKFREE(&pvximdi->lck); + return VXI_SUCCESS; +} + + +/* + * + * vxiMsgOpen() + * + * + */ +LOCAL int +vxiMsgOpen(la) +unsigned la; +{ + int status; + VXIMDI *pvximdi; + unsigned long resp; + unsigned long read_proto_resp; + unsigned long cmd; + struct vxi_csr *pcsr; + int signalSync = FALSE; + int intSync = FALSE; + + if(vxiMsgLibDriverId==UNINITIALIZED_DRIVER_ID){ + vxiMsgLibDriverId = vxiUniqueDriverID(); + } + + status = vxiOpen( + la, + vxiMsgLibDriverId, + (unsigned long)sizeof(*pvximdi), + NULL); + if(status<0){ + return status; + } + + pvximdi = epvxiPConfig(la, vxiMsgLibDriverId, VXIMDI *); + if(!pvximdi){ + abort(); + } + + if(!vxiMsgSignalInit){ + vxiMsgSignalSetup(); + } + + pcsr = VXIBASE(la); + + if(VXICLASS(pcsr) != VXI_MESSAGE_DEVICE){ + vxiClose(la, vxiMsgLibDriverId); + return VXI_NOT_MSG_DEVICE; + } + +# ifdef V5_vxWorks + pvximdi->syncSem = semBCreate(SEM_Q_PRIORITY, SEM_EMPTY); +# else + pvximdi->syncSem = semCreate(); +# endif + if(!pvximdi->syncSem){ + vxiClose(la, vxiMsgLibDriverId); + return VXI_NO_MEMORY; + } + + /* + * + * assume the worst for the transfers below + * + */ + pvximdi->timeout = DEFAULTMSGTMO; + pvximdi->syncType = syncPoll; + FASTLOCKINIT(&pvximdi->lck); + + /* + * if it is not an interrupter or a signal + * generator then we poll + */ + if(!VXIMBINT(pcsr) && !VXIVMEBM(pcsr)){ + return VXI_SUCCESS; + } + + /* + * if it is not a response generator then we poll + */ + status = epvxiCmdQuery( + la, + (unsigned long) MBC_READ_PROTOCOL, + &read_proto_resp); + if(status<0){ + /* + * All devices are required by the VXI standard + * to accept this command while in the + * configure state or in the normal operation + * state. Some dont. + * + */ + logMsg( "%s: Device rejected MBC_READ_PROTOCOL (la=%d)\n", + __FILE__, + la); + return VXI_SUCCESS; + } + +return VXI_SUCCESS; + + if(!MBR_RP_RG(read_proto_resp)){ + return VXI_SUCCESS; + } + +logMsg("mb device has response gen\n"); + + /* + * try to setup interrupt synchronization first + */ + if(VXIMBINT(pcsr)){ + cmd = MBC_ASYNC_MODE_CONTROL | + MBC_AMC_RESP_ENABLE | + MBC_AMC_RESP_INT_ENABLE; + status = vxiAttemptAsyncModeControl(la, cmd); + if(status>=0){ + logMsg( "%s: mb device has int sync!\n", + __FILE__); + intSync = TRUE; + } + } + + /* + * hopefully signal hardware is available if we get to here + */ + if(VXIVMEBM(pcsr) && !intSync && msgCommanderLA>=0){ + cmd = MBC_ASYNC_MODE_CONTROL | + MBC_AMC_RESP_ENABLE | + MBC_AMC_EVENT_ENABLE | + MBC_AMC_RESP_SIGNAL_ENABLE | + MBC_AMC_EVENT_SIGNAL_ENABLE; + status = vxiAttemptAsyncModeControl(la, cmd); + if(status>=0){ + logMsg( "%s: mb device has signal sync!\n", + __FILE__); + signalSync = TRUE; + } + } + + if(!intSync && !signalSync){ + logMsg( "%s: mb responder failed to configure\n", + __FILE__); + return VXI_SUCCESS; + } + + cmd = MBC_CONTROL_RESPONSE; + status = epvxiCmdQuery( + la, + cmd, + &resp); + if(status<0){ + logMsg( "%s: Control response rejected by responder\n", + __FILE__); + vxiMsgClose(la); + return status; + } + if( MBR_STATUS(resp) != MBR_STATUS_SUCCESS || + (resp^cmd)&MBR_CR_CONFIRM_MASK){ + logMsg( "%s: Control Response Failed %x\n", + __FILE__, + resp); + return VXI_SUCCESS; + } +logMsg("sent ctrl resp (la=%d) (cmd=%x)\n", la, cmd); + +logMsg("synchronized msg based device is ready!\n"); + + if(intSync){ + pvximdi->syncType = syncInt; + } + if(signalSync){ + pvximdi->syncType = syncSignal; + } + + return VXI_SUCCESS; +} + + +/* + * + * vxiMsgSignalSetup + * + * + */ +LOCAL int +vxiMsgSignalSetup() +{ + int status; + + vxiMsgSignalInit = TRUE; + + status = vxiHP1404MsgSignalSetup(); + if(status>=0){ + return OK; + } + + status = vxiCPU030MsgSignalSetup(); + if(status>=0){ + return OK; + } + + return ERROR; +} + + +/* + * + * vxiCPU030MsgSignalSetup + * + * + */ +LOCAL int +vxiCPU030MsgSignalSetup() +{ + int niMsgLA; + int status; + + if(pnivxi_func[(unsigned)e_GetMyLA]){ + niMsgLA = (*pnivxi_func[(unsigned)e_GetMyLA])(); + } + else{ + return ERROR; + } + + if( !pnivxi_func[(unsigned)e_EnableSignalInt] || + !pnivxi_func[(unsigned)e_SetSignalHandler] || + !pnivxi_func[(unsigned)e_RouteSignal]){ + return ERROR; + } + +# define ANY_DEVICE (-1) +# define MSG_RESP_ENABLE (0x3f) + status = (*pnivxi_func[(unsigned)e_RouteSignal])( + ANY_DEVICE, + MSG_RESP_ENABLE); + if(status<0){ + return ERROR; + } + +# define UKN_DEVICE (-2) + status = (*pnivxi_func[(unsigned)e_SetSignalHandler])( + UKN_DEVICE, + cpu030SignalInt); + if(status<0){ + return ERROR; + } + + status = (*pnivxi_func[(unsigned)e_EnableSignalInt])(); + if(status){ + return ERROR; + } + +logMsg("vxiCPU030MsgSignalSetup() done\n"); + msgCommanderLA = niMsgLA; + + return OK; +} + + +/* + * + * vxiHP1404MsgSignalSetup + * + * + */ +LOCAL int +vxiHP1404MsgSignalSetup() +{ + epvxiDeviceSearchPattern dsp; + int hpMsgLA = -1; + int hpRegLA = -1; + int status; + + dsp.flags = VXI_DSP_make | VXI_DSP_model; + dsp.make = VXI_MAKE_HP; + dsp.model = VXI_HP_MODEL_E1404_MSG; + status = epvxiLookupLA(&dsp, set_la, (void *)&hpMsgLA); + if(status<0){ + return ERROR; + } + if(hpMsgLA<0){ + return ERROR; + } + dsp.flags = VXI_DSP_make | VXI_DSP_slot; + dsp.make = VXI_MAKE_HP; + dsp.slot = epvxiLibDeviceList[hpMsgLA]->slot; + status = epvxiLookupLA(&dsp, set_la, (void *)&hpRegLA); + if(status<0){ + return ERROR; + } + + if(hpRegLA<0){ + return ERROR; + } + +logMsg("found HP1404 device\n"); + intConnect( + (unsigned char)hpRegLA, + vxiHP1404SignalInt, + (void *) hpRegLA); + + msgCommanderLA = hpMsgLA; + + return OK; +} + + +/* + * + * set_la + * + * + */ +LOCAL void +set_la(la, pla) +int la; +int *pla; +{ + *pla = la; +} + + +/* + * + * vxiAttemptAsyncModeControl + * + * + */ +LOCAL int +vxiAttemptAsyncModeControl(la, cmd) +unsigned la; +unsigned long cmd; +{ + int status; + unsigned long resp; + unsigned long tmpcmd; + + if(msgCommanderLA<0 && cmd&MBC_AMC_RESP_SIGNAL_ENABLE){ + return ERROR; + } + + /* + * this step tells the device what la to signal at + */ + if(cmd & MBC_AMC_RESP_SIGNAL_ENABLE){ + tmpcmd = MBC_IDENTIFY_COMMANDER | msgCommanderLA; + status = epvxiCmd( + la, + tmpcmd); + if(status<0){ + logMsg( "%s: IDENTIFY_COMMANDER rejected (la=%d)\n", + __FILE__, + la); + return ERROR; + } +logMsg("sent id cmdr (la=%d) (cmd=%x)\n", la, tmpcmd); + } + + status = epvxiCmdQuery( + la, + cmd, + &resp); + if(status<0){ + logMsg( "%s: Async mode control rejected (la=%d)\n", + __FILE__, + la); + return ERROR; + } + if( MBR_STATUS(resp) != MBR_STATUS_SUCCESS || + (resp^cmd)&MBR_AMC_CONFIRM_MASK){ + logMsg( "%s: async mode ctrl failure (la=%d,cmd=%x,resp=%x)\n", + __FILE__, + la, + cmd, + resp); + return ERROR; + } +logMsg("sent asynch mode control (la=%d) (cmd=%x)\n",la,cmd); + + + if(cmd & MBC_AMC_RESP_INT_ENABLE){ + intConnect( + la, + vxiMsgInt, + la); +logMsg("connected to interrupt (la=%d)\n", la); + } + + return OK; +} + + +/* + * + * vxiMsgSync() + * + * + */ +LOCAL int +vxiMsgSync(la, resp_mask, resp_state, override_err) +unsigned la; +unsigned resp_mask; +unsigned resp_state; +int override_err; +{ + VXIMDI *pvximdi; + struct vxi_csr *pcsr; + int status; + long timeout; + unsigned short resp; + int pollcnt = 100; + + + pvximdi = epvxiPConfig(la, vxiMsgLibDriverId, VXIMDI *); + if(!pvximdi){ + status = vxiMsgOpen(la); + if(status != VXI_SUCCESS){ + return status; + } + pvximdi = (VXIMDI *) epvxiLibDeviceList[la]->pDriverConfig; + } + + pcsr = VXIBASE(la); + +# ifdef DEBUG + logMsg( "Syncing to resp mask %4x, request %4x (la=%d)\n", + resp_mask, + resp_state, + la); +# endif + + timeout = pvximdi->timeout; + do{ + int sync; + + resp = pcsr->dir.r.dd.msg.response; + + sync = !((resp^resp_state)&resp_mask); + + if(!(resp & VXIERRNOTMASK)){ + if(!override_err && !pvximdi->err){ + pvximdi->err = TRUE; + return VXI_PROTOCOL_ERROR; + } + } + + if(sync){ + return VXI_SUCCESS; + } + + /* + * this improves VXI throughput at the + * expense of sucking CPU + */ + if(pollcnt>0){ + pollcnt--; + } + else{ + status = semTake( + pvximdi->syncSem, + VXIMSGSYNCDELAY); + if(status < 0){ + timeout -= VXIMSGSYNCDELAY; + } + } + } + while(timeout>0); + + /* + * sync timed out if we got here + */ + logMsg( "%s: msg dev timed out after %d sec\n", + __FILE__, + (pvximdi->timeout-timeout) / sysClkRateGet()); + logMsg( "%s: resp mask %4x, request %4x, actual %4x\n", + __FILE__, + resp_mask, + resp_state, + resp); + + return VXI_MSG_DEVICE_TMO; +} + + +/* + * + * fetch_protocol_error + * + */ +LOCAL int +fetch_protocol_error(la) +unsigned la; +{ + VXIMDI *pvximdi; + unsigned long error; + struct vxi_csr *pcsr; + unsigned short resp; + int status; + + pvximdi = epvxiPConfig(la, vxiMsgLibDriverId, VXIMDI *); + if(!pvximdi){ + return VXI_ERR_FETCH_FAIL; + } + + status = epvxiCmdQuery( + la, + (unsigned long)MBC_READ_PROTOCOL_ERROR, + &error); + if(status>=0){ + logMsg("%s: serial protocol error (code = %x)\n", + __FILE__, + error); + } + else{ + logMsg( "%s: serial protocol error fetch failed\n", + __FILE__); + return VXI_ERR_FETCH_FAIL; + } + + pcsr = VXIBASE(la); + resp = pcsr->dir.r.dd.msg.response; + + if(resp & VXIERRNOTMASK){ + pvximdi->err = FALSE; + } + else{ + logMsg( "%s: Device failed to clear its ERR bit (la=%d)\n", + __FILE__, + la); + } + + switch(error){ + case MBE_MULTIPLE_QUERIES: + return VXI_MULTIPLE_QUERIES; + case MBE_UNSUPPORTED_CMD: + return VXI_UNSUPPORTED_CMD; + case MBE_DIR_VIOLATION: + return VXI_DIR_VIOLATION; + case MBE_DOR_VIOLATION: + return VXI_DOR_VIOLATION; + case MBE_RR_VIOLATION: + return VXI_RR_VIOLATION; + case MBE_WR_VIOLATION: + return VXI_WR_VIOLATION; + case MBE_NO_ERROR: + default: + break; + } + return VXI_ERR_FETCH_FAIL; +} + + +/* + * + * vxiMsgInt + * + * + */ +LOCAL void +vxiMsgInt(la) +unsigned la; +{ + VXIMDI *pvximdi; + int status; + + /* + * verify that this device is open for business + */ + pvximdi = epvxiPConfig(la, vxiMsgLibDriverId, VXIMDI *); + if(pvximdi){ + + /* + * + * wakeup pending tasks + * + */ + status = semGive(pvximdi->syncSem); + if(status<0){ + logMsg("%s: vxiMsgInt(): bad sem id\n", + __FILE__); + } + } + else{ + logMsg( "%s: vxiMsgInt(): msg int to ukn dev\n", + __FILE__); + } +} + + + +/* + * vxiHP1404SignalInt() + */ +LOCAL void +vxiHP1404SignalInt(la) +unsigned la; +{ + struct vxi_csr *pcsr; + unsigned short signal; + +logMsg("signal was sent to the HP1040 at (la=%d)\n",la); + + pcsr = VXIBASE(la); + signal = pcsr->dir.r.dd.reg.ddx10; + signalHandler(signal); +} + + +/* + * cpu030SignalInt + */ +LOCAL void +cpu030SignalInt(signal) +unsigned short signal; +{ +logMsg("signal was sent to the CPU030\n"); + signalHandler(signal); +} + + +/* + * signalHandler + */ +void +signalHandler(signal) +unsigned short signal; +{ + unsigned signal_la; + + signal_la = signal & NVXIADDR; + + if(MBE_EVENT_TEST(signal)){ + logMsg( "%s: VXI event was ignored %x\n", + __FILE__, + signal); + } + else{ + vxiMsgInt(signal_la); + } +} diff --git a/src/drv/drvHp1404a.c b/src/drv/drvHp1404a.c new file mode 100644 index 000000000..c8441b11f --- /dev/null +++ b/src/drv/drvHp1404a.c @@ -0,0 +1,144 @@ +/* + * + * HP E1404A VXI bus slot zero translator + * device dependent routines + * + * Author Jeffrey O. Hill + * Date 030692 + * + * 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 + * + * Modification Log: + * ----------------- + * + * + * + */ + +#include + +#define TLTRIG(N) (1<<(N)) +#define ECLTRIG(N) (1<<((N)+8)) + +#define LOCAL static + +#define NULL 0 +#define TRUE 1 +#define FALSE 0 + +/* + * enable int when signal register is written + */ +#define HP1404A_INT_ENABLE 0x0008 + + + +/* + * + * hpE1404Init + * + */ +int +hpE1404Init(la) +unsigned la; +{ + return hpE1404SetMsgSelfTestPassed(la); +} + + +/* + * + * hpE1404SetSelfTestPassed + * + * set the self test status passed for the message based device + * + * + */ +LOCAL int +hpE1404SetMsgSelfTestPassed(la) +unsigned la; /* register based device's la */ +{ + struct vxi_csr *pcsr; + + pcsr = VXIBASE(la); + + pcsr->dir.w.dd.reg_s0.ddx1e = VXIPASS<<2; + + /* + * enable int when signal register is written + */ + pcsr->dir.w.dd.reg.ddx1a = HP1404A_INT_ENABLE; + + return VXI_SUCCESS; +} + + +/* + * + * hpE1404RouteTriggerECL + * + */ +hpE1404RouteTriggerECL(la, enable_map, io_map) +unsigned la; /* slot zero device logical address */ +unsigned enable_map; /* bits 0-5 correspond to trig 0-5 */ + /* a 1 enables a trigger */ + /* a 0 disables a trigger */ +unsigned io_map; /* bits 0-5 correspond to trig 0-5 */ + /* a 1 sources the front panel */ + /* a 0 sources the back plane */ +{ + struct vxi_csr *pcsr; + + pcsr = VXIBASE(la); + + pcsr->dir.w.dd.reg_s0.ddx2a = (io_map&enable_map)<<8; + pcsr->dir.w.dd.reg_s0.ddx22 = ((~io_map)&enable_map)<<8; + + return VXI_SUCCESS; +} + + +/* + * + * + * hpE1404RouteTriggerTTL + * + * + */ +hpE1404RouteTriggerTTL(la, enable_map, io_map) +unsigned la; /* slot zero device logical address */ +unsigned enable_map; /* bits 0-5 correspond to trig 0-5 */ + /* a 1 enables a trigger */ + /* a 0 disables a trigger */ +unsigned io_map; /* bits 0-5 correspond to trig 0-5 */ + /* a 1 sources the front panel */ + /* a 0 sources the back plane */ +{ + struct vxi_csr *pcsr; + + pcsr = VXIBASE(la); + + pcsr->dir.w.dd.reg_s0.ddx2a = io_map&enable_map; + pcsr->dir.w.dd.reg_s0.ddx22 = (~io_map)&enable_map; + + return VXI_SUCCESS; +} diff --git a/src/drv/drvHpe1368a.c b/src/drv/drvHpe1368a.c new file mode 100644 index 000000000..62a3b17ad --- /dev/null +++ b/src/drv/drvHpe1368a.c @@ -0,0 +1,282 @@ +/* + * hpe1368a_driver.c + * + * driver for hpe1368a and hpe1369a VXI modules + * + * Author: Jeff Hill + * Date: 052192 + * + * 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 + * + * Modification Log: + * ----------------- + * + */ + + +#include +#ifdef V5_vxWorks +# include <68k/iv.h> +#else +# include +#endif +#include +#include +#include +#include +#include + + +#define VXI_MODEL_HPE1368A (0xf28) + +#define HPE1368A_PCONFIG(LA) \ +epvxiPConfig((LA), hpe1368aDriverId, struct hpe1368a_config *) + +#define ChannelEnable(PCSR) ((PCSR)->dir.w.dd.reg.ddx08) +#define ModuleStatus(PCSR) ((PCSR)->dir.r.status) + +#define ALL_SWITCHES_OPEN 0 + +struct hpe1368a_config{ + FAST_LOCK lock; + unsigned short shadow; + int busy; +}; + +#define HPE1368A_INT_LEVEL 1 + +LOCAL +int hpe1368aDriverId; + +void hpe1368a_int_service(); +void hpe1368a_init_card(); +void hpe1368a_stat(); + + +/* + * hpe1368a_init + * + * initialize all hpe1368a cards + * + */ +hpe1368a_init() +{ + int r0; + + /* + * do nothing on crates without VXI + */ + if(!epvxiResourceMangerOK){ + return OK; + } + + hpe1368aDriverId = vxiUniqueDriverID(); + + { + epvxiDeviceSearchPattern dsp; + + dsp.flags = VXI_DSP_make | VXI_DSP_model; + dsp.make = VXI_MAKE_HP; + dsp.model = VXI_MODEL_HPE1368A; + r0 = epvxiLookupLA(&dsp, hpe1368a_init_card, (void *)NULL); + if(r0<0){ + return ERROR; + } + } + + return OK; +} + + + +/* + * HPE1368A_INIT_CARD + * + * initialize single at5vxi card + * + */ +LOCAL void +hpe1368a_init_card(la) +unsigned la; +{ + int r0; + struct hpe1368a_config *pc; + struct vxi_csr *pcsr; + + r0 = vxiOpen( + la, + hpe1368aDriverId, + (unsigned long) sizeof(*pc), + hpe1368a_stat); + if(r0<0){ + logMsg("hpe1368a: device open failed %d\n", la); + return; + } + + pc = HPE1368A_PCONFIG(la); + if(pc == NULL){ + return; + } + + pcsr = VXIBASE(la); + + /* + * we must reset the device to a known state since + * we cant read back the current state + */ + pc->shadow = ALL_SWITCHES_OPEN; + ChannelEnable(pcsr) = ALL_SWITCHES_OPEN; + + FASTLOCKINIT(&pc->lock); + + r0 = intConnect( + (unsigned char) INUM_TO_IVEC(la), + hpe1368a_int_service, + (void *) la); + if(r0 == ERROR) + return; + + sysIntEnable(HPE1368A_INT_LEVEL); + +} + + +/* + * + * hpe1368a_int_service() + * + */ +LOCAL void +hpe1368a_int_service(la) +unsigned la; +{ + struct hpe1368a_config *pc; + + pc = HPE1368A_PCONFIG(la); + if(pc == NULL){ + return; + } + + pc->busy = FALSE; +} + + +/* + * HPE1368A_STAT + * + * initialize single at5vxi card + * + */ +LOCAL void +hpe1368a_stat(la,level) +unsigned la; +int level; +{ + struct hpe1368a_config *pc; + struct vxi_csr *pcsr; + + pc = HPE1368A_PCONFIG(la); + if(pc == NULL){ + return; + } + pcsr = VXIBASE(la); + + if(level>0){ + printf("\tSwitch states %x\n", pc->shadow); + printf("\tModule status %x\n", pcsr->dir.r.status); + if(pc->busy){ + printf("\tModule is busy.\n"); + } + } +} + + + +/* + * + * HPE1368A_BO_DRIVER + * + * + * + */ +int +hpe1368a_bo_driver(la,val,mask) +register unsigned short la; +register unsigned int val; +unsigned int mask; +{ + struct hpe1368a_config *pc; + struct vxi_csr *pcsr; + unsigned int work; + + pc = HPE1368A_PCONFIG(la); + if(pc == NULL){ + return ERROR; + } + + pcsr = VXIBASE(la); + + FASTLOCK(&pc->lock); + + work = pc->shadow; + + /* alter specified bits */ + work = (work & ~mask) | (val & mask); + + pc->shadow = work; + + ChannelEnable(pcsr) = work; + + FASTUNLOCK(&pc->lock); + + return OK; +} + + + +/* + * + * HPE1368A_BI_DRIVER + * + * + * + */ +hpe1368a_bi_driver(la,mask,pval) +register unsigned short la; +unsigned int mask; +register unsigned int *pval; +{ + struct hpe1368a_config *pc; + + pc = HPE1368A_PCONFIG(la); + if(pc == NULL){ + return ERROR; + } + + FASTLOCK(&pc->lock); + + *pval = pc->shadow & mask; + + FASTUNLOCK(&pc->lock); + + return OK; +}