Merge to Fedora kernel-2.6.18-1.2224_FC5 patched with stable patch-2.6.18.1-vs2.0...
[linux-2.6.git] / sound / pci / maestro3.c
index 26a5de0..45214b3 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/pci.h>
+#include <linux/dma-mapping.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/control.h>
 #include <sound/pcm.h>
 #include <sound/mpu401.h>
 #include <sound/ac97_codec.h>
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 
 MODULE_AUTHOR("Zach Brown <zab@zabbo.net>, Takashi Iwai <tiwai@suse.de>");
 MODULE_DESCRIPTION("ESS Maestro3 PCI");
 MODULE_LICENSE("GPL");
-MODULE_CLASSES("{sound}");
-MODULE_DEVICES("{{ESS,Maestro3 PCI},"
+MODULE_SUPPORTED_DEVICE("{{ESS,Maestro3 PCI},"
                "{ESS,ES1988},"
                "{ESS,Allegro PCI},"
                "{ESS,Allegro-1 PCI},"
@@ -64,21 +64,16 @@ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* all enabled */
 static int external_amp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
 static int amp_gpio[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = -1};
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard.");
-MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, NULL, 0444);
 MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard.");
-MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, NULL, 0444);
 MODULE_PARM_DESC(enable, "Enable this soundcard.");
-MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
-MODULE_PARM(external_amp, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(external_amp, bool, NULL, 0444);
 MODULE_PARM_DESC(external_amp, "Enable external amp for " CARD_NAME " soundcard.");
-MODULE_PARM_SYNTAX(external_amp, SNDRV_ENABLED "," SNDRV_BOOLEAN_TRUE_DESC);
-MODULE_PARM(amp_gpio, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(amp_gpio, int, NULL, 0444);
 MODULE_PARM_DESC(amp_gpio, "GPIO pin number for external amp. (default = -1)");
-MODULE_PARM_SYNTAX(amp_gpio, SNDRV_ENABLED);
 
 #define MAX_PLAYBACKS  2
 #define MAX_CAPTURES   1
@@ -773,11 +768,6 @@ MODULE_PARM_SYNTAX(amp_gpio, SNDRV_ENABLED);
 /*
  */
 
-typedef struct snd_m3_dma m3_dma_t;
-typedef struct snd_m3 m3_t;
-#define chip_t m3_t
-
-
 /* quirk lists */
 struct m3_quirk {
        const char *name;       /* device name */
@@ -787,17 +777,22 @@ struct m3_quirk {
                                   (e.g. for IrDA on Dell Inspirons) */
 };
 
+struct m3_hv_quirk {
+       u16 vendor, device, subsystem_vendor, subsystem_device;
+       u32 config;             /* ALLEGRO_CONFIG hardware volume bits */
+       int is_omnibook;        /* Do HP OmniBook GPIO magic? */
+};
+
 struct m3_list {
        int curlen;
        int mem_addr;
        int max;
 };
 
-struct snd_m3_dma {
+struct m3_dma {
 
        int number;
-       m3_t *chip;
-       snd_pcm_substream_t *substream;
+       struct snd_pcm_substream *substream;
 
        struct assp_instance {
                unsigned short code, data;
@@ -823,20 +818,20 @@ struct snd_m3_dma {
     
 struct snd_m3 {
        
-       snd_card_t *card;
+       struct snd_card *card;
 
        unsigned long iobase;
-       struct resource *iobase_res;
 
        int irq;
-       int allegro_flag : 1;
+       unsigned int allegro_flag : 1;
 
-       ac97_t *ac97;
+       struct snd_ac97 *ac97;
 
-       snd_pcm_t *pcm;
+       struct snd_pcm *pcm;
 
        struct pci_dev *pci;
-       struct m3_quirk *quirk;
+       const struct m3_quirk *quirk;
+       const struct m3_hv_quirk *hv_quirk;
 
        int dacs_active;
        int timer_users;
@@ -853,13 +848,18 @@ struct snd_m3 {
        int amp_gpio;
 
        /* midi */
-       snd_rawmidi_t *rmidi;
+       struct snd_rawmidi *rmidi;
 
        /* pcm streams */
        int num_substreams;
-       m3_dma_t *substreams;
+       struct m3_dma *substreams;
 
        spinlock_t reg_lock;
+       spinlock_t ac97_lock;
+
+       struct snd_kcontrol *master_switch;
+       struct snd_kcontrol *master_volume;
+       struct tasklet_struct hwvol_tq;
 
 #ifdef CONFIG_PM
        u16 *suspend_mem;
@@ -869,35 +869,6 @@ struct snd_m3 {
 /*
  * pci ids
  */
-
-#ifndef PCI_VENDOR_ID_ESS
-#define PCI_VENDOR_ID_ESS         0x125D
-#endif
-#ifndef PCI_DEVICE_ID_ESS_ALLEGRO_1
-#define PCI_DEVICE_ID_ESS_ALLEGRO_1    0x1988
-#endif
-#ifndef PCI_DEVICE_ID_ESS_ALLEGRO
-#define PCI_DEVICE_ID_ESS_ALLEGRO      0x1989
-#endif
-#ifndef PCI_DEVICE_ID_ESS_CANYON3D_2LE
-#define PCI_DEVICE_ID_ESS_CANYON3D_2LE 0x1990
-#endif
-#ifndef PCI_DEVICE_ID_ESS_CANYON3D_2
-#define PCI_DEVICE_ID_ESS_CANYON3D_2   0x1992
-#endif
-#ifndef PCI_DEVICE_ID_ESS_MAESTRO3
-#define PCI_DEVICE_ID_ESS_MAESTRO3     0x1998
-#endif
-#ifndef PCI_DEVICE_ID_ESS_MAESTRO3_1
-#define PCI_DEVICE_ID_ESS_MAESTRO3_1   0x1999
-#endif
-#ifndef PCI_DEVICE_ID_ESS_MAESTRO3_HW
-#define PCI_DEVICE_ID_ESS_MAESTRO3_HW  0x199a
-#endif
-#ifndef PCI_DEVICE_ID_ESS_MAESTRO3_2
-#define PCI_DEVICE_ID_ESS_MAESTRO3_2   0x199b
-#endif
-
 static struct pci_device_id snd_m3_ids[] = {
        {PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_ALLEGRO_1, PCI_ANY_ID, PCI_ANY_ID,
         PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0},
@@ -920,7 +891,7 @@ static struct pci_device_id snd_m3_ids[] = {
 
 MODULE_DEVICE_TABLE(pci, snd_m3_ids);
 
-static struct m3_quirk m3_quirk_list[] = {
+static const struct m3_quirk m3_quirk_list[] = {
        /* panasonic CF-28 "toughbook" */
        {
                .name = "Panasonic CF-28",
@@ -966,36 +937,103 @@ static struct m3_quirk m3_quirk_list[] = {
                .device = 0x80f1,
                .amp_gpio = 0x03,
        },
+       /* LEGEND ZhaoYang 3100CF */
+       {
+               .name = "LEGEND ZhaoYang 3100CF",
+               .vendor = 0x1509,
+               .device = 0x1740,
+               .amp_gpio = 0x03,
+       },
        /* END */
-       { 0 }
+       { NULL }
 };
 
+/* These values came from the Windows driver. */
+static const struct m3_hv_quirk m3_hv_quirk_list[] = {
+       /* Allegro chips */
+       { 0x125D, 0x1988, 0x0E11, 0x002E, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
+       { 0x125D, 0x1988, 0x0E11, 0x0094, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
+       { 0x125D, 0x1988, 0x0E11, 0xB112, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
+       { 0x125D, 0x1988, 0x0E11, 0xB114, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
+       { 0x125D, 0x1988, 0x103C, 0x0012, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
+       { 0x125D, 0x1988, 0x103C, 0x0018, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
+       { 0x125D, 0x1988, 0x103C, 0x001C, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
+       { 0x125D, 0x1988, 0x103C, 0x001D, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
+       { 0x125D, 0x1988, 0x103C, 0x001E, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
+       { 0x125D, 0x1988, 0x107B, 0x3350, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
+       { 0x125D, 0x1988, 0x10F7, 0x8338, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
+       { 0x125D, 0x1988, 0x10F7, 0x833C, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
+       { 0x125D, 0x1988, 0x10F7, 0x833D, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
+       { 0x125D, 0x1988, 0x10F7, 0x833E, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
+       { 0x125D, 0x1988, 0x10F7, 0x833F, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
+       { 0x125D, 0x1988, 0x13BD, 0x1018, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
+       { 0x125D, 0x1988, 0x13BD, 0x1019, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
+       { 0x125D, 0x1988, 0x13BD, 0x101A, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
+       { 0x125D, 0x1988, 0x14FF, 0x0F03, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
+       { 0x125D, 0x1988, 0x14FF, 0x0F04, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
+       { 0x125D, 0x1988, 0x14FF, 0x0F05, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
+       { 0x125D, 0x1988, 0x156D, 0xB400, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
+       { 0x125D, 0x1988, 0x156D, 0xB795, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
+       { 0x125D, 0x1988, 0x156D, 0xB797, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
+       { 0x125D, 0x1988, 0x156D, 0xC700, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
+       { 0x125D, 0x1988, 0x1033, 0x80F1, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
+       { 0x125D, 0x1988, 0x103C, 0x001A, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, /* HP OmniBook 6100 */
+       { 0x125D, 0x1988, 0x107B, 0x340A, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
+       { 0x125D, 0x1988, 0x107B, 0x3450, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
+       { 0x125D, 0x1988, 0x109F, 0x3134, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
+       { 0x125D, 0x1988, 0x109F, 0x3161, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
+       { 0x125D, 0x1988, 0x144D, 0x3280, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
+       { 0x125D, 0x1988, 0x144D, 0x3281, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
+       { 0x125D, 0x1988, 0x144D, 0xC002, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
+       { 0x125D, 0x1988, 0x144D, 0xC003, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
+       { 0x125D, 0x1988, 0x1509, 0x1740, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
+       { 0x125D, 0x1988, 0x1610, 0x0010, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
+       { 0x125D, 0x1988, 0x1042, 0x1042, HV_CTRL_ENABLE, 0 },
+       { 0x125D, 0x1988, 0x107B, 0x9500, HV_CTRL_ENABLE, 0 },
+       { 0x125D, 0x1988, 0x14FF, 0x0F06, HV_CTRL_ENABLE, 0 },
+       { 0x125D, 0x1988, 0x1558, 0x8586, HV_CTRL_ENABLE, 0 },
+       { 0x125D, 0x1988, 0x161F, 0x2011, HV_CTRL_ENABLE, 0 },
+       /* Maestro3 chips */
+       { 0x125D, 0x1998, 0x103C, 0x000E, HV_CTRL_ENABLE, 0 },
+       { 0x125D, 0x1998, 0x103C, 0x0010, HV_CTRL_ENABLE, 1 }, /* HP OmniBook 6000 */
+       { 0x125D, 0x1998, 0x103C, 0x0011, HV_CTRL_ENABLE, 1 }, /* HP OmniBook 500 */
+       { 0x125D, 0x1998, 0x103C, 0x001B, HV_CTRL_ENABLE, 0 },
+       { 0x125D, 0x1998, 0x104D, 0x80A6, HV_CTRL_ENABLE, 0 },
+       { 0x125D, 0x1998, 0x104D, 0x80AA, HV_CTRL_ENABLE, 0 },
+       { 0x125D, 0x1998, 0x107B, 0x5300, HV_CTRL_ENABLE, 0 },
+       { 0x125D, 0x1998, 0x110A, 0x1998, HV_CTRL_ENABLE, 0 },
+       { 0x125D, 0x1998, 0x13BD, 0x1015, HV_CTRL_ENABLE, 0 },
+       { 0x125D, 0x1998, 0x13BD, 0x101C, HV_CTRL_ENABLE, 0 },
+       { 0x125D, 0x1998, 0x13BD, 0x1802, HV_CTRL_ENABLE, 0 },
+       { 0x125D, 0x1998, 0x1599, 0x0715, HV_CTRL_ENABLE, 0 },
+       { 0x125D, 0x1998, 0x5643, 0x5643, HV_CTRL_ENABLE, 0 },
+       { 0x125D, 0x199A, 0x144D, 0x3260, HV_CTRL_ENABLE | REDUCED_DEBOUNCE, 0 },
+       { 0x125D, 0x199A, 0x144D, 0x3261, HV_CTRL_ENABLE | REDUCED_DEBOUNCE, 0 },
+       { 0x125D, 0x199A, 0x144D, 0xC000, HV_CTRL_ENABLE | REDUCED_DEBOUNCE, 0 },
+       { 0x125D, 0x199A, 0x144D, 0xC001, HV_CTRL_ENABLE | REDUCED_DEBOUNCE, 0 },
+       { 0 }
+};
 
 /*
  * lowlevel functions
  */
 
-#define big_mdelay(msec) do {\
-       set_current_state(TASK_UNINTERRUPTIBLE);\
-       schedule_timeout(((msec) * HZ) / 1000);\
-} while (0)
-       
-inline static void snd_m3_outw(m3_t *chip, u16 value, unsigned long reg)
+static inline void snd_m3_outw(struct snd_m3 *chip, u16 value, unsigned long reg)
 {
        outw(value, chip->iobase + reg);
 }
 
-inline static u16 snd_m3_inw(m3_t *chip, unsigned long reg)
+static inline u16 snd_m3_inw(struct snd_m3 *chip, unsigned long reg)
 {
        return inw(chip->iobase + reg);
 }
 
-inline static void snd_m3_outb(m3_t *chip, u8 value, unsigned long reg)
+static inline void snd_m3_outb(struct snd_m3 *chip, u8 value, unsigned long reg)
 {
        outb(value, chip->iobase + reg);
 }
 
-inline static u8 snd_m3_inb(m3_t *chip, unsigned long reg)
+static inline u8 snd_m3_inb(struct snd_m3 *chip, unsigned long reg)
 {
        return inb(chip->iobase + reg);
 }
@@ -1004,28 +1042,28 @@ inline static u8 snd_m3_inb(m3_t *chip, unsigned long reg)
  * access 16bit words to the code or data regions of the dsp's memory.
  * index addresses 16bit words.
  */
-static u16 snd_m3_assp_read(m3_t *chip, u16 region, u16 index)
+static u16 snd_m3_assp_read(struct snd_m3 *chip, u16 region, u16 index)
 {
        snd_m3_outw(chip, region & MEMTYPE_MASK, DSP_PORT_MEMORY_TYPE);
        snd_m3_outw(chip, index, DSP_PORT_MEMORY_INDEX);
        return snd_m3_inw(chip, DSP_PORT_MEMORY_DATA);
 }
 
-static void snd_m3_assp_write(m3_t *chip, u16 region, u16 index, u16 data)
+static void snd_m3_assp_write(struct snd_m3 *chip, u16 region, u16 index, u16 data)
 {
        snd_m3_outw(chip, region & MEMTYPE_MASK, DSP_PORT_MEMORY_TYPE);
        snd_m3_outw(chip, index, DSP_PORT_MEMORY_INDEX);
        snd_m3_outw(chip, data, DSP_PORT_MEMORY_DATA);
 }
 
-static void snd_m3_assp_halt(m3_t *chip)
+static void snd_m3_assp_halt(struct snd_m3 *chip)
 {
        chip->reset_state = snd_m3_inb(chip, DSP_PORT_CONTROL_REG_B) & ~REGB_STOP_CLOCK;
-       big_mdelay(10);
+       msleep(10);
        snd_m3_outb(chip, chip->reset_state & ~REGB_ENABLE_RESET, DSP_PORT_CONTROL_REG_B);
 }
 
-static void snd_m3_assp_continue(m3_t *chip)
+static void snd_m3_assp_continue(struct snd_m3 *chip)
 {
        snd_m3_outb(chip, chip->reset_state | REGB_ENABLE_RESET, DSP_PORT_CONTROL_REG_B);
 }
@@ -1039,7 +1077,7 @@ static void snd_m3_assp_continue(m3_t *chip)
  * by the binary code images.
  */
 
-static int snd_m3_add_list(m3_t *chip, struct m3_list *list, u16 val)
+static int snd_m3_add_list(struct snd_m3 *chip, struct m3_list *list, u16 val)
 {
        snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA,
                          list->mem_addr + list->curlen,
@@ -1047,7 +1085,7 @@ static int snd_m3_add_list(m3_t *chip, struct m3_list *list, u16 val)
        return list->curlen++;
 }
 
-static void snd_m3_remove_list(m3_t *chip, struct m3_list *list, int index)
+static void snd_m3_remove_list(struct snd_m3 *chip, struct m3_list *list, int index)
 {
        u16  val;
        int lastindex = list->curlen - 1;
@@ -1067,7 +1105,7 @@ static void snd_m3_remove_list(m3_t *chip, struct m3_list *list, int index)
        list->curlen--;
 }
 
-static void snd_m3_inc_timer_users(m3_t *chip)
+static void snd_m3_inc_timer_users(struct snd_m3 *chip)
 {
        chip->timer_users++;
        if (chip->timer_users != 1) 
@@ -1086,7 +1124,7 @@ static void snd_m3_inc_timer_users(m3_t *chip)
                    HOST_INT_CTRL);
 }
 
-static void snd_m3_dec_timer_users(m3_t *chip)
+static void snd_m3_dec_timer_users(struct snd_m3 *chip)
 {
        chip->timer_users--;
        if (chip->timer_users > 0)  
@@ -1110,7 +1148,8 @@ static void snd_m3_dec_timer_users(m3_t *chip)
  */
 
 /* spinlock held! */
-static int snd_m3_pcm_start(m3_t *chip, m3_dma_t *s, snd_pcm_substream_t *subs)
+static int snd_m3_pcm_start(struct snd_m3 *chip, struct m3_dma *s,
+                           struct snd_pcm_substream *subs)
 {
        if (! s || ! subs)
                return -EINVAL;
@@ -1126,7 +1165,7 @@ static int snd_m3_pcm_start(m3_t *chip, m3_dma_t *s, snd_pcm_substream_t *subs)
                                  chip->dacs_active);
                break;
        case SNDRV_PCM_STREAM_CAPTURE:
-               snd_m3_assp_write(s->chip, MEMTYPE_INTERNAL_DATA,
+               snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA,
                                  KDATA_ADC1_REQUEST, 1);
                snd_m3_assp_write(chip, MEMTYPE_INTERNAL_DATA,
                                  s->inst.data + CDATA_INSTANCE_READY, 1);
@@ -1136,7 +1175,8 @@ static int snd_m3_pcm_start(m3_t *chip, m3_dma_t *s, snd_pcm_substream_t *subs)
 }
 
 /* spinlock held! */
-static int snd_m3_pcm_stop(m3_t *chip, m3_dma_t *s, snd_pcm_substream_t *subs)
+static int snd_m3_pcm_stop(struct snd_m3 *chip, struct m3_dma *s,
+                          struct snd_pcm_substream *subs)
 {
        if (! s || ! subs)
                return -EINVAL;
@@ -1160,16 +1200,15 @@ static int snd_m3_pcm_stop(m3_t *chip, m3_dma_t *s, snd_pcm_substream_t *subs)
 }
 
 static int
-snd_m3_pcm_trigger(snd_pcm_substream_t *subs, int cmd)
+snd_m3_pcm_trigger(struct snd_pcm_substream *subs, int cmd)
 {
-       m3_t *chip = snd_pcm_substream_chip(subs);
-       m3_dma_t *s = (m3_dma_t*)subs->runtime->private_data;
-       unsigned long flags;
+       struct snd_m3 *chip = snd_pcm_substream_chip(subs);
+       struct m3_dma *s = subs->runtime->private_data;
        int err = -EINVAL;
 
        snd_assert(s != NULL, return -ENXIO);
 
-       spin_lock_irqsave(&chip->reg_lock, flags);
+       spin_lock(&chip->reg_lock);
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_RESUME:
@@ -1190,7 +1229,7 @@ snd_m3_pcm_trigger(snd_pcm_substream_t *subs, int cmd)
                }
                break;
        }
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
+       spin_unlock(&chip->reg_lock);
        return err;
 }
 
@@ -1198,10 +1237,10 @@ snd_m3_pcm_trigger(snd_pcm_substream_t *subs, int cmd)
  * setup
  */
 static void 
-snd_m3_pcm_setup1(m3_t *chip, m3_dma_t *s, snd_pcm_substream_t *subs)
+snd_m3_pcm_setup1(struct snd_m3 *chip, struct m3_dma *s, struct snd_pcm_substream *subs)
 {
        int dsp_in_size, dsp_out_size, dsp_in_buffer, dsp_out_buffer;
-       snd_pcm_runtime_t *runtime = subs->runtime;
+       struct snd_pcm_runtime *runtime = subs->runtime;
 
        if (subs->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                dsp_in_size = MINISRC_IN_BUFFER_SIZE - (0x20 * 2);
@@ -1283,7 +1322,8 @@ snd_m3_pcm_setup1(m3_t *chip, m3_dma_t *s, snd_pcm_substream_t *subs)
                          dsp_out_buffer);
 }
 
-static void snd_m3_pcm_setup2(m3_t *chip, m3_dma_t *s, snd_pcm_runtime_t *runtime)
+static void snd_m3_pcm_setup2(struct snd_m3 *chip, struct m3_dma *s,
+                             struct snd_pcm_runtime *runtime)
 {
        u32 freq;
 
@@ -1320,7 +1360,7 @@ static void snd_m3_pcm_setup2(m3_t *chip, m3_dma_t *s, snd_pcm_runtime_t *runtim
 }
 
 
-static struct play_vals {
+static const struct play_vals {
        u16 addr, val;
 } pv[] = {
        {CDATA_LEFT_VOLUME, ARB_VOLUME},
@@ -1349,7 +1389,8 @@ static struct play_vals {
 
 /* the mode passed should be already shifted and masked */
 static void
-snd_m3_playback_setup(m3_t *chip, m3_dma_t *s, snd_pcm_substream_t *subs)
+snd_m3_playback_setup(struct snd_m3 *chip, struct m3_dma *s,
+                     struct snd_pcm_substream *subs)
 {
        unsigned int i;
 
@@ -1386,7 +1427,7 @@ snd_m3_playback_setup(m3_t *chip, m3_dma_t *s, snd_pcm_substream_t *subs)
 /*
  *    Native record driver 
  */
-static struct rec_vals {
+static const struct rec_vals {
        u16 addr, val;
 } rv[] = {
        {CDATA_LEFT_VOLUME, ARB_VOLUME},
@@ -1415,7 +1456,7 @@ static struct rec_vals {
 };
 
 static void
-snd_m3_capture_setup(m3_t *chip, m3_dma_t *s, snd_pcm_substream_t *subs)
+snd_m3_capture_setup(struct snd_m3 *chip, struct m3_dma *s, struct snd_pcm_substream *subs)
 {
        unsigned int i;
 
@@ -1441,10 +1482,10 @@ snd_m3_capture_setup(m3_t *chip, m3_dma_t *s, snd_pcm_substream_t *subs)
                                  s->inst.data + rv[i].addr, rv[i].val);
 }
 
-static int snd_m3_pcm_hw_params(snd_pcm_substream_t * substream,
-                               snd_pcm_hw_params_t * hw_params)
+static int snd_m3_pcm_hw_params(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *hw_params)
 {
-       m3_dma_t *s = (m3_dma_t*) substream->runtime->private_data;
+       struct m3_dma *s = substream->runtime->private_data;
        int err;
 
        if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0)
@@ -1452,31 +1493,30 @@ static int snd_m3_pcm_hw_params(snd_pcm_substream_t * substream,
        /* set buffer address */
        s->buffer_addr = substream->runtime->dma_addr;
        if (s->buffer_addr & 0x3) {
-               snd_printk("oh my, not aligned\n");
+               snd_printk(KERN_ERR "oh my, not aligned\n");
                s->buffer_addr = s->buffer_addr & ~0x3;
        }
        return 0;
 }
 
-static int snd_m3_pcm_hw_free(snd_pcm_substream_t * substream)
+static int snd_m3_pcm_hw_free(struct snd_pcm_substream *substream)
 {
-       m3_dma_t *s;
+       struct m3_dma *s;
        
        if (substream->runtime->private_data == NULL)
                return 0;
-       s = (m3_dma_t*) substream->runtime->private_data;
+       s = substream->runtime->private_data;
        snd_pcm_lib_free_pages(substream);
        s->buffer_addr = 0;
        return 0;
 }
 
 static int
-snd_m3_pcm_prepare(snd_pcm_substream_t *subs)
+snd_m3_pcm_prepare(struct snd_pcm_substream *subs)
 {
-       m3_t *chip = snd_pcm_substream_chip(subs);
-       snd_pcm_runtime_t *runtime = subs->runtime;
-       m3_dma_t *s = (m3_dma_t*)runtime->private_data;
-       unsigned long flags;
+       struct snd_m3 *chip = snd_pcm_substream_chip(subs);
+       struct snd_pcm_runtime *runtime = subs->runtime;
+       struct m3_dma *s = runtime->private_data;
 
        snd_assert(s != NULL, return -ENXIO);
 
@@ -1487,7 +1527,7 @@ snd_m3_pcm_prepare(snd_pcm_substream_t *subs)
            runtime->rate < 8000)
                return -EINVAL;
 
-       spin_lock_irqsave(&chip->reg_lock, flags);
+       spin_lock_irq(&chip->reg_lock);
 
        snd_m3_pcm_setup1(chip, s, subs);
 
@@ -1498,7 +1538,7 @@ snd_m3_pcm_prepare(snd_pcm_substream_t *subs)
 
        snd_m3_pcm_setup2(chip, s, runtime);
 
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
+       spin_unlock_irq(&chip->reg_lock);
 
        return 0;
 }
@@ -1507,7 +1547,7 @@ snd_m3_pcm_prepare(snd_pcm_substream_t *subs)
  * get current pointer
  */
 static unsigned int
-snd_m3_get_pointer(m3_t *chip, m3_dma_t *s, snd_pcm_substream_t *subs)
+snd_m3_get_pointer(struct snd_m3 *chip, struct m3_dma *s, struct snd_pcm_substream *subs)
 {
        u16 hi = 0, lo = 0;
        int retry = 10;
@@ -1532,11 +1572,11 @@ snd_m3_get_pointer(m3_t *chip, m3_dma_t *s, snd_pcm_substream_t *subs)
 }
 
 static snd_pcm_uframes_t
-snd_m3_pcm_pointer(snd_pcm_substream_t * subs)
+snd_m3_pcm_pointer(struct snd_pcm_substream *subs)
 {
-       m3_t *chip = snd_pcm_substream_chip(subs);
+       struct snd_m3 *chip = snd_pcm_substream_chip(subs);
        unsigned int ptr;
-       m3_dma_t *s = (m3_dma_t*)subs->runtime->private_data;
+       struct m3_dma *s = subs->runtime->private_data;
        snd_assert(s != NULL, return 0);
 
        spin_lock(&chip->reg_lock);
@@ -1548,31 +1588,107 @@ snd_m3_pcm_pointer(snd_pcm_substream_t * subs)
 
 /* update pointer */
 /* spinlock held! */
-static void snd_m3_update_ptr(m3_t *chip, m3_dma_t *s)
+static void snd_m3_update_ptr(struct snd_m3 *chip, struct m3_dma *s)
 {
-       snd_pcm_substream_t *subs = s->substream;
+       struct snd_pcm_substream *subs = s->substream;
        unsigned int hwptr;
        int diff;
 
        if (! s->running)
                return;
 
-       hwptr = snd_m3_get_pointer(chip, s, subs) % s->dma_size;
-       diff = (s->dma_size + hwptr - s->hwptr) % s->dma_size;
+       hwptr = snd_m3_get_pointer(chip, s, subs);
+
+       /* try to avoid expensive modulo divisions */
+       if (hwptr >= s->dma_size)
+               hwptr %= s->dma_size;
+
+       diff = s->dma_size + hwptr - s->hwptr;
+       if (diff >= s->dma_size)
+               diff %= s->dma_size;
+
        s->hwptr = hwptr;
        s->count += diff;
+
        if (s->count >= (signed)s->period_size) {
-               s->count %= s->period_size;
+
+               if (s->count < 2 * (signed)s->period_size)
+                       s->count -= (signed)s->period_size;
+               else
+                       s->count %= s->period_size;
+
                spin_unlock(&chip->reg_lock);
                snd_pcm_period_elapsed(subs);
                spin_lock(&chip->reg_lock);
        }
 }
 
+static void snd_m3_update_hw_volume(unsigned long private_data)
+{
+       struct snd_m3 *chip = (struct snd_m3 *) private_data;
+       int x, val;
+       unsigned long flags;
+
+       /* Figure out which volume control button was pushed,
+          based on differences from the default register
+          values. */
+       x = inb(chip->iobase + SHADOW_MIX_REG_VOICE) & 0xee;
+
+       /* Reset the volume control registers. */
+       outb(0x88, chip->iobase + SHADOW_MIX_REG_VOICE);
+       outb(0x88, chip->iobase + HW_VOL_COUNTER_VOICE);
+       outb(0x88, chip->iobase + SHADOW_MIX_REG_MASTER);
+       outb(0x88, chip->iobase + HW_VOL_COUNTER_MASTER);
+
+       if (!chip->master_switch || !chip->master_volume)
+               return;
+
+       /* FIXME: we can't call snd_ac97_* functions since here is in tasklet. */
+       spin_lock_irqsave(&chip->ac97_lock, flags);
+
+       val = chip->ac97->regs[AC97_MASTER_VOL];
+       switch (x) {
+       case 0x88:
+               /* mute */
+               val ^= 0x8000;
+               chip->ac97->regs[AC97_MASTER_VOL] = val;
+               outw(val, chip->iobase + CODEC_DATA);
+               outb(AC97_MASTER_VOL, chip->iobase + CODEC_COMMAND);
+               snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
+                              &chip->master_switch->id);
+               break;
+       case 0xaa:
+               /* volume up */
+               if ((val & 0x7f) > 0)
+                       val--;
+               if ((val & 0x7f00) > 0)
+                       val -= 0x0100;
+               chip->ac97->regs[AC97_MASTER_VOL] = val;
+               outw(val, chip->iobase + CODEC_DATA);
+               outb(AC97_MASTER_VOL, chip->iobase + CODEC_COMMAND);
+               snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
+                              &chip->master_volume->id);
+               break;
+       case 0x66:
+               /* volume down */
+               if ((val & 0x7f) < 0x1f)
+                       val++;
+               if ((val & 0x7f00) < 0x1f00)
+                       val += 0x0100;
+               chip->ac97->regs[AC97_MASTER_VOL] = val;
+               outw(val, chip->iobase + CODEC_DATA);
+               outb(AC97_MASTER_VOL, chip->iobase + CODEC_COMMAND);
+               snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
+                              &chip->master_volume->id);
+               break;
+       }
+       spin_unlock_irqrestore(&chip->ac97_lock, flags);
+}
+
 static irqreturn_t
 snd_m3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
-       m3_t *chip = snd_magic_cast(m3_t, dev_id, );
+       struct snd_m3 *chip = dev_id;
        u8 status;
        int i;
 
@@ -1580,7 +1696,10 @@ snd_m3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 
        if (status == 0xff)
                return IRQ_NONE;
-   
+
+       if (status & HV_INT_PENDING)
+               tasklet_hi_schedule(&chip->hwvol_tq);
+
        /*
         * ack an assp int if its running
         * and has an int pending
@@ -1594,7 +1713,7 @@ snd_m3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                                /* update adc/dac info if it was a timer int */
                                spin_lock(&chip->reg_lock);
                                for (i = 0; i < chip->num_substreams; i++) {
-                                       m3_dma_t *s = &chip->substreams[i];
+                                       struct m3_dma *s = &chip->substreams[i];
                                        if (s->running)
                                                snd_m3_update_ptr(chip, s);
                                }
@@ -1609,7 +1728,7 @@ snd_m3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 #endif
 
        /* ack ints */
-       snd_m3_outw(chip, HOST_INT_STATUS, status);
+       outb(status, chip->iobase + HOST_INT_STATUS);
 
        return IRQ_HANDLED;
 }
@@ -1618,7 +1737,7 @@ snd_m3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 /*
  */
 
-static snd_pcm_hardware_t snd_m3_playback =
+static struct snd_pcm_hardware snd_m3_playback =
 {
        .info =                 (SNDRV_PCM_INFO_MMAP |
                                 SNDRV_PCM_INFO_INTERLEAVED |
@@ -1639,7 +1758,7 @@ static snd_pcm_hardware_t snd_m3_playback =
        .periods_max =          1024,
 };
 
-static snd_pcm_hardware_t snd_m3_capture =
+static struct snd_pcm_hardware snd_m3_capture =
 {
        .info =                 (SNDRV_PCM_INFO_MMAP |
                                 SNDRV_PCM_INFO_INTERLEAVED |
@@ -1665,24 +1784,23 @@ static snd_pcm_hardware_t snd_m3_capture =
  */
 
 static int
-snd_m3_substream_open(m3_t *chip, snd_pcm_substream_t *subs)
+snd_m3_substream_open(struct snd_m3 *chip, struct snd_pcm_substream *subs)
 {
        int i;
-       m3_dma_t *s;
-       unsigned long flags;
+       struct m3_dma *s;
 
-       spin_lock_irqsave(&chip->reg_lock, flags);
+       spin_lock_irq(&chip->reg_lock);
        for (i = 0; i < chip->num_substreams; i++) {
                s = &chip->substreams[i];
                if (! s->opened)
                        goto __found;
        }
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
+       spin_unlock_irq(&chip->reg_lock);
        return -ENOMEM;
 __found:
        s->opened = 1;
        s->running = 0;
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
+       spin_unlock_irq(&chip->reg_lock);
 
        subs->runtime->private_data = s;
        s->substream = subs;
@@ -1699,15 +1817,14 @@ __found:
 }
 
 static void
-snd_m3_substream_close(m3_t *chip, snd_pcm_substream_t *subs)
+snd_m3_substream_close(struct snd_m3 *chip, struct snd_pcm_substream *subs)
 {
-       m3_dma_t *s = (m3_dma_t*) subs->runtime->private_data;
-       unsigned long flags;
+       struct m3_dma *s = subs->runtime->private_data;
 
        if (s == NULL)
                return; /* not opened properly */
 
-       spin_lock_irqsave(&chip->reg_lock, flags);
+       spin_lock_irq(&chip->reg_lock);
        if (s->substream && s->running)
                snd_m3_pcm_stop(chip, s, s->substream); /* does this happen? */
        if (s->in_lists) {
@@ -1718,14 +1835,14 @@ snd_m3_substream_close(m3_t *chip, snd_pcm_substream_t *subs)
        }
        s->running = 0;
        s->opened = 0;
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
+       spin_unlock_irq(&chip->reg_lock);
 }
 
 static int
-snd_m3_playback_open(snd_pcm_substream_t *subs)
+snd_m3_playback_open(struct snd_pcm_substream *subs)
 {
-       m3_t *chip = snd_pcm_substream_chip(subs);
-       snd_pcm_runtime_t *runtime = subs->runtime;
+       struct snd_m3 *chip = snd_pcm_substream_chip(subs);
+       struct snd_pcm_runtime *runtime = subs->runtime;
        int err;
 
        if ((err = snd_m3_substream_open(chip, subs)) < 0)
@@ -1738,19 +1855,19 @@ snd_m3_playback_open(snd_pcm_substream_t *subs)
 }
 
 static int
-snd_m3_playback_close(snd_pcm_substream_t *subs)
+snd_m3_playback_close(struct snd_pcm_substream *subs)
 {
-       m3_t *chip = snd_pcm_substream_chip(subs);
+       struct snd_m3 *chip = snd_pcm_substream_chip(subs);
 
        snd_m3_substream_close(chip, subs);
        return 0;
 }
 
 static int
-snd_m3_capture_open(snd_pcm_substream_t *subs)
+snd_m3_capture_open(struct snd_pcm_substream *subs)
 {
-       m3_t *chip = snd_pcm_substream_chip(subs);
-       snd_pcm_runtime_t *runtime = subs->runtime;
+       struct snd_m3 *chip = snd_pcm_substream_chip(subs);
+       struct snd_pcm_runtime *runtime = subs->runtime;
        int err;
 
        if ((err = snd_m3_substream_open(chip, subs)) < 0)
@@ -1763,9 +1880,9 @@ snd_m3_capture_open(snd_pcm_substream_t *subs)
 }
 
 static int
-snd_m3_capture_close(snd_pcm_substream_t *subs)
+snd_m3_capture_close(struct snd_pcm_substream *subs)
 {
-       m3_t *chip = snd_pcm_substream_chip(subs);
+       struct snd_m3 *chip = snd_pcm_substream_chip(subs);
 
        snd_m3_substream_close(chip, subs);
        return 0;
@@ -1775,7 +1892,7 @@ snd_m3_capture_close(snd_pcm_substream_t *subs)
  * create pcm instance
  */
 
-static snd_pcm_ops_t snd_m3_playback_ops = {
+static struct snd_pcm_ops snd_m3_playback_ops = {
        .open =         snd_m3_playback_open,
        .close =        snd_m3_playback_close,
        .ioctl =        snd_pcm_lib_ioctl,
@@ -1786,7 +1903,7 @@ static snd_pcm_ops_t snd_m3_playback_ops = {
        .pointer =      snd_m3_pcm_pointer,
 };
 
-static snd_pcm_ops_t snd_m3_capture_ops = {
+static struct snd_pcm_ops snd_m3_capture_ops = {
        .open =         snd_m3_capture_open,
        .close =        snd_m3_capture_close,
        .ioctl =        snd_pcm_lib_ioctl,
@@ -1798,9 +1915,9 @@ static snd_pcm_ops_t snd_m3_capture_ops = {
 };
 
 static int __devinit
-snd_m3_pcm(m3_t * chip, int device)
+snd_m3_pcm(struct snd_m3 * chip, int device)
 {
-       snd_pcm_t *pcm;
+       struct snd_pcm *pcm;
        int err;
 
        err = snd_pcm_new(chip->card, chip->card->driver, device,
@@ -1831,51 +1948,52 @@ snd_m3_pcm(m3_t * chip, int device)
  * Wait for the ac97 serial bus to be free.
  * return nonzero if the bus is still busy.
  */
-static int snd_m3_ac97_wait(m3_t *chip)
+static int snd_m3_ac97_wait(struct snd_m3 *chip)
 {
        int i = 10000;
 
        do {
                if (! (snd_m3_inb(chip, 0x30) & 1))
                        return 0;
+               cpu_relax();
        } while (i-- > 0);
 
-       snd_printk("ac97 serial bus busy\n");
+       snd_printk(KERN_ERR "ac97 serial bus busy\n");
        return 1;
 }
 
 static unsigned short
-snd_m3_ac97_read(ac97_t *ac97, unsigned short reg)
+snd_m3_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
 {
-       m3_t *chip = snd_magic_cast(m3_t, ac97->private_data, return -ENXIO);
-       unsigned short ret = 0;
+       struct snd_m3 *chip = ac97->private_data;
        unsigned long flags;
+       unsigned short data = 0xffff;
 
-       spin_lock_irqsave(&chip->reg_lock, flags);
        if (snd_m3_ac97_wait(chip))
-               goto __error;
-       snd_m3_outb(chip, 0x80 | (reg & 0x7f), 0x30);
+               goto fail;
+       spin_lock_irqsave(&chip->ac97_lock, flags);
+       snd_m3_outb(chip, 0x80 | (reg & 0x7f), CODEC_COMMAND);
        if (snd_m3_ac97_wait(chip))
-               goto __error;
-       ret = snd_m3_inw(chip, 0x32);
-__error:
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
-       return ret;
+               goto fail_unlock;
+       data = snd_m3_inw(chip, CODEC_DATA);
+fail_unlock:
+       spin_unlock_irqrestore(&chip->ac97_lock, flags);
+fail:
+       return data;
 }
 
 static void
-snd_m3_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short val)
+snd_m3_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val)
 {
-       m3_t *chip = snd_magic_cast(m3_t, ac97->private_data, return);
+       struct snd_m3 *chip = ac97->private_data;
        unsigned long flags;
 
-       spin_lock_irqsave(&chip->reg_lock, flags);
        if (snd_m3_ac97_wait(chip))
-               goto __error;
-       snd_m3_outw(chip, val, 0x32);
-       snd_m3_outb(chip, reg & 0x7f, 0x30);
-__error:
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
+               return;
+       spin_lock_irqsave(&chip->ac97_lock, flags);
+       snd_m3_outw(chip, val, CODEC_DATA);
+       snd_m3_outb(chip, reg & 0x7f, CODEC_COMMAND);
+       spin_unlock_irqrestore(&chip->ac97_lock, flags);
 }
 
 
@@ -1894,7 +2012,7 @@ static void snd_m3_remote_codec_config(int io, int isremote)
 /* 
  * hack, returns non zero on err 
  */
-static int snd_m3_try_read_vendor(m3_t *chip)
+static int snd_m3_try_read_vendor(struct snd_m3 *chip)
 {
        u16 ret;
 
@@ -1911,7 +2029,7 @@ static int snd_m3_try_read_vendor(m3_t *chip)
        return (ret == 0) || (ret == 0xffff);
 }
 
-static void snd_m3_ac97_reset(m3_t *chip)
+static void snd_m3_ac97_reset(struct snd_m3 *chip)
 {
        u16 dir;
        int delay1 = 0, delay2 = 0, i;
@@ -1946,8 +2064,7 @@ static void snd_m3_ac97_reset(m3_t *chip)
                outw(0, io + GPIO_DATA);
                outw(dir | GPO_PRIMARY_AC97, io + GPIO_DIRECTION);
 
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               schedule_timeout((delay1 * HZ) / 1000);
+               schedule_timeout_uninterruptible(msecs_to_jiffies(delay1));
 
                outw(GPO_PRIMARY_AC97, io + GPIO_DATA);
                udelay(5);
@@ -1955,8 +2072,7 @@ static void snd_m3_ac97_reset(m3_t *chip)
                outw(IO_SRAM_ENABLE | SERIAL_AC_LINK_ENABLE, io + RING_BUS_CTRL_A);
                outw(~0, io + GPIO_MASK);
 
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               schedule_timeout((delay2 * HZ) / 1000);
+               schedule_timeout_uninterruptible(msecs_to_jiffies(delay2));
 
                if (! snd_m3_try_read_vendor(chip))
                        break;
@@ -1974,22 +2090,24 @@ static void snd_m3_ac97_reset(m3_t *chip)
         */
        tmp = inw(io + RING_BUS_CTRL_A);
        outw(RAC_SDFS_ENABLE|LAC_SDFS_ENABLE, io + RING_BUS_CTRL_A);
-       big_mdelay(20);
+       msleep(20);
        outw(tmp, io + RING_BUS_CTRL_A);
-       big_mdelay(50);
+       msleep(50);
 #endif
 }
 
-static int __devinit snd_m3_mixer(m3_t *chip)
+static int __devinit snd_m3_mixer(struct snd_m3 *chip)
 {
-       ac97_bus_t bus, *pbus;
-       ac97_t ac97;
+       struct snd_ac97_bus *pbus;
+       struct snd_ac97_template ac97;
+       struct snd_ctl_elem_id id;
        int err;
+       static struct snd_ac97_bus_ops ops = {
+               .write = snd_m3_ac97_write,
+               .read = snd_m3_ac97_read,
+       };
 
-       memset(&bus, 0, sizeof(bus));
-       bus.write = snd_m3_ac97_write;
-       bus.read = snd_m3_ac97_read;
-       if ((err = snd_ac97_bus(chip->card, &bus, &pbus)) < 0)
+       if ((err = snd_ac97_bus(chip->card, 0, &ops, NULL, &pbus)) < 0)
                return err;
        
        memset(&ac97, 0, sizeof(ac97));
@@ -1999,10 +2117,18 @@ static int __devinit snd_m3_mixer(m3_t *chip)
 
        /* seems ac97 PCM needs initialization.. hack hack.. */
        snd_ac97_write(chip->ac97, AC97_PCM, 0x8000 | (15 << 8) | 15);
-       set_current_state(TASK_UNINTERRUPTIBLE);
-       schedule_timeout(HZ / 10);
+       schedule_timeout_uninterruptible(msecs_to_jiffies(100));
        snd_ac97_write(chip->ac97, AC97_PCM, 0);
 
+       memset(&id, 0, sizeof(id));
+       id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+       strcpy(id.name, "Master Playback Switch");
+       chip->master_switch = snd_ctl_find_id(chip->card, &id);
+       memset(&id, 0, sizeof(id));
+       id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+       strcpy(id.name, "Master Playback Volume");
+       chip->master_volume = snd_ctl_find_id(chip->card, &id);
+
        return 0;
 }
 
@@ -2011,7 +2137,7 @@ static int __devinit snd_m3_mixer(m3_t *chip)
  * DSP Code images
  */
 
-static u16 assp_kernel_image[] __devinitdata = {
+static const u16 assp_kernel_image[] = {
     0x7980, 0x0030, 0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x00FB, 0x7980, 0x00DD, 0x7980, 0x03B4, 
     0x7980, 0x0332, 0x7980, 0x0287, 0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x03B4, 
     0x7980, 0x031A, 0x7980, 0x03B4, 0x7980, 0x022F, 0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x03B4, 
@@ -2098,7 +2224,7 @@ static u16 assp_kernel_image[] __devinitdata = {
  * Mini sample rate converter code image
  * that is to be loaded at 0x400 on the DSP.
  */
-static u16 assp_minisrc_image[] __devinitdata = {
+static const u16 assp_minisrc_image[] = {
 
     0xBF80, 0x101E, 0x906E, 0x006E, 0x8B88, 0x6980, 0xEF88, 0x906F, 0x0D6F, 0x6900, 0xEB08, 0x0412, 
     0xBC20, 0x696E, 0xB801, 0x906E, 0x7980, 0x0403, 0xB90E, 0x8807, 0xBE43, 0xBF01, 0xBE47, 0xBE41, 
@@ -2141,12 +2267,12 @@ static u16 assp_minisrc_image[] __devinitdata = {
  */
 
 #define MINISRC_LPF_LEN 10
-static u16 minisrc_lpf[MINISRC_LPF_LEN] __devinitdata = {
+static const u16 minisrc_lpf[MINISRC_LPF_LEN] = {
        0X0743, 0X1104, 0X0A4C, 0XF88D, 0X242C,
        0X1023, 0X1AA9, 0X0B60, 0XEFDD, 0X186F
 };
 
-static void __devinit snd_m3_assp_init(m3_t *chip)
+static void snd_m3_assp_init(struct snd_m3 *chip)
 {
        unsigned int i;
 
@@ -2166,7 +2292,7 @@ static void __devinit snd_m3_assp_init(m3_t *chip)
                          KDATA_DMA_XFER0);
 
        /* write kernel into code memory.. */
-       for (i = 0 ; i < sizeof(assp_kernel_image) / 2; i++) {
+       for (i = 0 ; i < ARRAY_SIZE(assp_kernel_image); i++) {
                snd_m3_assp_write(chip, MEMTYPE_INTERNAL_CODE, 
                                  REV_B_CODE_MEMORY_BEGIN + i, 
                                  assp_kernel_image[i]);
@@ -2178,7 +2304,7 @@ static void __devinit snd_m3_assp_init(m3_t *chip)
         * drop it there.  It seems that the minisrc doesn't
         * need vectors, so we won't bother with them..
         */
-       for (i = 0; i < sizeof(assp_minisrc_image) / 2; i++) {
+       for (i = 0; i < ARRAY_SIZE(assp_minisrc_image); i++) {
                snd_m3_assp_write(chip, MEMTYPE_INTERNAL_CODE, 
                                  0x400 + i, 
                                  assp_minisrc_image[i]);
@@ -2235,7 +2361,7 @@ static void __devinit snd_m3_assp_init(m3_t *chip)
 }
 
 
-static int __devinit snd_m3_assp_client_init(m3_t *chip, m3_dma_t *s, int index)
+static int __devinit snd_m3_assp_client_init(struct snd_m3 *chip, struct m3_dma *s, int index)
 {
        int data_bytes = 2 * ( MINISRC_TMP_BUFFER_SIZE / 2 + 
                               MINISRC_IN_BUFFER_SIZE / 2 +
@@ -2248,7 +2374,7 @@ static int __devinit snd_m3_assp_client_init(m3_t *chip, m3_dma_t *s, int index)
         */
 
        /*
-        * align instance address to 256 bytes so that it's
+        * align instance address to 256 bytes so that its
         * shifted list address is aligned.
         * list address = (mem address >> 1) >> 7;
         */
@@ -2256,7 +2382,7 @@ static int __devinit snd_m3_assp_client_init(m3_t *chip, m3_dma_t *s, int index)
        address = 0x1100 + ((data_bytes/2) * index);
 
        if ((address + (data_bytes/2)) >= 0x1c00) {
-               snd_printk("no memory for %d bytes at ind %d (addr 0x%x)\n",
+               snd_printk(KERN_ERR "no memory for %d bytes at ind %d (addr 0x%x)\n",
                           data_bytes, index, address);
                return -ENOMEM;
        }
@@ -2281,7 +2407,7 @@ static int __devinit snd_m3_assp_client_init(m3_t *chip, m3_dma_t *s, int index)
  * this needs more magic for 4 speaker, but..
  */
 static void
-snd_m3_amp_enable(m3_t *chip, int enable)
+snd_m3_amp_enable(struct snd_m3 *chip, int enable)
 {
        int io = chip->iobase;
        u16 gpo, polarity;
@@ -2305,9 +2431,10 @@ snd_m3_amp_enable(m3_t *chip, int enable)
 }
 
 static int
-snd_m3_chip_init(m3_t *chip)
+snd_m3_chip_init(struct snd_m3 *chip)
 {
        struct pci_dev *pcidev = chip->pci;
+       unsigned long io = chip->iobase;
        u32 n;
        u16 w;
        u8 t; /* makes as much sense as 'n', no? */
@@ -2318,8 +2445,27 @@ snd_m3_chip_init(m3_t *chip)
               DISABLE_LEGACY);
        pci_write_config_word(pcidev, PCI_LEGACY_AUDIO_CTRL, w);
 
+       if (chip->hv_quirk && chip->hv_quirk->is_omnibook) {
+               /*
+                * Volume buttons on some HP OmniBook laptops don't work
+                * correctly. This makes them work for the most part.
+                *
+                * Volume up and down buttons on the laptop side work.
+                * Fn+cursor_up (volme up) works.
+                * Fn+cursor_down (volume down) doesn't work.
+                * Fn+F7 (mute) works acts as volume up.
+                */
+               outw(~(GPI_VOL_DOWN|GPI_VOL_UP), io + GPIO_MASK);
+               outw(inw(io + GPIO_DIRECTION) & ~(GPI_VOL_DOWN|GPI_VOL_UP), io + GPIO_DIRECTION);
+               outw((GPI_VOL_DOWN|GPI_VOL_UP), io + GPIO_DATA);
+               outw(0xffff, io + GPIO_MASK);
+       }
        pci_read_config_dword(pcidev, PCI_ALLEGRO_CONFIG, &n);
-       n &= REDUCED_DEBOUNCE;
+       n &= ~(HV_CTRL_ENABLE | REDUCED_DEBOUNCE | HV_BUTTON_FROM_GD);
+       if (chip->hv_quirk)
+               n |= chip->hv_quirk->config;
+       /* For some reason we must always use reduced debounce. */
+       n |= REDUCED_DEBOUNCE;
        n |= PM_CTRL_ENABLE | CLK_DIV_BY_49 | USE_PCI_TIMING;
        pci_write_config_dword(pcidev, PCI_ALLEGRO_CONFIG, n);
 
@@ -2345,18 +2491,29 @@ snd_m3_chip_init(m3_t *chip)
        t |= ASSP_0_WS_ENABLE; 
        outb(t, chip->iobase + ASSP_CONTROL_A);
 
+       snd_m3_assp_init(chip); /* download DSP code before starting ASSP below */
        outb(RUN_ASSP, chip->iobase + ASSP_CONTROL_B); 
 
+       outb(0x00, io + HARDWARE_VOL_CTRL);
+       outb(0x88, io + SHADOW_MIX_REG_VOICE);
+       outb(0x88, io + HW_VOL_COUNTER_VOICE);
+       outb(0x88, io + SHADOW_MIX_REG_MASTER);
+       outb(0x88, io + HW_VOL_COUNTER_MASTER);
+
        return 0;
 } 
 
 static void
-snd_m3_enable_ints(m3_t *chip)
+snd_m3_enable_ints(struct snd_m3 *chip)
 {
        unsigned long io = chip->iobase;
+       unsigned short val;
 
        /* TODO: MPU401 not supported yet */
-       outw(ASSP_INT_ENABLE /*| MPU401_INT_ENABLE*/, io + HOST_INT_CTRL);
+       val = ASSP_INT_ENABLE /*| MPU401_INT_ENABLE*/;
+       if (chip->hv_quirk && (chip->hv_quirk->config & HV_CTRL_ENABLE))
+               val |= HV_INT_ENABLE;
+       outw(val, io + HOST_INT_CTRL);
        outb(inb(io + ASSP_CONTROL_C) | ASSP_HOST_INT_ENABLE,
             io + ASSP_CONTROL_C);
 }
@@ -2365,43 +2522,40 @@ snd_m3_enable_ints(m3_t *chip)
 /*
  */
 
-static int snd_m3_free(m3_t *chip)
+static int snd_m3_free(struct snd_m3 *chip)
 {
-       unsigned long flags;
-       m3_dma_t *s;
+       struct m3_dma *s;
        int i;
 
        if (chip->substreams) {
-               spin_lock_irqsave(&chip->reg_lock, flags);
+               spin_lock_irq(&chip->reg_lock);
                for (i = 0; i < chip->num_substreams; i++) {
                        s = &chip->substreams[i];
                        /* check surviving pcms; this should not happen though.. */
                        if (s->substream && s->running)
                                snd_m3_pcm_stop(chip, s, s->substream);
                }
-               spin_unlock_irqrestore(&chip->reg_lock, flags);
+               spin_unlock_irq(&chip->reg_lock);
                kfree(chip->substreams);
        }
-       if (chip->iobase_res) {
-               snd_m3_outw(chip, HOST_INT_CTRL, 0); /* disable ints */
+       if (chip->iobase) {
+               outw(0, chip->iobase + HOST_INT_CTRL); /* disable ints */
        }
 
 #ifdef CONFIG_PM
-       if (chip->suspend_mem)
-               vfree(chip->suspend_mem);
+       vfree(chip->suspend_mem);
 #endif
 
-       if (chip->irq >= 0)
+       if (chip->irq >= 0) {
                synchronize_irq(chip->irq);
-
-       if (chip->iobase_res) {
-               release_resource(chip->iobase_res);
-               kfree_nocheck(chip->iobase_res);
+               free_irq(chip->irq, chip);
        }
-       if (chip->irq >= 0)
-               free_irq(chip->irq, (void *)chip);
 
-       snd_magic_kfree(chip);
+       if (chip->iobase)
+               pci_release_regions(chip->pci);
+
+       pci_disable_device(chip->pci);
+       kfree(chip);
        return 0;
 }
 
@@ -2410,20 +2564,20 @@ static int snd_m3_free(m3_t *chip)
  * APM support
  */
 #ifdef CONFIG_PM
-
-static void m3_suspend(m3_t *chip)
+static int m3_suspend(struct pci_dev *pci, pm_message_t state)
 {
-       snd_card_t *card = chip->card;
+       struct snd_card *card = pci_get_drvdata(pci);
+       struct snd_m3 *chip = card->private_data;
        int i, index;
 
        if (chip->suspend_mem == NULL)
-               return;
-       if (card->power_state == SNDRV_CTL_POWER_D3hot)
-               return;
+               return 0;
 
+       snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
        snd_pcm_suspend_all(chip->pcm);
+       snd_ac97_suspend(chip->ac97);
 
-       big_mdelay(10); /* give the assp a chance to idle.. */
+       msleep(10); /* give the assp a chance to idle.. */
 
        snd_m3_assp_halt(chip);
 
@@ -2439,18 +2593,24 @@ static void m3_suspend(m3_t *chip)
        /* power down apci registers */
        snd_m3_outw(chip, 0xffff, 0x54);
        snd_m3_outw(chip, 0xffff, 0x56);
-       snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+
+       pci_disable_device(pci);
+       pci_save_state(pci);
+       return 0;
 }
 
-static void m3_resume(m3_t *chip)
+static int m3_resume(struct pci_dev *pci)
 {
-       snd_card_t *card = chip->card;
+       struct snd_card *card = pci_get_drvdata(pci);
+       struct snd_m3 *chip = card->private_data;
        int i, index;
 
        if (chip->suspend_mem == NULL)
-               return;
-       if (card->power_state == SNDRV_CTL_POWER_D0)
-               return;
+               return 0;
+
+       pci_restore_state(pci);
+       pci_enable_device(pci);
+       pci_set_master(pci);
 
        /* first lets just bring everything back. .*/
        snd_m3_outw(chip, 0, 0x54);
@@ -2481,64 +2641,31 @@ static void m3_resume(m3_t *chip)
        snd_m3_amp_enable(chip, 1);
 
        snd_power_change_state(card, SNDRV_CTL_POWER_D0);
-}
-
-static int snd_m3_suspend(struct pci_dev *pci, u32 state)
-{
-       m3_t *chip = snd_magic_cast(m3_t, pci_get_drvdata(pci), return -ENXIO);
-       m3_suspend(chip);
-       return 0;
-}
-static int snd_m3_resume(struct pci_dev *pci)
-{
-       m3_t *chip = snd_magic_cast(m3_t, pci_get_drvdata(pci), return -ENXIO);
-       m3_resume(chip);
        return 0;
 }
-
-/* callback */
-static int snd_m3_set_power_state(snd_card_t *card, unsigned int power_state)
-{
-       m3_t *chip = snd_magic_cast(m3_t, card->power_state_private_data, return -ENXIO);
-       switch (power_state) {
-       case SNDRV_CTL_POWER_D0:
-       case SNDRV_CTL_POWER_D1:
-       case SNDRV_CTL_POWER_D2:
-               m3_resume(chip);
-               break;
-       case SNDRV_CTL_POWER_D3hot:
-       case SNDRV_CTL_POWER_D3cold:
-               m3_suspend(chip);
-               break;
-       default:
-               return -EINVAL;
-       }
-       return 0;
-}
-
 #endif /* CONFIG_PM */
 
 
 /*
  */
 
-static int snd_m3_dev_free(snd_device_t *device)
+static int snd_m3_dev_free(struct snd_device *device)
 {
-       m3_t *chip = snd_magic_cast(m3_t, device->device_data, return -ENXIO);
+       struct snd_m3 *chip = device->device_data;
        return snd_m3_free(chip);
 }
 
 static int __devinit
-snd_m3_create(snd_card_t *card, struct pci_dev *pci,
+snd_m3_create(struct snd_card *card, struct pci_dev *pci,
              int enable_amp,
              int amp_gpio,
-             m3_t **chip_ret)
+             struct snd_m3 **chip_ret)
 {
-       m3_t *chip;
+       struct snd_m3 *chip;
        int i, err;
-       struct m3_quirk *quirk;
-       u16 subsystem_vendor, subsystem_device;
-       static snd_device_ops_t ops = {
+       const struct m3_quirk *quirk;
+       const struct m3_hv_quirk *hv_quirk;
+       static struct snd_device_ops ops = {
                .dev_free =     snd_m3_dev_free,
        };
 
@@ -2548,17 +2675,22 @@ snd_m3_create(snd_card_t *card, struct pci_dev *pci,
                return -EIO;
 
        /* check, if we can restrict PCI DMA transfers to 28 bits */
-       if (pci_set_dma_mask(pci, 0x0fffffff) < 0 ||
-           pci_set_consistent_dma_mask(pci, 0x0fffffff) < 0) {
-               snd_printk("architecture does not support 28bit PCI busmaster DMA\n");
+       if (pci_set_dma_mask(pci, DMA_28BIT_MASK) < 0 ||
+           pci_set_consistent_dma_mask(pci, DMA_28BIT_MASK) < 0) {
+               snd_printk(KERN_ERR "architecture does not support 28bit PCI busmaster DMA\n");
+               pci_disable_device(pci);
                return -ENXIO;
        }
 
-       chip = snd_magic_kcalloc(m3_t, 0, GFP_KERNEL);
-       if (chip == NULL)
+       chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+       if (chip == NULL) {
+               pci_disable_device(pci);
                return -ENOMEM;
+       }
 
        spin_lock_init(&chip->reg_lock);
+       spin_lock_init(&chip->ac97_lock);
+
        switch (pci->device) {
        case PCI_DEVICE_ID_ESS_ALLEGRO:
        case PCI_DEVICE_ID_ESS_ALLEGRO_1:
@@ -2572,18 +2704,25 @@ snd_m3_create(snd_card_t *card, struct pci_dev *pci,
        chip->pci = pci;
        chip->irq = -1;
 
-       pci_read_config_word(pci, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vendor);
-       pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &subsystem_device);
-
        for (quirk = m3_quirk_list; quirk->vendor; quirk++) {
-               if (subsystem_vendor == quirk->vendor &&
-                   subsystem_device == quirk->device) {
+               if (pci->subsystem_vendor == quirk->vendor &&
+                   pci->subsystem_device == quirk->device) {
                        printk(KERN_INFO "maestro3: enabled hack for '%s'\n", quirk->name);
                        chip->quirk = quirk;
                        break;
                }
        }
 
+       for (hv_quirk = m3_hv_quirk_list; hv_quirk->vendor; hv_quirk++) {
+               if (pci->vendor == hv_quirk->vendor &&
+                   pci->device == hv_quirk->device &&
+                   pci->subsystem_vendor == hv_quirk->subsystem_vendor &&
+                   pci->subsystem_device == hv_quirk->subsystem_device) {
+                       chip->hv_quirk = hv_quirk;
+                       break;
+               }
+       }
+
        chip->external_amp = enable_amp;
        if (amp_gpio >= 0 && amp_gpio <= 0x0f)
                chip->amp_gpio = amp_gpio;
@@ -2595,20 +2734,19 @@ snd_m3_create(snd_card_t *card, struct pci_dev *pci,
                chip->amp_gpio = GPO_EXT_AMP_M3;
 
        chip->num_substreams = NR_DSPS;
-       chip->substreams = kmalloc(sizeof(m3_dma_t) * chip->num_substreams, GFP_KERNEL);
+       chip->substreams = kcalloc(chip->num_substreams, sizeof(struct m3_dma),
+                                  GFP_KERNEL);
        if (chip->substreams == NULL) {
-               snd_magic_kfree(chip);
+               kfree(chip);
+               pci_disable_device(pci);
                return -ENOMEM;
        }
-       memset(chip->substreams, 0, sizeof(m3_dma_t) * chip->num_substreams);
 
-       chip->iobase = pci_resource_start(pci, 0);
-       if ((chip->iobase_res = request_region(chip->iobase, 256,
-                                              card->driver)) == NULL) {
-               snd_printk("unable to grab i/o ports %ld\n", chip->iobase);
+       if ((err = pci_request_regions(pci, card->driver)) < 0) {
                snd_m3_free(chip);
-               return -EBUSY;
+               return err;
        }
+       chip->iobase = pci_resource_start(pci, 0);
        
        /* just to be sure */
        pci_set_master(pci);
@@ -2618,31 +2756,13 @@ snd_m3_create(snd_card_t *card, struct pci_dev *pci,
 
        snd_m3_ac97_reset(chip);
 
-       snd_m3_assp_init(chip);
        snd_m3_amp_enable(chip, 1);
-    
-       if ((err = snd_m3_mixer(chip)) < 0) {
-               snd_m3_free(chip);
-               return err;
-       }
 
-       for (i = 0; i < chip->num_substreams; i++) {
-               m3_dma_t *s = &chip->substreams[i];
-               s->chip = chip;
-               if ((err = snd_m3_assp_client_init(chip, s, i)) < 0) {
-                       snd_m3_free(chip);
-                       return err;
-               }
-       }
-    
-       if ((err = snd_m3_pcm(chip, 0)) < 0) {
-               snd_m3_free(chip);
-               return err;
-       }
-    
-       if (request_irq(pci->irq, snd_m3_interrupt, SA_INTERRUPT|SA_SHIRQ,
-                       card->driver, (void *)chip)) {
-               snd_printk("unable to grab IRQ %d\n", pci->irq);
+       tasklet_init(&chip->hwvol_tq, snd_m3_update_hw_volume, (unsigned long)chip);
+
+       if (request_irq(pci->irq, snd_m3_interrupt, IRQF_DISABLED|IRQF_SHARED,
+                       card->driver, chip)) {
+               snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
                snd_m3_free(chip);
                return -ENOMEM;
        }
@@ -2651,11 +2771,7 @@ snd_m3_create(snd_card_t *card, struct pci_dev *pci,
 #ifdef CONFIG_PM
        chip->suspend_mem = vmalloc(sizeof(u16) * (REV_B_CODE_MEMORY_LENGTH + REV_B_DATA_MEMORY_LENGTH));
        if (chip->suspend_mem == NULL)
-               snd_printk("can't allocate apm buffer\n");
-       else {
-               card->set_power_state = snd_m3_set_power_state;
-               card->power_state_private_data = chip;
-       }
+               snd_printk(KERN_WARNING "can't allocate apm buffer\n");
 #endif
 
        if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
@@ -2663,6 +2779,18 @@ snd_m3_create(snd_card_t *card, struct pci_dev *pci,
                return err;
        }
 
+       if ((err = snd_m3_mixer(chip)) < 0)
+               return err;
+
+       for (i = 0; i < chip->num_substreams; i++) {
+               struct m3_dma *s = &chip->substreams[i];
+               if ((err = snd_m3_assp_client_init(chip, s, i)) < 0)
+                       return err;
+       }
+
+       if ((err = snd_m3_pcm(chip, 0)) < 0)
+               return err;
+    
        snd_m3_enable_ints(chip);
        snd_m3_assp_continue(chip);
 
@@ -2679,8 +2807,8 @@ static int __devinit
 snd_m3_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
 {
        static int dev;
-       snd_card_t *card;
-       m3_t *chip;
+       struct snd_card *card;
+       struct snd_m3 *chip;
        int err;
 
        /* don't pick up modems */
@@ -2719,6 +2847,7 @@ snd_m3_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
                snd_card_free(card);
                return err;
        }
+       card->private_data = chip;
 
        sprintf(card->shortname, "ESS %s PCI", card->driver);
        sprintf(card->longname, "%s at 0x%lx, irq %d",
@@ -2730,24 +2859,23 @@ snd_m3_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
        }
 
 #if 0 /* TODO: not supported yet */
-       /* TODO enable midi irq and i/o */
+       /* TODO enable MIDI IRQ and I/O */
        err = snd_mpu401_uart_new(chip->card, 0, MPU401_HW_MPU401,
-                                 chip->iobase + MPU401_DATA_PORT, 1,
+                                 chip->iobase + MPU401_DATA_PORT,
+                                 MPU401_INFO_INTEGRATED,
                                  chip->irq, 0, &chip->rmidi);
        if (err < 0)
-               printk(KERN_WARNING "maestro3: no midi support.\n");
+               printk(KERN_WARNING "maestro3: no MIDI support.\n");
 #endif
 
-       pci_set_drvdata(pci, chip);
+       pci_set_drvdata(pci, card);
        dev++;
        return 0;
 }
 
 static void __devexit snd_m3_remove(struct pci_dev *pci)
 {
-       m3_t *chip = snd_magic_cast(m3_t, pci_get_drvdata(pci), return);
-       if (chip)
-               snd_card_free(chip->card);
+       snd_card_free(pci_get_drvdata(pci));
        pci_set_drvdata(pci, NULL);
 }
 
@@ -2757,22 +2885,14 @@ static struct pci_driver driver = {
        .probe = snd_m3_probe,
        .remove = __devexit_p(snd_m3_remove),
 #ifdef CONFIG_PM
-       .suspend = snd_m3_suspend,
-       .resume = snd_m3_resume,
+       .suspend = m3_suspend,
+       .resume = m3_resume,
 #endif
 };
        
 static int __init alsa_card_m3_init(void)
 {
-       int err;
-
-       if ((err = pci_module_init(&driver)) < 0) {
-#ifdef MODULE
-               printk(KERN_ERR "Maestro3/Allegro soundcard not found or device busy\n");
-#endif
-               return err;
-       }
-       return 0;
+       return pci_register_driver(&driver);
 }
 
 static void __exit alsa_card_m3_exit(void)
@@ -2782,26 +2902,3 @@ static void __exit alsa_card_m3_exit(void)
 
 module_init(alsa_card_m3_init)
 module_exit(alsa_card_m3_exit)
-
-#ifndef MODULE
-
-/* format is: snd-maestro3=enable,index,id,external_amp,amp_gpio */
-
-static int __init alsa_card_maestro3_setup(char *str)
-{
-       static unsigned __initdata nr_dev = 0;
-
-       if (nr_dev >= SNDRV_CARDS)
-               return 0;
-       (void)(get_option(&str,&enable[nr_dev]) == 2 &&
-              get_option(&str,&index[nr_dev]) == 2 &&
-              get_id(&str,&id[nr_dev]) == 2 &&
-              get_option(&str,&external_amp[nr_dev]) == 2 &&
-              get_option(&str,&amp_gpio[nr_dev]) == 2);
-       nr_dev++;
-       return 1;
-}
-
-__setup("snd-maestro3=", alsa_card_maestro3_setup);
-
-#endif /* ifndef MODULE */