/* mwave.c -- View and change MWave DSP settings
* By Dale Wick
*
* Rev  Date        Comments
* 0.1  1999 09 25  Initial version
*/
#define BANNER "MWave settings manager for IBM Thinkpad (*)\n"
#define VERSION "version 0.1  By Dale Wick (dmwick@home.com) 1999 08 25\n"
#define USAGE "Usage: %s [-hqv] [module [property value]]\n" \
	"  -h, --help    general help or help about a module\n" \
	"  -q            quiet mode (no banner)\n" \
	"  -v            verbose mode\n" \
	"  -V,--version  version information\n" \
	""

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

//#include <linux/apm_bios.h>
#include <asm/io.h>

#define INT15H(ax,bx,cx) printf("INT 15h apm bios call not implemented AX=0x%x, BX=0x%x, CX=0x%x\n",ax,bx,cx);
#define INITAPMMAGIC INT15H(0x5380,0x6000,0x1101);

/* The mwave DSP is at one of the following three base IO ports
 * The word at that port contains properties
 */
#define MWAVEBASE1 0xce30
#define MWAVEBASE2 0x8e30
#define MWAVEBASE3 0x4e30

#define DSPMISSING 0xffff
/* The Mwave DSP signature */
#define MWAVE0MASK 0x0046 /* 0b1000110 bits 1, 2, 6 */
#define MWAVE1MASK 0x0029 /* 0b0101001 bits 0, 3, 5 */


int verbose=0;
int quiet=0;
int version=0;
int help=0;
char *errarg;	/* If there was an error parsing an argument */
char *mod;
char *prop;
char *value;
int mwavebase=0;

#if 1
inline unsigned short  myinw  (unsigned short port) {
	unsigned short  _v;  
	__asm__ 
	__volatile__ 
	("in" "w" " %"  "w"  "1,%"   ""   "0"  
	: "=a" (_v) 
	: "Nd" (port)   ); 
	return _v; 
} 
inline unsigned short  myinw_p (unsigned short port) { 
	unsigned short  _v;  
	__asm__ 
	__volatile__ 
	("in" "w" " %"  "w"  "1,%"   ""   "0"  
	"\noutb %%al,$0x80"   
	: "=a" (_v) 
	: "Nd" (port)   ); 
	return _v; 
} 
inline void myoutw  (unsigned   short   value, unsigned short port) {  
	__asm__ 
	__volatile__ 
	("out" "w" " %"   "w"   "0,%"  "w"  "1"  : 
	: "a" (value), "Nd" (port)); 
} 
inline void myoutw_p (unsigned   short   value, unsigned short port) {  
	__asm__ 
	__volatile__ 
	("out" "w" " %"   "w"   "0,%"  "w"  "1"  
	"\noutb %%al,$0x80"   : 
	: "a" (value), "Nd" (port));
} 
#endif

int main(int argc,char* argv[])
{
	int i;
	int argstate=0;
	char *args[1] ;
	char erropt[3];
	int val;

	for(i=1;i<argc;i++) {
		if(argv[i][0]=='-') {
			if(argv[i][1]=='-') {
				/* We see if we recognise a long arg */
				if(strcasecmp(argv[i],"--verbose")==0) {
					verbose=1;
				} else if(strcasecmp(argv[i],"--help")==0) {
					help=1;
				} else if(strcasecmp(argv[i],"--quiet")==0) {
					quiet=1;
				} else if(strcasecmp(argv[i],"--version")==0) {
					version=1;
				} else if(errarg==0) {
					errarg=argv[i];
					help=1;
				}
			} else {
				int j;
				for(j=1;j<strlen(argv[i]);j++) {
					switch(argv[i][j]) {
					case 'V': version=1; break;
					case 'v': verbose=1; break;
					case 'q': quiet=1; break;
					case 'h': help=1; break;
					default: 
						if(errarg==NULL) {
							errarg=erropt;
							erropt[0]='-';
							erropt[1]=argv[i][j];
							erropt[3]=0;
						}
					}
				}
			}
		} else { /* Record and switch to a new state */
			switch(argstate) {
			case 0:
				mod=argv[i];
				argstate++;
				break;
			case 1:
				prop=argv[1];
				argstate++;
				break;
			case 2:
				value=argv[1];
				argstate++;
			default:
				if(errarg==NULL) {
					errarg=argv[1];
				}
			}
		}
	}
	if(!quiet) {
		printf(BANNER);
	}
	if(version){
		printf(VERSION);
	}
	if(help && argstate<1) {
		printf(USAGE,argv[0]);
	} else if(help && argstate>0) {
		printf("Full help unimplementated so far, try this general help:\n");
		printf(USAGE,argv[0]);
	}
	if(errarg!=NULL) {
		printf("%s: invalid option '%s'\n"
		"Try `%s --help' for more information.",argv[0],errarg,argv[0]);
		exit(5);
	}
	if(help) {
		exit(0);
	}

	/* First we need access to all of the IO ports */
	iopl(3);

	if(verbose) printf("probing for mwave base\n");
	/* Probe the ports for what we need */
	val=myinw(MWAVEBASE1);
	//insw(MWAVEBASE1,&val,1);
	if(verbose) printf("base 1 (0x%04x): 0x%04x\n",MWAVEBASE1,val);
	if(((val&MWAVE0MASK)==0) && ((val&MWAVE1MASK)==MWAVE1MASK)) {
		mwavebase=MWAVEBASE1;
	} else {
		val=myinw(MWAVEBASE2);
		if(verbose) printf("base 2 (0x%04x): 0x%04x\n",MWAVEBASE2,val);
		if(((val&MWAVE0MASK)==0) && ((val&MWAVE1MASK)==MWAVE1MASK)) {
			mwavebase=MWAVEBASE2;
		} else {
			val=myinw(MWAVEBASE3);
			if(verbose) printf("base 3 (0x%04x): 0x%04x\n",MWAVEBASE3,val);
			if(((val&MWAVE0MASK)==0) && ((val&MWAVE1MASK)==MWAVE1MASK)) {
				mwavebase=MWAVEBASE3;
			} else {
				printf("MWave base IO port not found.\n");
				exit(15);
			}
		}
		if(verbose) printf("MWave base detected at: 0x%04x\n",mwavebase);
	}

	/* Now we need to initialize the mwave card so that it listens to us */
	myoutw(mwavebase,val & 0xfbff | 0x0080);

	/* Next we need to collect the settings for various properties */

	/* Select register 3 */
	myoutw(mwavebase+4,3);
	val=myinw(mwavebase+8);
	if(verbose) printf("Reg 3=0x%04x\n",val);

	/* Select register 4 */
	myoutw(mwavebase+4,4);
	val=myinw(mwavebase+8);
	if(verbose) printf("Reg 4=0x%04x\n",val);

	/* Select register 16 */
	myoutw(mwavebase+4,16);
	val=myinw(mwavebase+8);
	if(verbose) printf("Reg 16=0x%04x\n",val);

	
	return 0;
}
