/* $Id: MaxVideo.c,v 1.1 89/12/07 16:18:09 nesheim Rel-5-2 $ */
/*****************************************************************************
* 	  (c) Copyright  1989 Thinking Machines Corporation, Inc.,	     *
*		of Cambridge, Mass.   All rights reserved.		     *
*									     *
*  This notice is intended as a precaution against inadvertent publication   *
*  and does not constitute an admission or acknowledgement that publication  *
*  has occurred or constitute a waiver of confidentiality.		     *
*									     *
*  Connection Machine software is the proprietary and confidential property  *
*  of Thinking Machines Corporation.					     *
*****************************************************************************/

#include <sys/types.h>

#include <stdio.h>
#include <errno.h>

#include "cm_ioctl.h"
#include "cm_param.h"
#include "cm_errno.h"
#include "cm_conf.h"
#include "cm_file.h"

#include "mvIntDefs.h"
#include "scHead.h"
#include "scTool.h"
#include "vmHead.h"
#undef CLEAR
#undef DISABLE
#undef ENABLE
#include "vmTool.h"
#include "vdHead.h"

/*
 * MaxVideo driver
 * for the CM file system
 */

#define MAXMAXV 1
#define READFRAMESIZE (512*512)
#define WRITEFRAMESIZE (512*512)
#define WRITEOFFSET (512*512)

#define swapshort(x)	(((x<<8)|((x>>8)&0xff))&0xffff)
#define swaplong(x)	(swapshort(x<<16)|swapshort(x>>16))

extern int errno;

struct maxv_info {
    int state;
    SC_DESC *scfd;
    VD_DESC *vdfd;
    VM_DESC *vmfd;
    int offset;
    int scan_line_length;
} maxv_info[MAXMAXV];

/* state flags */
#define OPEN 1

/*
 * Open routine
 * Open the MaxVideo stuff
 * If we're opened for read, set up the A->D stuff
 * If we're opened for write, set up the D->A stuff
 */
int maxopen(dev, flags)
dev_t dev;
int flags;
{
    int unit;
    struct maxv_info *mv;
    int a24addr = 0;		/* Variable for 24/32 bit mem address    */
    int nomem = 0;

    unit = minor(dev);
    mv = &maxv_info[unit];

    if (mv->state & OPEN) {
	printf("setup_acq: already OPEN?\n");
	return 0;
    }
    
    mv->scfd = scOpen(SC_BASE, SC_VECTOR, /* verobse */ 1);
    if (mv->scfd == (SC_DESC *)NULL) {
	printf("setup_acq: scOpen failed\n");
	return(1);
    }
    mv->vdfd = vdOpen(VD_BASE, /* verbose */ 1);
    if (mv->vdfd == (VD_DESC *)NULL) {
	printf("setup_acq: vdOpen failed\n");
	scClose(mv->scfd);
	return (1);
    }
    mv->vmfd = vm32Open(VM_BASE, VM_WVECTOR, /* verbose */ 1);
    if (mv->vmfd == (VM_DESC *) NULL) {
	printf("setup_acq: Can't do vm32Open\n");
	scClose(mv->scfd);
	vdClose(mv->vdfd);
	return(1);
    }

    /* Initialize A/D RS170 input, channel "b" */
    sc170Init(mv->scfd);
    scS20(mv->scfd, 1);
    scAnGain(mv->scfd, 200);	/* boost input gain */

    /* Initialize D/A output */
    vdInit(mv->vdfd);
    vd8158Set(mv->vdfd, 6, 4);
    vd8158Set(mv->vdfd, 5, 32);

    /* memory Init */
    /* initialize memory base variables */
    vm170Init(mv->vmfd, 
	      VM_VZMX1, 128, 1024, 512,
	      512, 250);
    vmClrAll(mv->vmfd,0);

    /* Flush all initialization commands and wait for completion */
    mvRefresh();
    mvEmpty();

    /* Set up to sync everything to the maxScan board */
    scMaster(mv->scfd);

    mv->offset = vmGetWPix0(mv->vmfd);
    mv->scan_line_length = vmGetDHLen(mv->vmfd);
    printf("vm base is 0x%x\n", mv->vmfd->MemBase);
    printf("vmGetDHLen returns %d\n", mv->scan_line_length);
    printf("vmGetWPix0 returns %d\n", mv->offset);

    mv->state = OPEN;
    return (0);
}


/*
 * Close routine
 * Close the UNIX max device
 */
int maxclose(dev, flags)
dev_t dev;
int flags;
{
    int unit;
    struct maxv_info *mv;

    unit = minor(dev);
    mv = &maxv_info[unit];

    if (!(mv->state & OPEN)) {
	printf("maxclose: not OPEN?\n");
	return 0;
    }
    
    mvRefresh();
    mvEmpty();
    (void) scClose(mv->scfd);
    (void) vdClose(mv->vdfd);
    (void) vmClose(mv->vmfd);

    mv->state = 0;
    printf("maxclose\n");
    return 0;
}

/*
 * Read from the max and write to the I/O system
 * We transfer the low 512k of the framestore to the CM each time.  
 */
int maxread(dev, uio)
dev_t dev;
struct cm_uio *uio;
{
    int unit;
    struct maxv_info *mv;
    int size;
    int err;
    unsigned char *src;

    unit = minor(dev);
    mv = &maxv_info[unit];

    if (!(mv->state&OPEN)) {
	printf("maxread: not open?\n");
	return (CMFS_EINVAL);
    }

    src = (unsigned char *)(mv->vmfd->MemBase + mv->offset);

    while (uio->uio_resid > 0) {
	/*
	 * Figure out how much to read
	 */
	size = min(READFRAMESIZE, uio->uio_resid);

	/* Here we should freeze the image somehow */

	/* Send it to the CM */
	if (err = (*uio->uio_xfr)(uio, src, size)) {
	    return(err);
	}
	uio->uio_resid -= size;

	/*
	 * Re-enable video transfers
	 */
    }
    return 0;
}

/*
 * Write data from the CM I/O system 
 * to the maxdrive
 */
int maxwrite(dev, uio)
dev_t dev;
struct cm_uio *uio;
{
    int unit;
    struct maxv_info *mv;
    int size;
    int err;
    unsigned char *dest;

    unit = minor(dev);
    mv = &maxv_info[unit];

    if (!(mv->state&OPEN)) {
	printf("maxread: not open?\n");
	return (CMFS_EINVAL);
    }

    dest = (unsigned char *) ((unsigned) (mv->vmfd->MemBase) + WRITEOFFSET);

    while (uio->uio_resid > 0) {
	/*
	 * Write the max with a blocksize of cti->max_bufsz
	 */
	size = min(WRITEFRAMESIZE, uio->uio_resid);
	if (err = (*uio->uio_xfr)(uio, dest, size)) {
	    return(err);
	}
	uio->uio_resid -= size;
    }
    return 0;
}

/*
 * Make a guess at how much we can read
 */
int 
maxsize(dev, count)
dev_t dev;
int count;
{
    int unit;
    struct maxv_info *mv;

    unit = minor(dev);
    mv = &maxv_info[unit];

    if (!(mv->state&OPEN)) {
	printf("maxsize: not open?\n");
	return (0);
    }

    return (count);
}


/*
 * IOCTL routine
 * Here we implement all the standard UNIX
 * magmax operations
 */
int maxioctl(dev, cmd, data, need_to_swap)
dev_t dev;
int cmd, need_to_swap;
caddr_t data;
{
    int unit;
    struct maxv_info *mv;
    int size;
    int err;

    unit = minor(dev);
    mv = &maxv_info[unit];

    if (!(mv->state&OPEN)) {
	printf("maxread: not open?\n");
	return (CMFS_EINVAL);
    }

    return(ENOTTY);
}

#ifdef notdef
char image_buf[512*512];

char *
grab_image()
{
    unsigned char *src;
    int lenght;
    int offset;
    register char *dest;
    register int i, j;

    vmFreeze(vmfd);
    dest = image_buf;
    lenght = vmGetDHLen(vmfd);
    offset = lenght - 512;
    src = (unsigned char *)(unsigned int)(vmfd->MemBase);
    src += vmGetWPix0(vmfd)+lenght;

    for(i = 0; i < 512; i++) {
	j = 512;
	while(j--) *(dest++) = *(src++);
	src += offset;
    }

    return image_buf;
}
#endif
