[comp.sys.hp] Needed: Interrupt handler.

kay@iccgcc.decnet.ab.com (10/26/90)

We're running HPUX 7.0 on a V/360 VXI workstation.  We've installed a VME
card in the VXI rack.  Can anyone tell us, or better yet, give us some example
code, on how to establish an interrupt handler for the VME card?

We have the VXI drivers software but the interrupt support doesn't seem to
apply to VME devices.

Thanks in advance.


Jim Kay
kay@astro.pc.ab.com

glen@hpfcmgw.HP.COM (Glen Robinson) (10/29/90)

kay@iccgcc.decnet.ab.com - writes:

>We're running HPUX 7.0 on a V/360 VXI workstation.  We've installed a VME
>card in the VXI rack.  Can anyone tell us, or better yet, give us some example
>code, on how to establish an interrupt handler for the VME card?
>
>We have the VXI drivers software but the interrupt support doesn't seem to
>apply to VME devices.
>
>Thanks in advance.
>
>
>Jim Kay
>kay@astro.pc.ab.com
----------

Well, actually you've got a problem here.  VXI interrupts on the V/360 are
not the same class of critters as hardware vectored interrupts on VME.

Someone from the folks who support/market V360's correct me if I'm wrong
here but I believe that the VXI stuff gets put into a HP-UX interrupt
service request chain which is polled to determine the interrupt initiator.

VME on the other hand expects to vector directly to your driver's interrupt
routine.  You are probably going to have to write your own driver if you
need to handle hardware vectored interrupts.  The pertinent data is in
the HP-UX Driver Development Guide (98577-90011) for VME.  However, there
is nothing in there for the V360.  My guess is you would need to do the
appropriate mapping using the VXI driver to enable processor -- VME card
communication and then use your driver to handle the actual reads/writes/
interrupts et. al.  None of the above is trivial or for the faint of heart.

Finally, of course, make sure that your VME card does not use P2A or P2C
because VXI specifically defines these pins.

Best regards and good luck.

Glen R

The usual proclamations here that these comments are mine alone and do not 
reflect ... nor set policy ... for my employer.

pha@hplvli.HP.COM (Rick Adams) (10/31/90)

First a disclaimer: I am by no means an expert on this subject.  However, 
I do have some recent experience using the VXI dil extensions and the 
somewhat opaque documentaion (just my personal opinion!) that accompanies 
it.

All of the interrupt request lines (IRQ1*-IRQ7*) are merged into a single
event, VXI_PSIGNAL_VME, that can optionally be used to send a unix signal
to your process.  If your VME device releases its request when it is 
acknowledged by the interrupt handler (I am assuming it will be the V360)
then there appears to be no immediate way of determining which IRQ caused the
signal to be sent, it appears that you have to poll all possible interrupters.
If your VME device does not release its request until some register is read 
(a so-called RORA device) then there is an ioctl call which allows you to 
determine the current state of all IRQ lines.

The following is an example of the way I used the provided interrupt
service functions.

----------------------
#include <sys/vxi.h>

int vxi_eid;
.
.
.
.
    /* Somewhere in an initialization function */
    stuct interrupt_struct my_int_cause;  /* struct found in vxi.h */
    int (*isr_hook)();

    vxi_eid = open( "/dev/vxi/primary", O_RDWR );

    my_int_cause.cause = VXI_INT_VME;  /* name defined in vxi.h */
    isr_hook = io_on_interrupt( vxi_eid, my_int_cause, my_isr );
    if ( isr_hook == (int(*)()) -1 ) {
        /* take some failure action */
    }
    .
    .
    .
void my_isr( )
{
    /* Do what ever needs doing here but be cautious.
       Signals that arrive while you are in this function
       are lost! 
    /*
    io_interrupt_ctl( vxi_eid, 1 );  /* Must re-enable interrupt signalling */
}

----------------------

Hope this was some help,
    Rick Adams, Hewlett-Packard, Loveland Instrument Division

larryc@hpislx.HP.COM (Larry Corsa) (11/02/90)

/ hpislx:comp.sys.hp / kay@iccgcc.decnet.ab.com /  3:45 pm  Oct 25, 1990 /

>>  We're running HPUX 7.0 on a V/360 VXI workstation.  We've installed a V
>>  card in the VXI rack.  Can anyone tell us, or better yet, give us some 
>>  code, on how to establish an interrupt handler for the VME card?
>>  
>>  We have the VXI drivers software but the interrupt support doesn't seem
>>  apply to VME devices.

Au contraire, mon frere.

VXI is a (mostly) pure superset of the VME bus.  The impurities stem mostly
from VME's lack of definition of P2 functionality.

Most of the V/360's VXI driver is centered around VXI devices (obviously)
which support a set of standard registers (card ID, etc.) and *may* support
high level protocols (word serial).  Well-behaved VME devices are certainly
welcome.  

I've attached some example code for an HP B-sized card.  This card does
implement the VXI device registers and so can identify itself to the VXI
resource manager, but is otherwise a pretty straightforward
register-based card, ala VME.

The incremental effort required to get interrupts from a pure VME card is:
1) identify your board to the resource mgr by using the "vmedevices"
config file.
2) instead of mapping a VXI device's A16 registers, you'll use
vxi_map_a24 (or a32) to get a pointer to the start of your card's
registers.
3) when the interrupt occurs, if the interrupt_struct-->cause is
VXI_INT_VME, the mask will be the IACK value defined by your card.


Regards,

Larry Corsa 

Technical Support Engineer     
Hewlett-Packard Company        
Measurement Systems Operation  
815 14th Street SW             
Mail Stop CU312                
Loveland, CO 80537, USA        
larryc@hpisla.lvld.hp.com



/*file: E1332Afreq.c */

/*********************************************************************
 *     Program for frequency measurements using HP E1332A Counter    *
 *********************************************************************/

#include <stdio.h>
#include <fcntl.h>
#include "sys/vxi.h"          /*source file for HP V/360 VXI drivers*/

#define	logical_address		48	/*Logical Address of HP E1332A*/
 
/*Initialize interrupt flag*/
int i_flag =0;

typedef unsigned short word;
typedef struct device_registers {  
	word id_register;
	word devtype_register;
	word statuscontrol_register;
	word reserved_register;
	word cmdresponse_register;
	word parameter_register;
	word reserved2_register;
	word ivector_register;
	}DEVICE_REGISTERS;

/*Function to reset the HP E1332A counter*/
void reset_dac32A(d32A_ptr)
DEVICE_REGISTERS *d32A_ptr;
{
 int l;
 /*send reset command 15 to command register*/
  d32A_ptr->cmdresponse_register=15;
 /*wait for READY bit to become valid*/
  while(((d32A_ptr->statuscontrol_register)&1)==0);
 /*send parameter to begin reset activity*/
  d32A_ptr->parameter_register=0;
 
 /*Wait a few microseconds to allow reset activity to complete*/
  for (l=0;l<100;l++) {}
}

/*Function to send commands and parameter to HP E1332A counter*/
void dac32A_send(d32A_ptr,command,parameter)
DEVICE_REGISTERS *d32A_ptr;
int command, parameter;
{
 /*wait for READY bit to become valid*/
  while(((d32A_ptr->statuscontrol_register)&1)==0);
 /*send the command to the command register*/
  d32A_ptr->cmdresponse_register=command;
 /*wait for the READY bit to become valid*/
  while(((d32A_ptr->statuscontrol_register)&1)==0);
 /*send the parameter to the parameter register*/
  d32A_ptr->parameter_register=parameter;
}

/*Function to retrieve and convert the counter reading*/
float d32A_read(d32A_ptr,command,channel)
DEVICE_REGISTERS *d32A_ptr;
{
 float result, r_exp = 1;
 int k;
 unsigned short data_word;

 /*wait for DONE, QUERY RESPONSE and READY bits to become valid*/
  while(((d32A_ptr->statuscontrol_register)&0x83)!=0x83);
 /*get the first byte of data*/
  data_word = ((d32A_ptr->cmdresponse_register)&0xff);
 /*check for overflow*/
  if ((data_word &1) == 1)
   {
    printf("\n\nOVERFLOW OCCURRED - DATA INVALID\n");
    exit(0);
   }
 /*place first byte in the result variable*/
  result = data_word << 32;
 /*wait for QUERY RESPONSE REGISTER READY bit to become valid*/
  while(((d32A_ptr->statuscontrol_register)&2)==0);
 /*get second byte of data*/
  data_word = ((d32A_ptr->cmdresponse_register)&0xff);
  result = result + (data_word << 24);
 /*wait for QUERY RESPONSE REGISTER READY bit to become valid*/
  while(((d32A_ptr->statuscontrol_register)&2)==0);
 /*get third byte of data*/
  data_word = ((d32A_ptr->cmdresponse_register)&0xff);
  result = result +(data_word << 16);
 /*wait for QUERY RESPONSE REGISTER READY bit to become valid*/
  while(((d32A_ptr->statuscontrol_register)&2)==0);
 /*get fourth byte of data*/
  data_word = ((d32A_ptr->cmdresponse_register)&0xff);
  result = result +  (data_word << 8);
 /*wait for QUERY RESPONSE REGISTER READY bit to become valid*/
  while(((d32A_ptr->statuscontrol_register)&2)==0);
 /*get fifth byte of data*/
  data_word = ((d32A_ptr->cmdresponse_register)&0xff);
  result = result + data_word;
 /*wait for QUERY RESPONSE REGISTER READY bit to become valid*/
  while(((d32A_ptr->statuscontrol_register)&2)==0);
 /*get sixth byte of data*/
  data_word = ((d32A_ptr->cmdresponse_register)&0xff);
 /*convert sixth byte, the exponent*/
   for (k=data_word-128; k<0; k++)
	{
      r_exp = r_exp/2;
    }
 result = result * r_exp;
 return result;
}


/*Interrupt handler routine*/
int handler(eid,causevec)
int eid;
struct interrupt_struct *causevec;
{
 /*set the interrupt flag to alert main program that counter has reading*/
  i_flag=1;
 /*ensure the correct interrupt has occurred*/
 if ((causevec->mask&0xffff) != 0xef30)
 {
  printf("\n\nReceived incorrect interrupt vector\n");
  printf("Expected interrupt from E1332A at logical address 48\n");
  printf("\n Received interrupt vector: %x HEX\n",causevec->mask&0xffff);
  printf("   Expecting: ef30  HEX \n");
  printf("     ef HEX --> channel one frequency complete\n");
  printf("     30 HEX --> logical address of 48\n");
  exit(0);
 }
}

main()
{
 int eid;
 DEVICE_REGISTERS *dev;
 int i;
 struct interrupt_struct causevec;
 float reading;


/*Open the HP V/360 VXI interface*/
 eid=open("/dev/vxi/primary",O_RDWR);
    if(eid<0){
    perror("open");
    exit(1);
             }

/*Mask for VME interrupts*/
 causevec.cause = 0x2;
/*Set up interrupt handler for interrupting device*/
 io_on_interrupt(eid,&causevec,handler);
/*Enable interrupts on on the VXI interface*/
 io_interrupt_ctl(eid,1);

/*Retrieve the pointer for the A16 registers of the device*/
 dev=(DEVICE_REGISTERS *)vxi_get_a16_addr(eid,logical_address);

/*Call the function to reset the counter*/
reset_dac32A(dev);

/*Set the function: Frequency with 1024 msec gate time*/
dac32A_send(dev,4,9);

/*Let computer perform some other task while waiting for interrupt*/
for (i=0;i<3500;i++)
     {
      printf("\r%i",i);
       /*check interrupt flag and if set, end looping*/
	   if (i_flag ==1)
		{ i=4000; }
     } 


/*Send the command to read the result*/ 
dac32A_send(dev,14,0);  

/*Call the function to retrieve and convert the reading*/
reading = d32A_read(dev,14,0);

/*Print out the measured frequency*/
 printf("\nFrequency is %.1f \n",reading);
}

ronh@hplvli.HP.COM (Ron Hanson) (11/07/90)

/ hplvli:comp.sys.hp / kay@iccgcc.decnet.ab.com /  3:45 pm  Oct 25, 1990 /

We're running HPUX 7.0 on a V/360 VXI workstation.  We've installed a VME
card in the VXI rack.  Can anyone tell us, or better yet, give us some example
code, on how to establish an interrupt handler for the VME card?

We have the VXI drivers software but the interrupt support doesn't seem to
apply to VME devices.

Thanks in advance.


Jim Kay
kay@astro.pc.ab.com
----------

ronh@hplvli.HP.COM (Ron Hanson) (11/07/90)

/ hplvli:comp.sys.hp / ronh@hplvli.HP.COM (Ron Hanson) /  4:50 pm  Nov  6, 1990 /
/ hplvli:comp.sys.hp / kay@iccgcc.decnet.ab.com /  3:45 pm  Oct 25, 1990 /

We're running HPUX 7.0 on a V/360 VXI workstation.  We've installed a VME
card in the VXI rack.  Can anyone tell us, or better yet, give us some example
code, on how to establish an interrupt handler for the VME card?

We have the VXI drivers software but the interrupt support doesn't seem to
apply to VME devices.

Thanks in advance.


Jim Kay
kay@astro.pc.ab.com
----------
----------

===============================================

I would like to add to all the previous responses the following notes:

The V/360 responds with a D32 IACK cycle in response to VME interrupts 
on the backplane.  It the device is a D32 interrupter, you will get all 
32 bits.  If the device is a D16 or D08(O) interrupter, then only the
lower 16 or 8 bits of the IACK word will be significant (the remaining
bits will be set to 1).  This allows the V/360 to handle the different
types of interrupters [as a matter of fact, the register-based device
examples in Larry Corsa's note are D16 interrupters].

Secondly, if you have multiple interrupters, remember to re-enable the
interrupt on the interface using the io_interrupt_ctl function in your
hanler.

Ron Hanson
Application Support Engineer
Loveland Instrument Division, Hewlett-Packard Company