--- alsa-kernel/ppc/awacs.c.orig 2008-02-05 11:23:24.000000000 +0200 +++ alsa-kernel/ppc/awacs.c 2008-03-31 16:21:41.000000000 +0300 @@ -28,6 +28,7 @@ #include #include "pmac.h" +#define chip_t struct snd_pmac #ifdef CONFIG_ADB_CUDA #define PMAC_AMP_AVAIL @@ -493,14 +494,14 @@ .private_value = AMP_CH_HD, }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Tone Control - Bass", + .name = "Tone Control - Bass Playback Volume", .info = snd_pmac_awacs_info_tone_amp, .get = snd_pmac_awacs_get_tone_amp, .put = snd_pmac_awacs_put_tone_amp, .private_value = 0, }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Tone Control - Treble", + .name = "Tone Control - Treble Playback Volume", .info = snd_pmac_awacs_info_tone_amp, .get = snd_pmac_awacs_get_tone_amp, .put = snd_pmac_awacs_put_tone_amp, @@ -544,7 +545,7 @@ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 1; uinfo->value.integer.min = 0; - uinfo->value.integer.max = 2; + uinfo->value.integer.max = 3; return 0; } @@ -552,16 +553,14 @@ struct snd_ctl_elem_value *ucontrol) { struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); - int val; + int val = 0; unsigned long flags; spin_lock_irqsave(&chip->reg_lock, flags); if (chip->awacs_reg[6] & MASK_MIC_BOOST) - val = 2; - else if (chip->awacs_reg[0] & MASK_GAINLINE) - val = 1; - else - val = 0; + val |= 2; + if (chip->awacs_reg[0] & MASK_GAINLINE) + val |= 1; spin_unlock_irqrestore(&chip->reg_lock, flags); ucontrol->value.integer.value[0] = val; return 0; @@ -578,10 +577,11 @@ spin_lock_irqsave(&chip->reg_lock, flags); val0 = chip->awacs_reg[0] & ~MASK_GAINLINE; val6 = chip->awacs_reg[6] & ~MASK_MIC_BOOST; - if (ucontrol->value.integer.value[0] > 0) { + if (ucontrol->value.integer.value[0] & 1) { val0 |= MASK_GAINLINE; - if (ucontrol->value.integer.value[0] > 1) - val6 |= MASK_MIC_BOOST; + } + if (ucontrol->value.integer.value[0] & 2) { + val6 |= MASK_MIC_BOOST; } if (val0 != chip->awacs_reg[0]) { snd_pmac_awacs_write_reg(chip, 0, val0); @@ -599,9 +599,32 @@ * lists of mixer elements */ static struct snd_kcontrol_new snd_pmac_awacs_mixers[] __initdata = { - AWACS_VOLUME("Master Playback Volume", 2, 6, 1), AWACS_SWITCH("Master Capture Switch", 1, SHIFT_LOOPTHRU, 0), - AWACS_VOLUME("Capture Volume", 0, 4, 0), + AWACS_VOLUME("Master Capture Volume", 0, 4, 0), +/* AWACS_SWITCH("Unknown Playback Switch", 6, SHIFT_PAROUT0, 0), */ +}; + +static struct snd_kcontrol_new snd_pmac_screamer_mixers_beige[] __initdata = { + AWACS_VOLUME("Master Playback Volume", 2, 6, 1), + AWACS_VOLUME("Play-through Playback Volume", 5, 6, 1), + AWACS_SWITCH("Line Capture Switch", 0, SHIFT_MUX_MIC, 0), + AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_LINE, 0), +}; + +static struct snd_kcontrol_new snd_pmac_screamer_mixers_imac[] __initdata = { + AWACS_VOLUME("Line out Playback Volume", 2, 6, 1), + AWACS_VOLUME("Master Playback Volume", 5, 6, 1), + AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_CD, 0), +}; + +static struct snd_kcontrol_new snd_pmac_awacs_mixers_pmac7500[] __initdata = { + AWACS_VOLUME("Line out Playback Volume", 2, 6, 1), + AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_CD, 0), + AWACS_SWITCH("Line Capture Switch", 0, SHIFT_MUX_MIC, 0), +}; + +static struct snd_kcontrol_new snd_pmac_awacs_mixers_pmac[] __initdata = { + AWACS_VOLUME("Master Playback Volume", 2, 6, 1), AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_CD, 0), }; @@ -621,25 +644,46 @@ static struct snd_kcontrol_new snd_pmac_awacs_master_sw __initdata = AWACS_SWITCH("Master Playback Switch", 1, SHIFT_HDMUTE, 1); +static struct snd_kcontrol_new snd_pmac_awacs_master_sw_imac __initdata = +AWACS_SWITCH("Line out Playback Switch", 1, SHIFT_HDMUTE, 1); + static struct snd_kcontrol_new snd_pmac_awacs_mic_boost[] __initdata = { - AWACS_SWITCH("Mic Boost", 0, SHIFT_GAINLINE, 0), + AWACS_SWITCH("Mic Boost Capture Switch", 0, SHIFT_GAINLINE, 0), }; static struct snd_kcontrol_new snd_pmac_screamer_mic_boost[] __initdata = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Mic Boost", + .name = "Mic Boost Capture Volume", .info = snd_pmac_screamer_mic_boost_info, .get = snd_pmac_screamer_mic_boost_get, .put = snd_pmac_screamer_mic_boost_put, }, }; +static struct snd_kcontrol_new snd_pmac_awacs_mic_boost_pmac7500[] __initdata = { + AWACS_SWITCH("Line Boost Capture Switch", 0, SHIFT_GAINLINE, 0), +}; + +static struct snd_kcontrol_new snd_pmac_screamer_mic_boost_beige[] __initdata = { + AWACS_SWITCH("Line Boost Capture Switch", 0, SHIFT_GAINLINE, 0), + AWACS_SWITCH("CD Boost Capture Switch", 6, SHIFT_MIC_BOOST, 0), +}; + +static struct snd_kcontrol_new snd_pmac_screamer_mic_boost_imac[] __initdata = { + AWACS_SWITCH("Line Boost Capture Switch", 0, SHIFT_GAINLINE, 0), + AWACS_SWITCH("Mic Boost Capture Switch", 6, SHIFT_MIC_BOOST, 0), +}; + static struct snd_kcontrol_new snd_pmac_awacs_speaker_vol[] __initdata = { AWACS_VOLUME("PC Speaker Playback Volume", 4, 6, 1), }; + static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw __initdata = AWACS_SWITCH("PC Speaker Playback Switch", 1, SHIFT_SPKMUTE, 1); +static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw_imac __initdata = +AWACS_SWITCH("PC Speaker Playback Switch", 1, SHIFT_PAROUT1, 0); + /* * add new mixer elements to the card @@ -708,6 +752,10 @@ } #endif /* CONFIG_PM */ +#define IS_PM7500 (machine_is_compatible("AAPL,7500")) +#define IS_BEIGE (machine_is_compatible("AAPL,Gossamer")) +#define IS_IMAC (machine_is_compatible("PowerMac2,1") || machine_is_compatible("PowerMac2,2") || machine_is_compatible("PowerMac4,1")) + #ifdef PMAC_SUPPORT_AUTOMUTE /* * auto-mute stuffs @@ -733,6 +781,7 @@ static void snd_pmac_awacs_update_automute(struct snd_pmac *chip, int do_notify) { + int imac = IS_IMAC; if (chip->auto_mute) { #ifdef PMAC_AMP_AVAIL if (chip->mixer_data) { @@ -751,8 +800,14 @@ #endif { int reg = chip->awacs_reg[1] | (MASK_HDMUTE|MASK_SPKMUTE); + if (imac) { + reg &= ~MASK_SPKMUTE; + reg &= ~MASK_PAROUT1; + } if (snd_pmac_awacs_detect_headphone(chip)) reg &= ~MASK_HDMUTE; + else if (imac) + reg |= MASK_PAROUT1; else reg &= ~MASK_SPKMUTE; if (do_notify && reg == chip->awacs_reg[1]) @@ -778,6 +833,9 @@ int __init snd_pmac_awacs_init(struct snd_pmac *chip) { + int pm7500 = IS_PM7500; + int beige = IS_BEIGE; + int imac = IS_IMAC; int err, vol; /* looks like MASK_GAINLINE triggers something, so we set here @@ -826,20 +884,24 @@ /* set headphone-jack detection bit */ switch (chip->model) { case PMAC_AWACS: - chip->hp_stat_mask = 0x04; + chip->hp_stat_mask = pm7500 ? MASK_HDPCONN : MASK_LOCONN; break; case PMAC_SCREAMER: switch (chip->device_id) { case 0x08: - /* 1 = side jack, 2 = front jack */ - chip->hp_stat_mask = 0x03; + case 0x0B: + chip->hp_stat_mask = imac + ? MASK_LOCONN_IMAC | + MASK_HDPLCONN_IMAC | + MASK_HDPRCONN_IMAC + : MASK_HDPCONN; break; case 0x00: case 0x05: - chip->hp_stat_mask = 0x04; + chip->hp_stat_mask = MASK_LOCONN; break; default: - chip->hp_stat_mask = 0x08; + chip->hp_stat_mask = MASK_HDPCONN; break; } break; @@ -857,15 +919,33 @@ if ((err = build_mixers(chip, ARRAY_SIZE(snd_pmac_awacs_mixers), snd_pmac_awacs_mixers)) < 0) return err; - if (chip->model == PMAC_SCREAMER) + if (beige) + ; + else if (chip->model == PMAC_SCREAMER) err = build_mixers(chip, ARRAY_SIZE(snd_pmac_screamer_mixers2), snd_pmac_screamer_mixers2); - else + else if (!pm7500) err = build_mixers(chip, ARRAY_SIZE(snd_pmac_awacs_mixers2), snd_pmac_awacs_mixers2); if (err < 0) return err; - chip->master_sw_ctl = snd_ctl_new1(&snd_pmac_awacs_master_sw, chip); + if (pm7500) + err = build_mixers(chip, ARRAY_SIZE(snd_pmac_awacs_mixers_pmac7500), + snd_pmac_awacs_mixers_pmac7500); + else if (beige) + err = build_mixers(chip, ARRAY_SIZE(snd_pmac_screamer_mixers_beige), + snd_pmac_screamer_mixers_beige); + else if (imac) + err = build_mixers(chip, ARRAY_SIZE(snd_pmac_screamer_mixers_imac), + snd_pmac_screamer_mixers_imac); + else + err = build_mixers(chip, ARRAY_SIZE(snd_pmac_awacs_mixers_pmac), + snd_pmac_awacs_mixers_pmac); + if (err < 0) + return err; + chip->master_sw_ctl = snd_ctl_new1((pm7500 || imac) + ? &snd_pmac_awacs_master_sw_imac + : &snd_pmac_awacs_master_sw, chip); if ((err = snd_ctl_add(chip->card, chip->master_sw_ctl)) < 0) return err; #ifdef PMAC_AMP_AVAIL @@ -893,15 +973,29 @@ if ((err = build_mixers(chip, ARRAY_SIZE(snd_pmac_awacs_speaker_vol), snd_pmac_awacs_speaker_vol)) < 0) return err; - chip->speaker_sw_ctl = snd_ctl_new1(&snd_pmac_awacs_speaker_sw, chip); + chip->speaker_sw_ctl = snd_ctl_new1(imac + ? &snd_pmac_awacs_speaker_sw_imac + : &snd_pmac_awacs_speaker_sw, chip); if ((err = snd_ctl_add(chip->card, chip->speaker_sw_ctl)) < 0) return err; } - if (chip->model == PMAC_SCREAMER) { + if (beige) { + if ((err = build_mixers(chip, ARRAY_SIZE(snd_pmac_screamer_mic_boost_beige), + snd_pmac_screamer_mic_boost_beige)) < 0) + return err; + } else if (imac) { + if ((err = build_mixers(chip, ARRAY_SIZE(snd_pmac_screamer_mic_boost_imac), + snd_pmac_screamer_mic_boost_imac)) < 0) + return err; + } else if (chip->model == PMAC_SCREAMER) { if ((err = build_mixers(chip, ARRAY_SIZE(snd_pmac_screamer_mic_boost), snd_pmac_screamer_mic_boost)) < 0) return err; + } else if (pm7500) { + if ((err = build_mixers(chip, ARRAY_SIZE(snd_pmac_awacs_mic_boost_pmac7500), + snd_pmac_awacs_mic_boost_pmac7500)) < 0) + return err; } else { if ((err = build_mixers(chip, ARRAY_SIZE(snd_pmac_awacs_mic_boost), snd_pmac_awacs_mic_boost)) < 0) --- alsa-kernel/ppc/awacs.h.orig 2008-02-05 11:23:24.000000000 +0200 +++ alsa-kernel/ppc/awacs.h 2008-03-31 23:45:36.000000000 +0300 @@ -116,6 +116,11 @@ #define MASK_HDMUTE MASK_AMUTE #define SHIFT_HDMUTE 9 #define MASK_PAROUT (0x3 << 10) /* Parallel Out (???) */ +#define MASK_PAROUT0 (0x1 << 10) /* Parallel Out (???) */ +#define MASK_PAROUT1 (0x1 << 11) /* Parallel Out (enable speaker) */ +#define SHIFT_PAROUT 10 +#define SHIFT_PAROUT0 10 +#define SHIFT_PAROUT1 11 #define SAMPLERATE_48000 (0x0 << 3) /* 48 or 44.1 kHz */ #define SAMPLERATE_32000 (0x1 << 3) /* 32 or 29.4 kHz */ @@ -152,8 +157,15 @@ #define MASK_REVISION (0xf << 12) /* Revision Number */ #define MASK_MFGID (0xf << 8) /* Mfg. ID */ #define MASK_CODSTATRES (0xf << 4) /* bits 4 - 7 reserved */ -#define MASK_INPPORT (0xf) /* Input Port */ -#define MASK_HDPCONN 8 /* headphone plugged in */ +#define MASK_INSENSE (0xf) /* port sense bits: */ +#define MASK_HDPCONN 8 /* headphone plugged in */ +#define MASK_LOCONN 4 /* line-out plugged in */ +#define MASK_LICONN 2 /* line-in plugged in */ +#define MASK_MICCONN 1 /* microphone plugged in */ +#define MASK_LICONN_IMAC 8 /* line-in plugged in */ +#define MASK_HDPRCONN_IMAC 4 /* headphone right plugged in */ +#define MASK_HDPLCONN_IMAC 2 /* headphone left plugged in */ +#define MASK_LOCONN_IMAC 1 /* line-out plugged in */ /* Clipping Count Reg Bit Masks */ /* -------- ----- --- --- ----- */ --- alsa-kernel/ppc/burgundy.c.orig 2008-02-05 11:23:24.000000000 +0200 +++ alsa-kernel/ppc/burgundy.c 2008-03-31 23:45:36.000000000 +0300 @@ -27,6 +27,7 @@ #include "pmac.h" #include "burgundy.h" +#define chip_t struct snd_pmac /* Waits for busy flag to clear */ static inline void @@ -126,8 +127,11 @@ return val; } +#define BASE2ADDR(base) ((base) << 12) +#define ADDR2BASE(addr) ((addr) >> 12) + /* - * Burgundy volume: 0 - 100, stereo + * Burgundy volume: 0 - 100, stereo, word reg */ static void snd_pmac_burgundy_write_volume(struct snd_pmac *chip, unsigned int address, @@ -168,13 +172,6 @@ volume[1] = 0; } - -/* - */ - -#define BASE2ADDR(base) ((base) << 12) -#define ADDR2BASE(addr) ((addr) >> 12) - static int snd_pmac_burgundy_info_volume(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -211,13 +208,247 @@ nvoices[1] != ucontrol->value.integer.value[1]); } -#define BURGUNDY_VOLUME(xname, xindex, addr, shift) \ +#define BURGUNDY_VOLUME_W(xname, xindex, addr, shift) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex,\ .info = snd_pmac_burgundy_info_volume,\ .get = snd_pmac_burgundy_get_volume,\ .put = snd_pmac_burgundy_put_volume,\ .private_value = ((ADDR2BASE(addr) & 0xff) | ((shift) << 8)) } +/* + * Burgundy volume: 0 - 100, stereo, 2-byte reg + */ +static void +snd_pmac_burgundy_write_volume_2b(struct snd_pmac *chip, unsigned int address, long *volume, int off) +{ + int lvolume, rvolume; + + off |= off << 2; + lvolume = volume[0] ? volume[0] + BURGUNDY_VOLUME_OFFSET : 0; + rvolume = volume[1] ? volume[1] + BURGUNDY_VOLUME_OFFSET : 0; + + snd_pmac_burgundy_wcb(chip, address + off, lvolume); + snd_pmac_burgundy_wcb(chip, address + off + 0x500, rvolume); +} + +static void +snd_pmac_burgundy_read_volume_2b(struct snd_pmac *chip, unsigned int address, long *volume, int off) +{ + volume[0] = snd_pmac_burgundy_rcb(chip, address + off); + if (volume[0] >= BURGUNDY_VOLUME_OFFSET) + volume[0] -= BURGUNDY_VOLUME_OFFSET; + else + volume[0] = 0; + volume[1] = snd_pmac_burgundy_rcb(chip, address + off + 0x100); + if (volume[1] >= BURGUNDY_VOLUME_OFFSET) + volume[1] -= BURGUNDY_VOLUME_OFFSET; + else + volume[1] = 0; +} + +static int snd_pmac_burgundy_info_volume_2b(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 2; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 100; + return 0; +} + +static int snd_pmac_burgundy_get_volume_2b(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); + unsigned int addr = BASE2ADDR(kcontrol->private_value & 0xff); + int off = kcontrol->private_value & 0x300; + snd_pmac_burgundy_read_volume_2b(chip, addr, ucontrol->value.integer.value, off); + return 0; +} + +static int snd_pmac_burgundy_put_volume_2b(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); + unsigned int addr = BASE2ADDR(kcontrol->private_value & 0xff); + int off = kcontrol->private_value & 0x300; + long nvoices[2]; + + snd_pmac_burgundy_write_volume_2b(chip, addr, ucontrol->value.integer.value, off); + snd_pmac_burgundy_read_volume_2b(chip, addr, nvoices, off); + return (nvoices[0] != ucontrol->value.integer.value[0] || + nvoices[1] != ucontrol->value.integer.value[1]); +} + +#define BURGUNDY_VOLUME_2B(xname, xindex, addr, off) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex,\ + .info = snd_pmac_burgundy_info_volume_2b,\ + .get = snd_pmac_burgundy_get_volume_2b,\ + .put = snd_pmac_burgundy_put_volume_2b,\ + .private_value = ((ADDR2BASE(addr) & 0xff) | ((off) << 8)) } + +/* + * Burgundy gain/attenuation: 0 - 15, mono/stereo, byte reg + */ +static int snd_pmac_burgundy_info_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) +{ + int stereo = (kcontrol->private_value >> 24) & 1; + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = stereo + 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 15; + return 0; +} + +static int snd_pmac_burgundy_get_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); + unsigned int addr = BASE2ADDR(kcontrol->private_value & 0xff); + int stereo = (kcontrol->private_value >> 24) & 1; + int atten = (kcontrol->private_value >> 25) & 1; + int oval; + + oval = snd_pmac_burgundy_rcb(chip, addr); + if (atten) + oval = ~oval & 0xff; + ucontrol->value.integer.value[0] = oval & 0xf; + if (stereo) + ucontrol->value.integer.value[1] = (oval >> 4) & 0xf; + return 0; +} + +static int snd_pmac_burgundy_put_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); + unsigned int addr = BASE2ADDR(kcontrol->private_value & 0xff); + int stereo = (kcontrol->private_value >> 24) & 1; + int atten = (kcontrol->private_value >> 25) & 1; + int oval, val; + + oval = snd_pmac_burgundy_rcb(chip, addr); + if (atten) + oval = ~oval & 0xff; + val = ucontrol->value.integer.value[0]; + if (stereo) + val |= ucontrol->value.integer.value[1] << 4; + else + val |= ucontrol->value.integer.value[0] << 4; + if (atten) + val = ~val & 0xff; + snd_pmac_burgundy_wcb(chip, addr, val); + return val != oval; +} + +#define BURGUNDY_VOLUME_B(xname, xindex, addr, stereo, atten) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex,\ + .info = snd_pmac_burgundy_info_gain,\ + .get = snd_pmac_burgundy_get_gain,\ + .put = snd_pmac_burgundy_put_gain,\ + .private_value = (ADDR2BASE(addr) | ((stereo) << 24) | ((atten) << 25)) } + +/* + * Burgundy switch: 0/1, mono/stereo, word reg + */ +static int snd_pmac_burgundy_info_switch_w(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) +{ + int stereo = (kcontrol->private_value >> 24) & 1; + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = stereo + 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int snd_pmac_burgundy_get_switch_w(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); + unsigned int addr = BASE2ADDR((kcontrol->private_value >> 16) & 0xff); + int lmask = 1 << (kcontrol->private_value & 0xff); + int rmask = 1 << ((kcontrol->private_value >> 8) & 0xff); + int stereo = (kcontrol->private_value >> 24) & 1; + int val = snd_pmac_burgundy_rcw(chip, addr); + ucontrol->value.integer.value[0] = (val & lmask) ? 1 : 0; + if (stereo) + ucontrol->value.integer.value[1] = (val & rmask) ? 1 : 0; + return 0; +} + +static int snd_pmac_burgundy_put_switch_w(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); + unsigned int addr = BASE2ADDR((kcontrol->private_value >> 16) & 0xff); + int lmask = 1 << (kcontrol->private_value & 0xff); + int rmask = 1 << ((kcontrol->private_value >> 8) & 0xff); + int stereo = (kcontrol->private_value >> 24) & 1; + int val, oval; + oval = snd_pmac_burgundy_rcw(chip, addr); + val = oval & ~(lmask | (stereo ? rmask : 0)); + if (ucontrol->value.integer.value[0]) + val |= lmask; + if (stereo && ucontrol->value.integer.value[1]) + val |= rmask; + snd_pmac_burgundy_wcw(chip, addr, val); + return val != oval; +} + +#define BURGUNDY_SWITCH_W(xname, xindex, addr, lbit, rbit, stereo) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex,\ + .info = snd_pmac_burgundy_info_switch_w,\ + .get = snd_pmac_burgundy_get_switch_w,\ + .put = snd_pmac_burgundy_put_switch_w,\ + .private_value = ((lbit) | ((rbit) << 8) | (ADDR2BASE(addr) << 16) | ((stereo) << 24)) } + +/* + * Burgundy switch: 0/1, mono/stereo, byte reg, bit mask + */ +static int snd_pmac_burgundy_info_switch_b(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) +{ + int stereo = (kcontrol->private_value >> 24) & 1; + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = stereo + 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int snd_pmac_burgundy_get_switch_b(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); + unsigned int addr = BASE2ADDR((kcontrol->private_value >> 16) & 0xff); + int lmask = kcontrol->private_value & 0xff; + int rmask = (kcontrol->private_value >> 8) & 0xff; + int stereo = (kcontrol->private_value >> 24) & 1; + int val = snd_pmac_burgundy_rcb(chip, addr); + ucontrol->value.integer.value[0] = (val & lmask) ? 1 : 0; + if (stereo) + ucontrol->value.integer.value[1] = (val & rmask) ? 1 : 0; + return 0; +} + +static int snd_pmac_burgundy_put_switch_b(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); + unsigned int addr = BASE2ADDR((kcontrol->private_value >> 16) & 0xff); + int lmask = kcontrol->private_value & 0xff; + int rmask = (kcontrol->private_value >> 8) & 0xff; + int stereo = (kcontrol->private_value >> 24) & 1; + int val, oval; + oval = snd_pmac_burgundy_rcb(chip, addr); + val = oval & ~(lmask | rmask); + if (ucontrol->value.integer.value[0]) + val |= lmask; + if (stereo && ucontrol->value.integer.value[1]) + val |= rmask; + snd_pmac_burgundy_wcb(chip, addr, val); + return val != oval; +} + +#define BURGUNDY_SWITCH_B(xname, xindex, addr, lmask, rmask, stereo) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex,\ + .info = snd_pmac_burgundy_info_switch_b,\ + .get = snd_pmac_burgundy_get_switch_b,\ + .put = snd_pmac_burgundy_put_switch_b,\ + .private_value = ((lmask) | ((rmask) << 8) | (ADDR2BASE(addr) << 16) | ((stereo) << 24)) } + +#if 0 + /* lineout/speaker */ static int snd_pmac_burgundy_info_switch_out(struct snd_kcontrol *kcontrol, @@ -271,6 +502,7 @@ .private_value = ((lmask) | ((rmask) << 8) | ((stereo) << 24)) } /* line/speaker output volume */ + static int snd_pmac_burgundy_info_volume_out(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -323,19 +555,68 @@ .put = snd_pmac_burgundy_put_volume_out,\ .private_value = (ADDR2BASE(addr) | ((stereo) << 24)) } +#endif + static struct snd_kcontrol_new snd_pmac_burgundy_mixers[] __initdata = { - BURGUNDY_VOLUME("Master Playback Volume", 0, MASK_ADDR_BURGUNDY_MASTER_VOLUME, 8), - BURGUNDY_VOLUME("Line Playback Volume", 0, MASK_ADDR_BURGUNDY_VOLLINE, 16), - BURGUNDY_VOLUME("CD Playback Volume", 0, MASK_ADDR_BURGUNDY_VOLCD, 16), - BURGUNDY_VOLUME("Mic Playback Volume", 0, MASK_ADDR_BURGUNDY_VOLMIC, 16), - BURGUNDY_OUTPUT_VOLUME("PC Speaker Playback Volume", 0, MASK_ADDR_BURGUNDY_ATTENHP, 0), - /*BURGUNDY_OUTPUT_VOLUME("PCM Playback Volume", 0, MASK_ADDR_BURGUNDY_ATTENLINEOUT, 1),*/ - BURGUNDY_OUTPUT_VOLUME("Headphone Playback Volume", 0, MASK_ADDR_BURGUNDY_ATTENSPEAKER, 1), + BURGUNDY_VOLUME_W("Master Playback Volume", 0, MASK_ADDR_BURGUNDY_MASTER_VOLUME, 8), + BURGUNDY_VOLUME_W("CD Capture Volume", 0, MASK_ADDR_BURGUNDY_VOLCD, 16), + BURGUNDY_VOLUME_2B("Input Capture Volume", 0, MASK_ADDR_BURGUNDY_VOLMIX01, 2), + BURGUNDY_VOLUME_2B("Mixer Playback Volume", 0, MASK_ADDR_BURGUNDY_VOLMIX23, 0), + BURGUNDY_VOLUME_B("CD Gain Capture Volume", 0, MASK_ADDR_BURGUNDY_GAINCD, 1, 0), + BURGUNDY_SWITCH_W("Master Capture Switch", 0, MASK_ADDR_BURGUNDY_OUTPUTENABLES, 24, 0, 0), + BURGUNDY_SWITCH_W("CD Capture Switch", 0, MASK_ADDR_BURGUNDY_CAPTURESELECTS, 0, 16, 1), + BURGUNDY_SWITCH_W("CD Playback Switch", 0, MASK_ADDR_BURGUNDY_OUTPUTSELECTS, 0, 16, 1), +/* BURGUNDY_SWITCH_W("Loop Capture Switch", 0, MASK_ADDR_BURGUNDY_CAPTURESELECTS, 8, 24, 1), + BURGUNDY_SWITCH_B("Mixer out Capture Switch", 0, MASK_ADDR_BURGUNDY_HOSTIFAD, 0x02, 0, 0), + BURGUNDY_SWITCH_B("Mixer Capture Switch", 0, MASK_ADDR_BURGUNDY_HOSTIFAD, 0x01, 0, 0), + BURGUNDY_SWITCH_B("PCM out Capture Switch", 0, MASK_ADDR_BURGUNDY_HOSTIFEH, 0x02, 0, 0), +*/ BURGUNDY_SWITCH_B("PCM Capture Switch", 0, MASK_ADDR_BURGUNDY_HOSTIFEH, 0x01, 0, 0) +}; +static struct snd_kcontrol_new snd_pmac_burgundy_mixers_imac[] __initdata = { + BURGUNDY_VOLUME_W("Line in Capture Volume", 0, MASK_ADDR_BURGUNDY_VOLLINE, 16), + BURGUNDY_VOLUME_W("Mic Capture Volume", 0, MASK_ADDR_BURGUNDY_VOLMIC, 16), + BURGUNDY_VOLUME_B("Line in Gain Capture Volume", 0, MASK_ADDR_BURGUNDY_GAINLINE, 1, 0), + BURGUNDY_VOLUME_B("Mic Gain Capture Volume", 0, MASK_ADDR_BURGUNDY_GAINMIC, 1, 0), + BURGUNDY_VOLUME_B("PC Speaker Playback Volume", 0, MASK_ADDR_BURGUNDY_ATTENSPEAKER, 1, 1), + BURGUNDY_VOLUME_B("Line out Playback Volume", 0, MASK_ADDR_BURGUNDY_ATTENLINEOUT, 1, 1), + BURGUNDY_VOLUME_B("Headphone Playback Volume", 0, MASK_ADDR_BURGUNDY_ATTENHP, 1, 1), + BURGUNDY_SWITCH_W("Line in Capture Switch", 0, MASK_ADDR_BURGUNDY_CAPTURESELECTS, 1, 17, 1), + BURGUNDY_SWITCH_W("Mic Capture Switch", 0, MASK_ADDR_BURGUNDY_CAPTURESELECTS, 2, 18, 1), + BURGUNDY_SWITCH_W("Line in Playback Switch", 0, MASK_ADDR_BURGUNDY_OUTPUTSELECTS, 1, 17, 1), + BURGUNDY_SWITCH_W("Mic Playback Switch", 0, MASK_ADDR_BURGUNDY_OUTPUTSELECTS, 2, 18, 1), + BURGUNDY_SWITCH_B("Mic Boost Capture Switch", 0, MASK_ADDR_BURGUNDY_INPBOOST, 0x40, 0x80, 1) +}; +static struct snd_kcontrol_new snd_pmac_burgundy_mixers_pmac[] __initdata = { + BURGUNDY_VOLUME_W("Line in Capture Volume", 0, MASK_ADDR_BURGUNDY_VOLMIC, 16), + BURGUNDY_VOLUME_B("Line in Gain Capture Volume", 0, MASK_ADDR_BURGUNDY_GAINMIC, 1, 0), + BURGUNDY_VOLUME_B("PC Speaker Playback Volume", 0, MASK_ADDR_BURGUNDY_ATTENMONO, 0, 1), + BURGUNDY_VOLUME_B("Line out Playback Volume", 0, MASK_ADDR_BURGUNDY_ATTENSPEAKER, 1, 1), + BURGUNDY_SWITCH_W("Line in Capture Switch", 0, MASK_ADDR_BURGUNDY_CAPTURESELECTS, 2, 18, 1), + BURGUNDY_SWITCH_W("Line in Playback Switch", 0, MASK_ADDR_BURGUNDY_OUTPUTSELECTS, 2, 18, 1), +/* BURGUNDY_SWITCH_B("Line in Boost Capture Switch", 0, MASK_ADDR_BURGUNDY_INPBOOST, 0x40, 0x80, 1) */ }; -static struct snd_kcontrol_new snd_pmac_burgundy_master_sw __initdata = -BURGUNDY_OUTPUT_SWITCH("Headphone Playback Switch", 0, BURGUNDY_OUTPUT_LEFT, BURGUNDY_OUTPUT_RIGHT, 1); -static struct snd_kcontrol_new snd_pmac_burgundy_speaker_sw __initdata = -BURGUNDY_OUTPUT_SWITCH("PC Speaker Playback Switch", 0, BURGUNDY_OUTPUT_INTERN, 0, 0); +static struct snd_kcontrol_new snd_pmac_burgundy_master_sw_imac __initdata = +BURGUNDY_SWITCH_B("Master Playback Switch", 0, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, + BURGUNDY_OUTPUT_LEFT | BURGUNDY_LINEOUT_LEFT | BURGUNDY_HP_LEFT, + BURGUNDY_OUTPUT_RIGHT | BURGUNDY_LINEOUT_RIGHT | BURGUNDY_HP_RIGHT, 1); +static struct snd_kcontrol_new snd_pmac_burgundy_master_sw_pmac __initdata = +BURGUNDY_SWITCH_B("Master Playback Switch", 0, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, + BURGUNDY_OUTPUT_INTERN | BURGUNDY_OUTPUT_LEFT, BURGUNDY_OUTPUT_RIGHT, 1); +static struct snd_kcontrol_new snd_pmac_burgundy_speaker_sw_imac __initdata = +BURGUNDY_SWITCH_B("PC Speaker Playback Switch", 0, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, + BURGUNDY_OUTPUT_LEFT, BURGUNDY_OUTPUT_RIGHT, 1); +static struct snd_kcontrol_new snd_pmac_burgundy_speaker_sw_pmac __initdata = +BURGUNDY_SWITCH_B("PC Speaker Playback Switch", 0, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, + BURGUNDY_OUTPUT_INTERN, 0, 0); +static struct snd_kcontrol_new snd_pmac_burgundy_line_sw_imac __initdata = +BURGUNDY_SWITCH_B("Line out Playback Switch", 0, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, + BURGUNDY_LINEOUT_LEFT, BURGUNDY_LINEOUT_RIGHT, 1); +static struct snd_kcontrol_new snd_pmac_burgundy_line_sw_pmac __initdata = +BURGUNDY_SWITCH_B("Line out Playback Switch", 0, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, + BURGUNDY_OUTPUT_LEFT, BURGUNDY_OUTPUT_RIGHT, 1); +static struct snd_kcontrol_new snd_pmac_burgundy_hp_sw_imac __initdata = +BURGUNDY_SWITCH_B("Headphone Playback Switch", 0, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, + BURGUNDY_HP_LEFT, BURGUNDY_HP_RIGHT, 1); #ifdef PMAC_SUPPORT_AUTOMUTE @@ -350,13 +631,17 @@ static void snd_pmac_burgundy_update_automute(struct snd_pmac *chip, int do_notify) { if (chip->auto_mute) { + int imac = machine_is_compatible("iMac"); int reg, oreg; reg = oreg = snd_pmac_burgundy_rcb(chip, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES); - reg &= ~(BURGUNDY_OUTPUT_LEFT | BURGUNDY_OUTPUT_RIGHT | BURGUNDY_OUTPUT_INTERN); + reg &= imac ? ~(BURGUNDY_OUTPUT_LEFT | BURGUNDY_OUTPUT_RIGHT | BURGUNDY_HP_LEFT | BURGUNDY_HP_RIGHT) + : ~(BURGUNDY_OUTPUT_LEFT | BURGUNDY_OUTPUT_RIGHT | BURGUNDY_OUTPUT_INTERN); if (snd_pmac_burgundy_detect_headphone(chip)) - reg |= BURGUNDY_OUTPUT_LEFT | BURGUNDY_OUTPUT_RIGHT; + reg |= imac ? (BURGUNDY_HP_LEFT | BURGUNDY_HP_RIGHT) + : (BURGUNDY_OUTPUT_LEFT | BURGUNDY_OUTPUT_RIGHT); else - reg |= BURGUNDY_OUTPUT_INTERN; + reg |= imac ? (BURGUNDY_OUTPUT_LEFT | BURGUNDY_OUTPUT_RIGHT) + : (BURGUNDY_OUTPUT_INTERN); if (do_notify && reg == oreg) return; snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, reg); @@ -378,6 +663,7 @@ */ int __init snd_pmac_burgundy_init(struct snd_pmac *chip) { + int imac = machine_is_compatible("iMac"); int i, err; /* Checks to see the chip is alive and kicking */ @@ -386,7 +672,7 @@ return 1; } - snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_OUTPUTENABLES, + snd_pmac_burgundy_wcw(chip, MASK_ADDR_BURGUNDY_OUTPUTENABLES, DEF_BURGUNDY_OUTPUTENABLES); snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, DEF_BURGUNDY_MORE_OUTPUTENABLES); @@ -396,7 +682,8 @@ snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_INPSEL21, DEF_BURGUNDY_INPSEL21); snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_INPSEL3, - DEF_BURGUNDY_INPSEL3); + imac ? DEF_BURGUNDY_INPSEL3_IMAC + : DEF_BURGUNDY_INPSEL3_PMAC); snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_GAINCD, DEF_BURGUNDY_GAINCD); snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_GAINLINE, @@ -422,10 +709,15 @@ snd_pmac_burgundy_wcw(chip, MASK_ADDR_BURGUNDY_VOLMIC, DEF_BURGUNDY_VOLMIC); - if (chip->hp_stat_mask == 0) + if (chip->hp_stat_mask == 0) { /* set headphone-jack detection bit */ - chip->hp_stat_mask = 0x04; - + if (imac) + chip->hp_stat_mask = BURGUNDY_HPDETECT_IMAC_UPPER | + BURGUNDY_HPDETECT_IMAC_LOWER | + BURGUNDY_HPDETECT_IMAC_SIDE; + else + chip->hp_stat_mask = BURGUNDY_HPDETECT_PMAC_BACK; + } /* * build burgundy mixers */ @@ -435,10 +727,22 @@ if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_pmac_burgundy_mixers[i], chip))) < 0) return err; } - chip->master_sw_ctl = snd_ctl_new1(&snd_pmac_burgundy_master_sw, chip); + for (i = 0; i < (imac ? ARRAY_SIZE(snd_pmac_burgundy_mixers_imac) : ARRAY_SIZE(snd_pmac_burgundy_mixers_pmac)); i++) { + if ((err = snd_ctl_add(chip->card, snd_ctl_new1(imac ? &snd_pmac_burgundy_mixers_imac[i] : &snd_pmac_burgundy_mixers_pmac[i], chip))) < 0) + return err; + } + chip->master_sw_ctl = snd_ctl_new1(imac ? &snd_pmac_burgundy_master_sw_imac : &snd_pmac_burgundy_master_sw_pmac, chip); + if ((err = snd_ctl_add(chip->card, chip->master_sw_ctl)) < 0) + return err; + chip->master_sw_ctl = snd_ctl_new1(imac ? &snd_pmac_burgundy_line_sw_imac : &snd_pmac_burgundy_line_sw_pmac, chip); if ((err = snd_ctl_add(chip->card, chip->master_sw_ctl)) < 0) return err; - chip->speaker_sw_ctl = snd_ctl_new1(&snd_pmac_burgundy_speaker_sw, chip); + if (imac) { + chip->master_sw_ctl = snd_ctl_new1(&snd_pmac_burgundy_hp_sw_imac, chip); + if ((err = snd_ctl_add(chip->card, chip->master_sw_ctl)) < 0) + return err; + } + chip->speaker_sw_ctl = snd_ctl_new1(imac ? &snd_pmac_burgundy_speaker_sw_imac : &snd_pmac_burgundy_speaker_sw_pmac, chip); if ((err = snd_ctl_add(chip->card, chip->speaker_sw_ctl)) < 0) return err; #ifdef PMAC_SUPPORT_AUTOMUTE --- alsa-kernel/ppc/burgundy.h.orig 2008-02-05 11:23:24.000000000 +0200 +++ alsa-kernel/ppc/burgundy.h 2008-03-31 23:45:36.000000000 +0300 @@ -22,6 +22,7 @@ #ifndef __BURGUNDY_H #define __BURGUNDY_H +#define MASK_ADDR_BURGUNDY_INPBOOST (0x10 << 12) #define MASK_ADDR_BURGUNDY_INPSEL21 (0x11 << 12) #define MASK_ADDR_BURGUNDY_INPSEL3 (0x12 << 12) @@ -35,7 +36,10 @@ #define MASK_ADDR_BURGUNDY_VOLCH3 (0x22 << 12) #define MASK_ADDR_BURGUNDY_VOLCH4 (0x23 << 12) +#define MASK_ADDR_BURGUNDY_CAPTURESELECTS (0x2A << 12) #define MASK_ADDR_BURGUNDY_OUTPUTSELECTS (0x2B << 12) +#define MASK_ADDR_BURGUNDY_VOLMIX01 (0x2D << 12) +#define MASK_ADDR_BURGUNDY_VOLMIX23 (0x2E << 12) #define MASK_ADDR_BURGUNDY_OUTPUTENABLES (0x2F << 12) #define MASK_ADDR_BURGUNDY_MASTER_VOLUME (0x30 << 12) @@ -45,6 +49,10 @@ #define MASK_ADDR_BURGUNDY_ATTENSPEAKER (0x62 << 12) #define MASK_ADDR_BURGUNDY_ATTENLINEOUT (0x63 << 12) #define MASK_ADDR_BURGUNDY_ATTENHP (0x64 << 12) +#define MASK_ADDR_BURGUNDY_ATTENMONO (0x65 << 12) + +#define MASK_ADDR_BURGUNDY_HOSTIFAD (0x78 << 12) +#define MASK_ADDR_BURGUNDY_HOSTIFEH (0x79 << 12) #define MASK_ADDR_BURGUNDY_VOLCD (MASK_ADDR_BURGUNDY_VOLCH1) #define MASK_ADDR_BURGUNDY_VOLLINE (MASK_ADDR_BURGUNDY_VOLCH2) @@ -59,21 +67,22 @@ /* These are all default values for the burgundy */ #define DEF_BURGUNDY_INPSEL21 (0xAA) -#define DEF_BURGUNDY_INPSEL3 (0x0A) +#define DEF_BURGUNDY_INPSEL3_IMAC (0x0A) +#define DEF_BURGUNDY_INPSEL3_PMAC (0x05) #define DEF_BURGUNDY_GAINCD (0x33) #define DEF_BURGUNDY_GAINLINE (0x44) #define DEF_BURGUNDY_GAINMIC (0x44) #define DEF_BURGUNDY_GAINMODEM (0x06) -/* Remember: lowest volume here is 0x9b */ +/* Remember: lowest volume here is 0x9B (155) */ #define DEF_BURGUNDY_VOLCD (0xCCCCCCCC) #define DEF_BURGUNDY_VOLLINE (0x00000000) #define DEF_BURGUNDY_VOLMIC (0x00000000) #define DEF_BURGUNDY_VOLMODEM (0xCCCCCCCC) -#define DEF_BURGUNDY_OUTPUTSELECTS (0x010f010f) -#define DEF_BURGUNDY_OUTPUTENABLES (0x0A) +#define DEF_BURGUNDY_OUTPUTSELECTS (0x010F010F) +#define DEF_BURGUNDY_OUTPUTENABLES (0x0100000A) /* #define DEF_BURGUNDY_MASTER_VOLUME (0xFFFFFFFF) */ /* too loud */ #define DEF_BURGUNDY_MASTER_VOLUME (0xDDDDDDDD) @@ -84,12 +93,22 @@ #define DEF_BURGUNDY_ATTENLINEOUT (0xCC) #define DEF_BURGUNDY_ATTENHP (0xCC) -/* OUTPUTENABLES bits */ +/* MORE_OUTPUTENABLES bits */ #define BURGUNDY_OUTPUT_LEFT 0x02 #define BURGUNDY_OUTPUT_RIGHT 0x04 +#define BURGUNDY_LINEOUT_LEFT 0x08 +#define BURGUNDY_LINEOUT_RIGHT 0x10 +#define BURGUNDY_HP_LEFT 0x20 +#define BURGUNDY_HP_RIGHT 0x40 #define BURGUNDY_OUTPUT_INTERN 0x80 -/* volume offset */ +/* Headphone detection bits */ +#define BURGUNDY_HPDETECT_PMAC_BACK 0x04 +#define BURGUNDY_HPDETECT_IMAC_SIDE 0x04 +#define BURGUNDY_HPDETECT_IMAC_UPPER 0x08 +#define BURGUNDY_HPDETECT_IMAC_LOWER 0x01 + +/* Volume offset */ #define BURGUNDY_VOLUME_OFFSET 155 #endif /* __BURGUNDY_H */ --- alsa-kernel/ppc/pmac.c.orig 2008-02-05 11:23:24.000000000 +0200 +++ alsa-kernel/ppc/pmac.c 2008-03-31 14:26:02.000000000 +0300 @@ -1063,6 +1063,9 @@ else { struct pci_dev *pdev = NULL; +#ifndef for_each_pci_dev +#define for_each_pci_dev(d) while ((d = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, d)) != NULL) +#endif for_each_pci_dev(pdev) { struct device_node *np = pci_device_to_OF_node(pdev); if (np && np == macio->of_node) { @@ -1300,9 +1303,12 @@ snd_pmac_sound_feature(chip, 1); - /* reset */ + /* reset & enable PORTCHG interrupt */ if (chip->model == PMAC_AWACS) - out_le32(&chip->awacs->control, 0x11); + out_le32(&chip->awacs->control, MASK_IEPC | 0x11); + /* enable PORTCHG interrupt */ + if (chip->model == PMAC_SCREAMER || chip->model == PMAC_BURGUNDY) + out_le32(&chip->awacs->control, chip->control_mask); /* Powerbooks have odd ways of enabling inputs such as an expansion-bay CD or sound from an internal modem --- ppc/pmac_old.c.orig 2008-02-05 11:23:23.000000000 +0200 +++ ppc/pmac_old.c 2008-03-31 19:35:58.000000000 +0300 @@ -796,12 +796,18 @@ snd_pmac_detach_beep(chip); /* release resources */ - if (chip->irq >= 0) + if (chip->irq >= 0) { + snd_printk(KERN_DEBUG "pmac: free_irq(%d)\n", chip->irq); free_irq(chip->irq, (void*)chip); - if (chip->tx_irq >= 0) + } + if (chip->tx_irq >= 0) { + snd_printk(KERN_DEBUG "pmac: free_irq(%d)\n", chip->tx_irq); free_irq(chip->tx_irq, (void*)chip); - if (chip->rx_irq >= 0) + } + if (chip->rx_irq >= 0) { + snd_printk(KERN_DEBUG "pmac: free_irq(%d)\n", chip->rx_irq); free_irq(chip->rx_irq, (void*)chip); + } snd_pmac_dbdma_free(chip, &chip->playback.cmd); snd_pmac_dbdma_free(chip, &chip->capture.cmd); snd_pmac_dbdma_free(chip, &chip->extra_dma); @@ -997,12 +1003,14 @@ chip->can_byte_swap = 0; /* FIXME: check this */ chip->control_mask = MASK_IEPC | 0x11;/* disable IEE */ break; +#ifdef SND_POWERMAC_SUPPORT_TOONIE case 0x3a: chip->num_freqs = ARRAY_SIZE(tumbler_freqs); chip->model = PMAC_TOONIE; chip->can_byte_swap = 0; /* FIXME: check this */ chip->control_mask = MASK_IEPC | 0x11;/* disable IEE */ break; +#endif } } prop = (unsigned int *)get_property(sound, "device-id", NULL); @@ -1019,6 +1027,9 @@ else { struct pci_dev *pdev = NULL; +#ifndef for_each_pci_dev +#define for_each_pci_dev(d) while ((d = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, d)) != NULL) +#endif for_each_pci_dev(pdev) { struct device_node *np = pci_device_to_OF_node(pdev); if (np && np == macio->of_node) { @@ -1258,9 +1269,12 @@ snd_pmac_sound_feature(chip, 1); - /* reset */ + /* reset & enable PORTCHG interrupt */ if (chip->model == PMAC_AWACS) - out_le32(&chip->awacs->control, 0x11); + out_le32(&chip->awacs->control, MASK_IEPC | 0x11); + /* enable PORTCHG interrupt */ + if (chip->model == PMAC_SCREAMER || chip->model == PMAC_BURGUNDY) + out_le32(&chip->awacs->control, chip->control_mask); /* Powerbooks have odd ways of enabling inputs such as an expansion-bay CD or sound from an internal modem --- alsa-kernel/ppc/pmac.h.orig 2008-02-05 11:23:24.000000000 +0200 +++ alsa-kernel/ppc/pmac.h 2008-03-31 23:45:36.000000000 +0300 @@ -207,4 +207,11 @@ int snd_pmac_add_automute(struct snd_pmac *chip); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16) +#define of_device_is_compatible(dev, s) device_is_compatible(dev, s) +#define input_get_drvdata(dev) (dev->private) +#define i2c_smbus_write_i2c_block_data(client, cmd, len, vals) \ + i2c_smbus_write_block_data(client, cmd, len, vals) +#endif + #endif /* __PMAC_H */ --- acore/memory.c.orig 2008-02-05 11:23:23.000000000 +0200 +++ acore/memory.c 2008-03-31 23:45:36.000000000 +0300 @@ -21,6 +21,9 @@ #ifndef __safe #define __safe #endif +#ifndef __bitwise +#define __bitwise +#endif #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) --- ppc/beep.patch.orig 2008-02-05 11:23:23.000000000 +0200 +++ ppc/beep.patch 2008-03-31 23:45:37.000000000 +0300 @@ -1,5 +1,5 @@ ---- ../alsa-kernel/ppc/beep.c 2007-12-20 11:47:37.000000000 +0100 -+++ beep.c 2007-12-20 12:23:31.000000000 +0100 +--- ../alsa-kernel/ppc/beep.c 2008-02-05 11:23:24.000000000 +0200 ++++ beep.c 2008-03-27 11:56:01.482564272 +0200 @@ -1,3 +1,10 @@ +#define __NO_VERSION__ +#include "adriver.h" @@ -39,7 +39,18 @@ beep->dev = input_dev; beep->buf = dmabuf; -@@ -263,7 +281,12 @@ +@@ -256,14 +274,23 @@ + + chip->beep = beep; + ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 15) + err = input_register_device(beep->dev); + if (err) + goto fail2; ++#else ++ input_register_device(beep->dev); ++#endif + return 0; fail2: snd_ctl_remove(chip->card, beep_ctl); @@ -53,14 +64,15 @@ if (dmabuf) dma_free_coherent(&chip->pdev->dev, BEEP_BUFLEN * 4, dmabuf, beep->addr); -@@ -275,9 +298,15 @@ +@@ -275,9 +302,16 @@ { if (chip->beep) { input_unregister_device(chip->beep->dev); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 15) + kfree(chip->beep->dev); -+#endif ++#else + input_free_device(chip->beep->dev); ++#endif dma_free_coherent(&chip->pdev->dev, BEEP_BUFLEN * 4, chip->beep->buf, chip->beep->addr); kfree(chip->beep);