/* @(#)iodev0.c	19.1 (ES0-DMD) 02/25/03 13:56:10 */
/*===========================================================================
  Copyright (C) 1995 European Southern Observatory (ESO)
 
  This program is free software; you can redistribute it and/or 
  modify it under the terms of the GNU General Public License as 
  published by the Free Software Foundation; either version 2 of 
  the License, or (at your option) any later version.
 
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
 
  You should have received a copy of the GNU General Public 
  License along with this program; if not, write to the Free 
  Software Foundation, Inc., 675 Massachusetss Ave, Cambridge, 
  MA 02139, USA.
 
  Corresponding concerning ESO-MIDAS should be addressed as follows:
	Internet e-mail: midas@eso.org
	Postal address: European Southern Observatory
			Data Management Division 
			Karl-Schwarzschild-Strasse 2
			D 85748 Garching bei Muenchen 
			GERMANY
===========================================================================*/

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.TYPE        	Module
.NAME        	iodev0.c
.LANGUAGE    	C
.AUTHOR      	IPG-ESO Garching
.CATEGORY    	Host operating system interfaces. TBD
.COMMENTS    	Dumb Devices
.VERSION 1.0	10-Jan-1990: Creation
.VERSION 1.1	18-May-1990: 2 parametesr for ioclose
.ENVIRONMENT 	VAX/VMS
------------------------------------------------------------*/
static char class_name[] = "dumb";	/* e.g. null device */

#include <osdefos.h>
#include <osudef.h>
#include <filedef.h>	/* Contains definitions of READ / WRITE, etc... */

#include    <iodef.h>                 /* VMS QIO function codes       */
#include    <ssdef.h>                 /* VMS status code definitions  */
#include    <descrip.h>               /* VMS descriptor macro         */
#include    <errno.h> 

struct iolist *iodev1();	/* Next io routines in list */

MID_EXTERN      int         oserror;      /* MIDAS os-error status        */
MID_EXTERN      int        vmserror;      /* translated by osmsg()        */

#define L	dsc$w_length
#define S	dsc$a_pointer
#define SET_STRING(dsc,str,l)	dsc.S = str, dsc.L = l		\
			 /* Set address & length of a string    */

static short chan;
static struct dsc$descriptor_s sdv = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0};
	struct IOSB {
		unsigned short int iostatus;
		unsigned short int length;
		unsigned long int  info;
	};
static struct IOSB iosb;	/* The i/o status block		*/

#define CheckVMS	if (!(vmserror&1)) { oserror = EIO; return(-1);}

/*======================================================================*/
static int io1 (op, buffer, length)
/*+++++++++++++ 
.PURPOSE	Interface to SYS$QIOW, with test of main returned status
.RETURNS	Byte count / -1
.REMARK	
--------------*/
	int	op;		/* IN: The operation to perform	*/
	char	*buffer;	/* OUT: Buffer address		*/
	int	length;		/* IN: Buffer length		*/
{
	register int l;

  if (oserror)	return(-1);

  iosb.iostatus = 0, iosb.length = 0;
  vmserror = SYS$QIOW (0,chan,op,&iosb,0,0,buffer,length,0,0,0,0);
  l = iosb.length;

  if (!(vmserror & 1))	oserror = EIO, l = -1;

  return(l);
}

/*======================================================================*/
static int io2 (op, buffer, length)
/*+++++++++++++ 
.PURPOSE	Interface to SYS$QIOW, with test of 2 returned codes
.RETURNS	Length / -1 if error / 0 for EOF
.REMARK	
--------------*/
	int	op;		/* IN: The operation to perform	*/
	char	*buffer;	/* OUT: Buffer address		*/
	int	length;		/* IN: Buffer length		*/
{
	register int l;
	
  l = io1(op, buffer, length);
  
  if (oserror == 0) 
  {	switch(iosb.iostatus)
	{ case SS$_NORMAL: 	break;
#if 0		/* Following cases ignored here */
	  case SS$_DATAOVERUN: if (l == length) l++;
	  			break;
	  case SS$_ENDOFTAPE:	oserrmsg = "Physical End reached";
	  			oserror = -1;
				break; 
	  case SS$_FORMAT:	/* This happens with virgin sectors on ODs. */
	  			break;
#endif
	  case SS$_ENDOFVOLUME:
	  case SS$_ENDOFFILE:	l = 0; break;	/* No error */


	  default:		oserror = EIO;
	  			vmserror = iosb.iostatus;
				break; 
	}
  }
  return (oserror ? -1 : l);
}

