[patch] ES978 docking support for Maestro 2E - advice requested

Ben Pfaff (pfaffben@msu.edu)
13 May 2001 17:22:22 -0400


Hi. I have an Compaq Armada M700 laptop and an ArmadaStation II
laptop. The laptop has a Maestro 2E sound chipset in it, and the
docking station has the matching ES978 chip which controls
speakers and handles volume up/down/mute buttons on the side of
the docking station. The maestro.c driver in 2.4.4 doesn't have
support for these, so I wrote some code to do it. The following
patch adds support. It does the following:

* Turns on the docking station speakers and sets the
playback volume on them to the max. (Their volume is
still scaled based on the Maestro's master volume.)

* Adds basic support for the hardware volume control
buttons: the up button increases volume by 10%, the
down button decreases volume by 10%, the mute button
toggles the master volume on and off.

It doesn't do any of the following:

* Add the docking station volumes to the mixer--it just
hard-wires them to the max values. Should I do this?

* Make the buttons from the hardware volume control
available to software. Should I do this (I assume that
hard-wiring +/- 10% isn't really acceptable)? What's
the best way to do it--create a /dev/es978buttons and a
daemon, or what?

* Add any support for the recording features of the
docking station--just playback.

All comments appreciated.

--- /root/linux-2.4.4.clean/drivers/sound/maestro.c Fri Mar 2 14:12:11 2001
+++ linux-2.4.5pre1/drivers/sound/maestro.c Sun May 13 17:14:07 2001
@@ -115,6 +115,8 @@
* themselves, but we'll see.
*
* History
+ * (still kind of v0.14) May 13 2001 - Ben Pfaff <pfaffben@msu.edu>
+ * Add support for 978 docking and basic hardware volume control
* (still kind of v0.14) Nov 23 - Alan Cox <alan@redhat.com>
* Add clocking= for people with seriously warped hardware
* (still v0.14) Nov 10 2000 - Bartlomiej Zolnierkiewicz <bkz@linux-ide.org>
@@ -189,7 +191,7 @@
* fix bob frequency
* endianness
* do smart things with ac97 2.0 bits.
- * docking and dual codecs and 978?
+ * dual codecs
* leave 54->61 open
*
* it also would be fun to have a mode that would not use pci dma at all
@@ -483,8 +485,12 @@

int bob_freq;
char dsps_open;
+
+ int dock_mute_vol;
};

+static void set_mixer(struct ess_card *card,unsigned int mixer, unsigned int val );
+
static unsigned
ld2(unsigned int x)
{
@@ -983,6 +989,17 @@
outw(inw(ioaddr+0x68) | 0x600, ioaddr + 0x68);
outw(0x0209, ioaddr + 0x60);
}
+
+ /* Turn on the 978 docking chip.
+ First frob the "master output enable" bit,
+ then set most of the playback volume control registers to max. */
+ outb(inb(ioaddr+0xc0)|(1<<5), ioaddr+0xc0);
+ outb(0xff, ioaddr+0xc3);
+ outb(0xff, ioaddr+0xc4);
+ outb(0xff, ioaddr+0xc6);
+ outb(0xff, ioaddr+0xc8);
+ outb(0x3f, ioaddr+0xcf);
+ outb(0x3f, ioaddr+0xd0);
}
/*
* Indirect register access. Not all registers are readable so we
@@ -1895,19 +1912,52 @@
outw(inw(c->iobase+4)&1, c->iobase+4);

/* M_printk("maestro int: %x\n",event);*/
-
if(event&(1<<6))
{
- /* XXX if we have a hw volume control int enable
- all the ints? doesn't make sense.. */
- event = inw(c->iobase+0x18);
- outb(0xFF, c->iobase+0x1A);
- }
- else
- {
- /* else ack 'em all, i imagine */
- outb(0xFF, c->iobase+0x1A);
+ int x;
+ enum {UP_EVT, DOWN_EVT, MUTE_EVT} vol_evt;
+ int volume;
+
+ /* Figure out which volume control button was pushed,
+ based on differences from the default register
+ values. */
+ x = inb(c->iobase+0x1c);
+ if (x&1) vol_evt = MUTE_EVT;
+ else if (((x>>1)&7) > 4) vol_evt = UP_EVT;
+ else vol_evt = DOWN_EVT;
+
+ /* Reset the volume control registers. */
+ outb(0x88, c->iobase+0x1c);
+ outb(0x88, c->iobase+0x1d);
+ outb(0x88, c->iobase+0x1e);
+ outb(0x88, c->iobase+0x1f);
+
+ /* Deal with the button press in a hammer-handed
+ manner by adjusting the master mixer volume. */
+ volume = c->mix.mixer_state[0] & 0xff;
+ if (vol_evt == UP_EVT) {
+ volume += 10;
+ if (volume > 100)
+ volume = 100;
+ }
+ else if (vol_evt == DOWN_EVT) {
+ volume -= 10;
+ if (volume < 0)
+ volume = 0;
+ } else {
+ /* vol_evt == MUTE_EVT */
+ if (volume == 0)
+ volume = c->dock_mute_vol;
+ else {
+ c->dock_mute_vol = volume;
+ volume = 0;
+ }
+ }
+ set_mixer (c, 0, (volume << 8) | volume);
}
+
+ /* Ack all the interrupts. */
+ outb(0xFF, c->iobase+0x1A);

