/***************************************************************************
                          netmoscard.cpp  -  description
                             -------------------
    begin                : Fri May 3 2002
    copyright            : (C) 2002 by Argo Vessmann (ARTEC Design)
    email                : 
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/

#include "netmoscard.h"

#include <iostream.h>

/* 
struct nmdefsstr nmdefs[10] = {{0x9705, 2, {NM_PRN, NM_ECPP, 0, 0, 0, 0}},
	{0x9735, 4, {NM_SER, NM_SER, NM_PRN, NM_ECPP, 0, 0}},
	{0x9745, 6, {NM_SER, NM_SER, NM_DEV, NM_DEV, NM_DEV, NM_DEV} },
	{0x9805, 6, {NM_PRN, NM_ECPP, NM_NO, NM_NO, NM_NO, NM_NO}},
	{0x9815, 6, {NM_PRN, NM_ECPP, NM_PRN, NM_ECPP, NM_NO, NM_NO} },
	{0x9820, 6, {NM_SER, 0, 0, 0, 0, 0}},
	{0x9825, 1, {NM_SER, 0, 0, 0, 0, 0}},
	{0x9835, 6, {NM_SER, NM_SER, NM_PRN, NM_ECPP, 0, 0}},
	{0x9845, 6, {NM_SER, NM_SER, NM_DEV, NM_DEV, NM_DEV, NM_DEV} },
	{0x9755, 6, {NM_PRN, NM_ECPP, NM_PRN, NM_ECPP, NM_DEV, NM_DEV}}};
*/

struct nmdefsstr nmdefs[2] = {
	{0x9805, 6, {NM_PRN, NM_ECPP, NM_NO, NM_NO, NM_NO, NM_NO}},
	{0x9835, 6, {NM_SER, NM_SER, NM_PRN, NM_ECPP, 0, 0}}};



#define NM_CARDDEFS	2

NetmosCard::NetmosCard()
{
	definition = NULL;
	valid = FALSE;
	for( int i=0;i<6;i++ ) {
		serports[i] = NULL;
		parenabled[i] = TRUE;
		ecpenabled[i] = TRUE;
	}
	sub_vendor_id = sub_device_id = 0;
	parallel_count = serial_count = 0;
	_fixedconf = FALSE;
}

NetmosCard::~NetmosCard()
{
}

/** Returns TRUE if info is valid */
bool NetmosCard::isValid()
{
	return( valid );
}

/** Initialise this card from pci device. */
void NetmosCard::init( struct pci_dev *d )
{

	definition = NULL;
	valid = FALSE;
	if ( d->vendor_id != NM_VENDOR_ID )
		return;
	for( int i=0;i<NM_CARDDEFS;i++ ) {
		if ( nmdefs[i].devid == d->device_id )
			definition = &nmdefs[i];		
	}
	if ( !definition )
		return;	
	for( int i=0;i<definition->ios;i++ )
		ioports[i] = d->base_addr[i] & PCI_BASE_ADDRESS_IO_MASK;
	bus = d->bus;
	func = d->func;
	dev = d->dev;
	irq = d->irq;
	byte config[256];
	sub_vendor_id = sub_device_id = 0;
	if ( pci_read_block( d, 0, config, 256 ) ) {
		sub_vendor_id = config[PCI_SUBSYSTEM_VENDOR_ID] | (config[PCI_SUBSYSTEM_VENDOR_ID+1]<<8);
		sub_device_id = config[PCI_SUBSYSTEM_ID] | (config[PCI_SUBSYSTEM_ID+1]<<8);
	}
	serial_count = sub_device_id & 0xF;
	parallel_count = ( sub_device_id & 0xF0 ) >> 4;
	valid = TRUE;
}

/** Creats a listview item into listview parent */
void NetmosCard::newListViewItem( QListView *parent )
{
	QString cname;
	cname.sprintf( "%02x:%02x.%d Board with Nm%xCV part", bus, dev, func, definition->devid );
	QListViewItem *iparent = new QListViewItem( parent, cname );

	for( int i=definition->ios-1;i>=0;i-- ) {
		cname.sprintf( "I/O at 0x%x", ioports[i] );
		QString ptype;
		if ( definition->types[i] == NM_SER )
			ptype = "serial port";
		else if ( definition->types[i] == NM_PRN )
			ptype = "printer port";
		else if ( definition->types[i] == NM_ECPP )
			ptype = "ECP/EPP config register";
		else if ( definition->types[i] == NM_DEV )
			ptype = "device";
		else if ( definition->types[i] == NM_NO )
			ptype = "not used";
		else
			ptype = "unknown";
		new QListViewItem( iparent, cname, ptype );
	}
}

