📄 main.c
字号:
if (dev->dev->id.revision < 5) return; /* Read all entries from the microcode TXstatus FIFO * and throw them away. */ while (1) { dummy = b43_read32(dev, B43_MMIO_XMITSTAT_0); if (!(dummy & 0x00000001)) break; dummy = b43_read32(dev, B43_MMIO_XMITSTAT_1); }}static u32 b43_jssi_read(struct b43_wldev *dev){ u32 val = 0; val = b43_shm_read16(dev, B43_SHM_SHARED, 0x08A); val <<= 16; val |= b43_shm_read16(dev, B43_SHM_SHARED, 0x088); return val;}static void b43_jssi_write(struct b43_wldev *dev, u32 jssi){ b43_shm_write16(dev, B43_SHM_SHARED, 0x088, (jssi & 0x0000FFFF)); b43_shm_write16(dev, B43_SHM_SHARED, 0x08A, (jssi & 0xFFFF0000) >> 16);}static void b43_generate_noise_sample(struct b43_wldev *dev){ b43_jssi_write(dev, 0x7F7F7F7F); b43_write32(dev, B43_MMIO_STATUS2_BITFIELD, b43_read32(dev, B43_MMIO_STATUS2_BITFIELD) | (1 << 4)); B43_WARN_ON(dev->noisecalc.channel_at_start != dev->phy.channel);}static void b43_calculate_link_quality(struct b43_wldev *dev){ /* Top half of Link Quality calculation. */ if (dev->noisecalc.calculation_running) return; dev->noisecalc.channel_at_start = dev->phy.channel; dev->noisecalc.calculation_running = 1; dev->noisecalc.nr_samples = 0; b43_generate_noise_sample(dev);}static void handle_irq_noise(struct b43_wldev *dev){ struct b43_phy *phy = &dev->phy; u16 tmp; u8 noise[4]; u8 i, j; s32 average; /* Bottom half of Link Quality calculation. */ B43_WARN_ON(!dev->noisecalc.calculation_running); if (dev->noisecalc.channel_at_start != phy->channel) goto drop_calculation; *((__le32 *)noise) = cpu_to_le32(b43_jssi_read(dev)); if (noise[0] == 0x7F || noise[1] == 0x7F || noise[2] == 0x7F || noise[3] == 0x7F) goto generate_new; /* Get the noise samples. */ B43_WARN_ON(dev->noisecalc.nr_samples >= 8); i = dev->noisecalc.nr_samples; noise[0] = limit_value(noise[0], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); noise[1] = limit_value(noise[1], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); noise[2] = limit_value(noise[2], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); noise[3] = limit_value(noise[3], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); dev->noisecalc.samples[i][0] = phy->nrssi_lt[noise[0]]; dev->noisecalc.samples[i][1] = phy->nrssi_lt[noise[1]]; dev->noisecalc.samples[i][2] = phy->nrssi_lt[noise[2]]; dev->noisecalc.samples[i][3] = phy->nrssi_lt[noise[3]]; dev->noisecalc.nr_samples++; if (dev->noisecalc.nr_samples == 8) { /* Calculate the Link Quality by the noise samples. */ average = 0; for (i = 0; i < 8; i++) { for (j = 0; j < 4; j++) average += dev->noisecalc.samples[i][j]; } average /= (8 * 4); average *= 125; average += 64; average /= 128; tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x40C); tmp = (tmp / 128) & 0x1F; if (tmp >= 8) average += 2; else average -= 25; if (tmp == 8) average -= 72; else average -= 48; dev->stats.link_noise = average; drop_calculation: dev->noisecalc.calculation_running = 0; return; } generate_new: b43_generate_noise_sample(dev);}static void handle_irq_tbtt_indication(struct b43_wldev *dev){ if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) { ///TODO: PS TBTT } else { if (1 /*FIXME: the last PSpoll frame was sent successfully */ ) b43_power_saving_ctl_bits(dev, 0); } dev->reg124_set_0x4 = 0; if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS)) dev->reg124_set_0x4 = 1;}static void handle_irq_atim_end(struct b43_wldev *dev){ if (!dev->reg124_set_0x4 /*FIXME rename this variable */ ) return; b43_write32(dev, B43_MMIO_STATUS2_BITFIELD, b43_read32(dev, B43_MMIO_STATUS2_BITFIELD) | 0x4);}static void handle_irq_pmq(struct b43_wldev *dev){ u32 tmp; //TODO: AP mode. while (1) { tmp = b43_read32(dev, B43_MMIO_PS_STATUS); if (!(tmp & 0x00000008)) break; } /* 16bit write is odd, but correct. */ b43_write16(dev, B43_MMIO_PS_STATUS, 0x0002);}static void b43_write_template_common(struct b43_wldev *dev, const u8 * data, u16 size, u16 ram_offset, u16 shm_size_offset, u8 rate){ u32 i, tmp; struct b43_plcp_hdr4 plcp; plcp.data = 0; b43_generate_plcp_hdr(&plcp, size + FCS_LEN, rate); b43_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; b43_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; b43_ram_write(dev, ram_offset + i - 2, tmp); } b43_shm_write16(dev, B43_SHM_SHARED, shm_size_offset, size + sizeof(struct b43_plcp_hdr6));}static void b43_write_beacon_template(struct b43_wldev *dev, u16 ram_offset, u16 shm_size_offset, u8 rate){ int len; const u8 *data; B43_WARN_ON(!dev->cached_beacon); len = min((size_t) dev->cached_beacon->len, 0x200 - sizeof(struct b43_plcp_hdr6)); data = (const u8 *)(dev->cached_beacon->data); b43_write_template_common(dev, data, len, ram_offset, shm_size_offset, rate);}static void b43_write_probe_resp_plcp(struct b43_wldev *dev, u16 shm_offset, u16 size, u8 rate){ struct b43_plcp_hdr4 plcp; u32 tmp; __le16 dur; plcp.data = 0; b43_generate_plcp_hdr(&plcp, size + FCS_LEN, rate); dur = ieee80211_generic_frame_duration(dev->wl->hw, dev->wl->if_id, size, B43_RATE_TO_BASE100KBPS(rate)); /* Write PLCP in two parts and timing for packet transfer */ tmp = le32_to_cpu(plcp.data); b43_shm_write16(dev, B43_SHM_SHARED, shm_offset, tmp & 0xFFFF); b43_shm_write16(dev, B43_SHM_SHARED, shm_offset + 2, tmp >> 16); b43_shm_write16(dev, B43_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 *b43_generate_probe_resp(struct b43_wldev *dev, u16 * dest_size, u8 rate){ const u8 *src_data; u8 *dest_data; u16 src_size, elem_size, src_pos, dest_pos; __le16 dur; struct ieee80211_hdr *hdr; B43_WARN_ON(!dev->cached_beacon); src_size = dev->cached_beacon->len; src_data = (const u8 *)dev->cached_beacon->data; if (unlikely(src_size < 0x24)) { b43dbg(dev->wl, "b43_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 = 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, B43_RATE_TO_BASE100KBPS(rate)); hdr->duration_id = dur; return dest_data;}static void b43_write_probe_resp_template(struct b43_wldev *dev, u16 ram_offset, u16 shm_size_offset, u8 rate){ u8 *probe_resp_data; u16 size; B43_WARN_ON(!dev->cached_beacon); size = dev->cached_beacon->len; probe_resp_data = b43_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 */ b43_write_probe_resp_plcp(dev, 0x31A, size, B43_CCK_RATE_1MB); b43_write_probe_resp_plcp(dev, 0x32C, size, B43_CCK_RATE_2MB); b43_write_probe_resp_plcp(dev, 0x33E, size, B43_CCK_RATE_5MB); b43_write_probe_resp_plcp(dev, 0x350, size, B43_CCK_RATE_11MB); size = min((size_t) size, 0x200 - sizeof(struct b43_plcp_hdr6)); b43_write_template_common(dev, probe_resp_data, size, ram_offset, shm_size_offset, rate); kfree(probe_resp_data);}static int b43_refresh_cached_beacon(struct b43_wldev *dev, struct sk_buff *beacon){ if (dev->cached_beacon) kfree_skb(dev->cached_beacon); dev->cached_beacon = beacon; return 0;}static void b43_update_templates(struct b43_wldev *dev){ u32 status; B43_WARN_ON(!dev->cached_beacon); b43_write_beacon_template(dev, 0x68, 0x18, B43_CCK_RATE_1MB); b43_write_beacon_template(dev, 0x468, 0x1A, B43_CCK_RATE_1MB); b43_write_probe_resp_template(dev, 0x268, 0x4A, B43_CCK_RATE_11MB); status = b43_read32(dev, B43_MMIO_STATUS2_BITFIELD); status |= 0x03; b43_write32(dev, B43_MMIO_STATUS2_BITFIELD, status);}static void b43_refresh_templates(struct b43_wldev *dev, struct sk_buff *beacon){ int err; err = b43_refresh_cached_beacon(dev, beacon); if (unlikely(err)) return; b43_update_templates(dev);}static void b43_set_ssid(struct b43_wldev *dev, const u8 * ssid, u8 ssid_len){ u32 tmp; u16 i, 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; b43_shm_write32(dev, B43_SHM_SHARED, 0x380 + i, tmp); } b43_shm_write16(dev, B43_SHM_SHARED, 0x48, len);}static void b43_set_beacon_int(struct b43_wldev *dev, u16 beacon_int){ b43_time_lock(dev); if (dev->dev->id.revision >= 3) { b43_write32(dev, 0x188, (beacon_int << 16)); } else { b43_write16(dev, 0x606, (beacon_int >> 6)); b43_write16(dev, 0x610, beacon_int); } b43_time_unlock(dev);}static void handle_irq_beacon(struct b43_wldev *dev){ u32 status; if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) return; dev->irq_savedstate &= ~B43_IRQ_BEACON; status = b43_read32(dev, B43_MMIO_STATUS2_BITFIELD); if (!dev->cached_beacon || ((status & 0x1) && (status & 0x2))) { /* ACK beacon IRQ. */ b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, B43_IRQ_BEACON); dev->irq_savedstate |= B43_IRQ_BEACON; if (dev->cached_beacon) kfree_skb(dev->cached_beacon); dev->cached_beacon = NULL; return; } if (!(status & 0x1)) { b43_write_beacon_template(dev, 0x68, 0x18, B43_CCK_RATE_1MB); status |= 0x1; b43_write32(dev, B43_MMIO_STATUS2_BITFIELD, status); } if (!(status & 0x2)) { b43_write_beacon_template(dev, 0x468, 0x1A, B43_CCK_RATE_1MB); status |= 0x2; b43_write32(dev, B43_MMIO_STATUS2_BITFIELD, status); }}static void handle_irq_ucode_debug(struct b43_wldev *dev){ //TODO}/* Interrupt handler bottom-half */static void b43_interrupt_tasklet(struct b43_wldev *dev){ u32 reason; u32 dma_reason[ARRAY_SIZE(dev->dma_reason)]; u32 merged_dma_reason = 0; int i; unsigned long flags; spin_lock_irqsave(&dev->wl->irq_lock, flags); B43_WARN_ON(b43_status(dev) != B43_STAT_STARTED); 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 & B43_IRQ_MAC_TXERR)) b43err(dev->wl, "MAC transmission error\n"); if (unlikely(reason & B43_IRQ_PHY_TXERR)) b43err(dev->wl, "PHY transmission error\n"); if (unlikely(merged_dma_reason & (B43_DMAIRQ_FATALMASK | B43_DMAIRQ_NONFATALMASK))) { if (merged_dma_reason & B43_DMAIRQ_FATALMASK) { b43err(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]); b43_controller_restart(dev, "DMA error"); mmiowb(); spin_unlock_irqrestore(&dev->wl->irq_lock, flags); return; } if (merged_dma_reason & B43_DMAIRQ_NONFATALMASK) { b43err(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 & B43_IRQ_UCODE_DEBUG)) handle_irq_ucode_debug(dev); if (reason & B43_IRQ_TBTT_INDI) handle_irq_tbtt_indication(dev); if (reason & B43_IRQ_ATIM_END) handle_irq_atim_end(dev); if (reason & B43_IRQ_BEACON) handle_irq_beacon(dev); if (reason & B43_IRQ_PMQ) handle_irq_pmq(dev); if (reason & B43_IRQ_TXFIFO_FLUSH_OK) ;/* TODO */ if (reason & B43_IRQ_NOISESAMPLE_OK) handle_irq_noise(dev); /* Check the DMA reason registers for received data. */ if (dma_reason[0] & B43_DMAIRQ_RX_DONE) { if (b43_using_pio(dev)) b43_pio_rx(dev->pio.queue0); else b43_dma_rx(dev->dma.rx_ring0); } B43_WARN_ON(dma_reason[1] & B43_DMAIRQ_RX_DONE); B43_WARN_ON(dma_reason[2] & B43_DMAIRQ_RX_DONE); if (dma_reason[3] & B43_DMAIRQ_RX_DONE) { if (b43_using_pio(dev)) b43_pio_rx(dev->pio.queue3); else b43_dma_rx(dev->dma.rx_ring3); } B43_WARN_ON(dma_reason[4] & B43_DMAIRQ_RX_DONE); B43_WARN_ON(dma_reason[5] & B43_DMAIRQ_RX_DONE); if (reason & B43_IRQ_TX_OK) handle_irq_transmit_status(dev); b43_interrupt_enable(dev, dev->irq_savedstate); mmiowb(); spin_unlock_irqrestore(&dev->wl->irq_lock, flags);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -