/*
 *   ALSA driver for RME Digi96, Digi96/8 and Digi96/8 PRO/PAD/PST audio
 *   interfaces 
 *
 *	Copyright (c) 2000 Anders Torger <torger@ludd.luth.se>
 *
 *   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 "../include/driver.h"
#include "../include/pcm.h"
#include "../include/hwdep.h"
#include "../include/rme96.h"
#include "../include/initval.h"

static rme96_t *snd_rme96_cards[SND_CARDS] = SND_DEFAULT_PTR;

int snd_index[SND_CARDS] = SND_DEFAULT_IDX;	/* Index 0-MAX */
char *snd_id[SND_CARDS] = SND_DEFAULT_STR;	/* ID for this card */

MODULE_PARM(snd_index, "1-" __MODULE_STRING(SND_CARDS) "i");
MODULE_PARM_DESC(snd_index, "Index value for RME Digi96 soundcard.");
MODULE_PARM(snd_id, "1-" __MODULE_STRING(SND_CARDS) "s");
MODULE_PARM_DESC(snd_id, "ID string for RME Digi96 soundcard.");
MODULE_AUTHOR("Anders Torger <torger@ludd.luth.se>");
MODULE_DESCRIPTION("\
Driver: RME Digi96, Digi96/8, Digi96/8 PRO\n\
PCI: 0x10ee=0x3fc0\n\
PCI: 0x10ee=0x3fc1\n\
PCI: 0x10ee=0x3fc2\n\
PCI: 0x10ee=0x3fc3\n\
");

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

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

static int
snd_rme96_scan_pci(rme96_t *rme96, unsigned short device)
{
	if ((rme96->pci = pci_find_device(PCI_VENDOR_ID_XILINX, device, rme96->pci)) == NULL)
		return -ENODEV;

	if ((rme96->port = pci_resource_start(rme96->pci, 0)) == 0) {
		return -ENODEV;
	}
	
	if (rme96->pci->irq == 0) {
		return -ENODEV;
	}
	
	return 0;
}

static int __init
snd_rme96_probe(int dev,
		rme96_t *rme96)
{
	snd_card_t *card;
	int err;

	rme96->pci = NULL;
	do {
		err = snd_rme96_scan_pci(rme96, PCI_DEVICE_ID_DIGI96);
	} while (rme96->pci != NULL && err < 0);
	if (!err)
		goto __found;
	rme96->pci = NULL;
	do {
		err = snd_rme96_scan_pci(rme96, PCI_DEVICE_ID_DIGI96_8);
	} while (rme96->pci != NULL && err < 0);
	if (!err)
		goto __found;
	rme96->pci = NULL;
	do {
		err = snd_rme96_scan_pci(rme96, PCI_DEVICE_ID_DIGI96_8_PRO);
	} while (rme96->pci != NULL && err < 0);
	rme96->pci = NULL;
	do {
		err = snd_rme96_scan_pci(rme96, PCI_DEVICE_ID_DIGI96_8_PAD_OR_PST);
	} while (rme96->pci != NULL && err < 0);
	if (err)
		return err;
	
      __found:
	if ((err = pci_enable_device(rme96->pci)) < 0)
		return err;
	if ((card = snd_card_new(snd_index[dev], snd_id[dev], snd_rme96_use_inc,
				 snd_rme96_use_dec)) == NULL)
	{
		return -ENOMEM;
	}
	
	card->type = SND_CARD_TYPE_DIGI96;
	rme96->card = card;
	if ((err = snd_register_interrupt(card,
					  "RME Digi96",
					  rme96->pci->irq,
					  SND_IRQ_TYPE_PCI, 
					  snd_rme96_interrupt,
					  rme96, 
					  NULL,
					  &rme96->irqptr)) < 0)
	{		
		snd_card_free(card);
		return err;
	}
	
	if ((err = snd_rme96_create(dev, rme96)) < 0) {		
		snd_card_free(card);
		return err;
	}
	
	strcpy(card->abbreviation, "Digi96");
	switch (rme96->pci->device) {
	case PCI_DEVICE_ID_DIGI96:
		strcpy(card->shortname, "RME Digi96");
		break;
	case PCI_DEVICE_ID_DIGI96_8:
		strcpy(card->shortname, "RME Digi96/8");
		break;
	case PCI_DEVICE_ID_DIGI96_8_PRO:
		strcpy(card->shortname, "RME Digi96/8 Pro");
		break;
	}
	sprintf(card->longname, "%s at 0x%lx, irq %li", card->shortname,
		rme96->port, rme96->irqptr->irq);
	
	if ((err = snd_card_register(card)) < 0) {
		snd_unregister_interrupts(card);
		snd_card_free(card);
		return err;
	}
	
	return 0;	
}

static int __init alsa_card_rme96_init(void)
{
	int dev, cards;
	rme96_t *rme96;

	for (dev = cards = 0; dev < SND_CARDS; dev++, cards++) {
		if ((rme96 = snd_kcalloc(sizeof(rme96_t),
					 GFP_KERNEL)) == NULL)
		{
			return -ENOMEM;
		}
		if (snd_rme96_probe(dev, rme96) < 0) {
			snd_kfree(rme96);
			break;
		}
		snd_rme96_cards[dev] = rme96;
	}
	if (cards == 0) {
#ifdef MODULE
		snd_printk("No RME Digi96 cards found\n");
#endif
		return -ENODEV;
	}
	return 0;
}

static void __exit alsa_card_rme96_exit(void)
{
	int dev;

	for (dev = 0; dev < SND_CARDS; dev++) {
		snd_rme96_free(snd_rme96_cards[dev]);
	}
}

module_init(alsa_card_rme96_init)
module_exit(alsa_card_rme96_exit)
