/*
 *  Copyright (c) by Jaroslav Kysela <perex@jcu.cz>
 *  Routines for control of SoundBlaster cards
 *
 *
 *   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 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

#include "driver.h"
#include "sb.h"
#include "initval.h"


int snd_sbdsp_command(sbdsp_t * codec, unsigned char val)
{
	int i;

	for (i = 100000; i; i--) {
		if ((in8(SBP(codec, STATUS)) & 0x80) == 0) {
			out8(SBP(codec, COMMAND), val);
			return 1;
		}
	}
	snd_printd("snd_sb_dsp_command: timeout (0x%x)\n", val);
	return 0;
}

int snd_sbdsp_get_byte(sbdsp_t * codec)
{
	int i;

	for (i = 1000; i; i--)
		if (in8(SBP(codec, DATA_AVAIL)) & 0x80)
			return in8(SBP(codec, READ));
	snd_printd("sb get byte failed: 0x%x = 0x%x!!!\n", SBP(codec, DATA_AVAIL), in8(SBP(codec, DATA_AVAIL)));
	return -ENODEV;
}

int snd_sbdsp_reset(sbdsp_t * codec)
{
	int i;

	out8(SBP(codec, RESET), 1);
	snd_delay(10);
	out8(SBP(codec, RESET), 0);
	snd_delay(30);
	for (i = 0; i < 1000 && !(in8(SBP(codec, DATA_AVAIL)) & 0x80); i++)
		;
	if (in8(SBP(codec, READ)) != 0xaa) {
//		snd_printd("sb_reset: failed at 0x%x!!!\n", codec->port);
		return -ENODEV;
	}
	return 0;
}

int snd_sbdsp_version(sbdsp_t *codec)
{
	unsigned int result = -1;
	int tmp;

	snd_sbdsp_command(codec, SB_DSP_GET_VERSION);
	if ((tmp = snd_sbdsp_get_byte(codec)) >= 0) {
		result = tmp << 8;
		if ((tmp = snd_sbdsp_get_byte(codec)) >= 0)
			result |= tmp;
		else
			result = -1;
	}
	return result;
}

/* snd_sb_cmdline() -- Oct 25th, 1999
 * Used by audiotrap for detecting commandline options
 * All drivers use exactly the same function prototype.
 * Don't add any more options to this function or change
 * its behaviour without changing the others too.
 */
int snd_sb_cmdline( int *count, char **cmdline, int verbose )
{
	static int possible_ports[] = {0x220, 0x240, 0x260, -1};
	int *ports;
        int cards = 0;
        int idx = 0;
	sbdsp_t *codec;
	int version;
	char *str;

        *count = 0;

	codec = (sbdsp_t*) snd_malloc( sizeof(sbdsp_t));
	if( !codec )
		return -ENOMEM;
	memset( codec, 0, sizeof(sbdsp_t));

	for (ports = possible_ports; *ports >= 0; ports++) {

		codec->port = *ports;

		if (snd_sbdsp_reset(codec) < 0) {
			if( verbose > 2 ) snd_printk("sb: [0x%x] reset failed... 0x%x\n", 
							codec->port, in8(SBP(codec, READ)));
			continue;
		}
		version = snd_sbdsp_version(codec);
		if (version < 0) {
			if( verbose > 2 ) snd_printk( "sb: [0x%x] version read failed...\n", 
							codec->port );
			continue;
		} else {
			switch (version >> 8) {
			case 1:
				str = "Sound Blaster 1.0";
				break;
			case 2:
				str = !(version & 0xff) ? "Sound Blaster 2.0" : 
							  "Sound Blaster 2.01+";
				break;
			case 3:
				str = "Sound Blaster Pro";
				break;
			case 4:
				str = "Sound Blaster 16";
				break;
			default:
				str = "???";
			}
			if( verbose > 2 ) snd_printk("sb: Found SB DSP v%i.%i (%s)\n @IO 0x%X", 
						version >> 8, version & 0xff, str, codec->port);
			cards++;
		}
	}

	snd_free( codec, sizeof(sbdsp_t));

        *count = cards;

        if (!cards) {
                if( verbose > 1 ) 
			snd_printk("sb: SoundBlaster-compatible interface not found or device busy\n");
                return -ENODEV;
        } 

	/* For now, no matter how many cards we find we only have to return one
         * simple commandline
	 */	
        cmdline[idx] = (char*) malloc( PATH_MAX );
        if( !cmdline[idx] )
                return -ENOMEM;
        sprintf( cmdline[idx], "deva-sb" );
        *count = idx + 1;

        return 0;
}