/*
* Update the pointers for all APU's we are running.
@@ -3087,8 +3137,8 @@
/* XXX how do we know which to use? */
w&=~(1<<14); /* External clock */

- w&=~(1<<7); /* HWV off */
- w&=~(1<<6); /* Debounce off */
+ w|= (1<<7); /* Hardware volume control on */
+ w|= (1<<6); /* Debounce off: easier to push the HWV buttons. */
w&=~(1<<5); /* GPIO 4:5 */
w|= (1<<4); /* Disconnect from the CHI. Enabling this made a dell 7500 work. */
w&=~(1<<2); /* MIDI fix off (undoc) */
@@ -3106,6 +3156,12 @@

pci_write_config_word(pcidev, 0x40, w);

+ /* Set up 978 docking control chip. */
+ pci_read_config_word(pcidev, 0x58, &w);
+ w|=1<<2; /* Enable 978. */
+ w|=1<<3; /* Turn on 978 hardware volume control. */
+ w&=~(1<<11); /* Turn on 978 mixer volume control. */
+ pci_write_config_word(pcidev, 0x58, w);

sound_reset(iobase);

@@ -3170,7 +3226,7 @@
outw(w, iobase+0x18);

w=inw(iobase+0x18);
- w&=~(1<<6); /* Harpo off */
+ w|=1<<6; /* Hardware volume control interrupt on. */
outw(w, iobase+0x18);

w=inw(iobase+0x18);
@@ -3193,6 +3249,13 @@
w|=(1<<0); /* SB IRQ on */
outw(w, iobase+0x18);

+ /* Set hardware volume control registers to midpoints.
+ We can tell which button was pushed based on how they change. */
+ outb(0x88, iobase+0x1c);
+ outb(0x88, iobase+0x1d);
+ outb(0x88, iobase+0x1e);
+ outb(0x88, iobase+0x1f);
+
/* it appears some maestros (dell 7500) only work if these are set,
regardless of wether we use the assp or not. */

@@ -3366,6 +3429,8 @@
spin_lock_init(&card->lock);
init_waitqueue_head(&card->suspend_queue);
devs = card;
+
+ card->dock_mute_vol = 50;

/* init our groups of 6 apus */
for(i=0;i<NR_DSPS;i++)

-- 
"Unix... is not so much a product
 as it is a painstakingly compiled oral history
 of the hacker subculture."
--Neal Stephenson
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/