QString NetmosCard::InfoStrForNewt()
{
	QString resp;
	resp.sprintf( "%02x:%02x.%d Board with Nm%xCV part\n", bus, dev, func, definition->devid );

	for( int i=definition->ios-1;i>=0;i-- ) {
		QString ptype;
		ptype.sprintf( "\tI/O at 0x%x ", ioports[i] );
		if ( definition->types[i] == NM_SER )
			ptype += "serial port\n";
		else if ( definition->types[i] == NM_PRN )
			ptype += "printer port\n";
		else if ( definition->types[i] == NM_ECPP )
			ptype += "ECP/EPP config register\n";
		else if ( definition->types[i] == NM_DEV )
			ptype += "device\n";
		else if ( definition->types[i] == NM_NO )
			ptype += "not used\n";
		else
			ptype += "unknown\n";
		resp += ptype;
	}
	return resp;
}

/** Returns cards name ( Nm<NR>CV ) */
QString NetmosCard::CardName()
{
	if ( !valid )
		return( NULL );
	QString resp;

	resp.sprintf( "Nm%xCV", definition->devid );

	return resp;
}

/** Returns cards pci id */
QString NetmosCard::CardID()
{
	if ( !valid )
		return( NULL );
	QString resp;

	resp.sprintf( "%02x:%02x.%d", bus, dev, func );

	return resp;
}

/** Returns TRUE if this card has one or many serial ports.
    Subdevice id must also indicate that we have serial ports. */
bool NetmosCard::hasSerials()
{
	for( int i = 0;i<definition->ios;i++ )
		if ( definition->types[i] == NM_SER ) {
			if( serial_count )
				return( TRUE );
		}
	return( FALSE );
}

/** Returns TRUE if this card has two serial Ports. 
    Subdevice id must also indicate that we have 2 serial ports. */
bool NetmosCard::has2SerialPorts()
{
	int scount = 0;
	for( int i = 0;i<definition->ios;i++ )
		if ( definition->types[i] == NM_SER )
			scount++;
	if ( scount >= 2 && serial_count >= 2 )
		return( TRUE );
	else
		return( FALSE );
}

/** Returns true if given serial port is configured to this card. Also remembers to
himself this port. */
bool NetmosCard::hasExistingSerial( SerialPort *sp )
{
	for( int i=0;i<definition->ios;i++ ) {
		if ( definition->types[i] != NM_SER )
			continue;
		if ( sp->io == ioports[i] && sp->irq == irq ) {
			serports[i] = sp;
			return( TRUE );
		}
	}
	return( FALSE );
}

/** Returns a string of serial devices name of serial port on netmoscard. */
QString NetmosCard::serialDevName( int nr )
{
	for( int i=0;i<definition->ios;i++ ) {
		if ( definition->types[i] != NM_SER )
			continue;
		if ( nr-- )
			continue;
		if ( !serports[i] )
			break;
		return( serports[i]->DevName() );
	}
	return( "" );		
}

/** Returns the serial ports speed number. nr says which port on netmos card is used. */
int NetmosCard::serialDevSpeed( int nr )
{
	for( int i=0;i<definition->ios;i++ ) {
		if ( definition->types[i] != NM_SER )
			continue;
		if ( nr-- )
			continue;
		if ( !serports[i] )
			break;
		return( serports[i]->Speed() );
	}
	return( 0 );		
}

/** Returns true if this ( nr ) port on this card is already configured. */
bool NetmosCard::isSerialConfigured( int nr )
{
	for( int i=0;i<definition->ios;i++ ) {
		if ( definition->types[i] != NM_SER )
			continue;
		if ( nr-- )
			continue;
		if ( !serports[i] )
			break;
		return( TRUE );
	}
	return( FALSE );			
}

/** Print into string current cards configuration. This string is displayed to user with QTextView. ( as a rich text ). */
void NetmosCard::sprintConfiguration( QString *str )
{
	QString tmp;
	tmp.sprintf( "%s\n", (const char *)CardName() );
	str->append( tmp );
	int scount = 1, pcount = 1;
	for( int i=0;i<definition->ios;i++ ) {
		if ( definition->types[i] == NM_SER ) {
			if ( !serports[i] )
				continue;
			tmp.sprintf( "\tSerial %i ", scount++ );
			str->append( tmp );
			tmp.sprintf( "/dev/ttyS%i\n", serports[i]->port );
			str->append( tmp );
		}
		if ( definition->types[i] == NM_PRN ) {
			tmp.sprintf( "\tParallel %i ", pcount++ );
			str->append( tmp );
			if ( parenabled[i] ) {
				str->append( "enabled" );
				if ( ecpenabled[i] )
					str->append( " with ECP" );
			} else
				str->append( "disabled" );
			str->append( "\n" );
		}
	}
		
}

