static bool yds_resume(device_t dv, const pmf_qual_t *qual) { struct yds_softc *sc = device_private(dv); pci_chipset_tag_t pc = sc->sc_pc; pcitag_t tag = sc->sc_pcitag; pcireg_t reg; /* Disable legacy mode */ mutex_enter(&sc->sc_lock); mutex_spin_enter(&sc->sc_intr_lock); reg = pci_conf_read(pc, tag, YDS_PCI_LEGACY); pci_conf_write(pc, tag, YDS_PCI_LEGACY, reg & YDS_PCI_LEGACY_LAD); /* Enable the device. */ reg = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); reg |= (PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE | PCI_COMMAND_MASTER_ENABLE); pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, reg); reg = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); if (yds_init(sc)) { aprint_error_dev(dv, "reinitialize failed\n"); mutex_spin_exit(&sc->sc_intr_lock); mutex_exit(&sc->sc_lock); return false; } pci_conf_write(pc, tag, YDS_PCI_DSCTRL, sc->sc_dsctrl); mutex_spin_exit(&sc->sc_intr_lock); sc->sc_codec[0].codec_if->vtbl->restore_ports(sc->sc_codec[0].codec_if); mutex_exit(&sc->sc_lock); return true; }
void yds_attachhook(void *xsc) { struct yds_softc *sc = xsc; struct yds_codec_softc *codec; mixer_ctrl_t ctl; int r, i; /* Initialize the device */ if (yds_init(sc, 0) == -1) return; /* * Attach ac97 codec */ for (i = 0; i < 2; i++) { static struct { int data; int addr; } statregs[] = { {AC97_STAT_DATA1, AC97_STAT_ADDR1}, {AC97_STAT_DATA2, AC97_STAT_ADDR2}, }; if (i == 1 && ac97_id2 == -1) break; /* secondary ac97 not available */ codec = &sc->sc_codec[i]; memcpy(&codec->sc_dev, &sc->sc_dev, sizeof(codec->sc_dev)); codec->sc = sc; codec->id = i == 1 ? ac97_id2 : 0; codec->status_data = statregs[i].data; codec->status_addr = statregs[i].addr; codec->host_if.arg = codec; codec->host_if.attach = yds_attach_codec; codec->host_if.read = yds_read_codec; codec->host_if.write = yds_write_codec; codec->host_if.reset = yds_reset_codec; if ((r = ac97_attach(&codec->host_if)) != 0) { printf("%s: can't attach codec (error 0x%X)\n", sc->sc_dev.dv_xname, r); return; } } /* Just enable the DAC and master volumes by default */ ctl.type = AUDIO_MIXER_ENUM; ctl.un.ord = 0; /* off */ ctl.dev = yds_get_portnum_by_name(sc, AudioCoutputs, AudioNmaster, AudioNmute); yds_mixer_set_port(sc, &ctl); ctl.dev = yds_get_portnum_by_name(sc, AudioCinputs, AudioNdac, AudioNmute); yds_mixer_set_port(sc, &ctl); ctl.dev = yds_get_portnum_by_name(sc, AudioCinputs, AudioNcd, AudioNmute); yds_mixer_set_port(sc, &ctl); ctl.dev = yds_get_portnum_by_name(sc, AudioCrecord, AudioNvolume, AudioNmute); yds_mixer_set_port(sc, &ctl); ctl.dev = yds_get_portnum_by_name(sc, AudioCrecord, AudioNsource, NULL); ctl.type = AUDIO_MIXER_ENUM; ctl.un.ord = 0; yds_mixer_set_port(sc, &ctl); /* Set a reasonable default volume */ ctl.type = AUDIO_MIXER_VALUE; ctl.un.value.num_channels = 2; ctl.un.value.level[AUDIO_MIXER_LEVEL_LEFT] = ctl.un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = 127; ctl.dev = sc->sc_codec[0].codec_if->vtbl->get_portnum_by_name( sc->sc_codec[0].codec_if, AudioCoutputs, AudioNmaster, NULL); yds_mixer_set_port(sc, &ctl); audio_attach_mi(&yds_hw_if, sc, &sc->sc_dev); /* Watch for power changes */ sc->suspend = DVACT_RESUME; yds_configure_legacy(sc); }
static void yds_attach(device_t parent, device_t self, void *aux) { struct yds_softc *sc; struct pci_attach_args *pa; pci_chipset_tag_t pc; char const *intrstr; pci_intr_handle_t ih; pcireg_t reg; struct yds_codec_softc *codec; int i, r, to; int revision; int ac97_id2; char intrbuf[PCI_INTRSTR_LEN]; sc = device_private(self); sc->sc_dev = self; pa = (struct pci_attach_args *)aux; pc = pa->pa_pc; revision = PCI_REVISION(pa->pa_class); pci_aprint_devinfo(pa, NULL); /* Map register to memory */ if (pci_mapreg_map(pa, YDS_PCI_MBA, PCI_MAPREG_TYPE_MEM, 0, &sc->memt, &sc->memh, NULL, NULL)) { aprint_error_dev(self, "can't map memory space\n"); return; } /* Map and establish the interrupt. */ if (pci_intr_map(pa, &ih)) { aprint_error_dev(self, "couldn't map interrupt\n"); return; } mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_AUDIO); /* XXX IPL_NONE? */ mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_AUDIO); intrstr = pci_intr_string(pc, ih, intrbuf, sizeof(intrbuf)); sc->sc_ih = pci_intr_establish(pc, ih, IPL_AUDIO, yds_intr, sc); if (sc->sc_ih == NULL) { aprint_error_dev(self, "couldn't establish interrupt"); if (intrstr != NULL) aprint_error(" at %s", intrstr); aprint_error("\n"); mutex_destroy(&sc->sc_lock); mutex_destroy(&sc->sc_intr_lock); return; } aprint_normal_dev(self, "interrupting at %s\n", intrstr); sc->sc_dmatag = pa->pa_dmat; sc->sc_pc = pc; sc->sc_pcitag = pa->pa_tag; sc->sc_id = pa->pa_id; sc->sc_revision = revision; sc->sc_flags = yds_get_dstype(sc->sc_id); #ifdef AUDIO_DEBUG if (ydsdebug) { char bits[80]; snprintb(bits, sizeof(bits), YDS_CAP_BITS, sc->sc_flags); printf("%s: chip has %s\n", device_xname(self), bits); } #endif /* Disable legacy mode */ reg = pci_conf_read(pc, pa->pa_tag, YDS_PCI_LEGACY); pci_conf_write(pc, pa->pa_tag, YDS_PCI_LEGACY, reg & YDS_PCI_LEGACY_LAD); /* Enable the device. */ reg = pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG); reg |= (PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE | PCI_COMMAND_MASTER_ENABLE); pci_conf_write(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, reg); reg = pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG); /* Mute all volumes */ for (i = 0x80; i < 0xc0; i += 2) YWRITE2(sc, i, 0); /* Initialize the device */ if (yds_init(sc)) { aprint_error_dev(self, "initialize failed\n"); mutex_destroy(&sc->sc_lock); mutex_destroy(&sc->sc_intr_lock); return; } /* * Detect primary/secondary AC97 * YMF754 Hardware Specification Rev 1.01 page 24 */ reg = pci_conf_read(pc, pa->pa_tag, YDS_PCI_DSCTRL); pci_conf_write(pc, pa->pa_tag, YDS_PCI_DSCTRL, reg & ~YDS_DSCTRL_CRST); delay(400000); /* Needed for 740C. */ /* Primary */ for (to = 0; to < AC97_TIMEOUT; to++) { if ((YREAD2(sc, AC97_STAT_ADDR1) & AC97_BUSY) == 0) break; delay(1); } if (to == AC97_TIMEOUT) { aprint_error_dev(self, "no AC97 available\n"); mutex_destroy(&sc->sc_lock); mutex_destroy(&sc->sc_intr_lock); return; } /* Secondary */ /* Secondary AC97 is used for 4ch audio. Currently unused. */ ac97_id2 = -1; if ((YREAD2(sc, YDS_ACTIVITY) & YDS_ACTIVITY_DOCKA) == 0) goto detected; #if 0 /* reset secondary... */ YWRITE2(sc, YDS_GPIO_OCTRL, YREAD2(sc, YDS_GPIO_OCTRL) & ~YDS_GPIO_GPO2); YWRITE2(sc, YDS_GPIO_FUNCE, (YREAD2(sc, YDS_GPIO_FUNCE)&(~YDS_GPIO_GPC2))|YDS_GPIO_GPE2); #endif for (to = 0; to < AC97_TIMEOUT; to++) { if ((YREAD2(sc, AC97_STAT_ADDR2) & AC97_BUSY) == 0) break; delay(1); } if (to < AC97_TIMEOUT) { /* detect id */ for (ac97_id2 = 1; ac97_id2 < 4; ac97_id2++) { YWRITE2(sc, AC97_CMD_ADDR, AC97_CMD_READ | AC97_ID(ac97_id2) | 0x28); for (to = 0; to < AC97_TIMEOUT; to++) { if ((YREAD2(sc, AC97_STAT_ADDR2) & AC97_BUSY) == 0) goto detected; delay(1); } } if (ac97_id2 == 4) ac97_id2 = -1; detected: ; } pci_conf_write(pc, pa->pa_tag, YDS_PCI_DSCTRL, reg | YDS_DSCTRL_CRST); delay (20); pci_conf_write(pc, pa->pa_tag, YDS_PCI_DSCTRL, reg & ~YDS_DSCTRL_CRST); delay (400000); for (to = 0; to < AC97_TIMEOUT; to++) { if ((YREAD2(sc, AC97_STAT_ADDR1) & AC97_BUSY) == 0) break; delay(1); } /* * Attach ac97 codec */ for (i = 0; i < 2; i++) { static struct { int data; int addr; } statregs[] = { {AC97_STAT_DATA1, AC97_STAT_ADDR1}, {AC97_STAT_DATA2, AC97_STAT_ADDR2}, }; if (i == 1 && ac97_id2 == -1) break; /* secondary ac97 not available */ codec = &sc->sc_codec[i]; codec->sc = sc; codec->id = i == 1 ? ac97_id2 : 0; codec->status_data = statregs[i].data; codec->status_addr = statregs[i].addr; codec->host_if.arg = codec; codec->host_if.attach = yds_attach_codec; codec->host_if.read = yds_read_codec; codec->host_if.write = yds_write_codec; codec->host_if.reset = yds_reset_codec; r = ac97_attach(&codec->host_if, self, &sc->sc_lock); if (r != 0) { aprint_error_dev(self, "can't attach codec (error 0x%X)\n", r); mutex_destroy(&sc->sc_lock); mutex_destroy(&sc->sc_intr_lock); return; } } if (0 != auconv_create_encodings(yds_formats, YDS_NFORMATS, &sc->sc_encodings)) { mutex_destroy(&sc->sc_lock); mutex_destroy(&sc->sc_intr_lock); return; } audio_attach_mi(&yds_hw_if, sc, self); sc->sc_legacy_iot = pa->pa_iot; config_defer(self, yds_configure_legacy); if (!pmf_device_register(self, yds_suspend, yds_resume)) aprint_error_dev(self, "couldn't establish power handler\n"); }