/*
 *  Main detection routines
 *  Copyright (c) by Jaroslav Kysela <perex@jcu.cz>
 *
 *
 *   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.
 *
 */

#define SND_MAIN_OBJECT_FILE
#include "driver.h"
#include "info.h"
#include <stdarg.h>

#define SND_DETECT_VERSION	"1.0"
#define SND_DETECT_BUFFER_SIZE	(32 * 1024)

typedef int (*snd_isa_probe)( snd_card_t *card, char *name, unsigned int *type, unsigned short *port );

extern int snd_detect_interwave( snd_card_t *card, char *name, unsigned int *type, unsigned short *port );
extern int snd_detect_gus( snd_card_t *card, char *name, unsigned int *type, unsigned short *port );
extern int snd_detect_es1688( snd_card_t *card, char *name, unsigned int *type, unsigned short *port );
extern int snd_detect_sb( snd_card_t *card, char *name, unsigned int *type, unsigned short *port );

static snd_info_entry_t *snd_detect_info_entry = NULL;

static snd_isa_probe snd_isa_probes[] = {
  snd_detect_es1688,
  snd_detect_interwave,
  snd_detect_gus,
  snd_detect_sb,
};

#define SND_DETECT_ISA_COUNT (sizeof(snd_isa_probes)/sizeof(void *))

static void snd_detect_use_inc( snd_card_t *card )
{
  MOD_INC_USE_COUNT;
}

static void snd_detect_use_dec( snd_card_t *card )
{
  MOD_DEC_USE_COUNT;
}

static void snd_detect_read( snd_info_buffer_t *buffer, void *private_data )
{
  int idx, cardidx;
  snd_card_t *cards[ SND_CARDS ];	/* detected cards */
  char name[64];
  unsigned int type;
  unsigned short port;

  buffer -> curr = buffer -> buffer;
  *buffer -> buffer = 0;
  snd_iprintf( buffer, "Version: " SND_DETECT_VERSION "\n" );
  if ( snd_cards_count > 0 ) {
    buffer -> error = -EBUSY;
    return;
  }
  memset( &cards, 0, sizeof( cards ) );
  cardidx = 0;
  for ( idx = 0; idx < SND_CARDS; idx++ ) {
    cards[ idx ] = snd_card_new( idx + 1, NULL, snd_detect_use_inc, snd_detect_use_dec );
    if ( !cards[ idx ] ) {
      for ( idx = 0; idx < SND_CARDS; idx++ ) {
        if ( cards[ idx ] ) snd_card_free( cards[ idx ] );
      }
      buffer -> error = -ENOMEM;
      return;
    }
  }
  for ( idx = 0; cardidx < SND_CARDS && idx < SND_DETECT_ISA_COUNT; idx++ ) {
    while ( !snd_isa_probes[ idx ]( cards[ cardidx ], name, &type, &port ) ) {
      snd_iprintf( buffer, "ISA#0x%x#%s#0x%x\n", type, name, port );
      cardidx++;
    }
  }
  for ( idx = 0; idx < SND_CARDS; idx++ ) {
    if ( cards[ idx ] ) snd_card_free( cards[ idx ] );
  }
}

static int snd_detect_info_init( void )
{
  snd_info_entry_t *entry;

  entry = snd_info_create_entry( NULL, "detect" );
  if ( !entry ) return -ENOMEM;
  entry -> t.text.read_size = PAGE_SIZE;
  entry -> t.text.read = snd_detect_read;
  if ( snd_info_register( entry ) < 0 ) {
    snd_info_free_entry( entry );
    return -ENOMEM;
  }
  snd_detect_info_entry = entry;
  return 0;
}

static int snd_detect_info_done( void )
{
  if ( snd_detect_info_entry )
    snd_info_unregister( snd_detect_info_entry );
  return 0;
}

int init_module( void )
{
#ifndef LINUX_2_1
  register_symtab( NULL );
#endif
  return snd_detect_info_init();
}

void cleanup_module( void )
{
  snd_detect_info_done();
}
