📄 main.c
字号:
u32 i; u32 tmp; struct b43legacy_plcp_hdr4 plcp; plcp.data = 0; b43legacy_generate_plcp_hdr(&plcp, size + FCS_LEN, rate); b43legacy_ram_write(dev, ram_offset, le32_to_cpu(plcp.data)); ram_offset += sizeof(u32); /* The PLCP is 6 bytes long, but we only wrote 4 bytes, yet. * So leave the first two bytes of the next write blank. */ tmp = (u32)(data[0]) << 16; tmp |= (u32)(data[1]) << 24; b43legacy_ram_write(dev, ram_offset, tmp); ram_offset += sizeof(u32); for (i = 2; i < size; i += sizeof(u32)) { tmp = (u32)(data[i + 0]); if (i + 1 < size) tmp |= (u32)(data[i + 1]) << 8; if (i + 2 < size) tmp |= (u32)(data[i + 2]) << 16; if (i + 3 < size) tmp |= (u32)(data[i + 3]) << 24; b43legacy_ram_write(dev, ram_offset + i - 2, tmp); } b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, shm_size_offset, size + sizeof(struct b43legacy_plcp_hdr6));}static void b43legacy_write_beacon_template(struct b43legacy_wldev *dev, u16 ram_offset, u16 shm_size_offset, u8 rate){ int len; const u8 *data; B43legacy_WARN_ON(!dev->cached_beacon); len = min((size_t)dev->cached_beacon->len, 0x200 - sizeof(struct b43legacy_plcp_hdr6)); data = (const u8 *)(dev->cached_beacon->data); b43legacy_write_template_common(dev, data, len, ram_offset, shm_size_offset, rate);}static void b43legacy_write_probe_resp_plcp(struct b43legacy_wldev *dev, u16 shm_offset, u16 size, u8 rate){ struct b43legacy_plcp_hdr4 plcp; u32 tmp; __le16 dur; plcp.data = 0; b43legacy_generate_plcp_hdr(&plcp, size + FCS_LEN, rate); dur = ieee80211_generic_frame_duration(dev->wl->hw, dev->wl->if_id, size, B43legacy_RATE_TO_100KBPS(rate)); /* Write PLCP in two parts and timing for packet transfer */ tmp = le32_to_cpu(plcp.data); b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, shm_offset, tmp & 0xFFFF); b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, shm_offset + 2, tmp >> 16); b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, shm_offset + 6, le16_to_cpu(dur));}/* Instead of using custom probe response template, this function * just patches custom beacon template by: * 1) Changing packet type * 2) Patching duration field * 3) Stripping TIM */static u8 *b43legacy_generate_probe_resp(struct b43legacy_wldev *dev, u16 *dest_size, u8 rate){ const u8 *src_data; u8 *dest_data; u16 src_size; u16 elem_size; u16 src_pos; u16 dest_pos; __le16 dur; struct ieee80211_hdr *hdr; B43legacy_WARN_ON(!dev->cached_beacon); src_size = dev->cached_beacon->len; src_data = (const u8 *)dev->cached_beacon->data; if (unlikely(src_size < 0x24)) { b43legacydbg(dev->wl, "b43legacy_generate_probe_resp: " "invalid beacon\n"); return NULL; } dest_data = kmalloc(src_size, GFP_ATOMIC); if (unlikely(!dest_data)) return NULL; /* 0x24 is offset of first variable-len Information-Element * in beacon frame. */ memcpy(dest_data, src_data, 0x24); src_pos = 0x24; dest_pos = 0x24; for (; src_pos < src_size - 2; src_pos += elem_size) { elem_size = src_data[src_pos + 1] + 2; if (src_data[src_pos] != 0x05) { /* TIM */ memcpy(dest_data + dest_pos, src_data + src_pos, elem_size); dest_pos += elem_size; } } *dest_size = dest_pos; hdr = (struct ieee80211_hdr *)dest_data; /* Set the frame control. */ hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_RESP); dur = ieee80211_generic_frame_duration(dev->wl->hw, dev->wl->if_id, *dest_size, B43legacy_RATE_TO_100KBPS(rate)); hdr->duration_id = dur; return dest_data;}static void b43legacy_write_probe_resp_template(struct b43legacy_wldev *dev, u16 ram_offset, u16 shm_size_offset, u8 rate){ u8 *probe_resp_data; u16 size; B43legacy_WARN_ON(!dev->cached_beacon); size = dev->cached_beacon->len; probe_resp_data = b43legacy_generate_probe_resp(dev, &size, rate); if (unlikely(!probe_resp_data)) return; /* Looks like PLCP headers plus packet timings are stored for * all possible basic rates */ b43legacy_write_probe_resp_plcp(dev, 0x31A, size, B43legacy_CCK_RATE_1MB); b43legacy_write_probe_resp_plcp(dev, 0x32C, size, B43legacy_CCK_RATE_2MB); b43legacy_write_probe_resp_plcp(dev, 0x33E, size, B43legacy_CCK_RATE_5MB); b43legacy_write_probe_resp_plcp(dev, 0x350, size, B43legacy_CCK_RATE_11MB); size = min((size_t)size, 0x200 - sizeof(struct b43legacy_plcp_hdr6)); b43legacy_write_template_common(dev, probe_resp_data, size, ram_offset, shm_size_offset, rate); kfree(probe_resp_data);}static int b43legacy_refresh_cached_beacon(struct b43legacy_wldev *dev, struct sk_buff *beacon){ if (dev->cached_beacon) kfree_skb(dev->cached_beacon); dev->cached_beacon = beacon; return 0;}static void b43legacy_update_templates(struct b43legacy_wldev *dev){ u32 status; B43legacy_WARN_ON(!dev->cached_beacon); b43legacy_write_beacon_template(dev, 0x68, 0x18, B43legacy_CCK_RATE_1MB); b43legacy_write_beacon_template(dev, 0x468, 0x1A, B43legacy_CCK_RATE_1MB); b43legacy_write_probe_resp_template(dev, 0x268, 0x4A, B43legacy_CCK_RATE_11MB); status = b43legacy_read32(dev, B43legacy_MMIO_STATUS2_BITFIELD); status |= 0x03; b43legacy_write32(dev, B43legacy_MMIO_STATUS2_BITFIELD, status);}static void b43legacy_refresh_templates(struct b43legacy_wldev *dev, struct sk_buff *beacon){ int err; err = b43legacy_refresh_cached_beacon(dev, beacon); if (unlikely(err)) return; b43legacy_update_templates(dev);}static void b43legacy_set_ssid(struct b43legacy_wldev *dev, const u8 *ssid, u8 ssid_len){ u32 tmp; u16 i; u16 len; len = min((u16)ssid_len, (u16)0x100); for (i = 0; i < len; i += sizeof(u32)) { tmp = (u32)(ssid[i + 0]); if (i + 1 < len) tmp |= (u32)(ssid[i + 1]) << 8; if (i + 2 < len) tmp |= (u32)(ssid[i + 2]) << 16; if (i + 3 < len) tmp |= (u32)(ssid[i + 3]) << 24; b43legacy_shm_write32(dev, B43legacy_SHM_SHARED, 0x380 + i, tmp); } b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x48, len);}static void b43legacy_set_beacon_int(struct b43legacy_wldev *dev, u16 beacon_int){ b43legacy_time_lock(dev); if (dev->dev->id.revision >= 3) b43legacy_write32(dev, 0x188, (beacon_int << 16)); else { b43legacy_write16(dev, 0x606, (beacon_int >> 6)); b43legacy_write16(dev, 0x610, beacon_int); } b43legacy_time_unlock(dev);}static void handle_irq_beacon(struct b43legacy_wldev *dev){ u32 status; if (!b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) return; dev->irq_savedstate &= ~B43legacy_IRQ_BEACON; status = b43legacy_read32(dev, B43legacy_MMIO_STATUS2_BITFIELD); if (!dev->cached_beacon || ((status & 0x1) && (status & 0x2))) { /* ACK beacon IRQ. */ b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_REASON, B43legacy_IRQ_BEACON); dev->irq_savedstate |= B43legacy_IRQ_BEACON; if (dev->cached_beacon) kfree_skb(dev->cached_beacon); dev->cached_beacon = NULL; return; } if (!(status & 0x1)) { b43legacy_write_beacon_template(dev, 0x68, 0x18, B43legacy_CCK_RATE_1MB); status |= 0x1; b43legacy_write32(dev, B43legacy_MMIO_STATUS2_BITFIELD, status); } if (!(status & 0x2)) { b43legacy_write_beacon_template(dev, 0x468, 0x1A, B43legacy_CCK_RATE_1MB); status |= 0x2; b43legacy_write32(dev, B43legacy_MMIO_STATUS2_BITFIELD, status); }}static void handle_irq_ucode_debug(struct b43legacy_wldev *dev){}/* Interrupt handler bottom-half */static void b43legacy_interrupt_tasklet(struct b43legacy_wldev *dev){ u32 reason; u32 dma_reason[ARRAY_SIZE(dev->dma_reason)]; u32 merged_dma_reason = 0; int i; int activity = 0; unsigned long flags; spin_lock_irqsave(&dev->wl->irq_lock, flags); B43legacy_WARN_ON(b43legacy_status(dev) < B43legacy_STAT_INITIALIZED); reason = dev->irq_reason; for (i = 0; i < ARRAY_SIZE(dma_reason); i++) { dma_reason[i] = dev->dma_reason[i]; merged_dma_reason |= dma_reason[i]; } if (unlikely(reason & B43legacy_IRQ_MAC_TXERR)) b43legacyerr(dev->wl, "MAC transmission error\n"); if (unlikely(reason & B43legacy_IRQ_PHY_TXERR)) b43legacyerr(dev->wl, "PHY transmission error\n"); if (unlikely(merged_dma_reason & (B43legacy_DMAIRQ_FATALMASK | B43legacy_DMAIRQ_NONFATALMASK))) { if (merged_dma_reason & B43legacy_DMAIRQ_FATALMASK) { b43legacyerr(dev->wl, "Fatal DMA error: " "0x%08X, 0x%08X, 0x%08X, " "0x%08X, 0x%08X, 0x%08X\n", dma_reason[0], dma_reason[1], dma_reason[2], dma_reason[3], dma_reason[4], dma_reason[5]); b43legacy_controller_restart(dev, "DMA error"); mmiowb(); spin_unlock_irqrestore(&dev->wl->irq_lock, flags); return; } if (merged_dma_reason & B43legacy_DMAIRQ_NONFATALMASK) b43legacyerr(dev->wl, "DMA error: " "0x%08X, 0x%08X, 0x%08X, " "0x%08X, 0x%08X, 0x%08X\n", dma_reason[0], dma_reason[1], dma_reason[2], dma_reason[3], dma_reason[4], dma_reason[5]); } if (unlikely(reason & B43legacy_IRQ_UCODE_DEBUG)) handle_irq_ucode_debug(dev); if (reason & B43legacy_IRQ_TBTT_INDI) handle_irq_tbtt_indication(dev); if (reason & B43legacy_IRQ_ATIM_END) handle_irq_atim_end(dev); if (reason & B43legacy_IRQ_BEACON) handle_irq_beacon(dev); if (reason & B43legacy_IRQ_PMQ) handle_irq_pmq(dev); if (reason & B43legacy_IRQ_TXFIFO_FLUSH_OK) ;/*TODO*/ if (reason & B43legacy_IRQ_NOISESAMPLE_OK) handle_irq_noise(dev); /* Check the DMA reason registers for received data. */ if (dma_reason[0] & B43legacy_DMAIRQ_RX_DONE) { if (b43legacy_using_pio(dev)) b43legacy_pio_rx(dev->pio.queue0); else b43legacy_dma_rx(dev->dma.rx_ring0); /* We intentionally don't set "activity" to 1, here. */ } B43legacy_WARN_ON(dma_reason[1] & B43legacy_DMAIRQ_RX_DONE); B43legacy_WARN_ON(dma_reason[2] & B43legacy_DMAIRQ_RX_DONE); if (dma_reason[3] & B43legacy_DMAIRQ_RX_DONE) { if (b43legacy_using_pio(dev)) b43legacy_pio_rx(dev->pio.queue3); else b43legacy_dma_rx(dev->dma.rx_ring3); activity = 1; } B43legacy_WARN_ON(dma_reason[4] & B43legacy_DMAIRQ_RX_DONE); B43legacy_WARN_ON(dma_reason[5] & B43legacy_DMAIRQ_RX_DONE); if (reason & B43legacy_IRQ_TX_OK) { handle_irq_transmit_status(dev); activity = 1; /* TODO: In AP mode, this also causes sending of powersave responses. */ } if (!modparam_noleds) b43legacy_leds_update(dev, activity); b43legacy_interrupt_enable(dev, dev->irq_savedstate); mmiowb(); spin_unlock_irqrestore(&dev->wl->irq_lock, flags);}static void pio_irq_workaround(struct b43legacy_wldev *dev, u16 base, int queueidx){ u16 rxctl; rxctl = b43legacy_read16(dev, base + B43legacy_PIO_RXCTL); if (rxctl & B43legacy_PIO_RXCTL_DATAAVAILABLE) dev->dma_reason[queueidx] |= B43legacy_DMAIRQ_RX_DONE; else dev->dma_reason[queueidx] &= ~B43legacy_DMAIRQ_RX_DONE;}static void b43legacy_interrupt_ack(struct b43legacy_wldev *dev, u32 reason){ if (b43legacy_using_pio(dev) && (dev->dev->id.revision < 3) && (!(reason & B43legacy_IRQ_PIO_WORKAROUND))) { /* Apply a PIO specific workaround to the dma_reasons */ pio_irq_workaround(dev, B43legacy_MMIO_PIO1_BASE, 0); pio_irq_workaround(dev, B43legacy_MMIO_PIO2_BASE, 1); pio_irq_workaround(dev, B43legacy_MMIO_PIO3_BASE, 2); pio_irq_workaround(dev, B43legacy_MMIO_PIO4_BASE, 3); } b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_REASON, reason); b43legacy_write32(dev, B43legacy_MMIO_DMA0_REASON, dev->dma_reason[0]); b43legacy_write32(dev, B43legacy_MMIO_DMA1_REASON, dev->dma_reason[1]); b43legacy_write32(dev, B43legacy_MMIO_DMA2_REASON, dev->dma_reason[2]); b43legacy_write32(dev, B43legacy_MMIO_DMA3_REASON, dev->dma_reason[3]); b43legacy_write32(dev, B43legacy_MMIO_DMA4_REASON, dev->dma_reason[4]); b43legacy_write32(dev, B43legacy_MMIO_DMA5_REASON, dev->dma_reason[5]);}/* Interrupt handler top-half */static irqreturn_t b43legacy_interrupt_handler(int irq, void *dev_id){ irqreturn_t ret = IRQ_NONE; struct b43legacy_wldev *dev = dev_id; u32 reason; if (!dev) return IRQ_NONE; spin_lock(&dev->wl->irq_lock); if (b43legacy_status(dev) < B43legacy_STAT_STARTED) goto out; reason = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON); if (reason == 0xffffffff) /* shared IRQ */ goto out; ret = IRQ_HANDLED; reason &= b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK); if (!reason) goto out; dev->dma_reason[0] = b43legacy_read32(dev, B43legacy_MMIO_DMA0_REASON) & 0x0001DC00; dev->dma_reason[1] = b43legacy_read32(dev, B43legacy_MMIO_DMA1_REASON) & 0x0000DC00; dev->dma_reason[2] = b43legacy_read32(dev, B43legacy_MMIO_DMA2_REASON) & 0x0000DC00; dev->dma_reason[3] = b43legacy_read32(dev, B43legacy_MMIO_DMA3_REASON) & 0x0001DC00; dev->dma_reason[4] = b43legacy_read32(dev, B43legacy_MMIO_DMA4_REASON) & 0x0000DC00; dev->dma_reason[5] = b43legacy_read32(dev, B43legacy_MMIO_DMA5_REASON) & 0x0000DC00; b43legacy_interrupt_ack(dev, reason); /* disable all IRQs. They are enabled again in the bottom half. */ dev->irq_savedstate = b43legacy_interrupt_disable(dev, B43legacy_IRQ_ALL); /* save the reason code and call our bottom half. */ dev->irq_reason = reason; tasklet_schedule(&dev->isr_tasklet);out: mmiowb();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -