aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci
diff options
context:
space:
mode:
authorAndreas Mohr <andi@lisas.de>2008-06-23 05:50:47 -0400
committerJaroslav Kysela <perex@perex.cz>2008-06-26 03:01:47 -0400
commit627d3e7abca30d6e86787c98dd7cbac0233bc5a9 (patch)
tree9837968886cda7893c827aaa9edfe3053d95139f /sound/pci
parent981bcead3f2279a1ec6fb5f2c57aff79ed61a700 (diff)
ALSA: PCI168 snd-azt3328: some more fixups
- fix problem with codec register 0x6a being write-only by adding a software shadow register (caused annoying noise after module loading due to _toggling_ between gameport and audio bits instead of configuring them properly) - rename several "Wave" mixer controls to "PCM", since this is what Wine and several other apps are looking for (IOW, _requiring_) and this is what AC97 specs use as naming, too, thus I'd guess it's what these controls are - cleanup, small optimizations Signed-off-by: Andreas Mohr <andi@lisas.de> Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Jaroslav Kysela <perex@perex.cz>
Diffstat (limited to 'sound/pci')
-rw-r--r--sound/pci/azt3328.c109
-rw-r--r--sound/pci/azt3328.h16
2 files changed, 76 insertions, 49 deletions
diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c
index b832333c3023..22f18f3cfbc9 100644
--- a/sound/pci/azt3328.c
+++ b/sound/pci/azt3328.c
@@ -289,6 +289,12 @@ struct snd_azf3328 {
289 struct pci_dev *pci; 289 struct pci_dev *pci;
290 int irq; 290 int irq;
291 291
292 /* register 0x6a is write-only, thus need to remember setting.
293 * If we need to add more registers here, then we might try to fold this
294 * into some transparent combined shadow register handling with
295 * CONFIG_PM register storage below, but that's slightly difficult. */
296 u16 shadow_reg_codec_6AH;
297
292#ifdef CONFIG_PM 298#ifdef CONFIG_PM
293 /* register value containers for power management 299 /* register value containers for power management
294 * Note: not always full I/O range preserved (just like Win driver!) */ 300 * Note: not always full I/O range preserved (just like Win driver!) */
@@ -324,21 +330,6 @@ snd_azf3328_io_reg_setb(unsigned reg, u8 mask, int do_set)
324 return 0; 330 return 0;
325} 331}
326 332
327static int
328snd_azf3328_io_reg_setw(unsigned reg, u16 mask, int do_set)
329{
330 u16 prev = inw(reg), new;
331
332 new = (do_set) ? (prev|mask) : (prev & ~mask);
333 /* we need to always write the new value no matter whether it differs
334 * or not, since some register bits don't indicate their setting */
335 outw(new, reg);
336 if (new != prev)
337 return 1;
338
339 return 0;
340}
341
342static inline void 333static inline void
343snd_azf3328_codec_outb(const struct snd_azf3328 *chip, unsigned reg, u8 value) 334snd_azf3328_codec_outb(const struct snd_azf3328 *chip, unsigned reg, u8 value)
344{ 335{
@@ -662,7 +653,7 @@ snd_azf3328_info_mixer_enum(struct snd_kcontrol *kcontrol,
662 "pre 3D", "post 3D" 653 "pre 3D", "post 3D"
663 }; 654 };
664 struct azf3328_mixer_reg reg; 655 struct azf3328_mixer_reg reg;
665 const char *p = NULL; 656 const char * const *p = NULL;
666 657
667 snd_azf3328_mixer_reg_decode(&reg, kcontrol->private_value); 658 snd_azf3328_mixer_reg_decode(&reg, kcontrol->private_value);
668 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 659 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
@@ -673,20 +664,20 @@ snd_azf3328_info_mixer_enum(struct snd_kcontrol *kcontrol,
673 if (reg.reg == IDX_MIXER_ADVCTL2) { 664 if (reg.reg == IDX_MIXER_ADVCTL2) {
674 switch(reg.lchan_shift) { 665 switch(reg.lchan_shift) {
675 case 8: /* modem out sel */ 666 case 8: /* modem out sel */
676 p = texts1[uinfo->value.enumerated.item]; 667 p = texts1;
677 break; 668 break;
678 case 9: /* mono sel source */ 669 case 9: /* mono sel source */
679 p = texts2[uinfo->value.enumerated.item]; 670 p = texts2;
680 break; 671 break;
681 case 15: /* PCM Out Path */ 672 case 15: /* PCM Out Path */
682 p = texts4[uinfo->value.enumerated.item]; 673 p = texts4;
683 break; 674 break;
684 } 675 }
685 } else 676 } else
686 if (reg.reg == IDX_MIXER_REC_SELECT) 677 if (reg.reg == IDX_MIXER_REC_SELECT)
687 p = texts3[uinfo->value.enumerated.item]; 678 p = texts3;
688 679
689 strcpy(uinfo->value.enumerated.name, p); 680 strcpy(uinfo->value.enumerated.name, p[uinfo->value.enumerated.item]);
690 return 0; 681 return 0;
691} 682}
692 683
@@ -745,9 +736,11 @@ snd_azf3328_put_mixer_enum(struct snd_kcontrol *kcontrol,
745static struct snd_kcontrol_new snd_azf3328_mixer_controls[] __devinitdata = { 736static struct snd_kcontrol_new snd_azf3328_mixer_controls[] __devinitdata = {
746 AZF3328_MIXER_SWITCH("Master Playback Switch", IDX_MIXER_PLAY_MASTER, 15, 1), 737 AZF3328_MIXER_SWITCH("Master Playback Switch", IDX_MIXER_PLAY_MASTER, 15, 1),
747 AZF3328_MIXER_VOL_STEREO("Master Playback Volume", IDX_MIXER_PLAY_MASTER, 0x1f, 1), 738 AZF3328_MIXER_VOL_STEREO("Master Playback Volume", IDX_MIXER_PLAY_MASTER, 0x1f, 1),
748 AZF3328_MIXER_SWITCH("Wave Playback Switch", IDX_MIXER_WAVEOUT, 15, 1), 739 AZF3328_MIXER_SWITCH("PCM Playback Switch", IDX_MIXER_WAVEOUT, 15, 1),
749 AZF3328_MIXER_VOL_STEREO("Wave Playback Volume", IDX_MIXER_WAVEOUT, 0x1f, 1), 740 AZF3328_MIXER_VOL_STEREO("PCM Playback Volume",
750 AZF3328_MIXER_SWITCH("Wave 3D Bypass Playback Switch", IDX_MIXER_ADVCTL2, 7, 1), 741 IDX_MIXER_WAVEOUT, 0x1f, 1),
742 AZF3328_MIXER_SWITCH("PCM 3D Bypass Playback Switch",
743 IDX_MIXER_ADVCTL2, 7, 1),
751 AZF3328_MIXER_SWITCH("FM Playback Switch", IDX_MIXER_FMSYNTH, 15, 1), 744 AZF3328_MIXER_SWITCH("FM Playback Switch", IDX_MIXER_FMSYNTH, 15, 1),
752 AZF3328_MIXER_VOL_STEREO("FM Playback Volume", IDX_MIXER_FMSYNTH, 0x1f, 1), 745 AZF3328_MIXER_VOL_STEREO("FM Playback Volume", IDX_MIXER_FMSYNTH, 0x1f, 1),
753 AZF3328_MIXER_SWITCH("CD Playback Switch", IDX_MIXER_CDAUDIO, 15, 1), 746 AZF3328_MIXER_SWITCH("CD Playback Switch", IDX_MIXER_CDAUDIO, 15, 1),
@@ -874,7 +867,7 @@ snd_azf3328_hw_free(struct snd_pcm_substream *substream)
874static void 867static void
875snd_azf3328_codec_setfmt(struct snd_azf3328 *chip, 868snd_azf3328_codec_setfmt(struct snd_azf3328 *chip,
876 unsigned reg, 869 unsigned reg,
877 unsigned int bitrate, 870 enum azf_freq_t bitrate,
878 unsigned int format_width, 871 unsigned int format_width,
879 unsigned int channels 872 unsigned int channels
880) 873)
@@ -958,15 +951,29 @@ snd_azf3328_codec_setfmt_lowpower(struct snd_azf3328 *chip,
958 snd_azf3328_codec_setfmt(chip, reg, AZF_FREQ_4000, 8, 1); 951 snd_azf3328_codec_setfmt(chip, reg, AZF_FREQ_4000, 8, 1);
959} 952}
960 953
954static void
955snd_azf3328_codec_reg_6AH_update(struct snd_azf3328 *chip,
956 unsigned bitmask,
957 int enable
958)
959{
960 if (enable)
961 chip->shadow_reg_codec_6AH &= ~bitmask;
962 else
963 chip->shadow_reg_codec_6AH |= bitmask;
964 snd_azf3328_dbgplay("6AH_update mask 0x%04x enable %d: val 0x%04x\n",
965 bitmask, enable, chip->shadow_reg_codec_6AH);
966 snd_azf3328_codec_outw(chip, IDX_IO_6AH, chip->shadow_reg_codec_6AH);
967}
968
961static inline void 969static inline void
962snd_azf3328_codec_enable(struct snd_azf3328 *chip, int enable) 970snd_azf3328_codec_enable(struct snd_azf3328 *chip, int enable)
963{ 971{
972 snd_azf3328_dbgplay("codec_enable %d\n", enable);
964 /* no idea what exactly is being done here, but I strongly assume it's 973 /* no idea what exactly is being done here, but I strongly assume it's
965 * PM related */ 974 * PM related */
966 snd_azf3328_io_reg_setw( 975 snd_azf3328_codec_reg_6AH_update(
967 chip->codec_io+IDX_IO_6AH, 976 chip, IO_6A_PAUSE_PLAYBACK_BIT8, enable
968 IO_6A_PAUSE_PLAYBACK_BIT8,
969 !enable
970 ); 977 );
971} 978}
972 979
@@ -1404,10 +1411,8 @@ snd_azf3328_gameport_legacy_address_enable(struct snd_azf3328 *chip, int enable)
1404static inline void 1411static inline void
1405snd_azf3328_gameport_axis_circuit_enable(struct snd_azf3328 *chip, int enable) 1412snd_azf3328_gameport_axis_circuit_enable(struct snd_azf3328 *chip, int enable)
1406{ 1413{
1407 snd_azf3328_io_reg_setw( 1414 snd_azf3328_codec_reg_6AH_update(
1408 chip->codec_io+IDX_IO_6AH, 1415 chip, IO_6A_SOMETHING2_GAMEPORT, enable
1409 IO_6A_SOMETHING2_GAMEPORT,
1410 !enable
1411 ); 1416 );
1412} 1417}
1413 1418
@@ -1525,8 +1530,6 @@ snd_azf3328_gameport(struct snd_azf3328 *chip, int dev)
1525{ 1530{
1526 struct gameport *gp; 1531 struct gameport *gp;
1527 1532
1528 int io_port = chip->game_io;
1529
1530 chip->gameport = gp = gameport_allocate_port(); 1533 chip->gameport = gp = gameport_allocate_port();
1531 if (!gp) { 1534 if (!gp) {
1532 printk(KERN_ERR "azt3328: cannot alloc memory for gameport\n"); 1535 printk(KERN_ERR "azt3328: cannot alloc memory for gameport\n");
@@ -1536,7 +1539,7 @@ snd_azf3328_gameport(struct snd_azf3328 *chip, int dev)
1536 gameport_set_name(gp, "AZF3328 Gameport"); 1539 gameport_set_name(gp, "AZF3328 Gameport");
1537 gameport_set_phys(gp, "pci%s/gameport0", pci_name(chip->pci)); 1540 gameport_set_phys(gp, "pci%s/gameport0", pci_name(chip->pci));
1538 gameport_set_dev_parent(gp, &chip->pci->dev); 1541 gameport_set_dev_parent(gp, &chip->pci->dev);
1539 gp->io = io_port; 1542 gp->io = chip->game_io;
1540 gameport_set_port_data(gp, chip); 1543 gameport_set_port_data(gp, chip);
1541 1544
1542 gp->open = snd_azf3328_gameport_open; 1545 gp->open = snd_azf3328_gameport_open;
@@ -1577,6 +1580,15 @@ snd_azf3328_gameport_interrupt(struct snd_azf3328 *chip)
1577 1580
1578/******************************************************************/ 1581/******************************************************************/
1579 1582
1583static inline void
1584snd_azf3328_irq_log_unknown_type(u8 which)
1585{
1586 snd_azf3328_dbgplay(
1587 "azt3328: unknown IRQ type (%x) occurred, please report!\n",
1588 which
1589 );
1590}
1591
1580static irqreturn_t 1592static irqreturn_t
1581snd_azf3328_interrupt(int irq, void *dev_id) 1593snd_azf3328_interrupt(int irq, void *dev_id)
1582{ 1594{
@@ -1594,11 +1606,14 @@ snd_azf3328_interrupt(int irq, void *dev_id)
1594 )) 1606 ))
1595 return IRQ_NONE; /* must be interrupt for another device */ 1607 return IRQ_NONE; /* must be interrupt for another device */
1596 1608
1597 snd_azf3328_dbgplay("Interrupt %ld!\nIDX_IO_PLAY_FLAGS %04x, IDX_IO_PLAY_IRQTYPE %04x, IDX_IO_IRQSTATUS %04x\n", 1609 snd_azf3328_dbgplay(
1598 irq_count++ /* debug-only */, 1610 "irq_count %ld! IDX_IO_PLAY_FLAGS %04x, "
1599 snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS), 1611 "IDX_IO_PLAY_IRQTYPE %04x, IDX_IO_IRQSTATUS %04x\n",
1600 snd_azf3328_codec_inw(chip, IDX_IO_PLAY_IRQTYPE), 1612 irq_count++ /* debug-only */,
1601 status); 1613 snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS),
1614 snd_azf3328_codec_inw(chip, IDX_IO_PLAY_IRQTYPE),
1615 status
1616 );
1602 1617
1603 if (status & IRQ_TIMER) { 1618 if (status & IRQ_TIMER) {
1604 /* snd_azf3328_dbgplay("timer %ld\n", 1619 /* snd_azf3328_dbgplay("timer %ld\n",
@@ -1631,9 +1646,9 @@ snd_azf3328_interrupt(int irq, void *dev_id)
1631 ) 1646 )
1632 ); 1647 );
1633 } else 1648 } else
1634 snd_azf3328_dbgplay("azt3328: ouch, irq handler problem!\n"); 1649 printk(KERN_WARNING "azt3328: irq handler problem!\n");
1635 if (which & IRQ_PLAY_SOMETHING) 1650 if (which & IRQ_PLAY_SOMETHING)
1636 snd_azf3328_dbgplay("azt3328: unknown play IRQ type occurred, please report!\n"); 1651 snd_azf3328_irq_log_unknown_type(which);
1637 } 1652 }
1638 if (status & IRQ_RECORDING) { 1653 if (status & IRQ_RECORDING) {
1639 spin_lock(&chip->reg_lock); 1654 spin_lock(&chip->reg_lock);
@@ -1653,9 +1668,9 @@ snd_azf3328_interrupt(int irq, void *dev_id)
1653 ) 1668 )
1654 ); 1669 );
1655 } else 1670 } else
1656 snd_azf3328_dbgplay("azt3328: ouch, irq handler problem!\n"); 1671 printk(KERN_WARNING "azt3328: irq handler problem!\n");
1657 if (which & IRQ_REC_SOMETHING) 1672 if (which & IRQ_REC_SOMETHING)
1658 snd_azf3328_dbgplay("azt3328: unknown rec IRQ type occurred, please report!\n"); 1673 snd_azf3328_irq_log_unknown_type(which);
1659 } 1674 }
1660 if (status & IRQ_GAMEPORT) 1675 if (status & IRQ_GAMEPORT)
1661 snd_azf3328_gameport_interrupt(chip); 1676 snd_azf3328_gameport_interrupt(chip);
@@ -2311,6 +2326,10 @@ snd_azf3328_suspend(struct pci_dev *pci, pm_message_t state)
2311 2326
2312 for (reg = 0; reg < AZF_IO_SIZE_CODEC_PM / 2; ++reg) 2327 for (reg = 0; reg < AZF_IO_SIZE_CODEC_PM / 2; ++reg)
2313 chip->saved_regs_codec[reg] = inw(chip->codec_io + reg * 2); 2328 chip->saved_regs_codec[reg] = inw(chip->codec_io + reg * 2);
2329
2330 /* manually store the one currently relevant write-only reg, too */
2331 chip->saved_regs_codec[IDX_IO_6AH / 2] = chip->shadow_reg_codec_6AH;
2332
2314 for (reg = 0; reg < AZF_IO_SIZE_GAME_PM / 2; ++reg) 2333 for (reg = 0; reg < AZF_IO_SIZE_GAME_PM / 2; ++reg)
2315 chip->saved_regs_game[reg] = inw(chip->game_io + reg * 2); 2334 chip->saved_regs_game[reg] = inw(chip->game_io + reg * 2);
2316 for (reg = 0; reg < AZF_IO_SIZE_MPU_PM / 2; ++reg) 2335 for (reg = 0; reg < AZF_IO_SIZE_MPU_PM / 2; ++reg)
diff --git a/sound/pci/azt3328.h b/sound/pci/azt3328.h
index 3448fd626f80..7e3e8942d073 100644
--- a/sound/pci/azt3328.h
+++ b/sound/pci/azt3328.h
@@ -1,7 +1,8 @@
1#ifndef __SOUND_AZT3328_H 1#ifndef __SOUND_AZT3328_H
2#define __SOUND_AZT3328_H 2#define __SOUND_AZT3328_H
3 3
4/* "PU" == "power-up value", as tested on PCI168 PCI rev. 10 */ 4/* "PU" == "power-up value", as tested on PCI168 PCI rev. 10
5 * "WRITE_ONLY" == register does not indicate actual bit values */
5 6
6/*** main I/O area port indices ***/ 7/*** main I/O area port indices ***/
7/* (only 0x70 of 0x80 bytes saved/restored by Windows driver) */ 8/* (only 0x70 of 0x80 bytes saved/restored by Windows driver) */
@@ -76,7 +77,7 @@
76 #define SOUNDFORMAT_FLAG_2CHANNELS 0x0020 77 #define SOUNDFORMAT_FLAG_2CHANNELS 0x0020
77 78
78/* define frequency helpers, for maximum value safety */ 79/* define frequency helpers, for maximum value safety */
79enum { 80enum azf_freq_t {
80#define AZF_FREQ(rate) AZF_FREQ_##rate = rate 81#define AZF_FREQ(rate) AZF_FREQ_##rate = rate
81 AZF_FREQ(4000), 82 AZF_FREQ(4000),
82 AZF_FREQ(4800), 83 AZF_FREQ(4800),
@@ -150,11 +151,18 @@ enum {
150 #define IO_68_RANDOM_TOGGLE1 0x0100 /* toggles randomly */ 151 #define IO_68_RANDOM_TOGGLE1 0x0100 /* toggles randomly */
151 #define IO_68_RANDOM_TOGGLE2 0x0200 /* toggles randomly */ 152 #define IO_68_RANDOM_TOGGLE2 0x0200 /* toggles randomly */
152 /* umm, nope, behaviour of these bits changes depending on what we wrote 153 /* umm, nope, behaviour of these bits changes depending on what we wrote
153 * to 0x6b!! */ 154 * to 0x6b!!
155 * And they change upon playback/stop, too:
156 * Writing a value to 0x68 will display this exact value during playback,
157 * too but when stopped it can fall back to a rather different
158 * seemingly random value). Hmm, possibly this is a register which
159 * has a remote shadow which needs proper device supply which only exists
160 * in case playback is active? Or is this driver-induced?
161 */
154 162
155/* this WORD can be set to have bits 0x0028 activated (FIXME: correct??); 163/* this WORD can be set to have bits 0x0028 activated (FIXME: correct??);
156 * actually inhibits PCM playback!!! maybe power management??: */ 164 * actually inhibits PCM playback!!! maybe power management??: */
157#define IDX_IO_6AH 0x6A 165#define IDX_IO_6AH 0x6A /* WRITE_ONLY! */
158 /* bit 5: enabling this will activate permanent counting of bytes 2/3 166 /* bit 5: enabling this will activate permanent counting of bytes 2/3
159 * at gameport I/O (0xb402/3) (equal values each) and cause 167 * at gameport I/O (0xb402/3) (equal values each) and cause
160 * gameport legacy I/O at 0x0200 to be _DISABLED_! 168 * gameport legacy I/O at 0x0200 to be _DISABLED_!