Sun VMEbus memory mapping for video frame grabber
Joseph Yip
ycy at walt.cc.utexas.edu
Tue Feb 27 15:17:12 AEST 1990
We bought a frame grabber from Imaging Technology Inc. for our Sun 4
(VMEbus). The board is supposed to come with the Toolbox (free) which
contains some programs on programming the frame grabber. But, Imaging
Tech. Inc. (ITI) stopped shipping the Toolbox AFTER we bought it! In the
diagnostic tape, I found this map.c source file which I think will help me
to program the interface between the Sun and the frame grabber. There are
a few questions I want to ask concerning interfacing with the VMEbus and
external hardware. First, I will describe what the frame grabber is like.
- VMEbus standard 16-bit data bus, 24-bit address bus
- 512 Kbytes of frame memory are memory mapped at one time
- frame memory and look-up tables are mapped into VMEbus standard
(24-bit address) non-privileged and supervisory address space.
- Registers are mapped into short (16-bit address) non-privileged and
supervisory address space.
Factory setting:
Register base address is set to 0x1000. All registers are I/O mapped
relative to this base address. The registers occupy
16 words within this space.
Memory base address is set to 0xA00000
The frame memory and look-up tables (LUTs) are memory-mapped, occupying 512K
bytes within the host computer memory address space, giving the host direct
access to the 512K bytes of memory. The LUTs are mapped into the same memory
space as the frame memory. During LUT addressing only the lower 32K
bytes are used.
The 16 registers that are I/O mapped occupying 16 words in the host computer
address space are used to program the frame grabber functions. So, to use the
frame grabber I need to handle the memory mapping. Once I can read and write to
registers and read and write to frame memory, I am home free!
The questions are as follows:
- what are the /dev/vme16d16 and /dev/vme24d16 device drivers? How do
they work? /dev/vme16d16 associates with I/O and /dev/vme24d16
associated with the memory.
- How does the mmap() work? The function returns the logical address.
How is the logical address be useful? How does the mmap() function
- mmap() takes 6 parameters. The "flags" parameter needs to be either
MAP_SHARED, MAP_FIXED, ... How do the MAP_SHARED and MAP_FIXED work?
work in mappng the register base address and the memory base address?
- In doing the mapping, why do we need to concern with the pagesize of
the system? Or even the page memory alignment.
- if the frame memory is memory mapped and if MAP_SHARED is set, then
changes in the frame memory or changes in the mapped memory space
should reflect changes in the corresponding mapped space?
- the map() (from map.c) below opens the appropriate device driver,
performs the mapping and returns the logical address. So, if I do
unsigned char *regbase;
/* IO indicates I/O mapping, 0x1000 = register base
32 = there are 16 registers (16 bit each)
*/
regbase = map(IO, 0x1000, 32);
/* if (regbase + 8) = status/control register, for frame
grabbing, snapping, ...
*/
*(regbase + 8) |= (SNAP); /* set bit to snap a frame */
should work. Right?
Thank you.
Joseph Yip
---------------------------------------------------------------------------
/* the following is part of the map.c file */
/*
* map.c Map bus address space to physical address space
* and return the base logical address of the mapped block.
*
* Synopsis: BYTE *map( mio, physaddr, size )
* short mio;
* DWORD physaddr;
* DWORD size;
*
* physaddr is a physical address.
*
* mio = IO (0) if physaddr is an I/O address.
* mio = MEM (1) if physaddr is a memory address.
*
* size is the size ( in bytes ) of the block.
*
* BYTE is typedef'd to be an unsigned 8-bit type
*
* DWORD is typedef'd to be an unsigned 32-bit type
*/
static struct {
char *iodevice; /* name of I/O space device driver */
char *memdevice; /* name of Memory space device driver */
} bus[] = {
"/dev/vme16d16", "/dev/vme24d16",
"/dev/vme16", "/dev/vme24",
0, 0
};
static int BUS_FD; /* file descriptor for the bus device */
static int IOBUS, MEMBUS; /* used by unmap() */
static DWORD logaddr; /* page-aligned logical base address */
static DWORD psize; /* determine system page size */
static DWORD raw_logaddr; /* unaligned logical base address */
static DWORD ioraw_logaddr, memraw_logaddr; /* used by unmap() */
static DWORD length; /* page-aligned block size */
static int nomap = 0; /* debug flag */
BYTE *map( mio, physaddr, size )
short mio; /* memory or I/O space */
DWORD physaddr; /* physical base address */
DWORD size; /* size of the mapped block needed */
{
DWORD offset; /* offset of physaddr */
/* from nearest page boundary */
char s[80]; /* message buffer */
int b; /* bus[] index */
int busfound; /* bus "found" flag */
DWORD v; /* mmap() return value */
psize = getpagesize(); /* determine system page size */
/*
* open the appropriate backplane bus device driver:
*
* - search through list of backplane bus device drivers
* - if unsuccessful in opening any device drivers, then
* report error and die
*/
for (b = 0, busfound = 0; bus[b].iodevice != (char *)0; b++) {
BUS_FD = open( (mio == 0) ? bus[b].iodevice : bus[b].memdevice,
2 );
if (BUS_FD >= 0) {
/* save file descriptor for use by unmap() */
if (mio == 0)
IOBUS = BUS_FD;
else
MEMBUS = BUS_FD;
busfound = 1;
break;
}
}
if (!busfound && (nomap == 0)) {
fprintf( stderr,
" Can't open %s space device driver. \n\n",
(mio == 0) ? "I/O" : "Memory" );
fprintf( stderr,
" Read/Write permissions have not been enabled for the \n" );
fprintf( stderr,
" appropriate backplane bus device drivers in your system. \n");
fprintf( stderr,
"\n Issue the command \"chmod a+rw /dev/%s\" as superuser. \n",
"vme{16,24}d16" );
}
/*
* allocate two more pages than needed to guarantee
* enough page-aligned memory blocks
*/
raw_logaddr = (DWORD) malloc((unsigned)(size + psize + psize));
/* save address for use by unmap() */
if (mio == 0)
ioraw_logaddr = raw_logaddr;
else /* MEM */
memraw_logaddr = raw_logaddr;
/* align pointer on page boundary */
logaddr = ((raw_logaddr + psize) & ~(psize - 1));
offset = physaddr - (physaddr & ~(psize - 1));
physaddr -= offset;
length = (size + offset + (psize - 1)) & ~(psize - 1);
if (nomap == 1) /* skip physical address mapping */
return (BYTE *)((DWORD)logaddr + offset);
v = (DWORD)mmap(logaddr,length,(0x1|0x2),(1|0x10),BUS_FD,physaddr);
printf("mmap(0x%lX, 0x%lX, %u, %u, %u, 0x%lX) returned 0x%lX\n",
logaddr, length, (0x1|0x2), (1|0x10), BUS_FD, physaddr, v );
if (v == (-1)) {
perror("mmap"); /* print system error message */
sprintf( s,"mmap: Can't map %lXH bytes at %s address %8lXH\n\n",
length, (mio == 0) ? "I/O" : "Memory", physaddr );
}
return (BYTE *)((DWORD)logaddr + offset);
}
unmap( mio ) /* Unmap last I/O or MEMORY region mapped */
short mio; /* memory or I/O space */
{
char s[80]; /* message buffer */
if (munmap( logaddr, length ) != 0) {
sprintf( s, "munmap: Can't unmap %lx bytes from %s space\n\n",
length, (mio == 0) ? "I/O" : "Memory" );
}
if (mio == 0) {
free(ioraw_logaddr); /* Deallocate virtual storage space */
if ( !nomap )
close(IOBUS); /* close bus device driver */
} else { /* MEM */
free(memraw_logaddr); /* Deallocate virtual storage space */
if ( !nomap )
close(MEMBUS); /* close bus device driver */
}
}
disable_map() /* disallow physical address mapping by map() */
{
if (nomap) return;
/* make sure this action does not go unnoticed */
printf( "\n" );
printf( " WARNING: Physical Address Mapping Disabled !!! " );
printf( "\n\n" );
nomap = 1;
}
More information about the Comp.unix.questions
mailing list