This manual has been written by Carsten Emde <ce@ceag.ch>.
Alpha is a trademark of Digital Equipment Corp. Eurocom is a registered trademark of Eltec Elektronik GmbH. PowerPC and MC68000 etc. are trademarks of Motorola, Inc. QNX is a registered trademark of QNX Software Systems Ltd. Universe is a trademark of Tundra Semiconductor Corporation.
The information contained in this manual is believed to be accurate as of the date of publication; neither ÄLVSJÖ DATA AB nor CE Computer Experts AG, however, will be liable for any damages, including directly or consequentially, from use of the software or reliance on the accuracy of this documentation. The information contained herein is subject to change without notice.
Due to the nature of a highly integrated chip such as the Tundra Universe, not all of the intended and documented functionality could be achieved in the final product. A current version of Tundra's Errata Sheet for the Universe chip was available when the v-q driver was developed, and all of the recommended solutions have been considered. In some cases, however, there were no appropriate solutions; ÄLVSJÖ DATA AB and CE Computer Experts AG reject any responsibility for such chip-related problems. The current version of the Errata Sheet may be obtained via Internet at the URL http://www.tundra.com.
|
These tasks are achieved by a PCI master, a PCI slave and a PCI interrupt interface to the PCI bus, and a VME master, a VME slave and a VME interrupt interface to the VMEbus. In order to use the Tundra Universe bridge, a wide variety of register settings must be done; in addition, the specific properties of the two very different bus architectures must be considered. Instead of re-inventing the wheel of Tundra Universe programming every time by every company, the required functionality is better integrated into a single software tool. This is the purpose of ÄLVSJÖ DATA's V-Q driver package for QNX described in this manual.
|
Irrespective of whether the v-q driver runs in file manager or in I/O control mode, it installs a virtual file in the system device directory (/dev) immediately after being invoked. The name of this device reflects the mode of operation as shown in the following table.
|
|
# install
as usual. After installation, the driver /bin/v-q, the utilities /bin/dump and /bin/dumpuni, and the example source environments of VMEaccess, VMEbench, VMEirq and VMEslave will appear on the system disk. To test the correct installation of the driver and the utilities, they may be started using the standard use utility or with the -? command line option both of which will produce a short usage message on screen:
# use v-q Function: 1. Create device '/dev/vme<base>' to access VMEbus window at <base> via Tundra Universe bridge. Default window size <length> is 65,536 Byte. 2. Option '-i': Create device '/dev/vmeioctl' to manage Tundra Universe bridge via special I/O control commands. 3. Option '-l<lvl>': Create device '/dev/vmeirq<lvl>' to manage VMEbus IRQ handlers for level <lvl>. Options: -1 force 8-bit access (D8) -2 force 16-bit access (D16) -4 force 32-bit access (D32) -s force short addressing mode (A16) -t force standard addressing mode (A24) -e force extended addressing mode (A32) -n non-privileged access (default supervisor) -p access VMEbus by pointer -i I/O control mode (may only be combined with -v or -vv) -l<lvl> IRQ handler mode (may only be combined with -v or -vv) -v verbose -vv even more verbose # use dump dump [-1|-1o|-2|-4|-b] <path> Options: -1 use 8-bit access -1o use 8-bit access (odd addresses only) -2 use 16-bit access -4 use 32-bit access -b access blocks of 256 Bytes at once (default) # use dumpuni Function: Display Tundra Universe registers Options: (none)
# v-q 0xfe800000 &
will create the device /dev/vmefe800000. Immediately after submitting this command, any program can access the static RAM on the PC Card using standard file I/O. If, for example, the first 256 Byte of this memory region need to be inspected, the provided dump utility can be used for this purpose:
# dump /dev/vmefe800000 Addr 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 2 4 6 8 A C E -------- ---- ---- ---- ---- ---- ---- ---- ---- ---------------- 00000000 1b00 0090 d823 62f8 9010 2001 4000 4bd0 ....X#bx.. .@.KP 00000010 d422 e2fc 8090 0008 0280 0108 b810 2000 T"b|........8. . 00000020 2100 0090 9e10 2001 de24 231c 2300 0090 !..... .^$#.#... 00000030 1080 0102 c024 6340 1100 0090 e402 2314 ....@$c@....d.#. 00000040 a404 a001 e422 2314 1100 0090 e802 2304 $. .d"#.....h.#. 00000050 a805 2001 1080 00f9 e822 2304 1100 0090 (. ....yh"#..... 00000060 ec02 230c ac05 a001 1080 00f4 ec22 230c l.#.,. ....tl"#. 00000070 1100 0090 d202 2360 9202 6001 1080 00ef ....R.#`..`....o 00000080 d222 2360 1100 0090 d602 2354 9602 e001 R"#`....V.#T..`. 00000090 1080 00ea d622 2354 1f00 0090 9a10 2001 ...jV"#T...... . 000000a0 da23 e31c 2100 0090 1080 00e4 c024 2340 Z#c.!......d@$#@ 000000b0 2300 0090 1080 00e1 c024 631c 2b00 0090 #......a@$c.+... 000000c0 2700 0090 a410 2001 e424 e320 e425 631c '...$. .d$c d%c. 000000d0 2d00 0090 c025 a340 1080 00d8 a810 2001 -...@%#@...X(. . 000000e0 1100 0090 1500 0090 c022 231c 9210 2001 ........@"#... . 000000f0 1080 00d2 d222 a340 1100 0090 d602 233c ...RR"#@....V.#<
If the same memory region is required within a program, the following sequence of C language instructions may be used:
#define BUFFERLEN 256 unsigned char buffer[BUFFERLEN]; int path; if ((path = open("/dev/vmefe800000", O_RDWR)) < 0) return(errno); return(0); if (read(path, buffer, sizeof(buffer)) != sizeof(buffer)) return(errno); return(0);
Similarly, of course, data can be written to this memory region. The following code writes the value of 206 to byte offset 16:
#define OFFSET_MODIFY 16 #define NEWVALUE 206 char c; if (lseek(path, OFFSET_MODIFY, SET_SEEK) < 0) return(errno); c = NEWVALUE; if (write(path, &c, sizeof(c)) != sizeof(c)) return(errno); return(0);
Alternatively, the entire memory block can be updated:
if (lseek(path, 0, SET_SEEK) < 0) return(errno); buffer[OFFSET_MODIFY] = NEWVALUE; if (write(path, buffer, sizeof(buffer)) != sizeof(buffer)) return(errno); return(0);
Several processes of the v-q driver may run simultaneously as long as they specify a different VMEbus base address. If the same address is specified twice, the driver aborts with error EEXIST, and the error message
v-q: driver for the specified VMEbus address already running
# v-q 0xffff0000 256 &
|
|
|
int qnx_ioctl(int path, QCTL_COMM_GET_VER, NULL, 0, NULL, 0);
returns version, release, edition and beta state of the v-q driver, every variable occupying one nibble of the unsigned short return value:
|
An example of the QCTL_COMM_GET_VER I/O control call is given in the source code of VMEslave (section 8.4.).
_qio_vmedev_slave slave; int qnx_ioctl(int path, QCTL_VMEDEV_SLAVE_OPEN, (void *) &slave, sizeof(slave), NULL, 0);
enables slave access of the local PCI bus from the VMEbus. Before calling this function, appropriate values must be assigned to all elements of the _qio_vmedev_slave structure. The window number windownum can only be 0, 1, 2 or 3, and the access modes addrsize, datatype, privilege, lockrmw (lock PCI bus during read-modify-write cycles) and space should only be assigned to one of the following predefined preprocessor variables that may be included from /usr/local/lib/VMEdev/VMEdev.h:
|
The transfer data structure has the following format and is used in the two functions QCTL_VMEDEV_SLAVE_OPEN and QCTL_VMEDEV_SLAVE_CLOSE:
typedef struct _qio_vmedev_slave_tag { unsigned char windownum, /* window number (0..3) */ addrsize, datatype, privilege, lockrmw, space; unsigned short reserved; unsigned long vmeaddr, /* VMEbus base address */ winsize, /* Window size */ pciaddr; /* PCI base address */ } _qio_vmedev_slave;The granularity of the specified base addressed may not exceed the specifications of the Universe chip:
|
The QCTL_VMEDEV_SLAVE_OPEN function returns 0, if the slave window could be installed as requested, -1 otherwise. In the latter case, the global variable errno is affected. Possible errors are EBUSY (the specified window number is already open) or EINVAL (one or more of the window specifications are illegal or the Universe chip could not be accessed). An example of the QCTL_VMEDEV_SLAVE_OPEN I/O control call is given in the source code of VMEslave (section 8.4.).
_qio_vmedev_slave slave; int qnx_ioctl(int path, QCTL_VMEDEV_SLAVE_CLOSE, (void *) &slave, sizeof(slave), NULL, 0);
disables slave access of the local PCI bus from the VMEbus. Before calling this function, the window number windownum of the _qio_vmedev_slave structure must be defined; all other structure elements will not be considered. The function returns 0, if the slave window was closed successfully, -1 otherwise. In the latter case, the global variable errno is affected. Possible errors are ENODEV (the specified window is not open) and EINVAL (the Universe chip could not be accessed). An example of the QCTL_VMEDEV_SLAVE_CLOSE I/O control call is given in the source code of VMEslave (section 8.4.).
char *vmeptr; _qio_vmedev_master master; int qnx_ioctl(int path, QCTL_VMEDEV_MASTER_OPEN, (void *) &master, sizeof(master), (void *) &vmeptr, sizeof(vmeptr));
retrieves a pointer to the specified VME memory range. A total of three windows are available, i.e. this functions may not be called more than three times. Before calling this function, appropriate values must be assigned to all elements of the _qio_vmedev_master structure. The access modes datasize, addrsize, datatype and privilege should only be assigned to one of the following predefined preprocessor variables that may be included from /usr/local/lib/VMEdev/VMEdev.h:
|
The transfer data structure has the following format and is used in the two functions QCTL_VMEDEV_MASTER_OPEN and QCTL_VMEDEV_MASTER_CLOSE:
typedef struct _qio_vmedev_master_tag { unsigned char datasize, addrsize, datatype, privilege; unsigned long vmeaddr, /* VMEbus base address */ winsize; /* Window size */ } _qio_vmedev_master;
The QCTL_VMEDEV_MASTER_OPEN function returns 0, if the slave window could be installed as requested, -1 otherwise. In the latter case, the global variable errno is affected. Possible errors are EBUSY (the available three windows are already in use) or EINVAL (one or more of the window specifications are illegal or the Universe chip could not be accessed). Before the retrieved pointer to physical memory can be used, it must be mapped to the program's memory space using the standard shared memory module /dev/shmem/Physical. This is normally done using the two functions shm_open() and mmap() as shown in the following example:
char *vmeptr_log, *vmeptr_phys; int shmpath; if ((shmpath = shm_open("Physical", O_RDWR, 0777)) < 0) { printf("Can't access physical memory due to error %d\n%s\n", errno, strerror(errno)); exit(EXIT_FAILURE); } if ((vmeptr_log = mmap(NULL, TESTSIZE, PROT_READ|PROT_WRITE, MAP_SHARED, shmpath, (long) vmeptr_phys)) < (char*) 0) { printf("Can't map physical memory due to error %d\n%s\n", errno, strerror(errno)); exit(EXIT_FAILURE); }
An example of the QCTL_VMEDEV_MASTER_OPEN I/O control call is given in the source code of VMEbench (section 8.2.).
int qnx_ioctl(int path, QCTL_VMEDEV_MASTER_CLOSE, NULL, 0, NULL, 0);
disables pointer access from the local PCI system to the VMEbus. The function returns 0, if the pointer was returned successfully, -1 otherwise. In the latter case, the global variable errno is affected. Possible errors are ENODEV (the pointer was never obtained) and EINVAL (the Universe chip could not be accessed). The function QCTL_VMEDEV_MASTER_CLOSE is called implicitly, whenever the /dev/vmeioctl device is closed; it is, however, considered good programming practice to call this function prior to close() (see example VMEbench in section 8.2.).
_qui_vmedev_slave_irq irq; int qnx_ioctl(int path, QCTL_VMEDEV_SLAVE_IRQ_OPEN, (void *) &irq, sizeof(irq), NULL, 0);
locally installs a VMEbus interrupt handler of specified level and vector. After having submitted this command, the program can use the Receive() function to asynchronously wait for a VMEbus interrupt to arrive. The transfer data structure has the following format and is used in the two functions QCTL_VMEDEV_SLAVE_IRQ_OPEN and QCTL_VMEDEV_SLAVE_IRQ_CLOSE:
typedef struct _qio_vmedev_slave_irq_tag { int locirq; int map; int vector; int ident; } _qio_vmedev_slave_irq;
The variable locirq must contain the number of the local ISA vector that is assigned to the Universe bridge (e.g. vector #10). It may be mapped using PCI interrupt 0 or 1 (usually 0), which can be specified in the map variable. This information can be obtained from the manufacturer of the VMEbus board. The required IRQ vector must be written to vector. The caller will only be informed, if both level (passed as command line option to the v-q driver) and vector exactly match. If the same program wants to install more than one VMEbus interrupt handler, identification information may be written to the variable ident. This value will be returned in the message part of the Receive() function in order to identify the origin of every message received. The QCTL_VMEDEV_SLAVE_IRQ_OPEN function returns 0, if the interrupt handler could be installed successfully, -1 otherwise. In the latter case, the global variable errno is affected. Possible errors are EBUSY (the specified interrupt level/vector combination is already in use), ENODEV (the specified device is not running in the requested I/O control mode), EINVAL (one or more of the interupt specifications are illegal or the Universe chip could not be accessed). The following program section exemplifies the usage of the QCTL_VMEDEV_SLAVE_IRQ_OPEN I/O control call.
/* Variable declaration */ int vmepath, ident; _qio_vmedev_slave_irq slave_irq; /* Open v-q device (must have been started with 'v-q -l3 &') */ vmepath = open("/dev/vmeirq3", O_RDONLY); /* Install interrupt handler */ slave_irq.locirq = 10; slave_irq.map = 0; slave_irq.vector = 128; slave_irq.ident = 12345678; qnx_ioctl(vmepath, QCTL_VMEDEV_SLAVE_IRQ_OPEN, (char *) &slave_irq, sizeof(slave_irq), NULL, 0); /* Wait until interrupt arrives */ Receive (0, &ident, sizeof(ident)); /* Deinstall interrupt handler */ qnx_ioctl(vmepath, QCTL_VMEDEV_SLAVE_IRQ_CLOSE, (char *) &slave_irq, sizeof(slave_irq), NULL, 0); /* Good bye */ close(vmepath);
A practical example of the QCTL_VMEDEV_SLAVE_IRQ_OPEN I/O control call is given in the source code of VMEirq (section 8.3.).
_qui_vmedev_slave_irq irq; int qnx_ioctl(int path, QCTL_VMEDEV_SLAVE_IRQ_CLOSE, (void *) &irq, sizeof(irq), NULL, 0);
disables the interrupt handler previously installed using the QCTL_VMEDEV_SLAVE_IRQ_OPEN I/O control mode. The element vector of the _qui_vmedev_slave_irq transfer structure must be set to the requested vector number, the other elements are not considered. The function QCTL_VMEDEV_SLAVE_IRQ_CLOSE is called implicitly, whenever the /dev/vmeirq<level> device is closed; it is, however, considered good programming practice to call this function prior to close().
_qui_vmedev_master_irq irq; int qnx_ioctl(int path, QCTL_VMEDEV_MASTER_IRQ_ASSERT, (void *) &irq, sizeof(irq), NULL, 0);
asserts a VMEbus interrupt of specified level and vector. This information must be written to the _qui_vmedev_master_irq structure prior to calling the QCTL_VMEDEV_MASTER_IRQ_ASSERT I/O control mode. The required transfer data structure has the following format:
typedef struct _qio_vmedev_master_irq_tag { int level; int vector; } _qio_vmedev_master_irq;
The function immediately returns after the IRQ was asserted. Possible errors are ENODEV (the specified device is not runing in this mode), and EINVAL (one or more of the interupt specifications are illegal or the Universe chip could not be accessed).
|
|
|
|
|
|
|
These options, however, have no effect on the v-q access data size, if one of the -1, -2, -4 driver options has been specified when v-q was started.
PCI_ID :000010E3 PCI_CSR :02000007 PCI_CLASS:06800000 PCI_MISC0:00800000 PCI_BS :03000000 PCI_MISC1:0003010A LSI0_CTL :00820000 LSI0_BS :20000000 LSI0_BD :22000000 LSI0_TO :60000000 LSI1_CTL :00800000 LSI1_BS :00000000 LSI1_BD :02000000 LSI1_TO :80000000 LSI2_CTL :00800000 LSI2_BS :00000000 LSI2_BD :00000000 LSI2_TO :00000000 LSI3_CTL :00800000 LSI3_BS :00000000 LSI3_BD :00000000 LSI3_TO :00000000 SCYC_CTL :00000000 SCYC_ADDR:00000000 SCYC_EN :00000000 SCYC_CMP :00000000 SCYC_SWP :00000000 LMISC :10000000 SLSI :00000000 L_CMDERR :70000000 LAERR :00000000 DCTL :00000080 DTBC :00000000 DLA :00000000 DVA :00000000 DCPP :00000000 DGCS :00000000 D_LLUE :00000000 LINT_EN :00000000 LINT_STAT:00004000 LINT_MAP0:00000000 LINT_MAP1:00000000 VINT_EN :00000000 VINT_STAT:00000000 VINT_MAP0:00000000 VINT_MAP1:00000000 STATID :FF000000 V1_STATID:00000000 V2_STATID:00000000 V3_STATID:00000000 V4_STATID:00000000 V5_STATID:00000000 V6_STATID:00000000 V7_STATID:00000000 MAST_CTL :80C00000 MISC_CTL :31040000 MISC_STAT:00260000 USER_AM :40400000 VSI0_CTL :00F00000 VSI0_BS :00000000 VSI0_BD :00000000 VSI0_TO :00000000 VSI1_CTL :00F00000 VSI1_BS :00000000 VSI1_BD :00000000 VSI1_TO :00000000 VSI2_CTL :00F00000 VSI2_BS :00000000 VSI2_BD :00000000 VSI2_TO :00000000 VSI3_CTL :00F00000 VSI3_BS :00000000 VSI3_BD :00000000 VSI3_TO :00000000 VRAI_CTL :00F00000 VRAI_BS :00000000 VCSR_CTL :00000000 VCSR_TO :00000000 V_AMERR :24000000 VAERR :800026FD VCSR_CLR :00000000 VCSR_SET :00000000 VCSR_BS :00000000
must be checked. As in the above example, the two least significant bytes must be 0x10e3 which is Tundra's registered vendor code.
#include <stdio.h> #include <stdlib.h> #include <errno.h> #include <fcntl.h> static void usage(void); /* * V M E a c c e s s * An example program to access the VMEbus via the v-q driver */ main(int argc, char *argv[]) { unsigned char buffer[256]; char *filename = NULL; int i, j, vmepath; for (i = 1; i < argc; i++) { if (argv[i][0] == '-') { for (j = 1; j < strlen(argv[i]); j++) { switch(argv[i][j]) { case '?': usage(); exit(EXIT_SUCCESS); break; default: printf("Option '%c' not recognized\n", argv[i][j]); exit(EXIT_FAILURE); break; } } } else if (filename == NULL) filename = argv[i]; else { printf("No more than one argument accepted\n"); exit(EXIT_FAILURE); } } if (filename == NULL) { printf("The v-q device, e.g. /dev/vme80000000, must be specified\n"); exit(EXIT_FAILURE); } if ((vmepath = open(filename, O_RDONLY)) < 0) { printf("Can't open v-q device '%s' due to error %d\n%s\n", filename, errno, strerror(errno)); exit(EXIT_FAILURE); } if (read(vmepath, buffer, sizeof(buffer)) < 1) { printf("Can't read from v-q device '%s' due to error %d\n%s\n", filename, errno, strerror(errno)); exit(EXIT_FAILURE); } printf("First byte read from v-q device '%s' is 0x%02x\n", filename, buffer[0]); close(vmepath); } /* * u s a g e */ #define __USAGE 1 static void usage(void) { #ifdef __USAGE puts("Syntax: VMEaccess [<opts>] <path>"); puts("Function: Exemplify usage of v-q driver (VMEbus master access)"); puts("Options:"); puts(" (none)"); #endif }
#include <stdio.h> #include <stdlib.h> #include <signal.h> #include <errno.h> #include <fcntl.h> #include <sys/mman.h> #include "../VMEdev/VMEdev.h" #define TESTDURATION 5 #define TESTADDR 0x80000000 #define TESTSIZE 0x10000 static void usage(void); static unsigned char buffer[0x10000]; volatile sig_atomic_t elapsed; /* * a l a r m h a n d l e r */ void alarmhandler(/* int signo */) { elapsed = 1; } /* * V M E b e n c h * An example program to benchmark VMEbus accesses via the v-q driver */ main(int argc, char *argv[]) { char filename_vq[32], *filename_io = "/dev/vmeioctl"; char *shmname = "Physical"; char *vmeptr_log, *vmeptr_phys; int i, j, vmepath, shmpath, size, loops, throughput; int accioctl = 0, accstdio = 0; _qio_vmedev_master master; for (i = 1; i < argc; i++) { if (argv[i][0] == '-') { for (j = 1; j < strlen(argv[i]); j++) { switch(argv[i][j]) { case 'i': accioctl = 1; break; case 's': accstdio = 1; break; case '?': usage(); exit(EXIT_SUCCESS); break; default: printf("Option '%c' not recognized\n", argv[i][j]); exit(EXIT_FAILURE); break; } } } else { printf("No arguments accepted\n"); exit(EXIT_FAILURE); } } if (accioctl == 0 && accstdio == 0) accioctl = accstdio = 1; signal(SIGALRM, alarmhandler); if (accstdio) { printf("Test VMEbus access via standard read/write\n"); printf("------------------------------------------\n"); sprintf(filename_vq, "/dev/vme%08x", TESTADDR); if ((vmepath = open(filename_vq, O_RDONLY)) < 0) { printf("Can't open v-q device '%s' due to error %d\n%s\n", filename_vq, errno, strerror(errno)); printf("Please run 'v-q [-x] 0x%08x 0x%08x &'\n", TESTADDR, TESTSIZE); exit(EXIT_FAILURE); } for (size = 1; size <= sizeof(buffer); size <<= 1) { elapsed = 0; loops = 0; if (alarm(TESTDURATION) < 0) { printf("No timer available, aborting\n"); exit(EXIT_FAILURE); } while (!elapsed) { lseek(vmepath, 0, SEEK_SET); if (read(vmepath, buffer, size) < 1 && errno != 4) { printf("Can't read from v-q device '%s' due to error %d\n%s\n", filename_vq, errno, strerror(errno)); exit(EXIT_FAILURE); } loops++; } throughput = (loops * size) / TESTDURATION; printf("Access data size %5d Bytes: %7d Bytes read per second\n", size, throughput); fflush(stdout); } close(vmepath); } if (accioctl) { if (accstdio) printf("\n\n"); printf("Test VMEbus access via special I/O control\n"); printf("------------------------------------------\n"); if ((vmepath = open(filename_io, O_RDONLY)) < 0) { printf("Can't open v-q device '%s' due to error %d\n%s\n", filename_io, errno, strerror(errno)); printf("Please run 'v-q -i &'\n"); exit(EXIT_FAILURE); } master.datasize = VMEDEV_MASTER_DATASIZE_D32; master.addrsize = VMEDEV_MASTER_ADDRSIZE_A32; master.datatype = VMEDEV_MASTER_DATATYPE_DATA; master.privilege = VMEDEV_MASTER_PRIVILEGE_USER; master.vmeaddr = TESTADDR; master.winsize = TESTSIZE; vmeptr_phys = 0; if (qnx_ioctl(vmepath, QCTL_VMEDEV_MASTER_OPEN, (char *) &master, sizeof(master), (char *) &vmeptr_phys, sizeof(vmeptr_phys)) < 0) { printf("Can't get pointer to VMEbus via '%s' due to error %d\n%s\n", filename_io, errno, strerror(errno)); exit(EXIT_FAILURE); } if ((shmpath = shm_open(shmname, O_RDWR, 0777)) < 0) { printf("Can't access physical memory due to error %d\n%s\n", errno, strerror(errno)); exit(EXIT_FAILURE); } if ((vmeptr_log = mmap(NULL, TESTSIZE, PROT_READ|PROT_WRITE, MAP_SHARED, shmpath, (long) vmeptr_phys)) == (char*) -1) { printf("Can't map physical memory due to error %d\n%s\n", errno, strerror(errno)); exit(EXIT_FAILURE); } for (size = 1; size <= sizeof(buffer); size <<= 1) { elapsed = 0; loops = 0; if (alarm(TESTDURATION) < 0) { printf("No timer available, aborting\n"); exit(EXIT_FAILURE); } switch (size) { case 1: while (!elapsed) { *buffer = *vmeptr_log; loops++; } break; case 2: while (!elapsed) { *((short *) buffer) = *((short *) vmeptr_log); loops++; } break; case 4: while (!elapsed) { *((long *) buffer) = *((long *) vmeptr_log); loops++; } break; case 8: while (!elapsed) { *((long *) buffer) = *((long *) vmeptr_log); *((long *) (buffer + 4)) = *((long *) (vmeptr_log + 4)); loops++; } break; case 16: while (!elapsed) { *((long *) buffer) = *((long *) vmeptr_log); *((long *) (buffer + 4)) = *((long *) (vmeptr_log + 4)); *((long *) (buffer + 8)) = *((long *) (vmeptr_log + 8)); *((long *) (buffer + 12)) = *((long *) (vmeptr_log + 12)); loops++; } break; default: while (!elapsed) { memcpy(buffer, vmeptr_log, size); loops++; } break; } throughput = (loops * size) / TESTDURATION; printf("Access data size %5d Bytes: %7d Bytes read per second\n", size, throughput); fflush(stdout); } qnx_ioctl(vmepath, QCTL_VMEDEV_MASTER_CLOSE, NULL, 0, NULL, 0); close(vmepath); } } /* * u s a g e */ #define __USAGE 1 static void usage(void) { #ifdef __USAGE puts("Syntax: VMEbench [<opts>]"); puts("Function: Exemplify usage of v-q driver (VMEbus benchmark)"); puts("Options:"); puts(" -s access via standard read/write"); puts(" -i access via special I/O control"); #endif }
#include <stdio.h> #include <stdlib.h> #include <errno.h> #include <signal.h> #include <fcntl.h> #include <sys/kernel.h> #include "../VMEdev/VMEdev.h" #define LEVEL 3 #define VECTOR 0 #define MYIDENT 3262 /* As good as any number */ static void usage(void); volatile sig_atomic_t ctrl_c; void breakhandler(int signum) { ctrl_c = 1; } /* * V M E i r q * An example program to install VMEbus IRQ via the v-q driver */ main(int argc, char *argv[]) { char filename[32]; int i, j, irqhndlpath, irqassertpath, sendpid, ident; int locirq = -2, level = -1, vector = -1, assert = 0; _qio_vmedev_slave_irq slave_irq; _qio_vmedev_master_irq master_irq; for (i = 1; i < argc; i++) { if (argv[i][0] == '-') { for (j = 1; j < strlen(argv[i]); j++) { switch(argv[i][j]) { case 'a': assert = 1; break; case '?': usage(); exit(EXIT_SUCCESS); break; default: printf("%s: Option '%c' not recognized\n", argv[0], argv[i][j]); exit(EXIT_FAILURE); break; } } } else { if (locirq == -2) { if (!strcmp(argv[i], "none")) locirq = -1; else locirq = atoi(argv[i]); if (locirq != -1 && !(locirq > 0 && locirq < 16)) { printf("%s: Invalid number (%d) specified for local IRQ\n", argv[0], locirq); exit(EXIT_FAILURE); } } else if (level == -1) { level = atoi(argv[i]); if (level < 1 || level > 7) { printf("%s: Invalid number (%d) specified for IRQ level\n", argv[0], level); exit(EXIT_FAILURE); } } else if (vector == -1) { vector = atoi(argv[i]); if (vector < 0 || vector > 255) { printf("%s: Invalid number (%d) specified for IRQ vector\n", argv[0], vector); exit(EXIT_FAILURE); } } else { printf("No more than three arguments accepted\n"); exit(EXIT_FAILURE); } } } if (locirq == -2) locirq = -1; if (level == -1) level = LEVEL; if (vector == -1) vector = VECTOR; if (assert) { if ((irqassertpath = open("/dev/vmeioctl", O_RDONLY)) < 0) { printf("Can't open v-q device '/dev/vmeioctl' due to error %d\n%s\n", errno, strerror(errno)); printf("Please run 'v-q -i &'\n"); exit(EXIT_FAILURE); } master_irq.level = level; master_irq.vector = vector; if (qnx_ioctl(irqassertpath, QCTL_VMEDEV_MASTER_IRQ_ASSERT, (char *) &master_irq, sizeof(master_irq), NULL, 0) < 0) { printf("Can't assert VMEbus IRQ due to error %d\n%s\n", errno, strerror(errno)); exit(EXIT_FAILURE); } close(irqassertpath); } else { signal(SIGINT, breakhandler); sprintf(filename, "/dev/vmeirq%1d", level); if ((irqhndlpath = open(filename, O_RDONLY)) < 0) { printf("Can't open v-q device '%s' due to error %d\n%s\n", filename, errno, strerror(errno)); printf("Please run 'v-q -l%d &'\n", level); exit(EXIT_FAILURE); } slave_irq.locirq = locirq; slave_irq.map = 0; slave_irq.vector = vector; slave_irq.ident = MYIDENT; if (qnx_ioctl(irqhndlpath, QCTL_VMEDEV_SLAVE_IRQ_OPEN, (char *) &slave_irq, sizeof(slave_irq), NULL, 0) < 0) { printf("Can't install VMEbus IRQ via '%s' due to error %d\n%s\n", filename, errno, strerror(errno)); exit(EXIT_FAILURE); } while ((sendpid = Receive(0, &ident, sizeof(ident))) != -1) { if (locirq == -1) printf("Message from Tundra Universe IRQ handler received\n"); else { if (ident == MYIDENT) printf("Message from VMEbus IRQ (level %d, vector %d) received\n", level, vector); else printf("Can't happen\n"); } } if (sendpid == -1) { if (ctrl_c) printf("User abort\n"); else printf("Unknown message received\n"); } qnx_ioctl(irqhndlpath, QCTL_VMEDEV_SLAVE_IRQ_CLOSE, (char *) &slave_irq, sizeof(slave_irq), NULL, 0); close(irqhndlpath); } } /* * u s a g e */ #define __USAGE 1 static void usage(void) { #ifdef __USAGE puts("Syntax: VMEirq <local irq> [<level>] [<vector>] [<opts>]"); puts("Function: Exemplify usage of v-q driver (VMEbus IRQ)"); puts("Options:"); puts(" -a assert interrupt (default handle)"); #endif }
#include <stdio.h> #include <stdlib.h> #include <errno.h> #include <fcntl.h> #include <sys/types.h> #include <sys/qioctl.h> #include "VMEdev.h" static void usage(void); /* * V M E s l a v e * An example program to open a VMEbus slave window via the v-q driver */ main(int argc, char *argv[]) { char *filename = "/dev/vmeioctl"; int i, j, vmepath, retval; _qio_vmedev_slave slave; for (i = 1; i < argc; i++) { if (argv[i][0] == '-') { for (j = 1; j < strlen(argv[i]); j++) { switch(argv[i][j]) { case '?': usage(); exit(EXIT_SUCCESS); break; default: printf("Option '%c' not recognized\n", argv[i][j]); exit(EXIT_FAILURE); break; } } } else { printf("No argument accepted\n"); exit(EXIT_FAILURE); } } if ((vmepath = open(filename, O_RDONLY)) < 0) { printf("Can't open v-q device '%s' due to error %d\n%s\n", filename, errno, strerror(errno)); exit(EXIT_FAILURE); } if ((retval = qnx_ioctl(vmepath, QCTL_COMM_GET_VER, NULL, 0, NULL, 0)) == -1) { printf("Can't get ioctl version info from v-q device '%s' due to error %d\n%s\n", filename, errno, strerror(errno)); exit(EXIT_FAILURE); } printf("Version of v-q device '%s' is %d.%d, edition %d%s\n", filename, (retval >> 12) & 0x0f, (retval >> 8) & 0x0f, (retval >> 4) & 0x0f, (retval & 0x0f) ? " (beta)" : ""); slave.windownum = 0; slave.addrsize = VMEDEV_SLAVE_ADDRSIZE_A32; slave.datatype = VMEDEV_SLAVE_DATATYPE_DATA; slave.privilege = VMEDEV_SLAVE_PRIVILEGE_BOTH; slave.lockrmw = VMEDEV_SLAVE_LOCKRMW_ENABLE; slave.space = VMEDEV_SLAVE_SPACE_MEMORY; slave.vmeaddr = 0x70000000; slave.winsize = 0x00100000; slave.pciaddr = 0; /* close the window: it *might* be open */ qnx_ioctl(vmepath, QCTL_VMEDEV_SLAVE_CLOSE, (void *) &slave, sizeof(slave), NULL, 0); if (qnx_ioctl(vmepath, QCTL_VMEDEV_SLAVE_OPEN, (void *) &slave, sizeof(slave), NULL, 0) < 0) { printf("Can't open VMEbus slave window via v-q device '%s' due to error %d\n%s\n", filename, errno, strerror(errno)); exit(EXIT_FAILURE); } printf("Enabled PCI slave window at 0x%08x to VMEbus at 0x%08x\n", slave.pciaddr, slave.vmeaddr); printf("Hit enter to close the window\n"); getchar(); if (qnx_ioctl(vmepath, QCTL_VMEDEV_SLAVE_CLOSE, (void *) &slave, sizeof(slave), NULL, 0) == -1) { printf("Can't close VMEbus slave window via v-q device '%s' due to error %d\n%s\n", filename, errno, strerror(errno)); exit(EXIT_FAILURE); } printf("PCI slave window closed\n"); close(vmepath); } /* * u s a g e */ #define __USAGE 1 static void usage(void) { #ifdef __USAGE puts("Syntax: VMEslave [<opts>] <path>"); puts("Function: Exemplify usage of v-q driver (VMEbus slave window)"); puts("Options:"); puts(" (none)"); #endif }