static int rtw_pci_attach(device_t dev) { struct rtw_softc *sc = device_get_softc(dev); struct rtw_regs *regs = &sc->sc_regs; int i, error; /* * No power management hooks. * XXX Maybe we should add some! */ sc->sc_flags |= RTW_F_ENABLED; sc->sc_rev = pci_get_revid(dev); #ifndef BURN_BRIDGES if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { uint32_t mem, port, irq; mem = pci_read_config(dev, RTW_PCI_MMBA, 4); port = pci_read_config(dev, RTW_PCI_IOBA, 4); irq = pci_read_config(dev, PCIR_INTLINE, 4); device_printf(dev, "chip is in D%d power mode " "-- setting to D0\n", pci_get_powerstate(dev)); pci_set_powerstate(dev, PCI_POWERSTATE_D0); pci_write_config(dev, RTW_PCI_MMBA, mem, 4); pci_write_config(dev, RTW_PCI_IOBA, port, 4); pci_write_config(dev, PCIR_INTLINE, irq, 4); } #endif /* !BURN_BRIDGES */ /* Enable PCI bus master */ pci_enable_busmaster(dev); /* Allocate IO memory/port */ for (i = 0; i < NELEM(rtw_pci_regs); ++i) { regs->r_rid = rtw_pci_regs[i].reg_rid; regs->r_type = rtw_pci_regs[i].reg_type; regs->r_res = bus_alloc_resource_any(dev, regs->r_type, ®s->r_rid, RF_ACTIVE); if (regs->r_res != NULL) break; } if (regs->r_res == NULL) { device_printf(dev, "can't allocate IO mem/port\n"); return ENXIO; } regs->r_bh = rman_get_bushandle(regs->r_res); regs->r_bt = rman_get_bustag(regs->r_res); error = rtw_attach(dev); if (error) rtw_pci_detach(dev); return error; }
static int ral_pci_attach(device_t dev) { struct ral_pci_softc *psc = device_get_softc(dev); struct rt2560_softc *sc = &psc->u.sc_rt2560; int error; if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { device_printf(dev, "chip is in D%d power mode " "-- setting to D0\n", pci_get_powerstate(dev)); pci_set_powerstate(dev, PCI_POWERSTATE_D0); } /* enable bus-mastering */ pci_enable_busmaster(dev); psc->sc_opns = (pci_get_device(dev) == 0x0201) ? &ral_rt2560_opns : &ral_rt2661_opns; psc->mem_rid = RAL_PCI_BAR0; psc->mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &psc->mem_rid, RF_ACTIVE); if (psc->mem == NULL) { device_printf(dev, "could not allocate memory resource\n"); return ENXIO; } sc->sc_st = rman_get_bustag(psc->mem); sc->sc_sh = rman_get_bushandle(psc->mem); sc->sc_invalid = 1; psc->irq_rid = 0; psc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &psc->irq_rid, RF_ACTIVE | RF_SHAREABLE); if (psc->irq == NULL) { device_printf(dev, "could not allocate interrupt resource\n"); return ENXIO; } error = (*psc->sc_opns->attach)(dev, pci_get_device(dev)); if (error != 0) return error; /* * Hook our interrupt after all initialization is complete. */ error = bus_setup_intr(dev, psc->irq, INTR_TYPE_NET | INTR_MPSAFE, NULL, psc->sc_opns->intr, psc, &psc->sc_ih); if (error != 0) { device_printf(dev, "could not set up interrupt\n"); return error; } sc->sc_invalid = 0; return 0; }
static int vga_pci_get_powerstate(device_t dev, device_t child) { device_printf(dev, "child %s requested pci_get_powerstate\n", device_get_nameunit(child)); return (pci_get_powerstate(dev)); }
static int ohci_pci_take_controller(device_t self) { uint32_t reg; uint32_t int_line; if (pci_get_powerstate(self) != PCI_POWERSTATE_D0) { device_printf(self, "chip is in D%d mode " "-- setting to D0\n", pci_get_powerstate(self)); reg = pci_read_config(self, PCI_CBMEM, 4); int_line = pci_read_config(self, PCIR_INTLINE, 4); pci_set_powerstate(self, PCI_POWERSTATE_D0); pci_write_config(self, PCI_CBMEM, reg, 4); pci_write_config(self, PCIR_INTLINE, int_line, 4); } return (0); }
pcireg_t pci_min_powerstate(pci_chipset_tag_t pc, pcitag_t tag) { #if NACPI > 0 return acpi_pci_min_powerstate(pc, tag); #else return pci_get_powerstate(pc, tag); #endif }
static int ohci_pci_resume(device_t self) { ohci_softc_t *sc = device_get_softc(self); uint32_t reg, int_line; if (pci_get_powerstate(self) != PCI_POWERSTATE_D0) { device_printf(self, "chip is in D%d mode " "-- setting to D0\n", pci_get_powerstate(self)); reg = pci_read_config(self, PCI_CBMEM, 4); int_line = pci_read_config(self, PCIR_INTLINE, 4); pci_set_powerstate(self, PCI_POWERSTATE_D0); pci_write_config(self, PCI_CBMEM, reg, 4); pci_write_config(self, PCIR_INTLINE, int_line, 4); } ohci_resume(sc); bus_generic_resume(self); return (0); }
/* * Still need this because the pci code only does power for type 0 * header devices. */ static void cbb_powerstate_d0(device_t dev) { u_int32_t membase, irq; if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { /* Save important PCI config data. */ membase = pci_read_config(dev, CBBR_SOCKBASE, 4); irq = pci_read_config(dev, PCIR_INTLINE, 4); /* Reset the power state. */ device_printf(dev, "chip is in D%d power mode " "-- setting to D0\n", pci_get_powerstate(dev)); pci_set_powerstate(dev, PCI_POWERSTATE_D0); /* Restore PCI config data. */ pci_write_config(dev, CBBR_SOCKBASE, membase, 4); pci_write_config(dev, PCIR_INTLINE, irq, 4); } }
static int ohci_pci_resume(device_t self) { ohci_softc_t *sc = device_get_softc(self); #ifndef BURN_BRIDGES uint32_t reg, int_line; if (pci_get_powerstate(self) != PCI_POWERSTATE_D0) { device_printf(self, "chip is in D%d mode " "-- setting to D0\n", pci_get_powerstate(self)); reg = pci_read_config(self, PCI_CBMEM, 4); int_line = pci_read_config(self, PCIR_INTLINE, 4); pci_set_powerstate(self, PCI_POWERSTATE_D0); pci_write_config(self, PCI_CBMEM, reg, 4); pci_write_config(self, PCIR_INTLINE, int_line, 4); } #endif /* !BURN_BRIDGES */ ohci_power(PWR_RESUME, sc); bus_generic_resume(self); return 0; }
/* * PCI power manangement */ static int acpi_pci_set_powerstate_method(device_t dev, device_t child, int state) { ACPI_HANDLE h; ACPI_STATUS status; int old_state, error; error = 0; if (state < ACPI_STATE_D0 || state > ACPI_STATE_D3) return (EINVAL); /* * We set the state using PCI Power Management outside of setting * the ACPI state. This means that when powering down a device, we * first shut it down using PCI, and then using ACPI, which lets ACPI * try to power down any Power Resources that are now no longer used. * When powering up a device, we let ACPI set the state first so that * it can enable any needed Power Resources before changing the PCI * power state. */ ACPI_SERIAL_BEGIN(pci_powerstate); old_state = pci_get_powerstate(child); if (old_state < state && pci_do_power_suspend) { error = pci_set_powerstate_method(dev, child, state); if (error) goto out; } h = acpi_get_handle(child); status = acpi_pwr_switch_consumer(h, state); if (ACPI_SUCCESS(status)) { if (bootverbose) device_printf(dev, "set ACPI power state D%d on %s\n", state, acpi_name(h)); } else if (status != AE_NOT_FOUND) device_printf(dev, "failed to set ACPI power state D%d on %s: %s\n", state, acpi_name(h), AcpiFormatException(status)); if (old_state > state && pci_do_power_resume) error = pci_set_powerstate_method(dev, child, state); out: ACPI_SERIAL_END(pci_powerstate); return (error); }
int pci_activate(pci_chipset_tag_t pc, pcitag_t tag, device_t dev, int (*wakefun)(pci_chipset_tag_t, pcitag_t, device_t, pcireg_t)) { pcireg_t pmode; int error; if ((error = pci_get_powerstate(pc, tag, &pmode))) return error; switch (pmode) { case PCI_PMCSR_STATE_D0: break; case PCI_PMCSR_STATE_D3: if (wakefun == NULL) { /* * The card has lost all configuration data in * this state, so punt. */ aprint_error_dev(dev, "unable to wake up from power state D3\n"); return EOPNOTSUPP; } /*FALLTHROUGH*/ default: if (wakefun) { error = (*wakefun)(pc, tag, dev, pmode); if (error) return error; } aprint_normal_dev(dev, "waking up from power state D%d\n", pmode); if ((error = pci_set_powerstate(pc, tag, PCI_PMCSR_STATE_D0))) return error; } return 0; }
static int cs4281_pci_attach(device_t dev) { struct sc_info *sc; struct ac97_info *codec = NULL; char status[SND_STATUSLEN]; sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO); sc->dev = dev; sc->type = pci_get_devid(dev); pci_enable_busmaster(dev); #if __FreeBSD_version > 500000 if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { /* Reset the power state. */ device_printf(dev, "chip is in D%d power mode " "-- setting to D0\n", pci_get_powerstate(dev)); pci_set_powerstate(dev, PCI_POWERSTATE_D0); } #else data = pci_read_config(dev, CS4281PCI_PMCS_OFFSET, 4); if (data & CS4281PCI_PMCS_PS_MASK) { /* Reset the power state. */ device_printf(dev, "chip is in D%d power mode " "-- setting to D0\n", data & CS4281PCI_PMCS_PS_MASK); pci_write_config(dev, CS4281PCI_PMCS_OFFSET, data & ~CS4281PCI_PMCS_PS_MASK, 4); } #endif sc->regid = PCIR_BAR(0); sc->regtype = SYS_RES_MEMORY; sc->reg = bus_alloc_resource(dev, sc->regtype, &sc->regid, 0, ~0, CS4281PCI_BA0_SIZE, RF_ACTIVE); if (!sc->reg) { sc->regtype = SYS_RES_IOPORT; sc->reg = bus_alloc_resource(dev, sc->regtype, &sc->regid, 0, ~0, CS4281PCI_BA0_SIZE, RF_ACTIVE); if (!sc->reg) { device_printf(dev, "unable to allocate register space\n"); goto bad; } } sc->st = rman_get_bustag(sc->reg); sc->sh = rman_get_bushandle(sc->reg); sc->memid = PCIR_BAR(1); sc->mem = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->memid, 0, ~0, CS4281PCI_BA1_SIZE, RF_ACTIVE); if (sc->mem == NULL) { device_printf(dev, "unable to allocate fifo space\n"); goto bad; } sc->irqid = 0; sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irqid, RF_ACTIVE | RF_SHAREABLE); if (!sc->irq) { device_printf(dev, "unable to allocate interrupt\n"); goto bad; } if (snd_setup_intr(dev, sc->irq, 0, cs4281_intr, sc, &sc->ih)) { device_printf(dev, "unable to setup interrupt\n"); goto bad; } sc->bufsz = pcm_getbuffersize(dev, 4096, CS4281_DEFAULT_BUFSZ, 65536); if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(dev), /*alignment*/2, /*boundary*/0, /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, /*highaddr*/BUS_SPACE_MAXADDR, /*filter*/NULL, /*filterarg*/NULL, /*maxsize*/sc->bufsz, /*nsegments*/1, /*maxsegz*/0x3ffff, /*flags*/0, /*lockfunc*/busdma_lock_mutex, /*lockarg*/&Giant, &sc->parent_dmat) != 0) { device_printf(dev, "unable to create dma tag\n"); goto bad; } /* power up */ cs4281_power(sc, 0); /* init chip */ if (cs4281_init(sc) == -1) { device_printf(dev, "unable to initialize the card\n"); goto bad; } /* create/init mixer */ codec = AC97_CREATE(dev, sc, cs4281_ac97); if (codec == NULL) goto bad; mixer_init(dev, ac97_getmixerclass(), codec); if (pcm_register(dev, sc, 1, 1)) goto bad; pcm_addchan(dev, PCMDIR_PLAY, &cs4281chan_class, sc); pcm_addchan(dev, PCMDIR_REC, &cs4281chan_class, sc); snprintf(status, SND_STATUSLEN, "at %s 0x%lx irq %ld %s", (sc->regtype == SYS_RES_IOPORT)? "io" : "memory", rman_get_start(sc->reg), rman_get_start(sc->irq),PCM_KLDSTRING(snd_cs4281)); pcm_setstatus(dev, status); return 0; bad: if (codec) ac97_destroy(codec); if (sc->reg) bus_release_resource(dev, sc->regtype, sc->regid, sc->reg); if (sc->mem) bus_release_resource(dev, SYS_RES_MEMORY, sc->memid, sc->mem); if (sc->ih) bus_teardown_intr(dev, sc->irq, sc->ih); if (sc->irq) bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq); if (sc->parent_dmat) bus_dma_tag_destroy(sc->parent_dmat); free(sc, M_DEVBUF); return ENXIO; }
int pci_probe_device(struct pci_softc *sc, pcitag_t tag, int (*match)(const struct pci_attach_args *), struct pci_attach_args *pap) { pci_chipset_tag_t pc = sc->sc_pc; struct pci_attach_args pa; pcireg_t id, /* csr, */ pciclass, intr, bhlcr, bar, endbar; #ifdef __HAVE_PCI_MSI_MSIX pcireg_t cap; int off; #endif int ret, pin, bus, device, function, i, width; int locs[PCICF_NLOCS]; pci_decompose_tag(pc, tag, &bus, &device, &function); /* a driver already attached? */ if (sc->PCI_SC_DEVICESC(device, function).c_dev != NULL && !match) return 0; bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG); if (PCI_HDRTYPE_TYPE(bhlcr) > 2) return 0; id = pci_conf_read(pc, tag, PCI_ID_REG); /* csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); */ pciclass = pci_conf_read(pc, tag, PCI_CLASS_REG); /* Invalid vendor ID value? */ if (PCI_VENDOR(id) == PCI_VENDOR_INVALID) return 0; /* XXX Not invalid, but we've done this ~forever. */ if (PCI_VENDOR(id) == 0) return 0; /* Collect memory range info */ memset(sc->PCI_SC_DEVICESC(device, function).c_range, 0, sizeof(sc->PCI_SC_DEVICESC(device, function).c_range)); i = 0; switch (PCI_HDRTYPE_TYPE(bhlcr)) { case PCI_HDRTYPE_PPB: endbar = PCI_MAPREG_PPB_END; break; case PCI_HDRTYPE_PCB: endbar = PCI_MAPREG_PCB_END; break; default: endbar = PCI_MAPREG_END; break; } for (bar = PCI_MAPREG_START; bar < endbar; bar += width) { struct pci_range *r; pcireg_t type; width = 4; if (pci_mapreg_probe(pc, tag, bar, &type) == 0) continue; if (PCI_MAPREG_TYPE(type) == PCI_MAPREG_TYPE_MEM) { if (PCI_MAPREG_MEM_TYPE(type) == PCI_MAPREG_MEM_TYPE_64BIT) width = 8; r = &sc->PCI_SC_DEVICESC(device, function).c_range[i++]; if (pci_mapreg_info(pc, tag, bar, type, &r->r_offset, &r->r_size, &r->r_flags) != 0) break; if ((PCI_VENDOR(id) == PCI_VENDOR_ATI) && (bar == 0x10) && (r->r_size == 0x1000000)) { struct pci_range *nr; /* * this has to be a mach64 * split things up so each half-aperture can * be mapped PREFETCHABLE except the last page * which may contain registers */ r->r_size = 0x7ff000; r->r_flags = BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE; nr = &sc->PCI_SC_DEVICESC(device, function).c_range[i++]; nr->r_offset = r->r_offset + 0x800000; nr->r_size = 0x7ff000; nr->r_flags = BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE; } } } pa.pa_iot = sc->sc_iot; pa.pa_memt = sc->sc_memt; pa.pa_dmat = sc->sc_dmat; pa.pa_dmat64 = sc->sc_dmat64; pa.pa_pc = pc; pa.pa_bus = bus; pa.pa_device = device; pa.pa_function = function; pa.pa_tag = tag; pa.pa_id = id; pa.pa_class = pciclass; /* * Set up memory, I/O enable, and PCI command flags * as appropriate. */ pa.pa_flags = sc->sc_flags; /* * If the cache line size is not configured, then * clear the MRL/MRM/MWI command-ok flags. */ if (PCI_CACHELINE(bhlcr) == 0) { pa.pa_flags &= ~(PCI_FLAGS_MRL_OKAY| PCI_FLAGS_MRM_OKAY|PCI_FLAGS_MWI_OKAY); } if (sc->sc_bridgetag == NULL) { pa.pa_intrswiz = 0; pa.pa_intrtag = tag; } else { pa.pa_intrswiz = sc->sc_intrswiz + device; pa.pa_intrtag = sc->sc_intrtag; } intr = pci_conf_read(pc, tag, PCI_INTERRUPT_REG); pin = PCI_INTERRUPT_PIN(intr); pa.pa_rawintrpin = pin; if (pin == PCI_INTERRUPT_PIN_NONE) { /* no interrupt */ pa.pa_intrpin = 0; } else { /* * swizzle it based on the number of busses we're * behind and our device number. */ pa.pa_intrpin = /* XXX */ ((pin + pa.pa_intrswiz - 1) % 4) + 1; } pa.pa_intrline = PCI_INTERRUPT_LINE(intr); #ifdef __HAVE_PCI_MSI_MSIX if (pci_get_ht_capability(pc, tag, PCI_HT_CAP_MSIMAP, &off, &cap)) { /* * XXX Should we enable MSI mapping ourselves on * systems that have it disabled? */ if (cap & PCI_HT_MSI_ENABLED) { uint64_t addr; if ((cap & PCI_HT_MSI_FIXED) == 0) { addr = pci_conf_read(pc, tag, off + PCI_HT_MSI_ADDR_LO); addr |= (uint64_t)pci_conf_read(pc, tag, off + PCI_HT_MSI_ADDR_HI) << 32; } else addr = PCI_HT_MSI_FIXED_ADDR; /* * XXX This will fail to enable MSI on systems * that don't use the canonical address. */ if (addr == PCI_HT_MSI_FIXED_ADDR) { pa.pa_flags |= PCI_FLAGS_MSI_OKAY; pa.pa_flags |= PCI_FLAGS_MSIX_OKAY; } } } #endif if (match != NULL) { ret = (*match)(&pa); if (ret != 0 && pap != NULL) *pap = pa; } else { struct pci_child *c; locs[PCICF_DEV] = device; locs[PCICF_FUNCTION] = function; c = &sc->PCI_SC_DEVICESC(device, function); pci_conf_capture(pc, tag, &c->c_conf); if (pci_get_powerstate(pc, tag, &c->c_powerstate) == 0) c->c_psok = true; else c->c_psok = false; c->c_dev = config_found_sm_loc(sc->sc_dev, "pci", locs, &pa, pciprint, config_stdsubmatch); ret = (c->c_dev != NULL); } return ret; }
int ppbactivate(struct device *self, int act) { struct ppb_softc *sc = (void *)self; pci_chipset_tag_t pc = sc->sc_pc; pcitag_t tag = sc->sc_tag; pcireg_t blr, reg; int off, rv = 0; switch (act) { case DVACT_QUIESCE: rv = config_activate_children(self, act); break; case DVACT_SUSPEND: rv = config_activate_children(self, act); /* Save registers that may get lost. */ sc->sc_csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); sc->sc_bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG); sc->sc_bir = pci_conf_read(pc, tag, PPB_REG_BUSINFO); sc->sc_bcr = pci_conf_read(pc, tag, PPB_REG_BRIDGECONTROL); sc->sc_int = pci_conf_read(pc, tag, PCI_INTERRUPT_REG); if (sc->sc_cap_off) sc->sc_slcsr = pci_conf_read(pc, tag, sc->sc_cap_off + PCI_PCIE_SLCSR); if (pci_get_capability(pc, tag, PCI_CAP_MSI, &off, ®)) { sc->sc_msi_ma = pci_conf_read(pc, tag, off + PCI_MSI_MA); if (reg & PCI_MSI_MC_C64) { sc->sc_msi_mau32 = pci_conf_read(pc, tag, off + PCI_MSI_MAU32); sc->sc_msi_md = pci_conf_read(pc, tag, off + PCI_MSI_MD64); } else { sc->sc_msi_md = pci_conf_read(pc, tag, off + PCI_MSI_MD32); } sc->sc_msi_mc = reg; } if (pci_dopm) { /* Place the bridge into D3. */ sc->sc_pmcsr_state = pci_get_powerstate(pc, tag); pci_set_powerstate(pc, tag, PCI_PMCSR_STATE_D3); } break; case DVACT_RESUME: if (pci_dopm) { /* Restore power. */ pci_set_powerstate(pc, tag, sc->sc_pmcsr_state); } /* Restore the registers saved above. */ pci_conf_write(pc, tag, PCI_BHLC_REG, sc->sc_bhlcr); pci_conf_write(pc, tag, PPB_REG_BUSINFO, sc->sc_bir); pci_conf_write(pc, tag, PPB_REG_BRIDGECONTROL, sc->sc_bcr); pci_conf_write(pc, tag, PCI_INTERRUPT_REG, sc->sc_int); if (sc->sc_cap_off) pci_conf_write(pc, tag, sc->sc_cap_off + PCI_PCIE_SLCSR, sc->sc_slcsr); /* Restore I/O window. */ blr = pci_conf_read(pc, tag, PPB_REG_IOSTATUS); blr &= 0xffff0000; blr |= sc->sc_iolimit & PPB_IO_MASK; blr |= (sc->sc_iobase >> PPB_IO_SHIFT); pci_conf_write(pc, tag, PPB_REG_IOSTATUS, blr); blr = (sc->sc_iobase & 0xffff0000) >> 16; blr |= sc->sc_iolimit & 0xffff0000; pci_conf_write(pc, tag, PPB_REG_IO_HI, blr); /* Restore memory mapped I/O window. */ blr = sc->sc_memlimit & PPB_MEM_MASK; blr |= (sc->sc_membase >> PPB_MEM_SHIFT); pci_conf_write(pc, tag, PPB_REG_MEM, blr); /* Restore prefetchable MMI/O window. */ blr = sc->sc_pmemlimit & PPB_MEM_MASK; blr |= (sc->sc_pmembase >> PPB_MEM_SHIFT); pci_conf_write(pc, tag, PPB_REG_PREFMEM, blr); #ifdef __LP64__ pci_conf_write(pc, tag, PPB_REG_PREFBASE_HI32, sc->sc_pmembase >> 32); pci_conf_write(pc, tag, PPB_REG_PREFLIM_HI32, sc->sc_pmemlimit >> 32); #endif if (pci_get_capability(pc, tag, PCI_CAP_MSI, &off, ®)) { pci_conf_write(pc, tag, off + PCI_MSI_MA, sc->sc_msi_ma); if (reg & PCI_MSI_MC_C64) { pci_conf_write(pc, tag, off + PCI_MSI_MAU32, sc->sc_msi_mau32); pci_conf_write(pc, tag, off + PCI_MSI_MD64, sc->sc_msi_md); } else { pci_conf_write(pc, tag, off + PCI_MSI_MD32, sc->sc_msi_md); } pci_conf_write(pc, tag, off + PCI_MSI_MC, sc->sc_msi_mc); } /* * Restore command register last to avoid exposing * uninitialised windows. */ reg = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, (reg & 0xffff0000) | (sc->sc_csr & 0x0000ffff)); rv = config_activate_children(self, act); break; } return (rv); }
static int cs4281_pci_attach(device_t dev) { struct sc_info *sc; struct ac97_info *codec = NULL; u_int32_t data; char status[SND_STATUSLEN]; if ((sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT)) == NULL) { device_printf(dev, "cannot allocate softc\n"); return ENXIO; } bzero(sc, sizeof(*sc)); sc->dev = dev; sc->type = pci_get_devid(dev); data = pci_read_config(dev, PCIR_COMMAND, 2); data |= (PCIM_CMD_PORTEN | PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN); pci_write_config(dev, PCIR_COMMAND, data, 2); data = pci_read_config(dev, PCIR_COMMAND, 2); #if __FreeBSD_version > 500000 if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { /* Reset the power state. */ device_printf(dev, "chip is in D%d power mode " "-- setting to D0\n", pci_get_powerstate(dev)); pci_set_powerstate(dev, PCI_POWERSTATE_D0); } #endif sc->regid = PCIR_MAPS; sc->regtype = SYS_RES_MEMORY; sc->reg = bus_alloc_resource(dev, sc->regtype, &sc->regid, 0, ~0, CS4281PCI_BA0_SIZE, RF_ACTIVE); if (!sc->reg) { sc->regtype = SYS_RES_IOPORT; sc->reg = bus_alloc_resource(dev, sc->regtype, &sc->regid, 0, ~0, CS4281PCI_BA0_SIZE, RF_ACTIVE); if (!sc->reg) { device_printf(dev, "unable to allocate register space\n"); goto bad; } } sc->st = rman_get_bustag(sc->reg); sc->sh = rman_get_bushandle(sc->reg); sc->memid = PCIR_MAPS + 4; sc->mem = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->memid, 0, ~0, CS4281PCI_BA1_SIZE, RF_ACTIVE); if (sc->mem == NULL) { device_printf(dev, "unable to allocate fifo space\n"); goto bad; } sc->irqid = 0; sc->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->irqid, 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE); if (!sc->irq) { device_printf(dev, "unable to allocate interrupt\n"); goto bad; } if (bus_setup_intr(dev, sc->irq, INTR_TYPE_TTY, cs4281_intr, sc, &sc->ih)) { device_printf(dev, "unable to setup interrupt\n"); goto bad; } if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0, /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, /*highaddr*/BUS_SPACE_MAXADDR, /*filter*/NULL, /*filterarg*/NULL, /*maxsize*/CS4281_BUFFER_SIZE, /*nsegments*/1, /*maxsegz*/0x3ffff, /*flags*/0, &sc->parent_dmat) != 0) { device_printf(dev, "unable to create dma tag\n"); goto bad; } /* power up */ cs4281_power(sc, 0); /* init chip */ if (cs4281_init(sc) == -1) { device_printf(dev, "unable to initialize the card\n"); goto bad; } /* create/init mixer */ codec = AC97_CREATE(dev, sc, cs4281_ac97); if (codec == NULL) goto bad; mixer_init(dev, ac97_getmixerclass(), codec); if (pcm_register(dev, sc, 1, 1)) goto bad; pcm_addchan(dev, PCMDIR_PLAY, &cs4281chan_class, sc); pcm_addchan(dev, PCMDIR_REC, &cs4281chan_class, sc); snprintf(status, SND_STATUSLEN, "at %s 0x%lx irq %ld", (sc->regtype == SYS_RES_IOPORT)? "io" : "memory", rman_get_start(sc->reg), rman_get_start(sc->irq)); pcm_setstatus(dev, status); return 0; bad: if (codec) ac97_destroy(codec); if (sc->reg) bus_release_resource(dev, sc->regtype, sc->regid, sc->reg); if (sc->mem) bus_release_resource(dev, SYS_RES_MEMORY, sc->memid, sc->mem); if (sc->ih) bus_teardown_intr(dev, sc->irq, sc->ih); if (sc->irq) bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq); if (sc->parent_dmat) bus_dma_tag_destroy(sc->parent_dmat); free(sc, M_DEVBUF); return ENXIO; }