Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 28504
b: refs/heads/master
c: ca54bde
h: refs/heads/master
v: v3
  • Loading branch information
Andreas Mohr authored and Jaroslav Kysela committed Jun 22, 2006
1 parent 7961735 commit f7a1a48
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 7 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 746df94898554b3d8e91d855e934852e626c701c
refs/heads/master: ca54bde3634360afecd0dada9c59399bbe88bd32
119 changes: 116 additions & 3 deletions trunk/sound/pci/azt3328.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,11 @@
*
* TODO
* - test MPU401 MIDI playback etc.
* - power management. See e.g. intel8x0 or cs4281.
* This would be nice since the chip runs a bit hot, and it's *required*
* anyway for proper ACPI power management.
* - add some power micro-management (disable various units of the card
* as long as they're unused). However this requires I/O ports which I
* haven't figured out yet and which thus might not even exist...
* The standard suspend/resume functionality could probably make use of
* some improvement, too...
* - figure out what all unknown port bits are responsible for
*/

Expand Down Expand Up @@ -214,6 +216,16 @@ struct snd_azf3328 {

struct pci_dev *pci;
int irq;

#ifdef CONFIG_PM
/* register value containers for power management
* Note: not always full I/O range preserved (just like Win driver!) */
u16 saved_regs_codec [AZF_IO_SIZE_CODEC_PM / 2];
u16 saved_regs_io2 [AZF_IO_SIZE_IO2_PM / 2];
u16 saved_regs_mpu [AZF_IO_SIZE_MPU_PM / 2];
u16 saved_regs_synth[AZF_IO_SIZE_SYNTH_PM / 2];
u16 saved_regs_mixer[AZF_IO_SIZE_MIXER_PM / 2];
#endif
};

static const struct pci_device_id snd_azf3328_ids[] __devinitdata = {
Expand Down Expand Up @@ -961,6 +973,13 @@ snd_azf3328_playback_trigger(struct snd_pcm_substream *substream, int cmd)
chip->is_playing = 1;
snd_azf3328_dbgplay("STARTED PLAYBACK\n");
break;
case SNDRV_PCM_TRIGGER_RESUME:
snd_azf3328_dbgplay("RESUME PLAYBACK\n");
/* resume playback if we were active */
if (chip->is_playing)
snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS,
snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS) | DMA_RESUME);
break;
case SNDRV_PCM_TRIGGER_STOP:
snd_azf3328_dbgplay("STOP PLAYBACK\n");

Expand Down Expand Up @@ -988,13 +1007,20 @@ snd_azf3328_playback_trigger(struct snd_pcm_substream *substream, int cmd)
chip->is_playing = 0;
snd_azf3328_dbgplay("STOPPED PLAYBACK\n");
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
snd_azf3328_dbgplay("SUSPEND PLAYBACK\n");
/* make sure playback is stopped */
snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS,
snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS) & ~DMA_RESUME);
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_PUSH NIY!\n");
break;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_RELEASE NIY!\n");
break;
default:
printk(KERN_ERR "FIXME: unknown trigger mode!\n");
return -EINVAL;
}

Expand Down Expand Up @@ -1068,6 +1094,13 @@ snd_azf3328_capture_trigger(struct snd_pcm_substream *substream, int cmd)
chip->is_recording = 1;
snd_azf3328_dbgplay("STARTED CAPTURE\n");
break;
case SNDRV_PCM_TRIGGER_RESUME:
snd_azf3328_dbgplay("RESUME CAPTURE\n");
/* resume recording if we were active */
if (chip->is_recording)
snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS,
snd_azf3328_codec_inw(chip, IDX_IO_REC_FLAGS) | DMA_RESUME);
break;
case SNDRV_PCM_TRIGGER_STOP:
snd_azf3328_dbgplay("STOP CAPTURE\n");

Expand All @@ -1088,13 +1121,20 @@ snd_azf3328_capture_trigger(struct snd_pcm_substream *substream, int cmd)
chip->is_recording = 0;
snd_azf3328_dbgplay("STOPPED CAPTURE\n");
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
snd_azf3328_dbgplay("SUSPEND CAPTURE\n");
/* make sure recording is stopped */
snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS,
snd_azf3328_codec_inw(chip, IDX_IO_REC_FLAGS) & ~DMA_RESUME);
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_PUSH NIY!\n");
break;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_RELEASE NIY!\n");
break;
default:
printk(KERN_ERR "FIXME: unknown trigger mode!\n");
return -EINVAL;
}

Expand Down Expand Up @@ -1766,6 +1806,8 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
goto out_err;
}

card->private_data = chip;

if ((err = snd_mpu401_uart_new( card, 0, MPU401_HW_MPU401,
chip->mpu_port, 1, pci->irq, 0,
&chip->rmidi)) < 0) {
Expand All @@ -1791,6 +1833,8 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
}
}

opl3->private_data = chip;

sprintf(card->longname, "%s at 0x%lx, irq %i",
card->shortname, chip->codec_port, chip->irq);

Expand Down Expand Up @@ -1834,11 +1878,80 @@ snd_azf3328_remove(struct pci_dev *pci)
snd_azf3328_dbgcallleave();
}

#ifdef CONFIG_PM
static int
snd_azf3328_suspend(struct pci_dev *pci, pm_message_t state)
{
struct snd_card *card = pci_get_drvdata(pci);
struct snd_azf3328 *chip = card->private_data;
int reg;

snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);

snd_pcm_suspend_all(chip->pcm);

for (reg = 0; reg < AZF_IO_SIZE_MIXER_PM / 2; reg++)
chip->saved_regs_mixer[reg] = inw(chip->mixer_port + reg * 2);

/* make sure to disable master volume etc. to prevent looping sound */
snd_azf3328_mixer_set_mute(chip, IDX_MIXER_PLAY_MASTER, 1);
snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 1);

for (reg = 0; reg < AZF_IO_SIZE_CODEC_PM / 2; reg++)
chip->saved_regs_codec[reg] = inw(chip->codec_port + reg * 2);
for (reg = 0; reg < AZF_IO_SIZE_IO2_PM / 2; reg++)
chip->saved_regs_io2[reg] = inw(chip->io2_port + reg * 2);
for (reg = 0; reg < AZF_IO_SIZE_MPU_PM / 2; reg++)
chip->saved_regs_mpu[reg] = inw(chip->mpu_port + reg * 2);
for (reg = 0; reg < AZF_IO_SIZE_SYNTH_PM / 2; reg++)
chip->saved_regs_synth[reg] = inw(chip->synth_port + reg * 2);

pci_set_power_state(pci, PCI_D3hot);
pci_disable_device(pci);
pci_save_state(pci);
return 0;
}

static int
snd_azf3328_resume(struct pci_dev *pci)
{
struct snd_card *card = pci_get_drvdata(pci);
struct snd_azf3328 *chip = card->private_data;
int reg;

pci_restore_state(pci);
pci_enable_device(pci);
pci_set_power_state(pci, PCI_D0);
pci_set_master(pci);

for (reg = 0; reg < AZF_IO_SIZE_IO2_PM / 2; reg++)
outw(chip->saved_regs_io2[reg], chip->io2_port + reg * 2);
for (reg = 0; reg < AZF_IO_SIZE_MPU_PM / 2; reg++)
outw(chip->saved_regs_mpu[reg], chip->mpu_port + reg * 2);
for (reg = 0; reg < AZF_IO_SIZE_SYNTH_PM / 2; reg++)
outw(chip->saved_regs_synth[reg], chip->synth_port + reg * 2);
for (reg = 0; reg < AZF_IO_SIZE_MIXER_PM / 2; reg++)
outw(chip->saved_regs_mixer[reg], chip->mixer_port + reg * 2);
for (reg = 0; reg < AZF_IO_SIZE_CODEC_PM / 2; reg++)
outw(chip->saved_regs_codec[reg], chip->codec_port + reg * 2);

snd_power_change_state(card, SNDRV_CTL_POWER_D0);
return 0;
}
#endif




static struct pci_driver driver = {
.name = "AZF3328",
.id_table = snd_azf3328_ids,
.probe = snd_azf3328_probe,
.remove = __devexit_p(snd_azf3328_remove),
#ifdef CONFIG_PM
.suspend = snd_azf3328_suspend,
.resume = snd_azf3328_resume,
#endif
};

static int __init
Expand Down
20 changes: 17 additions & 3 deletions trunk/sound/pci/azt3328.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@

/*** main I/O area port indices ***/
/* (only 0x70 of 0x80 bytes saved/restored by Windows driver) */
#define AZF_IO_SIZE_CODEC 0x80
#define AZF_IO_SIZE_CODEC_PM 0x70

/* the driver initialisation suggests a layout of 4 main areas:
* from 0x00 (playback), from 0x20 (recording) and from 0x40 (maybe MPU401??).
* And another area from 0x60 to 0x6f (DirectX timer, IRQ management,
Expand Down Expand Up @@ -107,23 +110,34 @@
#define IRQ_UNKNOWN2 0x0080 /* probably unused */
#define IDX_IO_66H 0x66 /* writing 0xffff returns 0x0000 */
#define IDX_IO_SOME_VALUE 0x68 /* this is set to e.g. 0x3ff or 0x300, and writable; maybe some buffer limit, but I couldn't find out more, PU:0x00ff */
#define IDX_IO_6AH 0x6A /* this WORD can be set to have bits 0x0028 activated; actually inhibits PCM playback!!! maybe power management?? */
#define IDX_IO_6AH 0x6A /* this WORD can be set to have bits 0x0028 activated (FIXME: correct??); actually inhibits PCM playback!!! maybe power management?? */
#define IO_6A_PAUSE_PLAYBACK 0x0200 /* bit 9; sure, this pauses playback, but what the heck is this really about?? */
#define IDX_IO_6CH 0x6C
#define IDX_IO_6EH 0x6E /* writing 0xffff returns 0x83fe */
/* further I/O indices not saved/restored, so probably not used */


/*** I/O 2 area port indices ***/
/* (only 0x06 of 0x08 bytes saved/restored by Windows driver) */
#define AZF_IO_SIZE_IO2 0x08
#define AZF_IO_SIZE_IO2_PM 0x06

#define IDX_IO2_LEGACY_ADDR 0x04
#define LEGACY_SOMETHING 0x01 /* OPL3?? */
#define LEGACY_JOY 0x08

#define AZF_IO_SIZE_MPU 0x04
#define AZF_IO_SIZE_MPU_PM 0x04

#define AZF_IO_SIZE_SYNTH 0x08
#define AZF_IO_SIZE_SYNTH_PM 0x06

/*** mixer I/O area port indices ***/
/* (only 0x22 of 0x40 bytes saved/restored by Windows driver)
* generally spoken: AC97 register index = AZF3328 mixer reg index + 2
* (in other words: AZF3328 NOT fully AC97 compliant) */
* UNFORTUNATELY azf3328 is NOT truly AC97 compliant: see main file intro */
#define AZF_IO_SIZE_MIXER 0x40
#define AZF_IO_SIZE_MIXER_PM 0x22

#define MIXER_VOLUME_RIGHT_MASK 0x001f
#define MIXER_VOLUME_LEFT_MASK 0x1f00
#define MIXER_MUTE_MASK 0x8000
Expand Down

0 comments on commit f7a1a48

Please sign in to comment.