Next | Prev | Up | Top | Contents | Index

Example VME Device Driver

The following code sample uses the user-level VME-bus interface to perform bus probes:

#include <sys/types.h>
#include <sys/mman.h>
#include <stdio.h>
#include <fcntl.h>
#include <getopt.h>
#include <errno.h>
#include <limits.h>
#include <signal.h>

int state = 0;

#define S_DIR 0x01
#define S_ADAP 0x02
#define S_SPACE 0x04
#define S_ADDR 0x08
#define S_SIZE 0x10
#define S_VAL 0x20

#define D_READ 0x1
#define D_WRITE 0x2

#define READSTATE (S_DIR|S_ADAP|S_SPACE|S_ADDR|S_SIZE)
#define WRITESTATE (READSTATE|S_VAL)

char *progname;

char *spaces[] = {
    "a16n",
    "a16s",
    "a24n",
    "a24s",
    "a32n",
    "a32s"
};

#define MAXSPACE (sizeof(spaces)/sizeof(spaces[0]))

void usage(void);
long ntol(char *);
long chkspc(char *);

char devnm[PATH_MAX];

static void probe_fail(int);

int
main(int ac, char *av[])
{
    int    c, errflg = 0;
    int    dir_f;
    long    adap_f;
    long    addr_f;
    long    size_f;
    long    val_f;
    char *space_f;
    int    fd;
    char *mapaddr;
    int    pgaddr, pgoff;
    int    pgsz;
    int    rtval;

    progname = av[0];

    while( (c = getopt(ac,av,"rws:a:b:p:v:")) != -1 )
        switch( c ) {
        case 'r':
            if( state & S_DIR ) {
                usage();
                return 1;
            }
            dir_f = D_READ;
            state |= S_DIR;
            break;
        case 'w':
            if( state & S_DIR ) {
                usage();
                return 1;
            }
            dir_f = D_WRITE;
            state |= S_DIR;
            break;
        case 's':
            if( state & S_SPACE ) {
                usage();
                return 1;
            }
            if( chkspc(optarg) ) {
                usage();
                return 1;
            }
            state |= S_SPACE;
            space_f = optarg;
            break;
        case 'a':
            if( ((adap_f = ntol(optarg)) < 0) || 
                (state & S_ADAP) ) {
                usage();
                return 1;
            }
            state |= S_ADAP;
            break;
        case 'b':
            if( ((addr_f = ntol(optarg)) < 0) || 
                (state & S_ADDR) ) {
                usage();
                return 1;
            }
            state |= S_ADDR;
            break;
        case 'p':
            if( ((size_f = ntol(optarg)) < 0) || 
                (state & S_SIZE) ) {
                usage();
                return 1;
            }
            state |= S_SIZE;
            break;
        case 'v':
            if( ((val_f = ntol(optarg)) < 0) || 
                (state & S_VAL) ) {
                usage();
                return 1;
            }
            state |= S_VAL;
            break;
        case '?':
            errflg++;
            break;
        }

        if( errflg || !(state & S_DIR) ) {
            usage();
            return 1;
        }

        if( (dir_f == D_READ) && (state != READSTATE) ) {
            usage();
            return 1;
        }
        if( (dir_f == D_WRITE) && (state != WRITESTATE) ) {
            usage();
            return 1;
        }


        /* check the size */
        switch( size_f ) {
        case 1:
        case 2:
        case 4:
            break;
        default:
            (void)fprintf(stderr,"invalid size %d\n",size_f);
            usage();
            return 1;
        }

        /* create name of device */
        sprintf(devnm,"/dev/vme/vme%d%s",adap_f,space_f);

        /* open the usrvme device */
        if( (fd = open(devnm,O_RDWR)) < 0 ) {
            perror("open");
            return 1;
        }

        /* we map in memory on page boundaries so figure out
         * the page and page offset
         */

        pgsz = getpagesize();
        pgaddr = (addr_f / pgsz) * pgsz;
        pgoff = addr_f % pgsz;
        
        /* map in the vme space surrounding the address */
        if( (mapaddr = mmap(
                NULL,pgsz,PROT_READ|PROT_WRITE,MAP_PRIVATE,
                fd,pgaddr)) == (void*)-1 ) {
            perror("mmap");
            return 1;
        }

        /* catch bus errors */
        signal(SIGBUS,probe_fail);

        /* do the probe */
        if( dir_f & D_READ ) {
            switch( size_f ) {
            case 1:
                rtval = *(char *)&mapaddr[pgoff];
                break;
            case 2:
                rtval = *(short *)&mapaddr[pgoff];
                break;
            case 4:
                rtval = *(int *)&mapaddr[pgoff];
                break;
            }
            printf("read probe of 0x%x\n",rtval);
        }
        else {
            switch( size_f ) {
            case 1:
                *(char *)&mapaddr[pgoff] = val_f;
                break;
            case 2:
                *(short *)&mapaddr[pgoff] = val_f;
                break;
            case 4:
                *(int *)&mapaddr[pgoff] = val_f;
                break;
            }
            printf("write probe of 0x%x\n",val_f);
            /* wait here to catch any bus errors... */
            sginap(CLK_TCK/50+1);
        }

        return 0;
}

long
ntol(str)
    char *str;
{
    char *strp;    
    ulong ret;

    if( *str == '"' ) {
        str++;
        return (*str)?*str:-1;
    }

    ret = strtoul(str,&strp,0);

    if( ((ret == 0) && (strp == str)) ||
        ((errno == ERANGE) && (ret = -1)) )
        return (long)-1;
    
    return (long)ret;
}

long
chkspc(char *nm)
{
    int i;

    for( i = 0 ; i < MAXSPACE ; i++ )
        if( strcmp(nm,spaces[i]) == 0 )
            return 0;

    return 1;
}

void
usage()
{
 (void)fprintf(stderr,
    "usage: %s -r -a adap -s space -b busaddr -p probesize\n",
    progname);
 (void)fprintf(stderr,
    "usage: %s -w -a adap -s space -b busaddr -p probesize -v val\n",
    progname);
 (void)fprintf(stderr,
    "    space is one of a16n, a16s, a24n, a24s, a32n, a32s\n");
 (void)fprintf(stderr,
    "    probesize is one of 1 2 or 4\n");
}

static void
probe_fail(int signo)
{
    fprintf(stderr,"*** probe failed\n");
    exit(1);
}

Next | Prev | Up | Top | Contents | Index