#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>
/*
*/
-typedef struct snd_m3_dma m3_dma_t;
-typedef struct snd_m3 m3_t;
-
/* quirk lists */
struct m3_quirk {
const char *name; /* device name */
(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;
struct snd_m3 {
- snd_card_t *card;
+ struct snd_card *card;
unsigned long iobase;
int irq;
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;
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;
/*
* 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[] = {
+static struct pci_device_id snd_m3_ids[] __devinitdata = {
{PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_ALLEGRO_1, PCI_ANY_ID, PCI_ANY_ID,
PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0},
{PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_ALLEGRO, PCI_ANY_ID, PCI_ANY_ID,
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",
{ 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);
}
* 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);
}
* 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,
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;
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)
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)
*/
/* 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;
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);
}
/* 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;
}
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;
+ 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);
* 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);
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;
}
-static struct play_vals {
+static const struct play_vals {
u16 addr, val;
} pv[] = {
{CDATA_LEFT_VOLUME, ARB_VOLUME},
/* 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;
/*
* Native record driver
*/
-static struct rec_vals {
+static const struct rec_vals {
u16 addr, val;
} rv[] = {
{CDATA_LEFT_VOLUME, ARB_VOLUME},
};
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;
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)
/* 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;
+ 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);
* 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;
}
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);
/* 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 = dev_id;
+ struct snd_m3 *chip = dev_id;
u8 status;
int i;
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
/* 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);
}
#endif
/* ack ints */
- snd_m3_outw(chip, HOST_INT_STATUS, status);
+ outb(status, chip->iobase + HOST_INT_STATUS);
return IRQ_HANDLED;
}
/*
*/
-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 |
.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 |
*/
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;
+ struct m3_dma *s;
spin_lock_irq(&chip->reg_lock);
for (i = 0; i < chip->num_substreams; i++) {
}
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;
+ struct m3_dma *s = subs->runtime->private_data;
if (s == NULL)
return; /* not opened properly */
}
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)
}
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)
}
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;
* 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,
.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,
};
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,
* 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 = ac97->private_data;
+ struct snd_m3 *chip = ac97->private_data;
+ unsigned long flags;
+ unsigned short data = 0xffff;
if (snd_m3_ac97_wait(chip))
- return 0xffff;
+ goto fail;
+ spin_lock_irqsave(&chip->ac97_lock, flags);
snd_m3_outb(chip, 0x80 | (reg & 0x7f), CODEC_COMMAND);
if (snd_m3_ac97_wait(chip))
- return 0xffff;
- return snd_m3_inw(chip, CODEC_DATA);
+ 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 = ac97->private_data;
+ struct snd_m3 *chip = ac97->private_data;
+ unsigned long flags;
if (snd_m3_ac97_wait(chip))
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);
}
/*
* 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;
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;
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);
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;
*/
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 *pbus;
- ac97_template_t ac97;
+ struct snd_ac97_bus *pbus;
+ struct snd_ac97_template ac97;
+ struct snd_ctl_elem_id id;
int err;
- static ac97_bus_ops_t ops = {
+ static struct snd_ac97_bus_ops ops = {
.write = snd_m3_ac97_write,
.read = snd_m3_ac97_read,
};
/* 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;
}
* DSP Code images
*/
-static u16 assp_kernel_image[] __devinitdata = {
+static const u16 assp_kernel_image[] __devinitdata = {
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,
* 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[] __devinitdata = {
0xBF80, 0x101E, 0x906E, 0x006E, 0x8B88, 0x6980, 0xEF88, 0x906F, 0x0D6F, 0x6900, 0xEB08, 0x0412,
0xBC20, 0x696E, 0xB801, 0x906E, 0x7980, 0x0403, 0xB90E, 0x8807, 0xBE43, 0xBF01, 0xBE47, 0xBE41,
*/
#define MINISRC_LPF_LEN 10
-static u16 minisrc_lpf[MINISRC_LPF_LEN] __devinitdata = {
+static const u16 minisrc_lpf[MINISRC_LPF_LEN] __devinitdata = {
0X0743, 0X1104, 0X0A4C, 0XF88D, 0X242C,
0X1023, 0X1AA9, 0X0B60, 0XEFDD, 0X186F
};
-static void __devinit snd_m3_assp_init(m3_t *chip)
+static void __devinit snd_m3_assp_init(struct snd_m3 *chip)
{
unsigned int i;
}
-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 +
*/
/*
- * 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;
*/
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;
}
* 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;
}
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? */
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);
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);
}
/*
*/
-static int snd_m3_free(m3_t *chip)
+static int snd_m3_free(struct snd_m3 *chip)
{
- m3_dma_t *s;
+ struct m3_dma *s;
int i;
if (chip->substreams) {
kfree(chip->substreams);
}
if (chip->iobase) {
- snd_m3_outw(chip, HOST_INT_CTRL, 0); /* disable ints */
+ outw(0, chip->iobase + HOST_INT_CTRL); /* disable ints */
}
#ifdef CONFIG_PM
if (chip->irq >= 0) {
synchronize_irq(chip->irq);
- free_irq(chip->irq, (void *)chip);
+ free_irq(chip->irq, chip);
}
if (chip->iobase)
* APM support
*/
#ifdef CONFIG_PM
-static int m3_suspend(snd_card_t *card, pm_message_t state)
+static int m3_suspend(struct pci_dev *pci, pm_message_t state)
{
- m3_t *chip = card->pm_private_data;
+ struct snd_card *card = pci_get_drvdata(pci);
+ struct snd_m3 *chip = card->private_data;
int i, index;
if (chip->suspend_mem == NULL)
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);
snd_m3_outw(chip, 0xffff, 0x54);
snd_m3_outw(chip, 0xffff, 0x56);
- pci_disable_device(chip->pci);
+ pci_disable_device(pci);
+ pci_save_state(pci);
return 0;
}
-static int m3_resume(snd_card_t *card)
+static int m3_resume(struct pci_dev *pci)
{
- m3_t *chip = card->pm_private_data;
+ struct snd_card *card = pci_get_drvdata(pci);
+ struct snd_m3 *chip = card->private_data;
int i, index;
if (chip->suspend_mem == NULL)
return 0;
- pci_enable_device(chip->pci);
- pci_set_master(chip->pci);
+ pci_restore_state(pci);
+ pci_enable_device(pci);
+ pci_set_master(pci);
/* first lets just bring everything back. .*/
snd_m3_outw(chip, 0, 0x54);
snd_m3_enable_ints(chip);
snd_m3_amp_enable(chip, 1);
+ snd_power_change_state(card, SNDRV_CTL_POWER_D0);
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 = device->device_data;
+ 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,
};
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 = kcalloc(1, sizeof(*chip), GFP_KERNEL);
+ 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:
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;
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) {
kfree(chip);
pci_disable_device(pci);
return -ENOMEM;
}
- memset(chip->substreams, 0, sizeof(m3_dma_t) * chip->num_substreams);
if ((err = pci_request_regions(pci, card->driver)) < 0) {
snd_m3_free(chip);
snd_m3_ac97_reset(chip);
- snd_m3_assp_init(chip);
snd_m3_amp_enable(chip, 1);
+ tasklet_init(&chip->hwvol_tq, snd_m3_update_hw_volume, (unsigned long)chip);
+
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);
+ card->driver, chip)) {
+ snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
snd_m3_free(chip);
return -ENOMEM;
}
chip->suspend_mem = vmalloc(sizeof(u16) * (REV_B_CODE_MEMORY_LENGTH + REV_B_DATA_MEMORY_LENGTH));
if (chip->suspend_mem == NULL)
snd_printk(KERN_WARNING "can't allocate apm buffer\n");
- else
- snd_card_set_pm_callback(card, m3_suspend, m3_resume, chip);
#endif
if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
return err;
for (i = 0; i < chip->num_substreams; i++) {
- m3_dma_t *s = &chip->substreams[i];
- s->chip = chip;
+ struct m3_dma *s = &chip->substreams[i];
if ((err = snd_m3_assp_client_init(chip, s, i)) < 0)
return err;
}
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 */
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",
}
#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->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, card);
.id_table = snd_m3_ids,
.probe = snd_m3_probe,
.remove = __devexit_p(snd_m3_remove),
- SND_PCI_PM_CALLBACKS
+#ifdef CONFIG_PM
+ .suspend = m3_suspend,
+ .resume = m3_resume,
+#endif
};
static int __init alsa_card_m3_init(void)
{
- return pci_module_init(&driver);
+ return pci_register_driver(&driver);
}
static void __exit alsa_card_m3_exit(void)