patch-2.3.38 linux/drivers/sound/via82cxxx.c
Next file: linux/drivers/sound/vwsnd.c
Previous file: linux/drivers/sound/trident.h
Back to the patch index
Back to the overall index
- Lines: 800
- Date:
Thu Jan 6 15:01:56 2000
- Orig file:
v2.3.37/linux/drivers/sound/via82cxxx.c
- Orig date:
Tue Sep 7 12:14:07 1999
diff -u --recursive --new-file v2.3.37/linux/drivers/sound/via82cxxx.c linux/drivers/sound/via82cxxx.c
@@ -1,101 +1,555 @@
/*
* Support for VIA 82Cxxx Audio Codecs
- * Copyright 1999 Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 1999,2000 Jeff Garzik <jgarzik@mandrakesoft.com>
*
* Distributed under the GNU GENERAL PUBLIC LICENSE (GPL) Version 2.
* See the "COPYING" file distributed with this software for more info.
*
- ********************************************************************
- *
- * TODO:
- *
- * - Integrate AC'97 support, when AC'97 interface released
+ * Documentation for this driver available as
+ * linux/Documentation/sound/via82cxxx.txt.
*
+ * Since the mixer is called from the OSS glue the kernel lock is always held
+ * on our AC97 mixing
*/
+
+#define VIA_VERSION "1.1.2"
+
+
+
#include <linux/module.h>
+#include <linux/config.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/init.h>
+#include <linux/proc_fs.h>
#include <asm/io.h>
#include "sound_config.h"
#include "soundmodule.h"
#include "sb.h"
+#include "ac97.h"
#ifndef SOUND_LOCK
#define SOUND_LOCK do {} while (0)
#define SOUND_LOCK_END do {} while (0)
#endif
+#define VIA_DEBUG 0 /* define to 1 to enable debugging output and checks */
+#if VIA_DEBUG
+/* note: prints function name for you */
+#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+#define VIA_NDEBUG 0 /* define to 1 to disable lightweight runtime checks */
+#if VIA_NDEBUG
+#define assert(expr)
+#else
+#define assert(expr) \
+ if(!(expr)) { \
+ printk( "Assertion failed! %s,%s,%s,line=%d\n", \
+ #expr,__FILE__,__FUNCTION__,__LINE__); \
+ }
+#endif
+
+#define arraysize(x) (sizeof(x)/sizeof(*(x)))
+
#define MAX_CARDS 2
-#define PFX "via82cxxx: "
+#define LINE_SIZE 10
-#define VIA_VERSION "1.0.0"
#define VIA_CARD_NAME "VIA 82Cxxx Audio driver " VIA_VERSION
+#define VIA_MODULE_NAME "via82cxxx"
+#define PFX VIA_MODULE_NAME ": "
+
+#define VIA_COUNTER_LIMIT 100000
+/* 82C686 function 5 (audio codec) PCI configuration registers */
#define VIA_FUNC_ENABLE 0x42
#define VIA_PNP_CONTROL 0x43
+#define VIA_AC97_CTRL 0x80
+
+/* PCI configuration register bits and masks */
+#define VIA_CR40_AC97_READY 0x01
+#define VIA_CR40_AC97_LOW_POWER 0x02
+#define VIA_CR40_SECONDARY_READY 0x04
+
+#define VIA_CR41_ACLINK_ENABLE 0x80
#define VIA_CR42_SB_ENABLE 0x01
#define VIA_CR42_MIDI_ENABLE 0x02
#define VIA_CR42_FM_ENABLE 0x04
+#define VIA_CR42_GAME_ENABLE 0x08
+
+#define VIA_CR44_SECOND_CODEC_SUPPORT (1 << 6)
+#define VIA_CR44_AC_LINK_ACCESS (1 << 7)
+
+#define VIA_CR80_FIRST_CODEC 0
+#define VIA_CR80_SECOND_CODEC (1 << 30)
+#define VIA_CR80_FIRST_CODEC_VALID (1 << 25)
+#define VIA_CR80_SECOND_CODEC_VALID (1 << 27)
+#define VIA_CR80_BUSY (1 << 24)
+#define VIA_CR80_READ_MODE (1 << 23)
+#define VIA_CR80_WRITE_MODE 0
+#define VIA_CR80_REG_IDX(idx) (((idx) & 0x7E) << 16)
+
+struct via_info {
+ struct address_info sb_data;
+ struct address_info opl3_data;
+ struct pci_dev *pdev;
+ struct ac97_hwint ac97;
+ int mixer_oss_dev;
+ int have_ac97;
+};
+static struct via_info cards [MAX_CARDS];
+static unsigned num_cards = 0;
+
+
+static const struct {
+ int revision;
+ const char *rev_name;
+} via_chip_revs[] __initdata = {
+ { 0x10, "A" },
+ { 0x11, "B" },
+ { 0x12, "C" },
+ { 0x13, "D" },
+ { 0x14, "E" },
+ { 0x20, "H" },
+};
+
+static inline void via_ac97_write32 (struct pci_dev *pdev, int port, u32 data)
+{
+ struct resource *rsrc = &pdev->resource[0];
+ outw ((u16)data,rsrc->start+port);
+ outw ((u16)(data>>16),rsrc->start+port+2);
+}
+
+static inline u32 via_ac97_read32 (struct pci_dev *pdev, int port)
+{
+ struct resource *rsrc = &pdev->resource[0];
+ return
+ ((u32)inw (rsrc->start+port)) |
+ (((u32)inw (rsrc->start+port+2)) << 16);
+}
+
+/****************************************************************
+ *
+ * Intel Audio Codec '97 interface
+ *
+ *
+ */
+
+static inline void via_ac97_wait_idle (struct pci_dev *pdev)
+{
+ u32 tmp;
+ int counter = VIA_COUNTER_LIMIT;
+
+ DPRINTK ("ENTER\n");
+
+ assert (pdev != NULL);
+
+ do {
+ tmp = via_ac97_read32 (pdev,VIA_AC97_CTRL);
+ } while ((tmp & VIA_CR80_BUSY) && (counter-- > 0));
+
+ DPRINTK ("EXIT%s\n", counter > 0 ? "" : ", counter limit reached");
+}
+
+
+static int via_ac97_read_reg (struct ac97_hwint *dev, u8 reg)
+{
+ u32 data;
+ struct via_info *card;
+ struct pci_dev *pdev;
+
+ DPRINTK ("ENTER\n");
+
+ assert (dev != NULL);
+ assert (dev->driver_private != NULL);
+
+ card = (struct via_info *) dev->driver_private;
+ pdev = card->pdev;
+ assert (pdev != NULL);
+
+ via_ac97_wait_idle (pdev);
+ data = VIA_CR80_FIRST_CODEC | VIA_CR80_FIRST_CODEC_VALID |
+ VIA_CR80_READ_MODE | VIA_CR80_REG_IDX(reg);
+ via_ac97_write32 (pdev,VIA_AC97_CTRL,data);
+ via_ac97_wait_idle (pdev);
+ data = via_ac97_read32 (pdev,VIA_AC97_CTRL);
+
+#if 0
+ if (! (data & VIA_CR80_FIRST_CODEC_VALID)) {
+ DPRINTK ("EXIT, first codec not valid, returning -1\n");
+ return -1;
+ }
+#endif
+
+ DPRINTK ("EXIT, returning %d\n", data & 0xFFFF);
+ return data & 0xFFFF;
+}
+
+
+static int via_ac97_write_reg (struct ac97_hwint *dev, u8 reg, u16 value)
+{
+ u32 data;
+ struct via_info *card;
+ struct pci_dev *pdev;
+
+ DPRINTK ("ENTER\n");
+
+ assert (dev != NULL);
+ assert (dev->driver_private != NULL);
+
+ card = (struct via_info *) dev->driver_private;
+ pdev = card->pdev;
+ assert (pdev != NULL);
+
+ via_ac97_wait_idle (pdev);
+ data = VIA_CR80_FIRST_CODEC | VIA_CR80_FIRST_CODEC_VALID |
+ VIA_CR80_WRITE_MODE | VIA_CR80_REG_IDX(reg) | value;
+ via_ac97_write32 (pdev,VIA_AC97_CTRL,data);
+
+#if 0
+ if (! (data & VIA_CR80_FIRST_CODEC_VALID)) {
+ DPRINTK ("EXIT, first codec invalid, returning -1\n");
+ return -1;
+ }
+#endif
+
+ DPRINTK ("EXIT, returning 0\n");
+ return 0;
+}
+
+
+static int via_ac97_reset (struct ac97_hwint *dev)
+{
+ struct via_info *card;
+ struct pci_dev *pdev;
+
+ DPRINTK ("ENTER\n");
+
+ assert (dev != NULL);
+ assert (dev->driver_private != NULL);
+
+ card = (struct via_info *) dev->driver_private;
+ pdev = card->pdev;
+ assert (pdev != NULL);
+
+ pci_write_config_word (pdev, PCI_COMMAND, PCI_COMMAND_IO);
+
+ DPRINTK ("EXIT, returning 0\n");
+ return 0;
+}
+
+
+static struct via_info *via_ac97_find_card_for_mixer (int dev)
+{
+ int x;
+
+ DPRINTK ("ENTER\n");
+
+ for (x = 0; x < num_cards; x++)
+ if (cards[x].mixer_oss_dev == dev) {
+ DPRINTK ("EXIT, returning %p\n", cards + x);
+ return cards + x;
+ }
+
+ DPRINTK ("EXIT, returning 0\n");
+ return NULL;
+}
+
+
+static int
+via_ac97_default_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg)
+{
+ int rc;
+ struct via_info *card = via_ac97_find_card_for_mixer (dev);
+
+ DPRINTK ("ENTER\n");
+
+ if (card != NULL) {
+ rc = ac97_mixer_ioctl (&card->ac97, cmd, arg);
+ DPRINTK ("EXIT, returning %d\n", rc);
+ return rc;
+ }
+
+ DPRINTK ("EXIT, returning -ENODEV\n");
+ return -ENODEV;
+
+}
+
+static struct mixer_operations via_ac97_mixer_operations =
+{
+ "VIA82Cxxx",
+ "via82cxxxAC97Mixer",
+ via_ac97_default_mixer_ioctl
+};
+
+static int __init via_attach_ac97 (struct via_info *card)
+{
+ int mixer;
+ struct ac97_hwint *mdev;
+
+ DPRINTK ("ENTER\n");
+
+ assert (card != NULL);
+
+ mdev = &card->ac97;
+
+ memset (mdev, 0, sizeof (*mdev));
+ mdev->reset_device = via_ac97_reset;
+ mdev->read_reg = via_ac97_read_reg;
+ mdev->write_reg = via_ac97_write_reg;
+ mdev->driver_private = (void *) card;
+
+ if (ac97_init (mdev)) {
+ printk (KERN_ERR PFX "Unable to init AC97\n");
+ DPRINTK ("EXIT, returning -1\n");
+ return -1;
+ }
+ mixer = sound_alloc_mixerdev ();
+ if (mixer < 0 || num_mixers >= MAX_MIXER_DEV) {
+ printk (KERN_ERR PFX "Unable to alloc mixerdev\n");
+ DPRINTK ("EXIT, returning -1\n");
+ return -1;
+ }
+ mixer_devs[mixer] = &via_ac97_mixer_operations;
+ card->mixer_oss_dev = mixer;
+
+ /* Some reasonable default values. */
+ ac97_set_mixer (mdev, SOUND_MIXER_VOLUME, (85 << 8) | 85);
+ ac97_set_mixer (mdev, SOUND_MIXER_SPEAKER, 100);
+ ac97_set_mixer (mdev, SOUND_MIXER_PCM, (65 << 8) | 65);
+ ac97_set_mixer (mdev, SOUND_MIXER_CD, (65 << 8) | 65);
-#define via_probe_midi probe_uart401
-#define via_attach_midi attach_uart401
-#define via_unload_midi unload_uart401
-
-static struct address_info sb_data[MAX_CARDS];
-static struct address_info opl3_data[MAX_CARDS];
-static unsigned cards = 0;
+ printk (KERN_INFO PFX "Initialized AC97 mixer\n");
+
+ card->have_ac97 = mixer;
+
+ DPRINTK ("EXIT, returning 0\n");
+ return 0;
+}
+
+
+static void via_unload_ac97 (struct via_info *card)
+{
+ DPRINTK ("ENTER\n");
+
+ assert (card != NULL);
+
+ if (card->have_ac97 >= 0)
+ sound_unload_mixerdev (card->have_ac97);
+
+ DPRINTK ("EXIT\n");
+}
+
+
+#ifdef CONFIG_PROC_FS
+
+/****************************************************************
+ *
+ * /proc/driver/via82cxxx/info
+ *
+ *
+ */
+
+static int via_info_read_proc (char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+#define YN(val,bit) (((val) & (bit)) ? "yes" : "no")
+
+ int len = 0, i;
+ u8 r40, r41, r42, r44;
+
+ DPRINTK ("ENTER\n");
+
+ len += sprintf (page+len, VIA_CARD_NAME "\n\n");
+
+ for (i = 0; i < num_cards; i++) {
+ pci_read_config_byte (cards[i].pdev, 0x40, &r40);
+ pci_read_config_byte (cards[i].pdev, 0x42, &r41);
+ pci_read_config_byte (cards[i].pdev, 0x42, &r42);
+ pci_read_config_byte (cards[i].pdev, 0x44, &r44);
+
+ len += sprintf (page+len,
+ "40 AC97 Codec Ready: %s\n"
+ " AC97 Codec Low-power: %s\n"
+ " Secondary Codec Ready: %s\n"
+
+ "41 AC-Link Interface Enable: %s\n"
+
+ "42 Game port enabled: %s\n"
+ " SoundBlaster enabled: %s\n"
+ " FM enabled: %s\n"
+ " MIDI enabled: %s\n"
+
+ "44 AC-Link Interface Access: %s\n"
+ " Secondary Codec Support: %s\n"
+
+ "\n",
+
+ YN (r40, VIA_CR40_AC97_READY),
+ YN (r40, VIA_CR40_AC97_LOW_POWER),
+ YN (r40, VIA_CR40_SECONDARY_READY),
+
+ YN (r41, VIA_CR41_ACLINK_ENABLE),
+
+ YN (r42, VIA_CR42_GAME_ENABLE),
+ YN (r42, VIA_CR42_SB_ENABLE),
+ YN (r42, VIA_CR42_FM_ENABLE),
+ YN (r42, VIA_CR42_MIDI_ENABLE),
+
+ YN (r44, VIA_CR44_AC_LINK_ACCESS),
+ YN (r44, VIA_CR44_SECOND_CODEC_SUPPORT)
+
+ );
+ }
+
+ DPRINTK("EXIT, returning %d\n", len);
+ return len;
+
+#undef YN
+}
+
+
+/****************************************************************
+ *
+ * /proc/driver/via82cxxx
+ *
+ *
+ */
+
+static int __init via_init_proc (void)
+{
+ DPRINTK ("ENTER\n");
+
+ proc_mkdir ("driver/via_audio", 0);
+ create_proc_read_entry ("driver/via_audio/info", 0, 0, via_info_read_proc, NULL);
+
+ DPRINTK("EXIT\n");
+ return 0;
+}
+
+
+
+static void __exit via_cleanup_proc (void)
+{
+ DPRINTK ("ENTER\n");
+ remove_proc_entry ("driver/via_audio/info", NULL);
+ remove_proc_entry ("driver/via_audio", NULL);
+ DPRINTK("EXIT\n");
+}
+
+
+#else
+
+static inline int via_init_proc (void) { return 0; }
+static inline void via_cleanup_proc (void) {}
+#endif /* CONFIG_PROC_FS */
+
+
+/****************************************************************
+ *
+ * Legacy SoundBlaster Pro, FM support via OSS
+ *
+ *
+ */
static void __init via_attach_sb(struct address_info *hw_config)
{
+ DPRINTK ("ENTER\n");
+
if(!sb_dsp_init(hw_config))
hw_config->slots[0] = -1;
+
+ DPRINTK("EXIT\n");
}
static int __init via_probe_sb(struct address_info *hw_config)
{
+ DPRINTK ("ENTER\n");
+
if (check_region(hw_config->io_base, 16))
{
printk(KERN_DEBUG PFX "SBPro port 0x%x is already in use\n",
hw_config->io_base);
return 0;
}
+ DPRINTK("EXIT after sb_dsp_detect\n");
return sb_dsp_detect(hw_config, 0, 0);
}
-static void __exit via_unload_sb(struct address_info *hw_config, int unload_mpu)
+static void __exit via_unload_sb(struct address_info *hw_config)
{
- if(hw_config->slots[0]!=-1)
- sb_dsp_unload(hw_config, unload_mpu);
+ DPRINTK ("ENTER\n");
+
+ if(hw_config->slots[0] != -1)
+ sb_dsp_unload(hw_config, 1);
+
+ DPRINTK("EXIT\n");
}
+static const struct {
+ int sb_irq,
+ sb_dma,
+ midi_base,
+ sb_io_base;
+} via_pnp_data[] __initdata = {
+ { 5, 0, 0x300, 0x220 },
+ { 7, 1, 0x310, 0x240 },
+ { 9, 2, 0x320, 0x260 },
+ { 10,3, 0x330, 0x280 },
+};
+
+
+/****************************************************************
+ *
+ * Chip setup and kernel registration
+ *
+ *
+ */
+
static int __init via82cxxx_install (struct pci_dev *pcidev)
{
- int sb_io_base = 0;
- int sb_irq = 0;
- int sb_dma = 0;
- int midi_base = 0;
+ int sb_io_base;
+ int sb_irq;
+ int sb_dma;
+ int midi_base, rc;
u8 tmp8;
+ struct via_info *card = &cards[num_cards];
- memset (&sb_data[cards], 0, sizeof (struct address_info));
- memset (&opl3_data[cards], 0, sizeof (struct address_info));
+ DPRINTK ("ENTER\n");
- sb_data[cards].name = opl3_data[cards].name = VIA_CARD_NAME;
- opl3_data[cards].irq = -1;
+ card->pdev = pcidev;
+ card->have_ac97 = -1;
+
+ /* turn off legacy features, if not already */
+ pci_read_config_byte (pcidev, VIA_FUNC_ENABLE, &tmp8);
+ tmp8 &= ~(VIA_CR42_SB_ENABLE | VIA_CR42_MIDI_ENABLE |
+ VIA_CR42_FM_ENABLE);
+ pci_write_config_byte (pcidev, VIA_FUNC_ENABLE, tmp8);
- /* turn on features, if not already */
+ /*
+ * try to init AC97 mixer device
+ */
+ rc = via_attach_ac97 (card);
+ if (rc) {
+ printk (KERN_WARNING PFX
+ "AC97 init failed, SB legacy mode only\n");
+ }
+
+ /* turn on legacy features */
pci_read_config_byte (pcidev, VIA_FUNC_ENABLE, &tmp8);
tmp8 |= VIA_CR42_SB_ENABLE | VIA_CR42_MIDI_ENABLE |
VIA_CR42_FM_ENABLE;
@@ -105,34 +559,10 @@
pci_read_config_byte (pcidev, VIA_PNP_CONTROL, &tmp8);
pci_write_config_byte (pcidev, VIA_PNP_CONTROL, tmp8);
- switch ((tmp8 >> 6) & 0x03) {
- case 0: sb_irq = 5; break;
- case 1: sb_irq = 7; break;
- case 2: sb_irq = 9; break;
- case 3: sb_irq = 10; break;
- default: /* do nothing */ break;
- }
- switch ((tmp8 >> 4) & 0x03) {
- case 0: sb_dma = 0; break;
- case 1: sb_dma = 1; break;
- case 2: sb_dma = 2; break;
- case 3: sb_dma = 3; break;
- default: /* do nothing */ break;
- }
- switch ((tmp8 >> 2) & 0x03) {
- case 0: midi_base = 0x300; break;
- case 1: midi_base = 0x310; break;
- case 2: midi_base = 0x320; break;
- case 3: midi_base = 0x330; break;
- default: /* do nothing */ break;
- }
- switch (tmp8 & 0x03) {
- case 0: sb_io_base = 0x220; break;
- case 1: sb_io_base = 0x240; break;
- case 2: sb_io_base = 0x260; break;
- case 3: sb_io_base = 0x280; break;
- default: /* do nothing */ break;
- }
+ sb_irq = via_pnp_data[((tmp8 >> 6) & 0x03)].sb_irq;
+ sb_dma = via_pnp_data[((tmp8 >> 4) & 0x03)].sb_dma;
+ midi_base = via_pnp_data[((tmp8 >> 2) & 0x03)].midi_base;
+ sb_io_base = via_pnp_data[(tmp8 & 0x03)].sb_io_base;
udelay(100);
@@ -140,33 +570,38 @@
"MIDI: 0x%X, SB: 0x%X / %d IRQ / %d DMA\n",
midi_base, sb_io_base, sb_irq, sb_dma);
- sb_data[cards].card_subtype = MDL_SBPRO;
- sb_data[cards].io_base = sb_io_base;
- sb_data[cards].irq = sb_irq;
- sb_data[cards].dma = sb_dma;
-
- opl3_data[cards].io_base = midi_base;
+ card->sb_data.name = VIA_CARD_NAME;
+ card->sb_data.card_subtype = MDL_SBPRO;
+ card->sb_data.io_base = sb_io_base;
+ card->sb_data.irq = sb_irq;
+ card->sb_data.dma = sb_dma;
/* register legacy SoundBlaster Pro */
- if (!via_probe_sb (&sb_data[cards])) {
+ if (!via_probe_sb (&card->sb_data)) {
printk (KERN_ERR PFX
"SB probe @ 0x%X failed, aborting\n",
sb_io_base);
+ DPRINTK ("EXIT, returning -1\n");
return -1;
}
- via_attach_sb (&sb_data[cards]);
+ via_attach_sb (&card->sb_data);
+ card->opl3_data.name = card->sb_data.name;
+ card->opl3_data.io_base = midi_base;
+ card->opl3_data.irq = -1;
+
/* register legacy MIDI */
- if (!via_probe_midi (&opl3_data[cards])) {
- printk (KERN_ERR PFX
- "MIDI probe @ 0x%X failed, aborting\n",
+ if (!probe_uart401 (&card->opl3_data)) {
+ printk (KERN_WARNING PFX
+ "MIDI probe @ 0x%X failed, continuing\n",
midi_base);
- via_unload_sb (&sb_data[cards], 0);
- return -1;
+ card->opl3_data.io_base = 0;
+ } else {
+ attach_uart401 (&card->opl3_data);
}
- via_attach_midi (&opl3_data[cards]);
- cards++;
+ num_cards++;
+ DPRINTK ("EXIT, returning 0\n");
return 0;
}
@@ -174,27 +609,28 @@
/*
* This loop walks the PCI configuration database and finds where
* the sound cards are.
+ *
+ * Note - only a single PCI scan occurs, eliminating possibility
+ * of multiple audio chips
+ *
*/
static int __init probe_via82cxxx (void)
{
struct pci_dev *pcidev = NULL;
- while ((pcidev = pci_find_device (PCI_VENDOR_ID_VIA,
- PCI_DEVICE_ID_VIA_82C686_5,
- pcidev)) != NULL) {
-
- if (via82cxxx_install (pcidev) != 0) {
- printk (KERN_ERR PFX "audio init failed\n");
- return -1;
- }
-
- if (cards == MAX_CARDS) {
- printk (KERN_DEBUG PFX "maximum number of cards reached\n");
- break;
- }
+ DPRINTK ("ENTER\n");
+
+ pcidev = pci_find_device (PCI_VENDOR_ID_VIA,
+ PCI_DEVICE_ID_VIA_82C686_5, NULL);
+
+ if (!pcidev || via82cxxx_install (pcidev) != 0) {
+ printk (KERN_ERR PFX "audio init failed\n");
+ DPRINTK ("EXIT, returning -1\n");
+ return -1;
}
+ DPRINTK ("EXIT, returning 0\n");
return 0;
}
@@ -207,28 +643,49 @@
static int __init init_via82cxxx_module(void)
{
+ u8 tmp;
+ int i;
+ const char *rev = "unknown!";
+
+ memset (cards, 0, sizeof (cards));
+
+ DPRINTK ("ENTER\n");
+
if (!pci_present ()) {
printk (KERN_DEBUG PFX "PCI not present, exiting\n");
+ DPRINTK ("EXIT, returning -ENODEV\n");
return -ENODEV;
}
if (probe_via82cxxx() != 0) {
printk(KERN_ERR PFX "probe failed, aborting\n");
/* XXX unload cards registered so far, if any */
+ DPRINTK ("EXIT, returning -ENODEV\n");
return -ENODEV;
}
- if (cards == 0) {
- printk(KERN_DEBUG PFX "No chips found, aborting\n");
- return -ENODEV;
- }
-
+ pci_read_config_byte (cards[0].pdev, PCI_REVISION_ID, &tmp);
+ for (i = 0; i < arraysize(via_chip_revs); i++)
+ if (via_chip_revs[i].revision == tmp) {
+ rev = via_chip_revs[i].rev_name;
+ break;
+ }
printk (KERN_INFO PFX VIA_CARD_NAME " loaded\n");
+ printk (KERN_INFO PFX "Chip rev %s. Features: SBPro compat%s%s\n",
+ rev,
+ cards[0].opl3_data.io_base == 0 ? "" : ", MPU-401 MIDI",
+ cards[0].have_ac97 == -1 ? "" : ", AC97 mixer");
+ if (via_init_proc () != 0) {
+ printk (KERN_WARNING PFX
+ "Unable to init experimental /proc, ignoring\n");
+ }
+
/*
* Binds us to the sound subsystem
*/
SOUND_LOCK;
+ DPRINTK ("EXIT, returning 0\n");
return 0;
}
@@ -240,15 +697,23 @@
static void __exit cleanup_via82cxxx_module(void)
{
- int i;
+ DPRINTK("ENTER\n");
+
+ if (cards[0].opl3_data.io_base)
+ unload_uart401 (&cards[0].opl3_data);
+
+ via_unload_sb (&cards[0].sb_data);
- for (i = 0; i < cards; i++)
- via_unload_sb (&sb_data[i], 1);
+ via_unload_ac97 (&cards[0]);
+ via_cleanup_proc ();
+
/*
* Final clean up with the sound layer
*/
SOUND_LOCK_END;
+
+ DPRINTK("EXIT\n");
}
module_init(init_via82cxxx_module);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)