static int iorew(fd)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE Go to sector #0
.RETURNS 0 (success) / -1 (error)
------------------------------------------------------------*/
        int    fd;	     	/* IN: File Descriptor */
{
	return(0);
}

static int ioinfo(fd, s, fileno, blkno)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE Retrieve Info concerning an opened device
.RETURNS 0 (success) / -1 (error)
------------------------------------------------------------*/
        int    fd;	     	/* IN: File Descriptor */
        struct osustat  *s;     /* OUT: The filled components */
	int	*fileno;	/* OUT: Where we are	*/
	long	*blkno;		/* OUT: Where we are	*/
{
        oserror = 0;
	if (fileno) {
		*fileno = -1;
		*blkno  = -1;	/* Unknown ...	*/
		}

        s->usize     = 0;
        s->blocksize = 0;
        s->density   = 0;
        s->isda = 0;

        return(0);
}

static int ioopen(name, mode, den)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE Open Raw Disk Tape
.RETURNS File descriptor / -1 (error)
.REMARKS  
------------------------------------------------------------*/
char *name;             /* IN:  Physical name of tape device */
int mode;               /* IN:  Open mode */
int den;                /* IN:  Density. Not used */
{
        int 	l;

    oserror = 0;
	/* Add the : if necessary */
    sdv.S = name;
    sdv.L = l = strlen(name);
    if (name[l-1] != ':') 	name[l] = ':', sdv.L += 1;

						/* Assign the device	*/
  vmserror = SYS$ASSIGN(&sdv,&chan,0,0);
  name[l] = '\0';
  CheckVMS

  return(chan);
}

static int ioclose(fd, option)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE Close the Device
.RETURNS 0 (success) / -1 (failure)
------------------------------------------------------------*/
int fd;                 /* IN:  Tape file descriptor */
int option;		/* IN: Option OPU_DISMOUNT	*/
{
    oserror=0;
    vmserror = SYS$DASSGN(fd);
    CheckVMS
    
    return(oserror ? -1 : 0);
}

static int ioread(fd, buffer, size)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE Read a buffer from a dumb device
.RETURNS Bytes read / -1 if error
.REMARKS 0 Bytes read, means EOF
------------------------------------------------------------*/
int 	fd;   		/* IN: Tape device file descriptor */
char 	*buffer;       	/* OUT:  Buffer for reading 	*/
int 	size;   	/* IN: Length of bytes to be read */
{
        int stat;

    oserror = 0, chan = fd;

    return (io2(IO$_READLBLK, buffer, size));
}

static int iowrite(fd, buffer, size)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE Write a block to a DA device
.RETURNS Bytes written / -1 if error
.REMARKS 0 Bytes read, means ???
------------------------------------------------------------*/
int 	fd;       	/* IN: Tape device file descriptor */
char 	*buffer; 	/* IN: Buffer for reading */
int 	size;    	/* IN: Length of bytes to be read */
{
        int stat;

    oserror = 0, chan = fd;

    return (io2(IO$_WRITELBLK, buffer, size));
}

/*=====================================================================
 * 		Definition of the structure returned to osu
 *=====================================================================*/

static OPITEM list_of_functions[] = {
	{ U_OPEN,	ioopen},		/* Open (name, mode)	*/
	{ U_CLOSE,  	ioclose},
	{ U_INFO,	ioinfo},
	{ U_READ,       ioread},  
	{ U_WRITE,      iowrite},
	{ U_REWIND, 	iorew}
 };


static struct iolist this_dev = {
        iodev1,                 /* Next iodev in List */
	class_name,		/* How it's written in DEVCAPFILE */
	sizeof(list_of_functions)/sizeof(list_of_functions[0]),
	list_of_functions
 };
 
struct iolist *iodev0()
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.PURPOSE Get All definitions concerning this class of Devices
.RETURNS The iolist
.REMARKS 
------------------------------------------------------------*/
{
  return(&this_dev);
}
