📄 main.c
字号:
static void pio_irq_workaround(struct b43_wldev *dev, u16 base, int queueidx){ u16 rxctl; rxctl = b43_read16(dev, base + B43_PIO_RXCTL); if (rxctl & B43_PIO_RXCTL_DATAAVAILABLE) dev->dma_reason[queueidx] |= B43_DMAIRQ_RX_DONE; else dev->dma_reason[queueidx] &= ~B43_DMAIRQ_RX_DONE;}static void b43_interrupt_ack(struct b43_wldev *dev, u32 reason){ if (b43_using_pio(dev) && (dev->dev->id.revision < 3) && (!(reason & B43_IRQ_PIO_WORKAROUND))) { /* Apply a PIO specific workaround to the dma_reasons */ pio_irq_workaround(dev, B43_MMIO_PIO1_BASE, 0); pio_irq_workaround(dev, B43_MMIO_PIO2_BASE, 1); pio_irq_workaround(dev, B43_MMIO_PIO3_BASE, 2); pio_irq_workaround(dev, B43_MMIO_PIO4_BASE, 3); } b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, reason); b43_write32(dev, B43_MMIO_DMA0_REASON, dev->dma_reason[0]); b43_write32(dev, B43_MMIO_DMA1_REASON, dev->dma_reason[1]); b43_write32(dev, B43_MMIO_DMA2_REASON, dev->dma_reason[2]); b43_write32(dev, B43_MMIO_DMA3_REASON, dev->dma_reason[3]); b43_write32(dev, B43_MMIO_DMA4_REASON, dev->dma_reason[4]); b43_write32(dev, B43_MMIO_DMA5_REASON, dev->dma_reason[5]);}/* Interrupt handler top-half */static irqreturn_t b43_interrupt_handler(int irq, void *dev_id){ irqreturn_t ret = IRQ_NONE; struct b43_wldev *dev = dev_id; u32 reason; if (!dev) return IRQ_NONE; spin_lock(&dev->wl->irq_lock); if (b43_status(dev) < B43_STAT_STARTED) goto out; reason = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON); if (reason == 0xffffffff) /* shared IRQ */ goto out; ret = IRQ_HANDLED; reason &= b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); if (!reason) goto out; dev->dma_reason[0] = b43_read32(dev, B43_MMIO_DMA0_REASON) & 0x0001DC00; dev->dma_reason[1] = b43_read32(dev, B43_MMIO_DMA1_REASON) & 0x0000DC00; dev->dma_reason[2] = b43_read32(dev, B43_MMIO_DMA2_REASON) & 0x0000DC00; dev->dma_reason[3] = b43_read32(dev, B43_MMIO_DMA3_REASON) & 0x0001DC00; dev->dma_reason[4] = b43_read32(dev, B43_MMIO_DMA4_REASON) & 0x0000DC00; dev->dma_reason[5] = b43_read32(dev, B43_MMIO_DMA5_REASON) & 0x0000DC00; b43_interrupt_ack(dev, reason); /* disable all IRQs. They are enabled again in the bottom half. */ dev->irq_savedstate = b43_interrupt_disable(dev, B43_IRQ_ALL); /* save the reason code and call our bottom half. */ dev->irq_reason = reason; tasklet_schedule(&dev->isr_tasklet); out: mmiowb(); spin_unlock(&dev->wl->irq_lock); return ret;}static void b43_release_firmware(struct b43_wldev *dev){ release_firmware(dev->fw.ucode); dev->fw.ucode = NULL; release_firmware(dev->fw.pcm); dev->fw.pcm = NULL; release_firmware(dev->fw.initvals); dev->fw.initvals = NULL; release_firmware(dev->fw.initvals_band); dev->fw.initvals_band = NULL;}static void b43_print_fw_helptext(struct b43_wl *wl){ b43err(wl, "You must go to " "http://linuxwireless.org/en/users/Drivers/b43#devicefirmware " "and download the correct firmware (version 4).\n");}static int do_request_fw(struct b43_wldev *dev, const char *name, const struct firmware **fw){ char path[sizeof(modparam_fwpostfix) + 32]; struct b43_fw_header *hdr; u32 size; int err; if (!name) return 0; snprintf(path, ARRAY_SIZE(path), "b43%s/%s.fw", modparam_fwpostfix, name); err = request_firmware(fw, path, dev->dev->dev); if (err) { b43err(dev->wl, "Firmware file \"%s\" not found " "or load failed.\n", path); return err; } if ((*fw)->size < sizeof(struct b43_fw_header)) goto err_format; hdr = (struct b43_fw_header *)((*fw)->data); switch (hdr->type) { case B43_FW_TYPE_UCODE: case B43_FW_TYPE_PCM: size = be32_to_cpu(hdr->size); if (size != (*fw)->size - sizeof(struct b43_fw_header)) goto err_format; /* fallthrough */ case B43_FW_TYPE_IV: if (hdr->ver != 1) goto err_format; break; default: goto err_format; } return err;err_format: b43err(dev->wl, "Firmware file \"%s\" format error.\n", path); return -EPROTO;}static int b43_request_firmware(struct b43_wldev *dev){ struct b43_firmware *fw = &dev->fw; const u8 rev = dev->dev->id.revision; const char *filename; u32 tmshigh; int err; tmshigh = ssb_read32(dev->dev, SSB_TMSHIGH); if (!fw->ucode) { if ((rev >= 5) && (rev <= 10)) filename = "ucode5"; else if ((rev >= 11) && (rev <= 12)) filename = "ucode11"; else if (rev >= 13) filename = "ucode13"; else goto err_no_ucode; err = do_request_fw(dev, filename, &fw->ucode); if (err) goto err_load; } if (!fw->pcm) { if ((rev >= 5) && (rev <= 10)) filename = "pcm5"; else if (rev >= 11) filename = NULL; else goto err_no_pcm; err = do_request_fw(dev, filename, &fw->pcm); if (err) goto err_load; } if (!fw->initvals) { switch (dev->phy.type) { case B43_PHYTYPE_A: if ((rev >= 5) && (rev <= 10)) { if (tmshigh & B43_TMSHIGH_GPHY) filename = "a0g1initvals5"; else filename = "a0g0initvals5"; } else goto err_no_initvals; break; case B43_PHYTYPE_G: if ((rev >= 5) && (rev <= 10)) filename = "b0g0initvals5"; else if (rev >= 13) filename = "lp0initvals13"; else goto err_no_initvals; break; default: goto err_no_initvals; } err = do_request_fw(dev, filename, &fw->initvals); if (err) goto err_load; } if (!fw->initvals_band) { switch (dev->phy.type) { case B43_PHYTYPE_A: if ((rev >= 5) && (rev <= 10)) { if (tmshigh & B43_TMSHIGH_GPHY) filename = "a0g1bsinitvals5"; else filename = "a0g0bsinitvals5"; } else if (rev >= 11) filename = NULL; else goto err_no_initvals; break; case B43_PHYTYPE_G: if ((rev >= 5) && (rev <= 10)) filename = "b0g0bsinitvals5"; else if (rev >= 11) filename = NULL; else goto err_no_initvals; break; default: goto err_no_initvals; } err = do_request_fw(dev, filename, &fw->initvals_band); if (err) goto err_load; } return 0;err_load: b43_print_fw_helptext(dev->wl); goto error;err_no_ucode: err = -ENODEV; b43err(dev->wl, "No microcode available for core rev %u\n", rev); goto error;err_no_pcm: err = -ENODEV; b43err(dev->wl, "No PCM available for core rev %u\n", rev); goto error;err_no_initvals: err = -ENODEV; b43err(dev->wl, "No Initial Values firmware file for PHY %u, " "core rev %u\n", dev->phy.type, rev); goto error;error: b43_release_firmware(dev); return err;}static int b43_upload_microcode(struct b43_wldev *dev){ const size_t hdr_len = sizeof(struct b43_fw_header); const __be32 *data; unsigned int i, len; u16 fwrev, fwpatch, fwdate, fwtime; u32 tmp; int err = 0; /* Upload Microcode. */ data = (__be32 *) (dev->fw.ucode->data + hdr_len); len = (dev->fw.ucode->size - hdr_len) / sizeof(__be32); b43_shm_control_word(dev, B43_SHM_UCODE | B43_SHM_AUTOINC_W, 0x0000); for (i = 0; i < len; i++) { b43_write32(dev, B43_MMIO_SHM_DATA, be32_to_cpu(data[i])); udelay(10); } if (dev->fw.pcm) { /* Upload PCM data. */ data = (__be32 *) (dev->fw.pcm->data + hdr_len); len = (dev->fw.pcm->size - hdr_len) / sizeof(__be32); b43_shm_control_word(dev, B43_SHM_HW, 0x01EA); b43_write32(dev, B43_MMIO_SHM_DATA, 0x00004000); /* No need for autoinc bit in SHM_HW */ b43_shm_control_word(dev, B43_SHM_HW, 0x01EB); for (i = 0; i < len; i++) { b43_write32(dev, B43_MMIO_SHM_DATA, be32_to_cpu(data[i])); udelay(10); } } b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, B43_IRQ_ALL); b43_write32(dev, B43_MMIO_MACCTL, B43_MACCTL_PSM_RUN | B43_MACCTL_IHR_ENABLED | B43_MACCTL_INFRA); /* Wait for the microcode to load and respond */ i = 0; while (1) { tmp = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON); if (tmp == B43_IRQ_MAC_SUSPENDED) break; i++; if (i >= 50) { b43err(dev->wl, "Microcode not responding\n"); b43_print_fw_helptext(dev->wl); err = -ENODEV; goto out; } udelay(10); } b43_read32(dev, B43_MMIO_GEN_IRQ_REASON); /* dummy read */ /* Get and check the revisions. */ fwrev = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_UCODEREV); fwpatch = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_UCODEPATCH); fwdate = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_UCODEDATE); fwtime = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_UCODETIME); if (fwrev <= 0x128) { b43err(dev->wl, "YOUR FIRMWARE IS TOO OLD. Firmware from " "binary drivers older than version 4.x is unsupported. " "You must upgrade your firmware files.\n"); b43_print_fw_helptext(dev->wl); b43_write32(dev, B43_MMIO_MACCTL, 0); err = -EOPNOTSUPP; goto out; } if (fwrev > 351) { b43err(dev->wl, "YOUR FIRMWARE IS TOO NEW. Please downgrade your " "firmware.\n"); b43err(dev->wl, "Use this firmware tarball: " "http://downloads.openwrt.org/sources/broadcom-wl-4.80.53.0.tar.bz2\n"); b43err(dev->wl, "Use this b43-fwcutter tarball: " "http://bu3sch.de/b43/fwcutter/b43-fwcutter-009.tar.bz2\n"); b43err(dev->wl, "Read, understand and _do_ what this message says, please.\n"); b43_write32(dev, B43_MMIO_MACCTL, 0); err = -EOPNOTSUPP; goto out; } b43dbg(dev->wl, "Loading firmware version %u.%u " "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n", fwrev, fwpatch, (fwdate >> 12) & 0xF, (fwdate >> 8) & 0xF, fwdate & 0xFF, (fwtime >> 11) & 0x1F, (fwtime >> 5) & 0x3F, fwtime & 0x1F); dev->fw.rev = fwrev; dev->fw.patch = fwpatch; out: return err;}static int b43_write_initvals(struct b43_wldev *dev, const struct b43_iv *ivals, size_t count, size_t array_size){ const struct b43_iv *iv; u16 offset; size_t i; bool bit32; BUILD_BUG_ON(sizeof(struct b43_iv) != 6); iv = ivals; for (i = 0; i < count; i++) { if (array_size < sizeof(iv->offset_size)) goto err_format; array_size -= sizeof(iv->offset_size); offset = be16_to_cpu(iv->offset_size); bit32 = !!(offset & B43_IV_32BIT); offset &= B43_IV_OFFSET_MASK; if (offset >= 0x1000) goto err_format; if (bit32) { u32 value; if (array_size < sizeof(iv->data.d32)) goto err_format; array_size -= sizeof(iv->data.d32); value = be32_to_cpu(get_unaligned(&iv->data.d32)); b43_write32(dev, offset, value); iv = (const struct b43_iv *)((const uint8_t *)iv + sizeof(__be16) + sizeof(__be32)); } else { u16 value; if (array_size < sizeof(iv->data.d16)) goto err_format; array_size -= sizeof(iv->data.d16); value = be16_to_cpu(iv->data.d16); b43_write16(dev, offset, value); iv = (const struct b43_iv *)((const uint8_t *)iv + sizeof(__be16) + sizeof(__be16)); } } if (array_size) goto err_format; return 0;err_format: b43err(dev->wl, "Initial Values Firmware file-format error.\n"); b43_print_fw_helptext(dev->wl); return -EPROTO;}static int b43_upload_initvals(struct b43_wldev *dev){ const size_t hdr_len = sizeof(struct b43_fw_header); const struct b43_fw_header *hdr; struct b43_firmware *fw = &dev->fw; const struct b43_iv *ivals; size_t count; int err; hdr = (const struct b43_fw_header *)(fw->initvals->data); ivals = (const struct b43_iv *)(fw->initvals->data + hdr_len); count = be32_to_cpu(hdr->size); err = b43_write_initvals(dev, ivals, count, fw->initvals->size - hdr_len); if (err) goto out; if (fw->initvals_band) { hdr = (const struct b43_fw_header *)(fw->initvals_band->data); ivals = (const struct b43_iv *)(fw->initvals_band->data + hdr_len); count = be32_to_cpu(hdr->size); err = b43_write_initvals(dev, ivals, count, fw->initvals_band->size - hdr_len); if (err) goto out; }out: return err;}/* Initialize the GPIOs * http://bcm-specs.sipsolutions.net/GPIO */static int b43_gpio_init(struct b43_wldev *dev){ struct ssb_bus *bus = dev->dev->bus; struct ssb_device *gpiodev, *pcidev = NULL; u32 mask, set; b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL) & ~B43_MACCTL_GPOUTSMSK); b43_write16(dev, B43_MMIO_GPIO_MASK, b43_read16(dev, B43_MMIO_GPIO_MASK) | 0x000F); mask = 0x0000001F; set = 0x0000000F; if (dev->dev->bus->chip_id == 0x4301) { mask |= 0x0060; set |= 0x0060; } if (0 /* FIXME: conditional unknown */ ) { b43_write16(dev, B43_MMIO_GPIO_MASK, b43_read16(dev, B43_MMIO_GPIO_MASK) | 0x0100); mask |= 0x0180; set |= 0x0180; } if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_PACTRL) { b43_write16(dev, B43_MMIO_GPIO_MASK, b43_read16(dev, B43_MMIO_GPIO_MASK) | 0x0200); mask |= 0x0200; set |= 0x0200; } if (dev->dev->id.revision >= 2) mask |= 0x0010; /* FIXME: This is redundant. */#ifdef CONFIG_SSB_DRIVER_PCICORE pcidev = bus->pcicore.dev;#endif gpiodev = bus->chipco.dev ? : pcidev; if (!gpiodev) return 0; ssb_write32(gpiodev, B43_GPIO_CONTROL,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -