Loading sound/pci/fm801.c +158 −87 Original line number Original line Diff line number Diff line Loading @@ -103,7 +103,11 @@ MODULE_PARM_DESC(tea575x_tuner, "Enable TEA575x tuner."); #define FM801_OPL3_DATA1 0x6b /* OPL3 Bank 1 Write */ #define FM801_OPL3_DATA1 0x6b /* OPL3 Bank 1 Write */ #define FM801_POWERDOWN 0x70 /* Blocks Power Down Control */ #define FM801_POWERDOWN 0x70 /* Blocks Power Down Control */ #define FM801_AC97_ADDR_SHIFT 10 /* codec access */ #define FM801_AC97_READ (1<<7) /* read=1, write=0 */ #define FM801_AC97_VALID (1<<8) /* port valid=1 */ #define FM801_AC97_BUSY (1<<9) /* busy=1 */ #define FM801_AC97_ADDR_SHIFT 10 /* codec id (2bit) */ /* playback and record control register bits */ /* playback and record control register bits */ #define FM801_BUF1_LAST (1<<1) #define FM801_BUF1_LAST (1<<1) Loading Loading @@ -189,6 +193,10 @@ struct fm801 { #ifdef TEA575X_RADIO #ifdef TEA575X_RADIO struct snd_tea575x tea; struct snd_tea575x tea; #endif #endif #ifdef CONFIG_PM u16 saved_regs[0x20]; #endif }; }; static struct pci_device_id snd_fm801_ids[] = { static struct pci_device_id snd_fm801_ids[] = { Loading Loading @@ -231,7 +239,7 @@ static void snd_fm801_codec_write(struct snd_ac97 *ac97, * Wait until the codec interface is not ready.. * Wait until the codec interface is not ready.. */ */ for (idx = 0; idx < 100; idx++) { for (idx = 0; idx < 100; idx++) { if (!(inw(FM801_REG(chip, AC97_CMD)) & (1<<9))) if (!(inw(FM801_REG(chip, AC97_CMD)) & FM801_AC97_BUSY)) goto ok1; goto ok1; udelay(10); udelay(10); } } Loading @@ -246,7 +254,7 @@ static void snd_fm801_codec_write(struct snd_ac97 *ac97, * Wait until the write command is not completed.. * Wait until the write command is not completed.. */ */ for (idx = 0; idx < 1000; idx++) { for (idx = 0; idx < 1000; idx++) { if (!(inw(FM801_REG(chip, AC97_CMD)) & (1<<9))) if (!(inw(FM801_REG(chip, AC97_CMD)) & FM801_AC97_BUSY)) return; return; udelay(10); udelay(10); } } Loading @@ -262,7 +270,7 @@ static unsigned short snd_fm801_codec_read(struct snd_ac97 *ac97, unsigned short * Wait until the codec interface is not ready.. * Wait until the codec interface is not ready.. */ */ for (idx = 0; idx < 100; idx++) { for (idx = 0; idx < 100; idx++) { if (!(inw(FM801_REG(chip, AC97_CMD)) & (1<<9))) if (!(inw(FM801_REG(chip, AC97_CMD)) & FM801_AC97_BUSY)) goto ok1; goto ok1; udelay(10); udelay(10); } } Loading @@ -271,9 +279,10 @@ static unsigned short snd_fm801_codec_read(struct snd_ac97 *ac97, unsigned short ok1: ok1: /* read command */ /* read command */ outw(reg | (ac97->addr << FM801_AC97_ADDR_SHIFT) | (1<<7), FM801_REG(chip, AC97_CMD)); outw(reg | (ac97->addr << FM801_AC97_ADDR_SHIFT) | FM801_AC97_READ, FM801_REG(chip, AC97_CMD)); for (idx = 0; idx < 100; idx++) { for (idx = 0; idx < 100; idx++) { if (!(inw(FM801_REG(chip, AC97_CMD)) & (1<<9))) if (!(inw(FM801_REG(chip, AC97_CMD)) & FM801_AC97_BUSY)) goto ok2; goto ok2; udelay(10); udelay(10); } } Loading @@ -282,7 +291,7 @@ static unsigned short snd_fm801_codec_read(struct snd_ac97 *ac97, unsigned short ok2: ok2: for (idx = 0; idx < 1000; idx++) { for (idx = 0; idx < 1000; idx++) { if (inw(FM801_REG(chip, AC97_CMD)) & (1<<8)) if (inw(FM801_REG(chip, AC97_CMD)) & FM801_AC97_VALID) goto ok3; goto ok3; udelay(10); udelay(10); } } Loading Loading @@ -354,9 +363,11 @@ static int snd_fm801_playback_trigger(struct snd_pcm_substream *substream, chip->ply_ctrl &= ~(FM801_START | FM801_PAUSE); chip->ply_ctrl &= ~(FM801_START | FM801_PAUSE); break; break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_SUSPEND: chip->ply_ctrl |= FM801_PAUSE; chip->ply_ctrl |= FM801_PAUSE; break; break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_RESUME: chip->ply_ctrl &= ~FM801_PAUSE; chip->ply_ctrl &= ~FM801_PAUSE; break; break; default: default: Loading Loading @@ -387,9 +398,11 @@ static int snd_fm801_capture_trigger(struct snd_pcm_substream *substream, chip->cap_ctrl &= ~(FM801_START | FM801_PAUSE); chip->cap_ctrl &= ~(FM801_START | FM801_PAUSE); break; break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_SUSPEND: chip->cap_ctrl |= FM801_PAUSE; chip->cap_ctrl |= FM801_PAUSE; break; break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_RESUME: chip->cap_ctrl &= ~FM801_PAUSE; chip->cap_ctrl &= ~FM801_PAUSE; break; break; default: default: Loading Loading @@ -557,7 +570,7 @@ static struct snd_pcm_hardware snd_fm801_playback = { { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_MMAP_VALID), SNDRV_PCM_INFO_MMAP_VALID), .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, .rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000, .rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000, Loading @@ -577,7 +590,7 @@ static struct snd_pcm_hardware snd_fm801_capture = { { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_MMAP_VALID), SNDRV_PCM_INFO_MMAP_VALID), .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, .rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000, .rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000, Loading Loading @@ -1218,6 +1231,85 @@ static int __devinit snd_fm801_mixer(struct fm801 *chip) * initialization routines * initialization routines */ */ static int wait_for_codec(struct fm801 *chip, unsigned int codec_id, unsigned short reg, unsigned long waits) { unsigned long timeout = jiffies + waits; outw(FM801_AC97_READ | (codec_id << FM801_AC97_ADDR_SHIFT) | reg, FM801_REG(chip, AC97_CMD)); udelay(5); do { if ((inw(FM801_REG(chip, AC97_CMD)) & (FM801_AC97_VALID|FM801_AC97_BUSY)) == FM801_AC97_VALID) return 0; schedule_timeout_uninterruptible(1); } while (time_after(timeout, jiffies)); return -EIO; } static int snd_fm801_chip_init(struct fm801 *chip, int resume) { int id; unsigned short cmdw; /* codec cold reset + AC'97 warm reset */ outw((1<<5) | (1<<6), FM801_REG(chip, CODEC_CTRL)); inw(FM801_REG(chip, CODEC_CTRL)); /* flush posting data */ udelay(100); outw(0, FM801_REG(chip, CODEC_CTRL)); if (wait_for_codec(chip, 0, AC97_RESET, msecs_to_jiffies(750)) < 0) { snd_printk(KERN_ERR "Primary AC'97 codec not found\n"); if (! resume) return -EIO; } if (chip->multichannel) { if (chip->secondary_addr) { wait_for_codec(chip, chip->secondary_addr, AC97_VENDOR_ID1, msecs_to_jiffies(50)); } else { /* my card has the secondary codec */ /* at address #3, so the loop is inverted */ for (id = 3; id > 0; id--) { if (! wait_for_codec(chip, id, AC97_VENDOR_ID1, msecs_to_jiffies(50))) { cmdw = inw(FM801_REG(chip, AC97_DATA)); if (cmdw != 0xffff && cmdw != 0) { chip->secondary = 1; chip->secondary_addr = id; break; } } } } /* the recovery phase, it seems that probing for non-existing codec might */ /* cause timeout problems */ wait_for_codec(chip, 0, AC97_VENDOR_ID1, msecs_to_jiffies(750)); } /* init volume */ outw(0x0808, FM801_REG(chip, PCM_VOL)); outw(0x9f1f, FM801_REG(chip, FM_VOL)); outw(0x8808, FM801_REG(chip, I2S_VOL)); /* I2S control - I2S mode */ outw(0x0003, FM801_REG(chip, I2S_MODE)); /* interrupt setup - unmask MPU, PLAYBACK & CAPTURE */ cmdw = inw(FM801_REG(chip, IRQ_MASK)); cmdw &= ~0x0083; outw(cmdw, FM801_REG(chip, IRQ_MASK)); /* interrupt clear */ outw(FM801_IRQ_PLAYBACK|FM801_IRQ_CAPTURE|FM801_IRQ_MPU, FM801_REG(chip, IRQ_STATUS)); return 0; } static int snd_fm801_free(struct fm801 *chip) static int snd_fm801_free(struct fm801 *chip) { { unsigned short cmdw; unsigned short cmdw; Loading Loading @@ -1255,9 +1347,7 @@ static int __devinit snd_fm801_create(struct snd_card *card, struct fm801 ** rchip) struct fm801 ** rchip) { { struct fm801 *chip; struct fm801 *chip; unsigned char rev, id; unsigned char rev; unsigned short cmdw; unsigned long timeout; int err; int err; static struct snd_device_ops ops = { static struct snd_device_ops ops = { .dev_free = snd_fm801_dev_free, .dev_free = snd_fm801_dev_free, Loading Loading @@ -1294,81 +1384,7 @@ static int __devinit snd_fm801_create(struct snd_card *card, if (rev >= 0xb1) /* FM801-AU */ if (rev >= 0xb1) /* FM801-AU */ chip->multichannel = 1; chip->multichannel = 1; /* codec cold reset + AC'97 warm reset */ snd_fm801_chip_init(chip, 0); outw((1<<5)|(1<<6), FM801_REG(chip, CODEC_CTRL)); inw(FM801_REG(chip, CODEC_CTRL)); /* flush posting data */ udelay(100); outw(0, FM801_REG(chip, CODEC_CTRL)); timeout = (jiffies + (3 * HZ) / 4) + 1; /* min 750ms */ outw((1<<7) | (0 << FM801_AC97_ADDR_SHIFT), FM801_REG(chip, AC97_CMD)); udelay(5); do { if ((inw(FM801_REG(chip, AC97_CMD)) & (3<<8)) == (1<<8)) goto __ac97_secondary; schedule_timeout_uninterruptible(1); } while (time_after(timeout, jiffies)); snd_printk(KERN_ERR "Primary AC'97 codec not found\n"); snd_fm801_free(chip); return -EIO; __ac97_secondary: if (!chip->multichannel) /* lookup is not required */ goto __ac97_ok; for (id = 3; id > 0; id--) { /* my card has the secondary codec */ /* at address #3, so the loop is inverted */ timeout = jiffies + HZ / 20; outw((1<<7) | (id << FM801_AC97_ADDR_SHIFT) | AC97_VENDOR_ID1, FM801_REG(chip, AC97_CMD)); udelay(5); do { if ((inw(FM801_REG(chip, AC97_CMD)) & (3<<8)) == (1<<8)) { cmdw = inw(FM801_REG(chip, AC97_DATA)); if (cmdw != 0xffff && cmdw != 0) { chip->secondary = 1; chip->secondary_addr = id; goto __ac97_ok; } } schedule_timeout_uninterruptible(1); } while (time_after(timeout, jiffies)); } /* the recovery phase, it seems that probing for non-existing codec might */ /* cause timeout problems */ timeout = (jiffies + (3 * HZ) / 4) + 1; /* min 750ms */ outw((1<<7) | (0 << FM801_AC97_ADDR_SHIFT), FM801_REG(chip, AC97_CMD)); udelay(5); do { if ((inw(FM801_REG(chip, AC97_CMD)) & (3<<8)) == (1<<8)) goto __ac97_ok; schedule_timeout_uninterruptible(1); } while (time_after(timeout, jiffies)); snd_printk(KERN_ERR "Primary AC'97 codec not responding\n"); snd_fm801_free(chip); return -EIO; __ac97_ok: /* init volume */ outw(0x0808, FM801_REG(chip, PCM_VOL)); outw(0x9f1f, FM801_REG(chip, FM_VOL)); outw(0x8808, FM801_REG(chip, I2S_VOL)); /* I2S control - I2S mode */ outw(0x0003, FM801_REG(chip, I2S_MODE)); /* interrupt setup - unmask MPU, PLAYBACK & CAPTURE */ cmdw = inw(FM801_REG(chip, IRQ_MASK)); cmdw &= ~0x0083; outw(cmdw, FM801_REG(chip, IRQ_MASK)); /* interrupt clear */ outw(FM801_IRQ_PLAYBACK|FM801_IRQ_CAPTURE|FM801_IRQ_MPU, FM801_REG(chip, IRQ_STATUS)); if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { snd_fm801_free(chip); snd_fm801_free(chip); Loading Loading @@ -1415,6 +1431,7 @@ static int __devinit snd_card_fm801_probe(struct pci_dev *pci, snd_card_free(card); snd_card_free(card); return err; return err; } } card->private_data = chip; strcpy(card->driver, "FM801"); strcpy(card->driver, "FM801"); strcpy(card->shortname, "ForteMedia FM801-"); strcpy(card->shortname, "ForteMedia FM801-"); Loading Loading @@ -1462,11 +1479,65 @@ static void __devexit snd_card_fm801_remove(struct pci_dev *pci) pci_set_drvdata(pci, NULL); pci_set_drvdata(pci, NULL); } } #ifdef CONFIG_PM static unsigned char saved_regs[] = { FM801_PCM_VOL, FM801_I2S_VOL, FM801_FM_VOL, FM801_REC_SRC, FM801_PLY_CTRL, FM801_PLY_COUNT, FM801_PLY_BUF1, FM801_PLY_BUF2, FM801_CAP_CTRL, FM801_CAP_COUNT, FM801_CAP_BUF1, FM801_CAP_BUF2, FM801_CODEC_CTRL, FM801_I2S_MODE, FM801_VOLUME, FM801_GEN_CTRL, }; static int snd_fm801_suspend(struct pci_dev *pci, pm_message_t state) { struct snd_card *card = pci_get_drvdata(pci); struct fm801 *chip = card->private_data; int i; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); snd_pcm_suspend_all(chip->pcm); snd_ac97_suspend(chip->ac97); snd_ac97_suspend(chip->ac97_sec); for (i = 0; i < ARRAY_SIZE(saved_regs); i++) chip->saved_regs[i] = inw(chip->port + saved_regs[i]); /* FIXME: tea575x suspend */ pci_set_power_state(pci, PCI_D3hot); pci_disable_device(pci); pci_save_state(pci); return 0; } static int snd_fm801_resume(struct pci_dev *pci) { struct snd_card *card = pci_get_drvdata(pci); struct fm801 *chip = card->private_data; int i; pci_restore_state(pci); pci_enable_device(pci); pci_set_power_state(pci, PCI_D0); pci_set_master(pci); snd_fm801_chip_init(chip, 1); snd_ac97_resume(chip->ac97); snd_ac97_resume(chip->ac97_sec); for (i = 0; i < ARRAY_SIZE(saved_regs); i++) outw(chip->saved_regs[i], chip->port + saved_regs[i]); snd_power_change_state(card, SNDRV_CTL_POWER_D0); return 0; } #endif static struct pci_driver driver = { static struct pci_driver driver = { .name = "FM801", .name = "FM801", .id_table = snd_fm801_ids, .id_table = snd_fm801_ids, .probe = snd_card_fm801_probe, .probe = snd_card_fm801_probe, .remove = __devexit_p(snd_card_fm801_remove), .remove = __devexit_p(snd_card_fm801_remove), #ifdef CONFIG_PM .suspend = snd_fm801_suspend, .resume = snd_fm801_resume, #endif }; }; static int __init alsa_card_fm801_init(void) static int __init alsa_card_fm801_init(void) Loading Loading
sound/pci/fm801.c +158 −87 Original line number Original line Diff line number Diff line Loading @@ -103,7 +103,11 @@ MODULE_PARM_DESC(tea575x_tuner, "Enable TEA575x tuner."); #define FM801_OPL3_DATA1 0x6b /* OPL3 Bank 1 Write */ #define FM801_OPL3_DATA1 0x6b /* OPL3 Bank 1 Write */ #define FM801_POWERDOWN 0x70 /* Blocks Power Down Control */ #define FM801_POWERDOWN 0x70 /* Blocks Power Down Control */ #define FM801_AC97_ADDR_SHIFT 10 /* codec access */ #define FM801_AC97_READ (1<<7) /* read=1, write=0 */ #define FM801_AC97_VALID (1<<8) /* port valid=1 */ #define FM801_AC97_BUSY (1<<9) /* busy=1 */ #define FM801_AC97_ADDR_SHIFT 10 /* codec id (2bit) */ /* playback and record control register bits */ /* playback and record control register bits */ #define FM801_BUF1_LAST (1<<1) #define FM801_BUF1_LAST (1<<1) Loading Loading @@ -189,6 +193,10 @@ struct fm801 { #ifdef TEA575X_RADIO #ifdef TEA575X_RADIO struct snd_tea575x tea; struct snd_tea575x tea; #endif #endif #ifdef CONFIG_PM u16 saved_regs[0x20]; #endif }; }; static struct pci_device_id snd_fm801_ids[] = { static struct pci_device_id snd_fm801_ids[] = { Loading Loading @@ -231,7 +239,7 @@ static void snd_fm801_codec_write(struct snd_ac97 *ac97, * Wait until the codec interface is not ready.. * Wait until the codec interface is not ready.. */ */ for (idx = 0; idx < 100; idx++) { for (idx = 0; idx < 100; idx++) { if (!(inw(FM801_REG(chip, AC97_CMD)) & (1<<9))) if (!(inw(FM801_REG(chip, AC97_CMD)) & FM801_AC97_BUSY)) goto ok1; goto ok1; udelay(10); udelay(10); } } Loading @@ -246,7 +254,7 @@ static void snd_fm801_codec_write(struct snd_ac97 *ac97, * Wait until the write command is not completed.. * Wait until the write command is not completed.. */ */ for (idx = 0; idx < 1000; idx++) { for (idx = 0; idx < 1000; idx++) { if (!(inw(FM801_REG(chip, AC97_CMD)) & (1<<9))) if (!(inw(FM801_REG(chip, AC97_CMD)) & FM801_AC97_BUSY)) return; return; udelay(10); udelay(10); } } Loading @@ -262,7 +270,7 @@ static unsigned short snd_fm801_codec_read(struct snd_ac97 *ac97, unsigned short * Wait until the codec interface is not ready.. * Wait until the codec interface is not ready.. */ */ for (idx = 0; idx < 100; idx++) { for (idx = 0; idx < 100; idx++) { if (!(inw(FM801_REG(chip, AC97_CMD)) & (1<<9))) if (!(inw(FM801_REG(chip, AC97_CMD)) & FM801_AC97_BUSY)) goto ok1; goto ok1; udelay(10); udelay(10); } } Loading @@ -271,9 +279,10 @@ static unsigned short snd_fm801_codec_read(struct snd_ac97 *ac97, unsigned short ok1: ok1: /* read command */ /* read command */ outw(reg | (ac97->addr << FM801_AC97_ADDR_SHIFT) | (1<<7), FM801_REG(chip, AC97_CMD)); outw(reg | (ac97->addr << FM801_AC97_ADDR_SHIFT) | FM801_AC97_READ, FM801_REG(chip, AC97_CMD)); for (idx = 0; idx < 100; idx++) { for (idx = 0; idx < 100; idx++) { if (!(inw(FM801_REG(chip, AC97_CMD)) & (1<<9))) if (!(inw(FM801_REG(chip, AC97_CMD)) & FM801_AC97_BUSY)) goto ok2; goto ok2; udelay(10); udelay(10); } } Loading @@ -282,7 +291,7 @@ static unsigned short snd_fm801_codec_read(struct snd_ac97 *ac97, unsigned short ok2: ok2: for (idx = 0; idx < 1000; idx++) { for (idx = 0; idx < 1000; idx++) { if (inw(FM801_REG(chip, AC97_CMD)) & (1<<8)) if (inw(FM801_REG(chip, AC97_CMD)) & FM801_AC97_VALID) goto ok3; goto ok3; udelay(10); udelay(10); } } Loading Loading @@ -354,9 +363,11 @@ static int snd_fm801_playback_trigger(struct snd_pcm_substream *substream, chip->ply_ctrl &= ~(FM801_START | FM801_PAUSE); chip->ply_ctrl &= ~(FM801_START | FM801_PAUSE); break; break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_SUSPEND: chip->ply_ctrl |= FM801_PAUSE; chip->ply_ctrl |= FM801_PAUSE; break; break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_RESUME: chip->ply_ctrl &= ~FM801_PAUSE; chip->ply_ctrl &= ~FM801_PAUSE; break; break; default: default: Loading Loading @@ -387,9 +398,11 @@ static int snd_fm801_capture_trigger(struct snd_pcm_substream *substream, chip->cap_ctrl &= ~(FM801_START | FM801_PAUSE); chip->cap_ctrl &= ~(FM801_START | FM801_PAUSE); break; break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_SUSPEND: chip->cap_ctrl |= FM801_PAUSE; chip->cap_ctrl |= FM801_PAUSE; break; break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_RESUME: chip->cap_ctrl &= ~FM801_PAUSE; chip->cap_ctrl &= ~FM801_PAUSE; break; break; default: default: Loading Loading @@ -557,7 +570,7 @@ static struct snd_pcm_hardware snd_fm801_playback = { { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_MMAP_VALID), SNDRV_PCM_INFO_MMAP_VALID), .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, .rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000, .rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000, Loading @@ -577,7 +590,7 @@ static struct snd_pcm_hardware snd_fm801_capture = { { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_MMAP_VALID), SNDRV_PCM_INFO_MMAP_VALID), .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, .rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000, .rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000, Loading Loading @@ -1218,6 +1231,85 @@ static int __devinit snd_fm801_mixer(struct fm801 *chip) * initialization routines * initialization routines */ */ static int wait_for_codec(struct fm801 *chip, unsigned int codec_id, unsigned short reg, unsigned long waits) { unsigned long timeout = jiffies + waits; outw(FM801_AC97_READ | (codec_id << FM801_AC97_ADDR_SHIFT) | reg, FM801_REG(chip, AC97_CMD)); udelay(5); do { if ((inw(FM801_REG(chip, AC97_CMD)) & (FM801_AC97_VALID|FM801_AC97_BUSY)) == FM801_AC97_VALID) return 0; schedule_timeout_uninterruptible(1); } while (time_after(timeout, jiffies)); return -EIO; } static int snd_fm801_chip_init(struct fm801 *chip, int resume) { int id; unsigned short cmdw; /* codec cold reset + AC'97 warm reset */ outw((1<<5) | (1<<6), FM801_REG(chip, CODEC_CTRL)); inw(FM801_REG(chip, CODEC_CTRL)); /* flush posting data */ udelay(100); outw(0, FM801_REG(chip, CODEC_CTRL)); if (wait_for_codec(chip, 0, AC97_RESET, msecs_to_jiffies(750)) < 0) { snd_printk(KERN_ERR "Primary AC'97 codec not found\n"); if (! resume) return -EIO; } if (chip->multichannel) { if (chip->secondary_addr) { wait_for_codec(chip, chip->secondary_addr, AC97_VENDOR_ID1, msecs_to_jiffies(50)); } else { /* my card has the secondary codec */ /* at address #3, so the loop is inverted */ for (id = 3; id > 0; id--) { if (! wait_for_codec(chip, id, AC97_VENDOR_ID1, msecs_to_jiffies(50))) { cmdw = inw(FM801_REG(chip, AC97_DATA)); if (cmdw != 0xffff && cmdw != 0) { chip->secondary = 1; chip->secondary_addr = id; break; } } } } /* the recovery phase, it seems that probing for non-existing codec might */ /* cause timeout problems */ wait_for_codec(chip, 0, AC97_VENDOR_ID1, msecs_to_jiffies(750)); } /* init volume */ outw(0x0808, FM801_REG(chip, PCM_VOL)); outw(0x9f1f, FM801_REG(chip, FM_VOL)); outw(0x8808, FM801_REG(chip, I2S_VOL)); /* I2S control - I2S mode */ outw(0x0003, FM801_REG(chip, I2S_MODE)); /* interrupt setup - unmask MPU, PLAYBACK & CAPTURE */ cmdw = inw(FM801_REG(chip, IRQ_MASK)); cmdw &= ~0x0083; outw(cmdw, FM801_REG(chip, IRQ_MASK)); /* interrupt clear */ outw(FM801_IRQ_PLAYBACK|FM801_IRQ_CAPTURE|FM801_IRQ_MPU, FM801_REG(chip, IRQ_STATUS)); return 0; } static int snd_fm801_free(struct fm801 *chip) static int snd_fm801_free(struct fm801 *chip) { { unsigned short cmdw; unsigned short cmdw; Loading Loading @@ -1255,9 +1347,7 @@ static int __devinit snd_fm801_create(struct snd_card *card, struct fm801 ** rchip) struct fm801 ** rchip) { { struct fm801 *chip; struct fm801 *chip; unsigned char rev, id; unsigned char rev; unsigned short cmdw; unsigned long timeout; int err; int err; static struct snd_device_ops ops = { static struct snd_device_ops ops = { .dev_free = snd_fm801_dev_free, .dev_free = snd_fm801_dev_free, Loading Loading @@ -1294,81 +1384,7 @@ static int __devinit snd_fm801_create(struct snd_card *card, if (rev >= 0xb1) /* FM801-AU */ if (rev >= 0xb1) /* FM801-AU */ chip->multichannel = 1; chip->multichannel = 1; /* codec cold reset + AC'97 warm reset */ snd_fm801_chip_init(chip, 0); outw((1<<5)|(1<<6), FM801_REG(chip, CODEC_CTRL)); inw(FM801_REG(chip, CODEC_CTRL)); /* flush posting data */ udelay(100); outw(0, FM801_REG(chip, CODEC_CTRL)); timeout = (jiffies + (3 * HZ) / 4) + 1; /* min 750ms */ outw((1<<7) | (0 << FM801_AC97_ADDR_SHIFT), FM801_REG(chip, AC97_CMD)); udelay(5); do { if ((inw(FM801_REG(chip, AC97_CMD)) & (3<<8)) == (1<<8)) goto __ac97_secondary; schedule_timeout_uninterruptible(1); } while (time_after(timeout, jiffies)); snd_printk(KERN_ERR "Primary AC'97 codec not found\n"); snd_fm801_free(chip); return -EIO; __ac97_secondary: if (!chip->multichannel) /* lookup is not required */ goto __ac97_ok; for (id = 3; id > 0; id--) { /* my card has the secondary codec */ /* at address #3, so the loop is inverted */ timeout = jiffies + HZ / 20; outw((1<<7) | (id << FM801_AC97_ADDR_SHIFT) | AC97_VENDOR_ID1, FM801_REG(chip, AC97_CMD)); udelay(5); do { if ((inw(FM801_REG(chip, AC97_CMD)) & (3<<8)) == (1<<8)) { cmdw = inw(FM801_REG(chip, AC97_DATA)); if (cmdw != 0xffff && cmdw != 0) { chip->secondary = 1; chip->secondary_addr = id; goto __ac97_ok; } } schedule_timeout_uninterruptible(1); } while (time_after(timeout, jiffies)); } /* the recovery phase, it seems that probing for non-existing codec might */ /* cause timeout problems */ timeout = (jiffies + (3 * HZ) / 4) + 1; /* min 750ms */ outw((1<<7) | (0 << FM801_AC97_ADDR_SHIFT), FM801_REG(chip, AC97_CMD)); udelay(5); do { if ((inw(FM801_REG(chip, AC97_CMD)) & (3<<8)) == (1<<8)) goto __ac97_ok; schedule_timeout_uninterruptible(1); } while (time_after(timeout, jiffies)); snd_printk(KERN_ERR "Primary AC'97 codec not responding\n"); snd_fm801_free(chip); return -EIO; __ac97_ok: /* init volume */ outw(0x0808, FM801_REG(chip, PCM_VOL)); outw(0x9f1f, FM801_REG(chip, FM_VOL)); outw(0x8808, FM801_REG(chip, I2S_VOL)); /* I2S control - I2S mode */ outw(0x0003, FM801_REG(chip, I2S_MODE)); /* interrupt setup - unmask MPU, PLAYBACK & CAPTURE */ cmdw = inw(FM801_REG(chip, IRQ_MASK)); cmdw &= ~0x0083; outw(cmdw, FM801_REG(chip, IRQ_MASK)); /* interrupt clear */ outw(FM801_IRQ_PLAYBACK|FM801_IRQ_CAPTURE|FM801_IRQ_MPU, FM801_REG(chip, IRQ_STATUS)); if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { snd_fm801_free(chip); snd_fm801_free(chip); Loading Loading @@ -1415,6 +1431,7 @@ static int __devinit snd_card_fm801_probe(struct pci_dev *pci, snd_card_free(card); snd_card_free(card); return err; return err; } } card->private_data = chip; strcpy(card->driver, "FM801"); strcpy(card->driver, "FM801"); strcpy(card->shortname, "ForteMedia FM801-"); strcpy(card->shortname, "ForteMedia FM801-"); Loading Loading @@ -1462,11 +1479,65 @@ static void __devexit snd_card_fm801_remove(struct pci_dev *pci) pci_set_drvdata(pci, NULL); pci_set_drvdata(pci, NULL); } } #ifdef CONFIG_PM static unsigned char saved_regs[] = { FM801_PCM_VOL, FM801_I2S_VOL, FM801_FM_VOL, FM801_REC_SRC, FM801_PLY_CTRL, FM801_PLY_COUNT, FM801_PLY_BUF1, FM801_PLY_BUF2, FM801_CAP_CTRL, FM801_CAP_COUNT, FM801_CAP_BUF1, FM801_CAP_BUF2, FM801_CODEC_CTRL, FM801_I2S_MODE, FM801_VOLUME, FM801_GEN_CTRL, }; static int snd_fm801_suspend(struct pci_dev *pci, pm_message_t state) { struct snd_card *card = pci_get_drvdata(pci); struct fm801 *chip = card->private_data; int i; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); snd_pcm_suspend_all(chip->pcm); snd_ac97_suspend(chip->ac97); snd_ac97_suspend(chip->ac97_sec); for (i = 0; i < ARRAY_SIZE(saved_regs); i++) chip->saved_regs[i] = inw(chip->port + saved_regs[i]); /* FIXME: tea575x suspend */ pci_set_power_state(pci, PCI_D3hot); pci_disable_device(pci); pci_save_state(pci); return 0; } static int snd_fm801_resume(struct pci_dev *pci) { struct snd_card *card = pci_get_drvdata(pci); struct fm801 *chip = card->private_data; int i; pci_restore_state(pci); pci_enable_device(pci); pci_set_power_state(pci, PCI_D0); pci_set_master(pci); snd_fm801_chip_init(chip, 1); snd_ac97_resume(chip->ac97); snd_ac97_resume(chip->ac97_sec); for (i = 0; i < ARRAY_SIZE(saved_regs); i++) outw(chip->saved_regs[i], chip->port + saved_regs[i]); snd_power_change_state(card, SNDRV_CTL_POWER_D0); return 0; } #endif static struct pci_driver driver = { static struct pci_driver driver = { .name = "FM801", .name = "FM801", .id_table = snd_fm801_ids, .id_table = snd_fm801_ids, .probe = snd_card_fm801_probe, .probe = snd_card_fm801_probe, .remove = __devexit_p(snd_card_fm801_remove), .remove = __devexit_p(snd_card_fm801_remove), #ifdef CONFIG_PM .suspend = snd_fm801_suspend, .resume = snd_fm801_resume, #endif }; }; static int __init alsa_card_fm801_init(void) static int __init alsa_card_fm801_init(void) Loading