/*
 * DATlib   Copyright (c) 1995-1996 Marcus Meissner &
 *          Friedrich-Alexander Universitaet Erlangen-Nuernberg (FAU), IMMD4
 *          All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *    This product includes software developed by Marcus Meissner
 *    at the Friedrich-Alexander Universitaet Erlangen-Nuernberg (FAU), IMMD4
 *
 * 4. The name of the University or the author may not be used
 *    to endorse or promote products derived from this software without
 *    specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND THE AUTHOR ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR THE AUTHOR BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

/* $Id: datlib_main.c,v 1.4 1997/08/06 14:57:38 msmeissn Exp $
 *
 * $Log: datlib_main.c,v $
 * Revision 1.4  1997/08/06 14:57:38  msmeissn
 * some error checks
 *
 * Revision 1.3  1997/06/02 18:42:11  msmeissn
 * added get_inquiry_extended and read_buffer (Arne Ludwig)
 *
 * Revision 1.2  1997/04/24 10:56:03  msmeissn
 * *** empty log message ***
 *
 * Revision 1.1  1997/03/16 20:28:55  msmeissn
 * Initial revision
 *
 *
 */

/* 
 * Datlib main file.
 * Will do do initialization. And contains all of the stub functions to call.
 */

#define __IN_DATLIB_C
#include <stdio.h>	/* NULL */
#include <stdlib.h>	/* malloc,realloc,free protohypes */
#include <sys/types.h>	
#include <errno.h>	/* errno #defines */
#include <string.h>

#include "datlib.h"

int	errno;

static int datlib_maxfd=0;
static struct datlib_functions **datlib_funs=NULL;

extern struct datlib_functions *datlib_uscsicmd_init(int fd);
extern struct datlib_functions *datlib_kernelp_init(int fd);
extern struct datlib_functions *datlib_gscsi_init(int fd);

static struct datlib_access_kinds datlib_access[]={
	{"uscsicmd",datlib_uscsicmd_init},
	{"kernelp",datlib_kernelp_init},
	{"gscsi",datlib_gscsi_init},
	{NULL,NULL}
};

int
datlib_init(int fd,char *optname) {
	int	i;
	struct	datlib_functions	*res;

	if (fd<0) RETURN(-EBADF);
	res=NULL;
	if (optname) {
		for (i=0;datlib_access[i].name!=NULL;i++) {
			if (strcmp(datlib_access[i].name,optname))
				continue;
			/* we've found the named entry. */
			res=datlib_access[i].init(fd);
			if (res==NULL) {
				perror(datlib_access[i].name); 
				fprintf(stderr,"Trying all other available methods.\n");
			}
			/* there will be no other entries with that name. */
			break;
		}
	}
	if (!res) {
		for (i=0;datlib_access[i].name!=NULL;i++) {
			res=datlib_access[i].init(fd);
			if (res==NULL) {
				perror(datlib_access[i].name); 
				continue;
			}
			/* we've found an entry. */
			break;
		}
	}
	if (datlib_access[i].name==NULL) {
		fprintf(stderr,"Failed to initialise ANY kind of accessing the enhanced DAT facilities.\n");
		RETURN (-ENOENT);/* FIXME: kein besserer fehler ? */
	}
	/* assuming fd's are usally below 255 and are not reaching very high
	 * numbers... 
	 */
	if (fd>datlib_maxfd) {
		datlib_funs=(datlib_funs==NULL)?
			malloc((fd+1)*sizeof(datlib_funs[0])):
			realloc(datlib_funs,(fd+1)*sizeof(datlib_funs[0]));

		/* initialise them to NULL, so we can spot bad references 
		 * easily 
		 */
		for (i=datlib_maxfd;i<(fd+1);i++)
			datlib_funs[i]=(struct datlib_functions*)NULL;
		datlib_maxfd=fd+1;
	}
	datlib_funs[fd]=res;
	RETURN(0);
}

char**
datlib_get_methods() {
	int	i;
	char	**methods;

	for (i=0;datlib_access[i].name!=NULL;i++) /*EMPTY*/;
	methods = (char**)malloc(sizeof(char*)*i);
	for (i=0;datlib_access[i].name!=NULL;i++)
		methods[i]=strdup(datlib_access[i].name);
	methods[i]=NULL;
	return methods;
}

#define DATLIB_STUB(FUN,PARGS,ARGS)\
int \
datlib_##FUN PARGS {\
	if (fd<0) RETURN(-EBADF);\
	if (datlib_maxfd<fd) RETURN(-EBADF);\
	if (datlib_funs[fd]==NULL) RETURN (-EBADF);\
	if (datlib_funs[fd]->FUN==NULL) RETURN (-ENOTTY);\
	return datlib_funs[fd]->FUN ARGS;\
}

DATLIB_STUB(create_partition,(int fd,int size,int size_kind),(fd,size,size_kind))
DATLIB_STUB(delete_partition,(int fd),(fd))
DATLIB_STUB(switch_active_partition,(int fd,int targpart),(fd,targpart))
DATLIB_STUB(query_active_partition,(int fd),(fd))
DATLIB_STUB(set_compression,(int fd,int comptype),(fd,comptype))
DATLIB_STUB(set_decompression,(int fd,int decomptype),(fd,decomptype))
DATLIB_STUB(query_compression,(int fd),(fd))
DATLIB_STUB(query_decompression,(int fd),(fd))
DATLIB_STUB(get_log_page,(int fd,int nr,unsigned char*logpage,int logsize),(fd,nr,logpage,logsize))
DATLIB_STUB(get_mode_page,(int fd,int nr,unsigned char*modepage,int modesize),(fd,nr,modepage,modesize))
DATLIB_STUB(set_mode_page,(int fd,unsigned char*modepage,int modesize),(fd,modepage,modesize))
DATLIB_STUB(get_inquiry,(int fd,unsigned char*inqbuf,int inqsize),(fd,inqbuf,inqsize))
DATLIB_STUB(request_sense,(int fd,char*inqbuf,int inqsize),(fd,inqbuf,inqsize))
DATLIB_STUB(get_inquiry_extended,(int fd,int page,unsigned char*inqbuf,int inqsize),(fd,page,inqbuf,inqsize))
DATLIB_STUB(read_buffer,(int fd,int memid,unsigned long memoff,unsigned char*buf,int size),(fd,memid,memoff,buf,size))

int
datlib_get_version(int fd,char *buf,int bufsize) {
	if (fd<0) RETURN(-EBADF);
	if (datlib_maxfd<fd) RETURN(-EBADF);
	if (datlib_funs[fd]==NULL) RETURN(-EBADF);
	if (datlib_funs[fd]->get_version==NULL) {
		char	xbuf[200];

		sprintf(xbuf,"datlib version: %s",DATLIBVERSION);
		strncpy(buf,xbuf,bufsize);
		return strlen(xbuf);
	}
	return datlib_funs[fd]->get_version(fd,buf,bufsize);
}

int
datlib_get_density(int fd) {
	unsigned char buf[100];
	if (fd<0) RETURN(-EBADF);
	if (datlib_maxfd<fd) RETURN(-EBADF);
	if (datlib_funs[fd]==NULL) RETURN (-EBADF);
	if (datlib_funs[fd]->get_mode_page == NULL)  RETURN (-ENOTTY);
	if (-1==datlib_funs[fd]->get_mode_page(fd,0x00,buf,100)) {
		perror("get_mode_page 0x00");
		return -1;
	}
	return buf[4];
}

int
datlib_set_density(int fd,int density) {
	unsigned char buf[100];
	int	size;

	if (fd<0) RETURN(-EBADF);
	if (datlib_maxfd<fd) RETURN(-EBADF);
	if (datlib_funs[fd]==NULL) RETURN (-EBADF);
	if (datlib_funs[fd]->get_mode_page == NULL)  RETURN (-ENOTTY);
	if (-1==datlib_funs[fd]->get_mode_page(fd,0x00,buf,100)) {
		perror("get_mode_page 0x00");
		return -1;
	}
	buf[0]=0;
	buf[4]=density;
	if (-1==datlib_funs[fd]->set_mode_page(fd,buf,12)) {
		fprintf(stderr,"set_mode_page 0x00 failed, %d",density);
		return -1;
	}
	if (-1==datlib_funs[fd]->get_mode_page(fd,0x00,buf,100)) {
		perror("get_mode_page 0x00");
		return -1;
	}
	if (buf[4]!=density)
		return -1;
	return 0;
}