/** Sets this cards nr serial port to serialport sp. */
void NetmosCard::setSerial( int nr, SerialPort *sp )
{
	for( int i=0;i<definition->ios;i++ ) {
		if ( definition->types[i] != NM_SER )
			continue;
		if ( nr-- )
			continue;
		serports[i] = sp;
		sp->irq = irq;
		sp->uart = QString( "16550A" );
		sp->io = ioports[i];
	}
}

/** Returns the serial port that is configured as serial port nr on netmos card. */
SerialPort *NetmosCard::GetConfiguredSerialPort(int nr)
{
	for( int i=0;i<definition->ios;i++ ) {
		if ( definition->types[i] != NM_SER )
			continue;
		if ( nr-- )
			continue;
		return( serports[i] );
	}
	return( NULL );
}

/** Returns true if this card has parallel with number nr. 
    It returns true only when parallel count from subsystem id 
    indicates that we have enough parallels and card definition has
    enough parallels. */
bool NetmosCard::hasParallel( int nr )
{
	if ( parallel_count < (nr+1) )
		return( FALSE );
	nr = convertnrtoint( nr, NM_PRN );
	if ( nr == -1 )
		return( FALSE );
	else
		return( TRUE );
}

/** Returns TRUE if this card has parallel nr and it is enabled. */
bool NetmosCard::parallelenabled( int nr )
{
	nr = convertnrtoint( nr, NM_PRN );
	if ( nr == -1 )
		return( FALSE );
	if ( parenabled[nr] )
		return( TRUE );
	else
		return( FALSE );
}

/** Returns true if this card has parallel number nr and it's ECP is enabled. */
bool NetmosCard::parallelECP( int nr )
{
	nr = convertnrtoint( nr, NM_PRN );
	if ( nr == -1 )
		return( FALSE );
	if ( ecpenabled[nr] )
		return( TRUE );
	else
		return( FALSE );
}

/** Convert external nummeration into classes internal numeration.  */
int NetmosCard::convertnrtoint( int nr, int type )
{
	for( int i=0;i<definition->ios;i++ ) {
		if ( definition->types[i] != type )
			continue;
		if ( !nr-- )
			return( i );
	}
	return( -1 );
}

/** Set wether the parallel is enabled or not. */
void NetmosCard::setParallel( int nr, bool enab )
{
	nr = convertnrtoint( nr, NM_PRN );
	if ( nr == -1 )
		return;
	parenabled[nr] = enab;
}

/** Sets ECP enabled or nor. */
void NetmosCard::setParallelECP( int nr, bool enab )
{
	nr = convertnrtoint( nr, NM_PRN );
	if ( nr == -1 )
		return;
	ecpenabled[nr] = enab;
}

/** Returns nr parallel port as a QString. */
QString NetmosCard::getsParallelPort( int nr )
{
	nr = convertnrtoint( nr, NM_PRN );

	QString resp;
	resp.sprintf( "0x%x", ioports[nr] );
	return( resp );
}

/** Returns nr parallel hi-port as a QString. */
QString NetmosCard::getsParallelPortHi( int nr )
{
	int tmp = convertnrtoint( nr, NM_ECPP );

	int io_hi = ioports[tmp];
	tmp = convertnrtoint( nr, NM_PRN );
	if ( !ecpenabled[tmp] )
		io_hi++;
	QString resp;
	resp.sprintf( "0x%x", io_hi );
	return( resp );
}

/** Returns nr parallel irq as a QString. */
QString NetmosCard::getsIrq()
{
	QString resp;

	resp.sprintf( "%i", irq );
	return( resp );
}

/** Returns TRUE if given port belongs to us. */
bool NetmosCard::isNetmosPort( int p )
{
	for( int i=0;i<definition->ios;i++ ) {
		if ( ioports[i] == p )
			return TRUE;
	}
	return FALSE;
}

bool NetmosCard::fixedConf()
{
	return _fixedconf;
}

void NetmosCard::setFixedConf( bool v )
{
	_fixedconf = v;
}

void NetmosCard::debug( void )
{
/*
	cerr << "In netmoscard debug " << endl;
	cerr << "Card on " << this << endl;
	cerr << "\tser port 0-i aadress " << serports[0] << endl;
	if ( serports[0] )
		cerr << "\tser port 0-i name " << serports[0]->DevName() << endl;
	cerr << "\tser port 1-i aadress " << serports[1] << endl; */
	
}
