static void auich_attach(device_t parent, device_t self, void *aux) { struct auich_softc *sc = device_private(self); struct pci_attach_args *pa; pcireg_t v, subdev; const char *intrstr; const struct auich_devtype *d; const struct sysctlnode *node, *node_ac97clock; int err, node_mib, i; sc->sc_dev = self; pa = aux; if ((d = auich_lookup(pa, auich_modem_devices)) != NULL) { sc->sc_modem_offset = 0x10; sc->sc_codectype = AC97_CODEC_TYPE_MODEM; } else if ((d = auich_lookup(pa, auich_audio_devices)) != NULL) { sc->sc_modem_offset = 0; sc->sc_codectype = AC97_CODEC_TYPE_AUDIO; } else panic("auich_attach: impossible"); if (sc->sc_codectype == AC97_CODEC_TYPE_AUDIO) aprint_naive(": Audio controller\n"); else aprint_naive(": Modem controller\n"); sc->sc_pc = pa->pa_pc; sc->sc_pt = pa->pa_tag; aprint_normal(": %s\n", d->name); if (d->id == PCIID_ICH4 || d->id == PCIID_ICH5 || d->id == PCIID_ICH6 || d->id == PCIID_ICH7 || d->id == PCIID_I6300ESB || d->id == PCIID_ICH4MODEM) { /* * Use native mode for Intel 6300ESB and ICH4/ICH5/ICH6/ICH7 */ if (pci_mapreg_map(pa, ICH_MMBAR, PCI_MAPREG_TYPE_MEM, 0, &sc->iot, &sc->mix_ioh, NULL, &sc->mix_size)) { goto retry_map; } if (pci_mapreg_map(pa, ICH_MBBAR, PCI_MAPREG_TYPE_MEM, 0, &sc->iot, &sc->aud_ioh, NULL, &sc->aud_size)) { goto retry_map; } goto map_done; } else goto non_native_map; retry_map: sc->sc_iose = 1; v = pci_conf_read(pa->pa_pc, pa->pa_tag, ICH_CFG); pci_conf_write(pa->pa_pc, pa->pa_tag, ICH_CFG, v | ICH_CFG_IOSE); non_native_map: if (pci_mapreg_map(pa, ICH_NAMBAR, PCI_MAPREG_TYPE_IO, 0, &sc->iot, &sc->mix_ioh, NULL, &sc->mix_size)) { aprint_error_dev(self, "can't map codec i/o space\n"); return; } if (pci_mapreg_map(pa, ICH_NABMBAR, PCI_MAPREG_TYPE_IO, 0, &sc->iot, &sc->aud_ioh, NULL, &sc->aud_size)) { aprint_error_dev(self, "can't map device i/o space\n"); return; } map_done: sc->dmat = pa->pa_dmat; /* enable bus mastering */ v = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG); pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, v | PCI_COMMAND_MASTER_ENABLE | PCI_COMMAND_BACKTOBACK_ENABLE); mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_AUDIO); /* Map and establish the interrupt. */ if (pci_intr_map(pa, &sc->intrh)) { aprint_error_dev(self, "can't map interrupt\n"); return; } intrstr = pci_intr_string(pa->pa_pc, sc->intrh); sc->sc_ih = pci_intr_establish(pa->pa_pc, sc->intrh, IPL_AUDIO, auich_intr, sc); if (sc->sc_ih == NULL) { aprint_error_dev(self, "can't establish interrupt"); if (intrstr != NULL) aprint_error(" at %s", intrstr); aprint_error("\n"); return; } aprint_normal_dev(self, "interrupting at %s\n", intrstr); snprintf(sc->sc_audev.name, MAX_AUDIO_DEV_LEN, "%s AC97", d->shortname); snprintf(sc->sc_audev.version, MAX_AUDIO_DEV_LEN, "0x%02x", PCI_REVISION(pa->pa_class)); strlcpy(sc->sc_audev.config, device_xname(self), MAX_AUDIO_DEV_LEN); /* SiS 7012 needs special handling */ if (d->id == PCIID_SIS7012) { sc->sc_sts_reg = ICH_PICB; sc->sc_sample_shift = 0; sc->sc_pcm246_mask = ICH_SIS_PCM246_MASK; sc->sc_pcm2 = ICH_SIS_PCM2; sc->sc_pcm4 = ICH_SIS_PCM4; sc->sc_pcm6 = ICH_SIS_PCM6; /* Un-mute output. From Linux. */ bus_space_write_4(sc->iot, sc->aud_ioh, ICH_SIS_NV_CTL, bus_space_read_4(sc->iot, sc->aud_ioh, ICH_SIS_NV_CTL) | ICH_SIS_CTL_UNMUTE); } else { sc->sc_sts_reg = ICH_STS; sc->sc_sample_shift = 1; sc->sc_pcm246_mask = ICH_PCM246_MASK; sc->sc_pcm2 = ICH_PCM2; sc->sc_pcm4 = ICH_PCM4; sc->sc_pcm6 = ICH_PCM6; } /* Workaround for a 440MX B-stepping erratum */ sc->sc_dmamap_flags = BUS_DMA_COHERENT; if (d->id == PCIID_440MX) { sc->sc_dmamap_flags |= BUS_DMA_NOCACHE; aprint_normal_dev(self, "DMA bug workaround enabled\n"); } /* Set up DMA lists. */ sc->pcmo.qptr = sc->pcmi.qptr = sc->mici.qptr = 0; auich_alloc_cdata(sc); DPRINTF(ICH_DEBUG_DMA, ("auich_attach: lists %p %p %p\n", sc->pcmo.dmalist, sc->pcmi.dmalist, sc->mici.dmalist)); /* Modem codecs are always the secondary codec on ICH */ sc->sc_codecnum = sc->sc_codectype == AC97_CODEC_TYPE_MODEM ? 1 : 0; sc->host_if.arg = sc; sc->host_if.attach = auich_attach_codec; sc->host_if.read = auich_read_codec; sc->host_if.write = auich_write_codec; sc->host_if.reset = auich_reset_codec; sc->host_if.flags = auich_flags_codec; sc->host_if.spdif_event = auich_spdif_event; subdev = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG); switch (subdev) { case 0x202f161f: /* Gateway 7326GZ */ case 0x203a161f: /* Gateway 4028GZ */ case 0x204c161f: /* Kvazar-Micro Senator 3592XT */ case 0x8144104d: /* Sony VAIO PCG-TR* */ case 0x8197104d: /* Sony S1XP */ case 0x81c0104d: /* Sony VAIO type T */ case 0x81c5104d: /* Sony VAIO VGN-B1XP */ sc->sc_codecflags = AC97_HOST_INVERTED_EAMP; break; default: sc->sc_codecflags = 0; break; } if (ac97_attach_type(&sc->host_if, self, sc->sc_codectype, &sc->sc_lock) != 0) return; mutex_enter(&sc->sc_lock); sc->codec_if->vtbl->unlock(sc->codec_if); sc->sc_fixedrate = AC97_IS_FIXED_RATE(sc->codec_if); /* setup audio_format */ if (sc->sc_codectype == AC97_CODEC_TYPE_AUDIO) { memcpy(sc->sc_audio_formats, auich_audio_formats, sizeof(auich_audio_formats)); if (!AC97_IS_4CH(sc->codec_if)) AUFMT_INVALIDATE(&sc->sc_audio_formats[AUICH_FORMATS_4CH]); if (!AC97_IS_6CH(sc->codec_if)) AUFMT_INVALIDATE(&sc->sc_audio_formats[AUICH_FORMATS_6CH]); if (AC97_IS_FIXED_RATE(sc->codec_if)) { for (i = 0; i < AUICH_AUDIO_NFORMATS; i++) { sc->sc_audio_formats[i].frequency_type = 1; sc->sc_audio_formats[i].frequency[0] = 48000; } } mutex_exit(&sc->sc_lock); if (0 != auconv_create_encodings(sc->sc_audio_formats, AUICH_AUDIO_NFORMATS, &sc->sc_encodings)) return; if (0 != auconv_create_encodings(auich_spdif_formats, AUICH_SPDIF_NFORMATS, &sc->sc_spdif_encodings)) return; } else { mutex_exit(&sc->sc_lock); memcpy(sc->sc_modem_formats, auich_modem_formats, sizeof(auich_modem_formats)); if (0 != auconv_create_encodings(sc->sc_modem_formats, AUICH_MODEM_NFORMATS, &sc->sc_encodings)) return; } /* Watch for power change */ if (!pmf_device_register(self, NULL, auich_resume)) aprint_error_dev(self, "couldn't establish power handler\n"); config_interrupts(self, auich_finish_attach); /* sysctl setup */ if (sc->sc_fixedrate && sc->sc_codectype == AC97_CODEC_TYPE_AUDIO) return; err = sysctl_createv(&sc->sc_log, 0, NULL, NULL, 0, CTLTYPE_NODE, "hw", NULL, NULL, 0, NULL, 0, CTL_HW, CTL_EOL); if (err != 0) goto sysctl_err; err = sysctl_createv(&sc->sc_log, 0, NULL, &node, 0, CTLTYPE_NODE, device_xname(self), NULL, NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL); if (err != 0) goto sysctl_err; node_mib = node->sysctl_num; if (!sc->sc_fixedrate) { /* passing the sc address instead of &sc->sc_ac97_clock */ err = sysctl_createv(&sc->sc_log, 0, NULL, &node_ac97clock, CTLFLAG_READWRITE, CTLTYPE_INT, "ac97rate", SYSCTL_DESCR("AC'97 codec link rate"), auich_sysctl_verify, 0, (void *)sc, 0, CTL_HW, node_mib, CTL_CREATE, CTL_EOL); if (err != 0) goto sysctl_err; sc->sc_ac97_clock_mib = node_ac97clock->sysctl_num; } return; sysctl_err: printf("%s: failed to add sysctl nodes. (%d)\n", device_xname(self), err); return; /* failure of sysctl is not fatal. */ }
static void auacer_attach(struct device *parent, struct device *self, void *aux) { struct auacer_softc *sc; struct pci_attach_args *pa; pci_intr_handle_t ih; bus_size_t aud_size; pcireg_t v; const char *intrstr; int i; sc = (struct auacer_softc *)self; pa = aux; aprint_normal(": Acer Labs M5455 Audio controller\n"); if (pci_mapreg_map(pa, 0x10, PCI_MAPREG_TYPE_IO, 0, &sc->iot, &sc->aud_ioh, NULL, &aud_size)) { aprint_error(": can't map i/o space\n"); return; } sc->sc_pc = pa->pa_pc; sc->sc_pt = pa->pa_tag; sc->dmat = pa->pa_dmat; sc->sc_dmamap_flags = BUS_DMA_COHERENT; /* XXX remove */ /* enable bus mastering */ v = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG); pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, v | PCI_COMMAND_MASTER_ENABLE); /* Map and establish the interrupt. */ if (pci_intr_map(pa, &ih)) { aprint_error_dev(&sc->sc_dev, "can't map interrupt\n"); return; } intrstr = pci_intr_string(pa->pa_pc, ih); sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_AUDIO, auacer_intr, sc); if (sc->sc_ih == NULL) { aprint_error_dev(&sc->sc_dev, "can't establish interrupt"); if (intrstr != NULL) aprint_normal(" at %s", intrstr); aprint_normal("\n"); return; } aprint_normal_dev(&sc->sc_dev, "interrupting at %s\n", intrstr); strlcpy(sc->sc_audev.name, "M5455 AC97", MAX_AUDIO_DEV_LEN); snprintf(sc->sc_audev.version, MAX_AUDIO_DEV_LEN, "0x%02x", PCI_REVISION(pa->pa_class)); strlcpy(sc->sc_audev.config, device_xname(&sc->sc_dev), MAX_AUDIO_DEV_LEN); /* Set up DMA lists. */ auacer_alloc_cdata(sc); sc->sc_pcmo.dmalist = sc->sc_cdata->ic_dmalist_pcmo; sc->sc_pcmo.ptr = 0; sc->sc_pcmo.port = ALI_BASE_PO; DPRINTF(ALI_DEBUG_DMA, ("auacer_attach: lists %p\n", sc->sc_pcmo.dmalist)); sc->host_if.arg = sc; sc->host_if.attach = auacer_attach_codec; sc->host_if.read = auacer_read_codec; sc->host_if.write = auacer_write_codec; sc->host_if.reset = auacer_reset_codec; if (ac97_attach(&sc->host_if, self) != 0) return; /* setup audio_format */ memcpy(sc->sc_formats, auacer_formats, sizeof(auacer_formats)); if (!AC97_IS_4CH(sc->codec_if)) AUFMT_INVALIDATE(&sc->sc_formats[AUACER_FORMATS_4CH]); if (!AC97_IS_6CH(sc->codec_if)) AUFMT_INVALIDATE(&sc->sc_formats[AUACER_FORMATS_6CH]); if (AC97_IS_FIXED_RATE(sc->codec_if)) { for (i = 0; i < AUACER_NFORMATS; i++) { sc->sc_formats[i].frequency_type = 1; sc->sc_formats[i].frequency[0] = 48000; } } if (0 != auconv_create_encodings(sc->sc_formats, AUACER_NFORMATS, &sc->sc_encodings)) { return; } audio_attach_mi(&auacer_hw_if, sc, &sc->sc_dev); auacer_reset(sc); if (!pmf_device_register(self, NULL, auacer_resume)) aprint_error_dev(self, "couldn't establish power handler\n"); }
static void auvia_attach(device_t parent, device_t self, void *aux) { struct pci_attach_args *pa; struct auvia_softc *sc; const char *intrstr; pci_chipset_tag_t pc; pcitag_t pt; pci_intr_handle_t ih; pcireg_t pr; int r; const char *revnum; /* VT823xx revision number */ char intrbuf[PCI_INTRSTR_LEN]; pa = aux; sc = device_private(self); sc->sc_dev = self; intrstr = NULL; pc = pa->pa_pc; pt = pa->pa_tag; revnum = NULL; aprint_naive(": Audio controller\n"); sc->sc_play.sc_base = AUVIA_PLAY_BASE; sc->sc_record.sc_base = AUVIA_RECORD_BASE; if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_VIATECH_VT8233_AC97) { sc->sc_flags |= AUVIA_FLAGS_VT8233; sc->sc_play.sc_base = VIA8233_MP_BASE; sc->sc_record.sc_base = VIA8233_WR_BASE; } if (pci_mapreg_map(pa, 0x10, PCI_MAPREG_TYPE_IO, 0, &sc->sc_iot, &sc->sc_ioh, NULL, &sc->sc_iosize)) { aprint_error(": can't map i/o space\n"); return; } sc->sc_dmat = pa->pa_dmat; sc->sc_pc = pc; sc->sc_pt = pt; r = PCI_REVISION(pa->pa_class); if (sc->sc_flags & AUVIA_FLAGS_VT8233) { snprintf(sc->sc_revision, sizeof(sc->sc_revision), "0x%02X", r); switch(r) { case VIA_REV_8233PRE: /* same as 8233, but should not be in the market */ revnum = "3-Pre"; break; case VIA_REV_8233C: /* 2 rec, 4 pb, 1 multi-pb */ revnum = "3C"; break; case VIA_REV_8233: /* 2 rec, 4 pb, 1 multi-pb, spdif */ revnum = "3"; break; case VIA_REV_8233A: /* 1 rec, 1 multi-pb, spdif */ revnum = "3A"; break; default: break; } if (r >= VIA_REV_8237) revnum = "7"; else if (r >= VIA_REV_8235) /* 2 rec, 4 pb, 1 multi-pb, spdif */ revnum = "5"; aprint_normal(": VIA Technologies VT823%s AC'97 Audio " "(rev %s)\n", revnum, sc->sc_revision); } else { sc->sc_revision[1] = '\0'; if (r == 0x20) { sc->sc_revision[0] = 'H'; } else if ((r >= 0x10) && (r <= 0x14)) { sc->sc_revision[0] = 'A' + (r - 0x10); } else { snprintf(sc->sc_revision, sizeof(sc->sc_revision), "0x%02X", r); } aprint_normal(": VIA Technologies VT82C686A AC'97 Audio " "(rev %s)\n", sc->sc_revision); } if (pci_intr_map(pa, &ih)) { aprint_error(": couldn't map interrupt\n"); bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_iosize); return; } intrstr = pci_intr_string(pc, ih, intrbuf, sizeof(intrbuf)); mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_AUDIO); sc->sc_ih = pci_intr_establish(pc, ih, IPL_AUDIO, auvia_intr, sc); if (sc->sc_ih == NULL) { aprint_error_dev(sc->sc_dev, "couldn't establish interrupt"); if (intrstr != NULL) aprint_error(" at %s", intrstr); aprint_error("\n"); bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_iosize); mutex_destroy(&sc->sc_lock); mutex_destroy(&sc->sc_intr_lock); return; } aprint_normal_dev(sc->sc_dev, "interrupting at %s\n", intrstr); /* disable SBPro compat & others */ pr = pci_conf_read(pc, pt, AUVIA_PCICONF_JUNK); pr &= ~AUVIA_PCICONF_ENABLES; /* clear compat function enables */ /* XXX what to do about MIDI, FM, joystick? */ pr |= (AUVIA_PCICONF_ACLINKENAB | AUVIA_PCICONF_ACNOTRST | AUVIA_PCICONF_ACVSR | AUVIA_PCICONF_ACSGD); pr &= ~(AUVIA_PCICONF_ACFM | AUVIA_PCICONF_ACSB); pci_conf_write(pc, pt, AUVIA_PCICONF_JUNK, pr); sc->host_if.arg = sc; sc->host_if.attach = auvia_attach_codec; sc->host_if.read = auvia_read_codec; sc->host_if.write = auvia_write_codec; sc->host_if.reset = auvia_reset_codec; sc->host_if.spdif_event = auvia_spdif_event; if ((r = ac97_attach(&sc->host_if, self, &sc->sc_lock)) != 0) { aprint_error_dev(sc->sc_dev, "can't attach codec (error 0x%X)\n", r); pci_intr_disestablish(pc, sc->sc_ih); bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_iosize); mutex_destroy(&sc->sc_lock); mutex_destroy(&sc->sc_intr_lock); return; } /* setup audio_format */ memcpy(sc->sc_formats, auvia_formats, sizeof(auvia_formats)); mutex_enter(&sc->sc_lock); if (sc->sc_play.sc_base != VIA8233_MP_BASE || !AC97_IS_4CH(sc->codec_if)) { AUFMT_INVALIDATE(&sc->sc_formats[AUVIA_FORMATS_4CH_8]); AUFMT_INVALIDATE(&sc->sc_formats[AUVIA_FORMATS_4CH_16]); } if (sc->sc_play.sc_base != VIA8233_MP_BASE || !AC97_IS_6CH(sc->codec_if)) { AUFMT_INVALIDATE(&sc->sc_formats[AUVIA_FORMATS_6CH_8]); AUFMT_INVALIDATE(&sc->sc_formats[AUVIA_FORMATS_6CH_16]); } if (AC97_IS_FIXED_RATE(sc->codec_if)) { for (r = 0; r < AUVIA_NFORMATS; r++) { sc->sc_formats[r].frequency_type = 1; sc->sc_formats[r].frequency[0] = 48000; } } mutex_exit(&sc->sc_lock); if (0 != auconv_create_encodings(sc->sc_formats, AUVIA_NFORMATS, &sc->sc_encodings)) { mutex_enter(&sc->sc_lock); sc->codec_if->vtbl->detach(sc->codec_if); mutex_exit(&sc->sc_lock); pci_intr_disestablish(pc, sc->sc_ih); bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_iosize); mutex_destroy(&sc->sc_lock); mutex_destroy(&sc->sc_intr_lock); aprint_error_dev(sc->sc_dev, "can't create encodings\n"); return; } if (0 != auconv_create_encodings(auvia_spdif_formats, AUVIA_SPDIF_NFORMATS, &sc->sc_spdif_encodings)) { mutex_enter(&sc->sc_lock); sc->codec_if->vtbl->detach(sc->codec_if); mutex_exit(&sc->sc_lock); pci_intr_disestablish(pc, sc->sc_ih); bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_iosize); mutex_destroy(&sc->sc_lock); mutex_destroy(&sc->sc_intr_lock); aprint_error_dev(sc->sc_dev, "can't create spdif encodings\n"); return; } if (!pmf_device_register(self, NULL, auvia_resume)) aprint_error_dev(self, "couldn't establish power handler\n"); audio_attach_mi(&auvia_hw_if, sc, sc->sc_dev); mutex_enter(&sc->sc_lock); sc->codec_if->vtbl->unlock(sc->codec_if); mutex_exit(&sc->sc_lock); return; }