Add mt7601u-sta and rtl8188eus driver in drivers
New file |
| | |
| | | EXTRA_CFLAGS += -Werror -Wenum-compare |
| | | ccflags-y += -D__CHECK_ENDIAN__ |
| | | |
| | | obj-m := mt7601u.o |
| | | |
| | | mt7601u-y := \ |
| | | usb.o init.o main.o mcu.o trace.o dma.o core.o eeprom.o phy.o \ |
| | | mac.o util.o debugfs.o tx.o |
| | | |
| | | CFLAGS_trace.o := -I$(src) |
New file |
| | |
| | | |
| | | KDIR ?= ../../linux-at91/ |
| | | CROSS_COMPILE=/opt/buildroot/cortex-a5/bin/arm-linux- |
| | | |
| | | default: |
| | | $(MAKE) -C $(KDIR) M=$$PWD |
| | | clean: |
| | | $(MAKE) -C $(KDIR) M=$$PWD clean |
| | | install: |
| | | $(MAKE) -C $(KDIR) M=$$PWD modules_install |
New file |
| | |
| | | |
| | | ### Download: |
| | | Download from: https://github.com/kuba-moo/mt7601u.git |
| | | MT7601 driver builtin linux kernel since version v4.2, the kernel under the version need this driver. And it's just only server for wpa_supplicant but not hostapd |
| | | |
| | | ### ChangeLog: |
| | | |
| | | 1, Updata Makefile to support SAMA5D4 build |
| | | |
| | | |
| | | |
| | | This is a Linux driver for MediaTek MT7601U USB dongle. It was written from scratch based on the vendor GPL-driver. Unlike the vendor driver this driver uses modern Linux WiFi infrastructure and should work flawlessly with NetworkManager, wicd, wpa_supplicant and such. This driver was merged into mainline and is part of official Linux kernel since version v4.2. If you are using Linux 4.2 or later there is no need to install this driver. |
| | | |
| | | ### Building and using |
| | | To use this driver you need to upgrade your kernel to at least **Linux 3.19**. You also have to grab a copy of the firmware from the vendor driver. Download the vendor driver (see section below) and copy file *MT7601U.bin* to */lib/firmware*: |
| | | |
| | | ```sh |
| | | # cd where-you-put-the-vendor-driver |
| | | # cp src/mcu/bin/MT7601.bin /lib/firmware/mt7601u.bin |
| | | ``` |
| | | Note that name of the file in */lib/firmware* is in lowercase. |
| | | |
| | | After that **make sure you have installed all packages required by your distro to build kernel modules** (```apt-get install linux-headers-$(uname -r)``` or ```yum install kernel-devel``` etc). Build the driver and load it: |
| | | |
| | | ```sh |
| | | $ git clone https://github.com/kuba-moo/mt7601u.git |
| | | $ cd mt7601u |
| | | $ make |
| | | # modprobe mac80211 |
| | | # insmod ./mt7601u.ko |
| | | ``` |
| | | |
| | | Now when you connect your device a new network interface should be created. Something like this should appear in your kernel logs: |
| | | |
| | | ``` |
| | | [ 5515.098424] mt7601u 1-6:1.0: ASIC revision: 76010001 MAC revision: 76010500 |
| | | [ 5515.100954] mt7601u 1-6:1.0: Firmware Version: 0.1.00 Build: 7640 Build time: 201302052146____ |
| | | [ 5515.466817] mt7601u 1-6:1.0: Warning: unsupported EEPROM version 0d |
| | | [ 5515.466876] mt7601u 1-6:1.0: EEPROM ver:0d fae:00 |
| | | [ 5515.467561] mt7601u 1-6:1.0: EEPROM country region 01 (channels 1-13) |
| | | [ 5515.713155] ieee80211 phy26: Selected rate control algorithm 'minstrel_ht' |
| | | [ 5515.718977] usbcore: registered new interface driver mt7601u |
| | | ``` |
| | | |
| | | The warning about EEPROM version is harmless but keep an eye on the logs and if you spot any errors please report them here. |
| | | |
| | | If you want the driver to load automatically you can do the following: |
| | | ``` |
| | | $ make && sudo make install && depmod |
| | | ``` |
| | | However, please remember that this installs the driver *only for your current kernel* and you will have to redo this every time your kernel is updated! |
| | | |
| | | ### Supported hardware |
| | | The driver was tested for devices with USB ID of 148f:7601. Specifically I tested it with: |
| | | * TP-LINK TL-WN727N v4; |
| | | * Xiaomi Mini USB; |
| | | * the no-name black&red device from ebay with small detachable antenna. |
| | | |
| | | Also tested with USB ID of 148f:760b wich has MT7601UM chip and works fine with this driver. |
| | | |
| | | But in principle it *should* work with any device supported by the vendor driver. |
| | | |
| | | ### Vendor driver |
| | | The original vendor driver can be downloaded from MediaTek's website (http://www.mediatek.com/en/downloads1/downloads/mt7601u-usb/). However, version 3.0.0.4 is broken on recent kernels so you may want to grab one of the improved versions which people put up on GH (like this one: https://github.com/porjo/mt7601u). |
New file |
| | |
| | | /* |
| | | * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> |
| | | * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> |
| | | * |
| | | * This program is free software; you can redistribute it and/or modify |
| | | * it under the terms of the GNU General Public License version 2 |
| | | * as published by the Free Software Foundation |
| | | * |
| | | * This program is distributed in the hope that it will be useful, |
| | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| | | * GNU General Public License for more details. |
| | | */ |
| | | |
| | | #include "mt7601u.h" |
| | | |
| | | int mt7601u_wait_asic_ready(struct mt7601u_dev *dev) |
| | | { |
| | | int i = 100; |
| | | u32 val; |
| | | |
| | | do { |
| | | if (test_bit(MT7601U_STATE_REMOVED, &dev->state)) |
| | | return -EIO; |
| | | |
| | | val = mt7601u_rr(dev, MT_MAC_CSR0); |
| | | if (val && ~val) |
| | | return 0; |
| | | |
| | | udelay(10); |
| | | } while (i--); |
| | | |
| | | return -EIO; |
| | | } |
| | | |
| | | bool mt76_poll(struct mt7601u_dev *dev, u32 offset, u32 mask, u32 val, |
| | | int timeout) |
| | | { |
| | | u32 cur; |
| | | |
| | | timeout /= 10; |
| | | do { |
| | | if (test_bit(MT7601U_STATE_REMOVED, &dev->state)) |
| | | return false; |
| | | |
| | | cur = mt7601u_rr(dev, offset) & mask; |
| | | if (cur == val) |
| | | return true; |
| | | |
| | | udelay(10); |
| | | } while (timeout-- > 0); |
| | | |
| | | dev_err(dev->dev, "Error: Time out with reg %08x\n", offset); |
| | | |
| | | return false; |
| | | } |
| | | |
| | | bool mt76_poll_msec(struct mt7601u_dev *dev, u32 offset, u32 mask, u32 val, |
| | | int timeout) |
| | | { |
| | | u32 cur; |
| | | |
| | | timeout /= 10; |
| | | do { |
| | | if (test_bit(MT7601U_STATE_REMOVED, &dev->state)) |
| | | return false; |
| | | |
| | | cur = mt7601u_rr(dev, offset) & mask; |
| | | if (cur == val) |
| | | return true; |
| | | |
| | | msleep(10); |
| | | } while (timeout-- > 0); |
| | | |
| | | dev_err(dev->dev, "Error: Time out with reg %08x\n", offset); |
| | | |
| | | return false; |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> |
| | | * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> |
| | | * |
| | | * This program is free software; you can redistribute it and/or modify |
| | | * it under the terms of the GNU General Public License version 2 |
| | | * as published by the Free Software Foundation |
| | | * |
| | | * This program is distributed in the hope that it will be useful, |
| | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| | | * GNU General Public License for more details. |
| | | */ |
| | | |
| | | #include <linux/debugfs.h> |
| | | |
| | | #include "mt7601u.h" |
| | | #include "eeprom.h" |
| | | |
| | | static int |
| | | mt76_reg_set(void *data, u64 val) |
| | | { |
| | | struct mt7601u_dev *dev = data; |
| | | |
| | | mt76_wr(dev, dev->debugfs_reg, val); |
| | | return 0; |
| | | } |
| | | |
| | | static int |
| | | mt76_reg_get(void *data, u64 *val) |
| | | { |
| | | struct mt7601u_dev *dev = data; |
| | | |
| | | *val = mt76_rr(dev, dev->debugfs_reg); |
| | | return 0; |
| | | } |
| | | |
| | | DEFINE_SIMPLE_ATTRIBUTE(fops_regval, mt76_reg_get, mt76_reg_set, "0x%08llx\n"); |
| | | |
| | | static int |
| | | mt7601u_ampdu_stat_read(struct seq_file *file, void *data) |
| | | { |
| | | struct mt7601u_dev *dev = file->private; |
| | | int i, j; |
| | | |
| | | #define stat_printf(grp, off, name) \ |
| | | seq_printf(file, #name ":\t%llu\n", dev->stats.grp[off]) |
| | | |
| | | stat_printf(rx_stat, 0, rx_crc_err); |
| | | stat_printf(rx_stat, 1, rx_phy_err); |
| | | stat_printf(rx_stat, 2, rx_false_cca); |
| | | stat_printf(rx_stat, 3, rx_plcp_err); |
| | | stat_printf(rx_stat, 4, rx_fifo_overflow); |
| | | stat_printf(rx_stat, 5, rx_duplicate); |
| | | |
| | | stat_printf(tx_stat, 0, tx_fail_cnt); |
| | | stat_printf(tx_stat, 1, tx_bcn_cnt); |
| | | stat_printf(tx_stat, 2, tx_success); |
| | | stat_printf(tx_stat, 3, tx_retransmit); |
| | | stat_printf(tx_stat, 4, tx_zero_len); |
| | | stat_printf(tx_stat, 5, tx_underflow); |
| | | |
| | | stat_printf(aggr_stat, 0, non_aggr_tx); |
| | | stat_printf(aggr_stat, 1, aggr_tx); |
| | | |
| | | stat_printf(zero_len_del, 0, tx_zero_len_del); |
| | | stat_printf(zero_len_del, 1, rx_zero_len_del); |
| | | #undef stat_printf |
| | | |
| | | seq_puts(file, "Aggregations stats:\n"); |
| | | for (i = 0; i < 4; i++) { |
| | | for (j = 0; j < 8; j++) |
| | | seq_printf(file, "%08llx ", |
| | | dev->stats.aggr_n[i * 8 + j]); |
| | | seq_putc(file, '\n'); |
| | | } |
| | | |
| | | seq_printf(file, "recent average AMPDU len: %d\n", |
| | | atomic_read(&dev->avg_ampdu_len)); |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | static int |
| | | mt7601u_ampdu_stat_open(struct inode *inode, struct file *f) |
| | | { |
| | | return single_open(f, mt7601u_ampdu_stat_read, inode->i_private); |
| | | } |
| | | |
| | | static const struct file_operations fops_ampdu_stat = { |
| | | .open = mt7601u_ampdu_stat_open, |
| | | .read = seq_read, |
| | | .llseek = seq_lseek, |
| | | .release = single_release, |
| | | }; |
| | | |
| | | static int |
| | | mt7601u_eeprom_param_read(struct seq_file *file, void *data) |
| | | { |
| | | struct mt7601u_dev *dev = file->private; |
| | | struct mt7601u_rate_power *rp = &dev->ee->power_rate_table; |
| | | struct tssi_data *td = &dev->ee->tssi_data; |
| | | int i; |
| | | |
| | | seq_printf(file, "RF freq offset: %hhx\n", dev->ee->rf_freq_off); |
| | | seq_printf(file, "RSSI offset: %hhx %hhx\n", |
| | | dev->ee->rssi_offset[0], dev->ee->rssi_offset[1]); |
| | | seq_printf(file, "Reference temp: %hhx\n", dev->ee->ref_temp); |
| | | seq_printf(file, "LNA gain: %hhx\n", dev->ee->lna_gain); |
| | | seq_printf(file, "Reg channels: %hhu-%hhu\n", dev->ee->reg.start, |
| | | dev->ee->reg.start + dev->ee->reg.num - 1); |
| | | |
| | | seq_puts(file, "Per rate power:\n"); |
| | | for (i = 0; i < 2; i++) |
| | | seq_printf(file, "\t raw:%02hhx bw20:%02hhx bw40:%02hhx\n", |
| | | rp->cck[i].raw, rp->cck[i].bw20, rp->cck[i].bw40); |
| | | for (i = 0; i < 4; i++) |
| | | seq_printf(file, "\t raw:%02hhx bw20:%02hhx bw40:%02hhx\n", |
| | | rp->ofdm[i].raw, rp->ofdm[i].bw20, rp->ofdm[i].bw40); |
| | | for (i = 0; i < 4; i++) |
| | | seq_printf(file, "\t raw:%02hhx bw20:%02hhx bw40:%02hhx\n", |
| | | rp->ht[i].raw, rp->ht[i].bw20, rp->ht[i].bw40); |
| | | |
| | | seq_puts(file, "Per channel power:\n"); |
| | | for (i = 0; i < 7; i++) |
| | | seq_printf(file, "\t tx_power ch%u:%02hhx ch%u:%02hhx\n", |
| | | i * 2 + 1, dev->ee->chan_pwr[i * 2], |
| | | i * 2 + 2, dev->ee->chan_pwr[i * 2 + 1]); |
| | | |
| | | if (!dev->ee->tssi_enabled) |
| | | return 0; |
| | | |
| | | seq_puts(file, "TSSI:\n"); |
| | | seq_printf(file, "\t slope:%02hhx\n", td->slope); |
| | | seq_printf(file, "\t offset=%02hhx %02hhx %02hhx\n", |
| | | td->offset[0], td->offset[1], td->offset[2]); |
| | | seq_printf(file, "\t delta_off:%08x\n", td->tx0_delta_offset); |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | static int |
| | | mt7601u_eeprom_param_open(struct inode *inode, struct file *f) |
| | | { |
| | | return single_open(f, mt7601u_eeprom_param_read, inode->i_private); |
| | | } |
| | | |
| | | static const struct file_operations fops_eeprom_param = { |
| | | .open = mt7601u_eeprom_param_open, |
| | | .read = seq_read, |
| | | .llseek = seq_lseek, |
| | | .release = single_release, |
| | | }; |
| | | |
| | | void mt7601u_init_debugfs(struct mt7601u_dev *dev) |
| | | { |
| | | struct dentry *dir; |
| | | |
| | | dir = debugfs_create_dir("mt7601u", dev->hw->wiphy->debugfsdir); |
| | | if (!dir) |
| | | return; |
| | | |
| | | debugfs_create_u8("temperature", S_IRUSR, dir, &dev->raw_temp); |
| | | debugfs_create_u32("temp_mode", S_IRUSR, dir, &dev->temp_mode); |
| | | |
| | | debugfs_create_u32("regidx", S_IRUSR | S_IWUSR, dir, &dev->debugfs_reg); |
| | | debugfs_create_file("regval", S_IRUSR | S_IWUSR, dir, dev, |
| | | &fops_regval); |
| | | debugfs_create_file("ampdu_stat", S_IRUSR, dir, dev, &fops_ampdu_stat); |
| | | debugfs_create_file("eeprom_param", S_IRUSR, dir, dev, |
| | | &fops_eeprom_param); |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> |
| | | * |
| | | * This program is free software; you can redistribute it and/or modify |
| | | * it under the terms of the GNU General Public License version 2 |
| | | * as published by the Free Software Foundation |
| | | * |
| | | * This program is distributed in the hope that it will be useful, |
| | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| | | * GNU General Public License for more details. |
| | | */ |
| | | |
| | | #include "mt7601u.h" |
| | | #include "dma.h" |
| | | #include "usb.h" |
| | | #include "trace.h" |
| | | |
| | | static int mt7601u_submit_rx_buf(struct mt7601u_dev *dev, |
| | | struct mt7601u_dma_buf_rx *e, gfp_t gfp); |
| | | |
| | | static unsigned int ieee80211_get_hdrlen_from_buf(const u8 *data, unsigned len) |
| | | { |
| | | const struct ieee80211_hdr *hdr = (const struct ieee80211_hdr *)data; |
| | | unsigned int hdrlen; |
| | | |
| | | if (unlikely(len < 10)) |
| | | return 0; |
| | | hdrlen = ieee80211_hdrlen(hdr->frame_control); |
| | | if (unlikely(hdrlen > len)) |
| | | return 0; |
| | | return hdrlen; |
| | | } |
| | | |
| | | static struct sk_buff * |
| | | mt7601u_rx_skb_from_seg(struct mt7601u_dev *dev, struct mt7601u_rxwi *rxwi, |
| | | void *data, u32 seg_len, u32 truesize, struct page *p) |
| | | { |
| | | struct sk_buff *skb; |
| | | u32 true_len, hdr_len = 0, copy, frag; |
| | | |
| | | skb = alloc_skb(p ? 128 : seg_len, GFP_ATOMIC); |
| | | if (!skb) |
| | | return NULL; |
| | | |
| | | true_len = mt76_mac_process_rx(dev, skb, data, rxwi); |
| | | if (!true_len || true_len > seg_len) |
| | | goto bad_frame; |
| | | |
| | | hdr_len = ieee80211_get_hdrlen_from_buf(data, true_len); |
| | | if (!hdr_len) |
| | | goto bad_frame; |
| | | |
| | | if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_L2PAD)) { |
| | | memcpy(skb_put(skb, hdr_len), data, hdr_len); |
| | | |
| | | data += hdr_len + 2; |
| | | true_len -= hdr_len; |
| | | hdr_len = 0; |
| | | } |
| | | |
| | | /* If not doing paged RX allocated skb will always have enough space */ |
| | | copy = (true_len <= skb_tailroom(skb)) ? true_len : hdr_len + 8; |
| | | frag = true_len - copy; |
| | | |
| | | memcpy(skb_put(skb, copy), data, copy); |
| | | data += copy; |
| | | |
| | | if (frag) { |
| | | skb_add_rx_frag(skb, 0, p, data - page_address(p), |
| | | frag, truesize); |
| | | get_page(p); |
| | | } |
| | | |
| | | return skb; |
| | | |
| | | bad_frame: |
| | | dev_err(dev->dev, "Error: incorrect frame len:%u hdr:%u\n", |
| | | true_len, hdr_len); |
| | | dev_kfree_skb(skb); |
| | | return NULL; |
| | | } |
| | | |
| | | static void mt7601u_rx_process_seg(struct mt7601u_dev *dev, u8 *data, |
| | | u32 seg_len, struct page *p) |
| | | { |
| | | struct sk_buff *skb; |
| | | struct mt7601u_rxwi *rxwi; |
| | | u32 fce_info, truesize = seg_len; |
| | | |
| | | /* DMA_INFO field at the beginning of the segment contains only some of |
| | | * the information, we need to read the FCE descriptor from the end. |
| | | */ |
| | | fce_info = get_unaligned_le32(data + seg_len - MT_FCE_INFO_LEN); |
| | | seg_len -= MT_FCE_INFO_LEN; |
| | | |
| | | data += MT_DMA_HDR_LEN; |
| | | seg_len -= MT_DMA_HDR_LEN; |
| | | |
| | | rxwi = (struct mt7601u_rxwi *) data; |
| | | data += sizeof(struct mt7601u_rxwi); |
| | | seg_len -= sizeof(struct mt7601u_rxwi); |
| | | |
| | | if (unlikely(rxwi->zero[0] || rxwi->zero[1] || rxwi->zero[2])) |
| | | dev_err_once(dev->dev, "Error: RXWI zero fields are set\n"); |
| | | if (unlikely(MT76_GET(MT_RXD_INFO_TYPE, fce_info))) |
| | | dev_err_once(dev->dev, "Error: RX path seen a non-pkt urb\n"); |
| | | |
| | | trace_mt_rx(dev, rxwi, fce_info); |
| | | |
| | | skb = mt7601u_rx_skb_from_seg(dev, rxwi, data, seg_len, truesize, p); |
| | | if (!skb) |
| | | return; |
| | | |
| | | spin_lock(&dev->mac_lock); |
| | | ieee80211_rx(dev->hw, skb); |
| | | spin_unlock(&dev->mac_lock); |
| | | } |
| | | |
| | | static u16 mt7601u_rx_next_seg_len(u8 *data, u32 data_len) |
| | | { |
| | | u32 min_seg_len = MT_DMA_HDR_LEN + MT_RX_INFO_LEN + |
| | | sizeof(struct mt7601u_rxwi) + MT_FCE_INFO_LEN; |
| | | u16 dma_len = get_unaligned_le16(data); |
| | | |
| | | if (data_len < min_seg_len || |
| | | WARN_ON(!dma_len) || |
| | | WARN_ON(dma_len + MT_DMA_HDRS > data_len) || |
| | | WARN_ON(dma_len & 0x3)) |
| | | return 0; |
| | | |
| | | return MT_DMA_HDRS + dma_len; |
| | | } |
| | | |
| | | static void |
| | | mt7601u_rx_process_entry(struct mt7601u_dev *dev, struct mt7601u_dma_buf_rx *e) |
| | | { |
| | | u32 seg_len, data_len = e->urb->actual_length; |
| | | u8 *data = page_address(e->p); |
| | | struct page *new_p = NULL; |
| | | int cnt = 0; |
| | | |
| | | if (!test_bit(MT7601U_STATE_INITIALIZED, &dev->state)) |
| | | return; |
| | | |
| | | /* Copy if there is very little data in the buffer. */ |
| | | if (data_len > 512) |
| | | new_p = dev_alloc_pages(MT_RX_ORDER); |
| | | |
| | | while ((seg_len = mt7601u_rx_next_seg_len(data, data_len))) { |
| | | mt7601u_rx_process_seg(dev, data, seg_len, new_p ? e->p : NULL); |
| | | |
| | | data_len -= seg_len; |
| | | data += seg_len; |
| | | cnt++; |
| | | } |
| | | |
| | | if (cnt > 1) |
| | | trace_mt_rx_dma_aggr(dev, cnt, !!new_p); |
| | | |
| | | if (new_p) { |
| | | /* we have one extra ref from the allocator */ |
| | | __free_pages(e->p, MT_RX_ORDER); |
| | | |
| | | e->p = new_p; |
| | | } |
| | | } |
| | | |
| | | static struct mt7601u_dma_buf_rx * |
| | | mt7601u_rx_get_pending_entry(struct mt7601u_dev *dev) |
| | | { |
| | | struct mt7601u_rx_queue *q = &dev->rx_q; |
| | | struct mt7601u_dma_buf_rx *buf = NULL; |
| | | unsigned long flags; |
| | | |
| | | spin_lock_irqsave(&dev->rx_lock, flags); |
| | | |
| | | if (!q->pending) |
| | | goto out; |
| | | |
| | | buf = &q->e[q->start]; |
| | | q->pending--; |
| | | q->start = (q->start + 1) % q->entries; |
| | | out: |
| | | spin_unlock_irqrestore(&dev->rx_lock, flags); |
| | | |
| | | return buf; |
| | | } |
| | | |
| | | static void mt7601u_complete_rx(struct urb *urb) |
| | | { |
| | | struct mt7601u_dev *dev = urb->context; |
| | | struct mt7601u_rx_queue *q = &dev->rx_q; |
| | | unsigned long flags; |
| | | |
| | | spin_lock_irqsave(&dev->rx_lock, flags); |
| | | |
| | | if (mt7601u_urb_has_error(urb)) |
| | | dev_err(dev->dev, "Error: RX urb failed:%d\n", urb->status); |
| | | if (WARN_ONCE(q->e[q->end].urb != urb, "RX urb mismatch")) |
| | | goto out; |
| | | |
| | | q->end = (q->end + 1) % q->entries; |
| | | q->pending++; |
| | | tasklet_schedule(&dev->rx_tasklet); |
| | | out: |
| | | spin_unlock_irqrestore(&dev->rx_lock, flags); |
| | | } |
| | | |
| | | static void mt7601u_rx_tasklet(unsigned long data) |
| | | { |
| | | struct mt7601u_dev *dev = (struct mt7601u_dev *) data; |
| | | struct mt7601u_dma_buf_rx *e; |
| | | |
| | | while ((e = mt7601u_rx_get_pending_entry(dev))) { |
| | | if (e->urb->status) |
| | | continue; |
| | | |
| | | mt7601u_rx_process_entry(dev, e); |
| | | mt7601u_submit_rx_buf(dev, e, GFP_ATOMIC); |
| | | } |
| | | } |
| | | |
| | | static void mt7601u_complete_tx(struct urb *urb) |
| | | { |
| | | struct mt7601u_tx_queue *q = urb->context; |
| | | struct mt7601u_dev *dev = q->dev; |
| | | struct sk_buff *skb; |
| | | unsigned long flags; |
| | | |
| | | spin_lock_irqsave(&dev->tx_lock, flags); |
| | | |
| | | if (mt7601u_urb_has_error(urb)) |
| | | dev_err(dev->dev, "Error: TX urb failed:%d\n", urb->status); |
| | | if (WARN_ONCE(q->e[q->start].urb != urb, "TX urb mismatch")) |
| | | goto out; |
| | | |
| | | skb = q->e[q->start].skb; |
| | | trace_mt_tx_dma_done(dev, skb); |
| | | |
| | | __skb_queue_tail(&dev->tx_skb_done, skb); |
| | | tasklet_schedule(&dev->tx_tasklet); |
| | | |
| | | if (q->used == q->entries - q->entries / 8) |
| | | ieee80211_wake_queue(dev->hw, skb_get_queue_mapping(skb)); |
| | | |
| | | q->start = (q->start + 1) % q->entries; |
| | | q->used--; |
| | | out: |
| | | spin_unlock_irqrestore(&dev->tx_lock, flags); |
| | | } |
| | | |
| | | static void mt7601u_tx_tasklet(unsigned long data) |
| | | { |
| | | struct mt7601u_dev *dev = (struct mt7601u_dev *) data; |
| | | struct sk_buff_head skbs; |
| | | unsigned long flags; |
| | | |
| | | __skb_queue_head_init(&skbs); |
| | | |
| | | spin_lock_irqsave(&dev->tx_lock, flags); |
| | | |
| | | set_bit(MT7601U_STATE_MORE_STATS, &dev->state); |
| | | if (!test_and_set_bit(MT7601U_STATE_READING_STATS, &dev->state)) |
| | | queue_delayed_work(dev->stat_wq, &dev->stat_work, |
| | | msecs_to_jiffies(10)); |
| | | |
| | | skb_queue_splice_init(&dev->tx_skb_done, &skbs); |
| | | |
| | | spin_unlock_irqrestore(&dev->tx_lock, flags); |
| | | |
| | | while (!skb_queue_empty(&skbs)) { |
| | | struct sk_buff *skb = __skb_dequeue(&skbs); |
| | | |
| | | mt7601u_tx_status(dev, skb); |
| | | } |
| | | } |
| | | |
| | | static int mt7601u_dma_submit_tx(struct mt7601u_dev *dev, |
| | | struct sk_buff *skb, u8 ep) |
| | | { |
| | | struct usb_device *usb_dev = mt7601u_to_usb_dev(dev); |
| | | unsigned snd_pipe = usb_sndbulkpipe(usb_dev, dev->out_eps[ep]); |
| | | struct mt7601u_dma_buf_tx *e; |
| | | struct mt7601u_tx_queue *q = &dev->tx_q[ep]; |
| | | unsigned long flags; |
| | | int ret; |
| | | |
| | | spin_lock_irqsave(&dev->tx_lock, flags); |
| | | |
| | | if (WARN_ON(q->entries <= q->used)) { |
| | | ret = -ENOSPC; |
| | | goto out; |
| | | } |
| | | |
| | | e = &q->e[q->end]; |
| | | e->skb = skb; |
| | | usb_fill_bulk_urb(e->urb, usb_dev, snd_pipe, skb->data, skb->len, |
| | | mt7601u_complete_tx, q); |
| | | ret = usb_submit_urb(e->urb, GFP_ATOMIC); |
| | | if (ret) { |
| | | /* Special-handle ENODEV from TX urb submission because it will |
| | | * often be the first ENODEV we see after device is removed. |
| | | */ |
| | | if (ret == -ENODEV) |
| | | set_bit(MT7601U_STATE_REMOVED, &dev->state); |
| | | else |
| | | dev_err(dev->dev, "Error: TX urb submit failed:%d\n", |
| | | ret); |
| | | goto out; |
| | | } |
| | | |
| | | q->end = (q->end + 1) % q->entries; |
| | | q->used++; |
| | | |
| | | if (q->used >= q->entries) |
| | | ieee80211_stop_queue(dev->hw, skb_get_queue_mapping(skb)); |
| | | out: |
| | | spin_unlock_irqrestore(&dev->tx_lock, flags); |
| | | |
| | | return ret; |
| | | } |
| | | |
| | | /* Map hardware Q to USB endpoint number */ |
| | | static u8 q2ep(u8 qid) |
| | | { |
| | | /* TODO: take management packets to queue 5 */ |
| | | return qid + 1; |
| | | } |
| | | |
| | | /* Map USB endpoint number to Q id in the DMA engine */ |
| | | static enum mt76_qsel ep2dmaq(u8 ep) |
| | | { |
| | | if (ep == 5) |
| | | return MT_QSEL_MGMT; |
| | | return MT_QSEL_EDCA; |
| | | } |
| | | |
| | | int mt7601u_dma_enqueue_tx(struct mt7601u_dev *dev, struct sk_buff *skb, |
| | | struct mt76_wcid *wcid, int hw_q) |
| | | { |
| | | u8 ep = q2ep(hw_q); |
| | | u32 dma_flags; |
| | | int ret; |
| | | |
| | | dma_flags = MT_TXD_PKT_INFO_80211; |
| | | if (wcid->hw_key_idx == 0xff) |
| | | dma_flags |= MT_TXD_PKT_INFO_WIV; |
| | | |
| | | ret = mt7601u_dma_skb_wrap_pkt(skb, ep2dmaq(ep), dma_flags); |
| | | if (ret) |
| | | return ret; |
| | | |
| | | ret = mt7601u_dma_submit_tx(dev, skb, ep); |
| | | if (ret) { |
| | | ieee80211_free_txskb(dev->hw, skb); |
| | | return ret; |
| | | } |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | static void mt7601u_kill_rx(struct mt7601u_dev *dev) |
| | | { |
| | | int i; |
| | | unsigned long flags; |
| | | |
| | | spin_lock_irqsave(&dev->rx_lock, flags); |
| | | |
| | | for (i = 0; i < dev->rx_q.entries; i++) { |
| | | int next = dev->rx_q.end; |
| | | |
| | | spin_unlock_irqrestore(&dev->rx_lock, flags); |
| | | usb_poison_urb(dev->rx_q.e[next].urb); |
| | | spin_lock_irqsave(&dev->rx_lock, flags); |
| | | } |
| | | |
| | | spin_unlock_irqrestore(&dev->rx_lock, flags); |
| | | } |
| | | |
| | | static int mt7601u_submit_rx_buf(struct mt7601u_dev *dev, |
| | | struct mt7601u_dma_buf_rx *e, gfp_t gfp) |
| | | { |
| | | struct usb_device *usb_dev = mt7601u_to_usb_dev(dev); |
| | | u8 *buf = page_address(e->p); |
| | | unsigned pipe; |
| | | int ret; |
| | | |
| | | pipe = usb_rcvbulkpipe(usb_dev, dev->in_eps[MT_EP_IN_PKT_RX]); |
| | | |
| | | usb_fill_bulk_urb(e->urb, usb_dev, pipe, buf, MT_RX_URB_SIZE, |
| | | mt7601u_complete_rx, dev); |
| | | |
| | | trace_mt_submit_urb(dev, e->urb); |
| | | ret = usb_submit_urb(e->urb, gfp); |
| | | if (ret) |
| | | dev_err(dev->dev, "Error: submit RX URB failed:%d\n", ret); |
| | | |
| | | return ret; |
| | | } |
| | | |
| | | static int mt7601u_submit_rx(struct mt7601u_dev *dev) |
| | | { |
| | | int i, ret; |
| | | |
| | | for (i = 0; i < dev->rx_q.entries; i++) { |
| | | ret = mt7601u_submit_rx_buf(dev, &dev->rx_q.e[i], GFP_KERNEL); |
| | | if (ret) |
| | | return ret; |
| | | } |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | static void mt7601u_free_rx(struct mt7601u_dev *dev) |
| | | { |
| | | int i; |
| | | |
| | | for (i = 0; i < dev->rx_q.entries; i++) { |
| | | __free_pages(dev->rx_q.e[i].p, MT_RX_ORDER); |
| | | usb_free_urb(dev->rx_q.e[i].urb); |
| | | } |
| | | } |
| | | |
| | | static int mt7601u_alloc_rx(struct mt7601u_dev *dev) |
| | | { |
| | | int i; |
| | | |
| | | memset(&dev->rx_q, 0, sizeof(dev->rx_q)); |
| | | dev->rx_q.dev = dev; |
| | | dev->rx_q.entries = N_RX_ENTRIES; |
| | | |
| | | for (i = 0; i < N_RX_ENTRIES; i++) { |
| | | dev->rx_q.e[i].urb = usb_alloc_urb(0, GFP_KERNEL); |
| | | dev->rx_q.e[i].p = dev_alloc_pages(MT_RX_ORDER); |
| | | |
| | | if (!dev->rx_q.e[i].urb || !dev->rx_q.e[i].p) |
| | | return -ENOMEM; |
| | | } |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | static void mt7601u_free_tx_queue(struct mt7601u_tx_queue *q) |
| | | { |
| | | int i; |
| | | |
| | | WARN_ON(q->used); |
| | | |
| | | for (i = 0; i < q->entries; i++) { |
| | | usb_poison_urb(q->e[i].urb); |
| | | usb_free_urb(q->e[i].urb); |
| | | } |
| | | } |
| | | |
| | | static void mt7601u_free_tx(struct mt7601u_dev *dev) |
| | | { |
| | | int i; |
| | | |
| | | for (i = 0; i < __MT_EP_OUT_MAX; i++) |
| | | mt7601u_free_tx_queue(&dev->tx_q[i]); |
| | | } |
| | | |
| | | static int mt7601u_alloc_tx_queue(struct mt7601u_dev *dev, |
| | | struct mt7601u_tx_queue *q) |
| | | { |
| | | int i; |
| | | |
| | | q->dev = dev; |
| | | q->entries = N_TX_ENTRIES; |
| | | |
| | | for (i = 0; i < N_TX_ENTRIES; i++) { |
| | | q->e[i].urb = usb_alloc_urb(0, GFP_KERNEL); |
| | | if (!q->e[i].urb) |
| | | return -ENOMEM; |
| | | } |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | static int mt7601u_alloc_tx(struct mt7601u_dev *dev) |
| | | { |
| | | int i; |
| | | |
| | | dev->tx_q = devm_kcalloc(dev->dev, __MT_EP_OUT_MAX, |
| | | sizeof(*dev->tx_q), GFP_KERNEL); |
| | | |
| | | for (i = 0; i < __MT_EP_OUT_MAX; i++) |
| | | if (mt7601u_alloc_tx_queue(dev, &dev->tx_q[i])) |
| | | return -ENOMEM; |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | int mt7601u_dma_init(struct mt7601u_dev *dev) |
| | | { |
| | | int ret = -ENOMEM; |
| | | |
| | | tasklet_init(&dev->tx_tasklet, mt7601u_tx_tasklet, (unsigned long) dev); |
| | | tasklet_init(&dev->rx_tasklet, mt7601u_rx_tasklet, (unsigned long) dev); |
| | | |
| | | ret = mt7601u_alloc_tx(dev); |
| | | if (ret) |
| | | goto err; |
| | | ret = mt7601u_alloc_rx(dev); |
| | | if (ret) |
| | | goto err; |
| | | |
| | | ret = mt7601u_submit_rx(dev); |
| | | if (ret) |
| | | goto err; |
| | | |
| | | return 0; |
| | | err: |
| | | mt7601u_dma_cleanup(dev); |
| | | return ret; |
| | | } |
| | | |
| | | void mt7601u_dma_cleanup(struct mt7601u_dev *dev) |
| | | { |
| | | mt7601u_kill_rx(dev); |
| | | |
| | | tasklet_kill(&dev->rx_tasklet); |
| | | |
| | | mt7601u_free_rx(dev); |
| | | mt7601u_free_tx(dev); |
| | | |
| | | tasklet_kill(&dev->tx_tasklet); |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> |
| | | * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> |
| | | * |
| | | * This program is free software; you can redistribute it and/or modify |
| | | * it under the terms of the GNU General Public License version 2 |
| | | * as published by the Free Software Foundation |
| | | * |
| | | * This program is distributed in the hope that it will be useful, |
| | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| | | * GNU General Public License for more details. |
| | | */ |
| | | |
| | | #ifndef __MT7601U_DMA_H |
| | | #define __MT7601U_DMA_H |
| | | |
| | | #include <asm/unaligned.h> |
| | | #include <linux/skbuff.h> |
| | | |
| | | #include "util.h" |
| | | |
| | | #define MT_DMA_HDR_LEN 4 |
| | | #define MT_RX_INFO_LEN 4 |
| | | #define MT_FCE_INFO_LEN 4 |
| | | #define MT_DMA_HDRS (MT_DMA_HDR_LEN + MT_RX_INFO_LEN) |
| | | |
| | | /* Common Tx DMA descriptor fields */ |
| | | #define MT_TXD_INFO_LEN GENMASK(15, 0) |
| | | #define MT_TXD_INFO_D_PORT GENMASK(29, 27) |
| | | #define MT_TXD_INFO_TYPE GENMASK(31, 30) |
| | | |
| | | enum mt76_msg_port { |
| | | WLAN_PORT, |
| | | CPU_RX_PORT, |
| | | CPU_TX_PORT, |
| | | HOST_PORT, |
| | | VIRTUAL_CPU_RX_PORT, |
| | | VIRTUAL_CPU_TX_PORT, |
| | | DISCARD, |
| | | }; |
| | | |
| | | enum mt76_info_type { |
| | | DMA_PACKET, |
| | | DMA_COMMAND, |
| | | }; |
| | | |
| | | /* Tx DMA packet specific flags */ |
| | | #define MT_TXD_PKT_INFO_NEXT_VLD BIT(16) |
| | | #define MT_TXD_PKT_INFO_TX_BURST BIT(17) |
| | | #define MT_TXD_PKT_INFO_80211 BIT(19) |
| | | #define MT_TXD_PKT_INFO_TSO BIT(20) |
| | | #define MT_TXD_PKT_INFO_CSO BIT(21) |
| | | #define MT_TXD_PKT_INFO_WIV BIT(24) |
| | | #define MT_TXD_PKT_INFO_QSEL GENMASK(26, 25) |
| | | |
| | | enum mt76_qsel { |
| | | MT_QSEL_MGMT, |
| | | MT_QSEL_HCCA, |
| | | MT_QSEL_EDCA, |
| | | MT_QSEL_EDCA_2, |
| | | }; |
| | | |
| | | /* Tx DMA MCU command specific flags */ |
| | | #define MT_TXD_CMD_INFO_SEQ GENMASK(19, 16) |
| | | #define MT_TXD_CMD_INFO_TYPE GENMASK(26, 20) |
| | | |
| | | static inline int mt7601u_dma_skb_wrap(struct sk_buff *skb, |
| | | enum mt76_msg_port d_port, |
| | | enum mt76_info_type type, u32 flags) |
| | | { |
| | | u32 info; |
| | | |
| | | /* Buffer layout: |
| | | * | 4B | xfer len | pad | 4B | |
| | | * | TXINFO | pkt/cmd | zero pad to 4B | zero | |
| | | * |
| | | * length field of TXINFO should be set to 'xfer len'. |
| | | */ |
| | | |
| | | info = flags | |
| | | MT76_SET(MT_TXD_INFO_LEN, round_up(skb->len, 4)) | |
| | | MT76_SET(MT_TXD_INFO_D_PORT, d_port) | |
| | | MT76_SET(MT_TXD_INFO_TYPE, type); |
| | | |
| | | put_unaligned_le32(info, skb_push(skb, sizeof(info))); |
| | | return skb_put_padto(skb, round_up(skb->len, 4) + 4); |
| | | } |
| | | |
| | | static inline int |
| | | mt7601u_dma_skb_wrap_pkt(struct sk_buff *skb, enum mt76_qsel qsel, u32 flags) |
| | | { |
| | | flags |= MT76_SET(MT_TXD_PKT_INFO_QSEL, qsel); |
| | | return mt7601u_dma_skb_wrap(skb, WLAN_PORT, DMA_PACKET, flags); |
| | | } |
| | | |
| | | /* Common Rx DMA descriptor fields */ |
| | | #define MT_RXD_INFO_LEN GENMASK(13, 0) |
| | | #define MT_RXD_INFO_PCIE_INTR BIT(24) |
| | | #define MT_RXD_INFO_QSEL GENMASK(26, 25) |
| | | #define MT_RXD_INFO_PORT GENMASK(29, 27) |
| | | #define MT_RXD_INFO_TYPE GENMASK(31, 30) |
| | | |
| | | /* Rx DMA packet specific flags */ |
| | | #define MT_RXD_PKT_INFO_UDP_ERR BIT(16) |
| | | #define MT_RXD_PKT_INFO_TCP_ERR BIT(17) |
| | | #define MT_RXD_PKT_INFO_IP_ERR BIT(18) |
| | | #define MT_RXD_PKT_INFO_PKT_80211 BIT(19) |
| | | #define MT_RXD_PKT_INFO_L3L4_DONE BIT(20) |
| | | #define MT_RXD_PKT_INFO_MAC_LEN GENMASK(23, 21) |
| | | |
| | | /* Rx DMA MCU command specific flags */ |
| | | #define MT_RXD_CMD_INFO_SELF_GEN BIT(15) |
| | | #define MT_RXD_CMD_INFO_CMD_SEQ GENMASK(19, 16) |
| | | #define MT_RXD_CMD_INFO_EVT_TYPE GENMASK(23, 20) |
| | | |
| | | enum mt76_evt_type { |
| | | CMD_DONE, |
| | | CMD_ERROR, |
| | | CMD_RETRY, |
| | | EVENT_PWR_RSP, |
| | | EVENT_WOW_RSP, |
| | | EVENT_CARRIER_DETECT_RSP, |
| | | EVENT_DFS_DETECT_RSP, |
| | | }; |
| | | |
| | | #endif |
New file |
| | |
| | | /* |
| | | * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> |
| | | * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> |
| | | * |
| | | * This program is free software; you can redistribute it and/or modify |
| | | * it under the terms of the GNU General Public License version 2 |
| | | * as published by the Free Software Foundation |
| | | * |
| | | * This program is distributed in the hope that it will be useful, |
| | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| | | * GNU General Public License for more details. |
| | | */ |
| | | |
| | | #include <linux/of.h> |
| | | #include <linux/mtd/mtd.h> |
| | | #include <linux/mtd/partitions.h> |
| | | #include <linux/etherdevice.h> |
| | | #include <asm/unaligned.h> |
| | | #include "mt7601u.h" |
| | | #include "eeprom.h" |
| | | |
| | | static bool |
| | | field_valid(u8 val) |
| | | { |
| | | return val != 0xff; |
| | | } |
| | | |
| | | static s8 |
| | | field_validate(u8 val) |
| | | { |
| | | if (!field_valid(val)) |
| | | return 0; |
| | | |
| | | return val; |
| | | } |
| | | |
| | | static int |
| | | mt7601u_efuse_read(struct mt7601u_dev *dev, u16 addr, u8 *data, |
| | | enum mt7601u_eeprom_access_modes mode) |
| | | { |
| | | u32 val; |
| | | int i; |
| | | |
| | | val = mt76_rr(dev, MT_EFUSE_CTRL); |
| | | val &= ~(MT_EFUSE_CTRL_AIN | |
| | | MT_EFUSE_CTRL_MODE); |
| | | val |= MT76_SET(MT_EFUSE_CTRL_AIN, addr & ~0xf) | |
| | | MT76_SET(MT_EFUSE_CTRL_MODE, mode) | |
| | | MT_EFUSE_CTRL_KICK; |
| | | mt76_wr(dev, MT_EFUSE_CTRL, val); |
| | | |
| | | if (!mt76_poll(dev, MT_EFUSE_CTRL, MT_EFUSE_CTRL_KICK, 0, 1000)) |
| | | return -ETIMEDOUT; |
| | | |
| | | val = mt76_rr(dev, MT_EFUSE_CTRL); |
| | | if ((val & MT_EFUSE_CTRL_AOUT) == MT_EFUSE_CTRL_AOUT) { |
| | | /* Parts of eeprom not in the usage map (0x80-0xc0,0xf0) |
| | | * will not return valid data but it's ok. |
| | | */ |
| | | memset(data, 0xff, 16); |
| | | return 0; |
| | | } |
| | | |
| | | for (i = 0; i < 4; i++) { |
| | | val = mt76_rr(dev, MT_EFUSE_DATA(i)); |
| | | put_unaligned_le32(val, data + 4 * i); |
| | | } |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | static int |
| | | mt7601u_efuse_physical_size_check(struct mt7601u_dev *dev) |
| | | { |
| | | const int map_reads = DIV_ROUND_UP(MT_EFUSE_USAGE_MAP_SIZE, 16); |
| | | u8 data[map_reads * 16]; |
| | | int ret, i; |
| | | u32 start = 0, end = 0, cnt_free; |
| | | |
| | | for (i = 0; i < map_reads; i++) { |
| | | ret = mt7601u_efuse_read(dev, MT_EE_USAGE_MAP_START + i * 16, |
| | | data + i * 16, MT_EE_PHYSICAL_READ); |
| | | if (ret) |
| | | return ret; |
| | | } |
| | | |
| | | for (i = 0; i < MT_EFUSE_USAGE_MAP_SIZE; i++) |
| | | if (!data[i]) { |
| | | if (!start) |
| | | start = MT_EE_USAGE_MAP_START + i; |
| | | end = MT_EE_USAGE_MAP_START + i; |
| | | } |
| | | cnt_free = end - start + 1; |
| | | |
| | | if (MT_EFUSE_USAGE_MAP_SIZE - cnt_free < 5) { |
| | | dev_err(dev->dev, "Error: your device needs default EEPROM file and this driver doesn't support it!\n"); |
| | | return -EINVAL; |
| | | } |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | static bool |
| | | mt7601u_has_tssi(struct mt7601u_dev *dev, u8 *eeprom) |
| | | { |
| | | u16 nic_conf1 = get_unaligned_le16(eeprom + MT_EE_NIC_CONF_1); |
| | | |
| | | return ~nic_conf1 && (nic_conf1 & MT_EE_NIC_CONF_1_TX_ALC_EN); |
| | | } |
| | | |
| | | static void |
| | | mt7601u_set_chip_cap(struct mt7601u_dev *dev, u8 *eeprom) |
| | | { |
| | | u16 nic_conf0 = get_unaligned_le16(eeprom + MT_EE_NIC_CONF_0); |
| | | u16 nic_conf1 = get_unaligned_le16(eeprom + MT_EE_NIC_CONF_1); |
| | | |
| | | if (!field_valid(nic_conf1 & 0xff)) |
| | | nic_conf1 &= 0xff00; |
| | | |
| | | dev->ee->tssi_enabled = mt7601u_has_tssi(dev, eeprom) && |
| | | !(nic_conf1 & MT_EE_NIC_CONF_1_TEMP_TX_ALC); |
| | | |
| | | if (nic_conf1 & MT_EE_NIC_CONF_1_HW_RF_CTRL) |
| | | dev_err(dev->dev, |
| | | "Error: this driver does not support HW RF ctrl\n"); |
| | | |
| | | if (!field_valid(nic_conf0 >> 8)) |
| | | return; |
| | | |
| | | if (MT76_GET(MT_EE_NIC_CONF_0_RX_PATH, nic_conf0) > 1 || |
| | | MT76_GET(MT_EE_NIC_CONF_0_TX_PATH, nic_conf0) > 1) |
| | | dev_err(dev->dev, |
| | | "Error: device has more than 1 RX/TX stream!\n"); |
| | | } |
| | | |
| | | static int |
| | | mt7601u_set_macaddr(struct mt7601u_dev *dev, const u8 *eeprom) |
| | | { |
| | | const void *src = eeprom + MT_EE_MAC_ADDR; |
| | | |
| | | ether_addr_copy(dev->macaddr, src); |
| | | |
| | | if (!is_valid_ether_addr(dev->macaddr)) { |
| | | eth_random_addr(dev->macaddr); |
| | | dev_info(dev->dev, |
| | | "Invalid MAC address, using random address %pM\n", |
| | | dev->macaddr); |
| | | } |
| | | |
| | | mt76_wr(dev, MT_MAC_ADDR_DW0, get_unaligned_le32(dev->macaddr)); |
| | | mt76_wr(dev, MT_MAC_ADDR_DW1, get_unaligned_le16(dev->macaddr + 4) | |
| | | MT76_SET(MT_MAC_ADDR_DW1_U2ME_MASK, 0xff)); |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | static void mt7601u_set_channel_target_power(struct mt7601u_dev *dev, |
| | | u8 *eeprom, u8 max_pwr) |
| | | { |
| | | u8 trgt_pwr = eeprom[MT_EE_TX_TSSI_TARGET_POWER]; |
| | | |
| | | if (trgt_pwr > max_pwr || !trgt_pwr) { |
| | | dev_warn(dev->dev, "Error: EEPROM trgt power invalid %hhx!\n", |
| | | trgt_pwr); |
| | | trgt_pwr = 0x20; |
| | | } |
| | | |
| | | memset(dev->ee->chan_pwr, trgt_pwr, sizeof(dev->ee->chan_pwr)); |
| | | } |
| | | |
| | | static void |
| | | mt7601u_set_channel_power(struct mt7601u_dev *dev, u8 *eeprom) |
| | | { |
| | | u32 i, val; |
| | | u8 max_pwr; |
| | | |
| | | val = mt7601u_rr(dev, MT_TX_ALC_CFG_0); |
| | | max_pwr = MT76_GET(MT_TX_ALC_CFG_0_LIMIT_0, val); |
| | | |
| | | if (mt7601u_has_tssi(dev, eeprom)) { |
| | | mt7601u_set_channel_target_power(dev, eeprom, max_pwr); |
| | | return; |
| | | } |
| | | |
| | | for (i = 0; i < 14; i++) { |
| | | s8 power = field_validate(eeprom[MT_EE_TX_POWER_OFFSET + i]); |
| | | |
| | | if (power > max_pwr || power < 0) |
| | | power = MT7601U_DEFAULT_TX_POWER; |
| | | |
| | | dev->ee->chan_pwr[i] = power; |
| | | } |
| | | } |
| | | |
| | | static void |
| | | mt7601u_set_country_reg(struct mt7601u_dev *dev, u8 *eeprom) |
| | | { |
| | | /* Note: - region 31 is not valid for mt7601u (see rtmp_init.c) |
| | | * - comments in rtmp_def.h are incorrect (see rt_channel.c) |
| | | */ |
| | | static const struct reg_channel_bounds chan_bounds[] = { |
| | | /* EEPROM country regions 0 - 7 */ |
| | | { 1, 11 }, { 1, 13 }, { 10, 2 }, { 10, 4 }, |
| | | { 14, 1 }, { 1, 14 }, { 3, 7 }, { 5, 9 }, |
| | | /* EEPROM country regions 32 - 33 */ |
| | | { 1, 11 }, { 1, 14 } |
| | | }; |
| | | u8 val = eeprom[MT_EE_COUNTRY_REGION]; |
| | | int idx = -1; |
| | | |
| | | if (val < 8) |
| | | idx = val; |
| | | if (val > 31 && val < 33) |
| | | idx = val - 32 + 8; |
| | | |
| | | if (idx != -1) |
| | | dev_info(dev->dev, |
| | | "EEPROM country region %02hhx (channels %hhd-%hhd)\n", |
| | | val, chan_bounds[idx].start, |
| | | chan_bounds[idx].start + chan_bounds[idx].num - 1); |
| | | else |
| | | idx = 5; /* channels 1 - 14 */ |
| | | |
| | | dev->ee->reg = chan_bounds[idx]; |
| | | |
| | | /* TODO: country region 33 is special - phy should be set to B-mode |
| | | * before entering channel 14 (see sta/connect.c) |
| | | */ |
| | | } |
| | | |
| | | static void |
| | | mt7601u_set_rf_freq_off(struct mt7601u_dev *dev, u8 *eeprom) |
| | | { |
| | | u8 comp; |
| | | |
| | | dev->ee->rf_freq_off = field_validate(eeprom[MT_EE_FREQ_OFFSET]); |
| | | comp = field_validate(eeprom[MT_EE_FREQ_OFFSET_COMPENSATION]); |
| | | |
| | | if (comp & BIT(7)) |
| | | dev->ee->rf_freq_off -= comp & 0x7f; |
| | | else |
| | | dev->ee->rf_freq_off += comp; |
| | | } |
| | | |
| | | static void |
| | | mt7601u_set_rssi_offset(struct mt7601u_dev *dev, u8 *eeprom) |
| | | { |
| | | int i; |
| | | s8 *rssi_offset = dev->ee->rssi_offset; |
| | | |
| | | for (i = 0; i < 2; i++) { |
| | | rssi_offset[i] = eeprom[MT_EE_RSSI_OFFSET + i]; |
| | | |
| | | if (rssi_offset[i] < -10 || rssi_offset[i] > 10) { |
| | | dev_warn(dev->dev, |
| | | "Warning: EEPROM RSSI is invalid %02hhx\n", |
| | | rssi_offset[i]); |
| | | rssi_offset[i] = 0; |
| | | } |
| | | } |
| | | } |
| | | |
| | | static void |
| | | mt7601u_extra_power_over_mac(struct mt7601u_dev *dev) |
| | | { |
| | | u32 val; |
| | | |
| | | val = ((mt7601u_rr(dev, MT_TX_PWR_CFG_1) & 0x0000ff00) >> 8); |
| | | val |= ((mt7601u_rr(dev, MT_TX_PWR_CFG_2) & 0x0000ff00) << 8); |
| | | mt7601u_wr(dev, MT_TX_PWR_CFG_7, val); |
| | | |
| | | val = ((mt7601u_rr(dev, MT_TX_PWR_CFG_4) & 0x0000ff00) >> 8); |
| | | mt7601u_wr(dev, MT_TX_PWR_CFG_9, val); |
| | | } |
| | | |
| | | static void |
| | | mt7601u_set_power_rate(struct power_per_rate *rate, s8 delta, u8 value) |
| | | { |
| | | /* Invalid? Note: vendor driver does not handle this */ |
| | | if (value == 0xff) |
| | | return; |
| | | |
| | | rate->raw = s6_validate(value); |
| | | rate->bw20 = s6_to_int(value); |
| | | /* Note: vendor driver does cap the value to s6 right away */ |
| | | rate->bw40 = rate->bw20 + delta; |
| | | } |
| | | |
| | | static void |
| | | mt7601u_save_power_rate(struct mt7601u_dev *dev, s8 delta, u32 val, int i) |
| | | { |
| | | struct mt7601u_rate_power *t = &dev->ee->power_rate_table; |
| | | |
| | | switch (i) { |
| | | case 0: |
| | | mt7601u_set_power_rate(&t->cck[0], delta, (val >> 0) & 0xff); |
| | | mt7601u_set_power_rate(&t->cck[1], delta, (val >> 8) & 0xff); |
| | | /* Save cck bw20 for fixups of channel 14 */ |
| | | dev->ee->real_cck_bw20[0] = t->cck[0].bw20; |
| | | dev->ee->real_cck_bw20[1] = t->cck[1].bw20; |
| | | |
| | | mt7601u_set_power_rate(&t->ofdm[0], delta, (val >> 16) & 0xff); |
| | | mt7601u_set_power_rate(&t->ofdm[1], delta, (val >> 24) & 0xff); |
| | | break; |
| | | case 1: |
| | | mt7601u_set_power_rate(&t->ofdm[2], delta, (val >> 0) & 0xff); |
| | | mt7601u_set_power_rate(&t->ofdm[3], delta, (val >> 8) & 0xff); |
| | | mt7601u_set_power_rate(&t->ht[0], delta, (val >> 16) & 0xff); |
| | | mt7601u_set_power_rate(&t->ht[1], delta, (val >> 24) & 0xff); |
| | | break; |
| | | case 2: |
| | | mt7601u_set_power_rate(&t->ht[2], delta, (val >> 0) & 0xff); |
| | | mt7601u_set_power_rate(&t->ht[3], delta, (val >> 8) & 0xff); |
| | | break; |
| | | } |
| | | } |
| | | |
| | | static s8 |
| | | get_delta(u8 val) |
| | | { |
| | | s8 ret; |
| | | |
| | | if (!field_valid(val) || !(val & BIT(7))) |
| | | return 0; |
| | | |
| | | ret = val & 0x1f; |
| | | if (ret > 8) |
| | | ret = 8; |
| | | if (val & BIT(6)) |
| | | ret = -ret; |
| | | |
| | | return ret; |
| | | } |
| | | |
| | | static void |
| | | mt7601u_config_tx_power_per_rate(struct mt7601u_dev *dev, u8 *eeprom) |
| | | { |
| | | u32 val; |
| | | s8 bw40_delta; |
| | | int i; |
| | | |
| | | bw40_delta = get_delta(eeprom[MT_EE_TX_POWER_DELTA_BW40]); |
| | | |
| | | for (i = 0; i < 5; i++) { |
| | | val = get_unaligned_le32(eeprom + MT_EE_TX_POWER_BYRATE(i)); |
| | | |
| | | mt7601u_save_power_rate(dev, bw40_delta, val, i); |
| | | |
| | | if (~val) |
| | | mt7601u_wr(dev, MT_TX_PWR_CFG_0 + i * 4, val); |
| | | } |
| | | |
| | | mt7601u_extra_power_over_mac(dev); |
| | | } |
| | | |
| | | static void |
| | | mt7601u_init_tssi_params(struct mt7601u_dev *dev, u8 *eeprom) |
| | | { |
| | | struct tssi_data *d = &dev->ee->tssi_data; |
| | | |
| | | if (!dev->ee->tssi_enabled) |
| | | return; |
| | | |
| | | d->slope = eeprom[MT_EE_TX_TSSI_SLOPE]; |
| | | d->tx0_delta_offset = eeprom[MT_EE_TX_TSSI_OFFSET] * 1024; |
| | | d->offset[0] = eeprom[MT_EE_TX_TSSI_OFFSET_GROUP]; |
| | | d->offset[1] = eeprom[MT_EE_TX_TSSI_OFFSET_GROUP + 1]; |
| | | d->offset[2] = eeprom[MT_EE_TX_TSSI_OFFSET_GROUP + 2]; |
| | | } |
| | | |
| | | int |
| | | mt7601u_eeprom_init(struct mt7601u_dev *dev) |
| | | { |
| | | u8 *eeprom; |
| | | int i, ret; |
| | | |
| | | ret = mt7601u_efuse_physical_size_check(dev); |
| | | if (ret) |
| | | return ret; |
| | | |
| | | dev->ee = devm_kzalloc(dev->dev, sizeof(*dev->ee), GFP_KERNEL); |
| | | if (!dev->ee) |
| | | return -ENOMEM; |
| | | |
| | | eeprom = kmalloc(MT7601U_EEPROM_SIZE, GFP_KERNEL); |
| | | if (!eeprom) |
| | | return -ENOMEM; |
| | | |
| | | for (i = 0; i + 16 <= MT7601U_EEPROM_SIZE; i += 16) { |
| | | ret = mt7601u_efuse_read(dev, i, eeprom + i, MT_EE_READ); |
| | | if (ret) |
| | | goto out; |
| | | } |
| | | |
| | | if (eeprom[MT_EE_VERSION_EE] > MT7601U_EE_MAX_VER) |
| | | dev_warn(dev->dev, |
| | | "Warning: unsupported EEPROM version %02hhx\n", |
| | | eeprom[MT_EE_VERSION_EE]); |
| | | dev_info(dev->dev, "EEPROM ver:%02hhx fae:%02hhx\n", |
| | | eeprom[MT_EE_VERSION_EE], eeprom[MT_EE_VERSION_FAE]); |
| | | |
| | | mt7601u_set_macaddr(dev, eeprom); |
| | | mt7601u_set_chip_cap(dev, eeprom); |
| | | mt7601u_set_channel_power(dev, eeprom); |
| | | mt7601u_set_country_reg(dev, eeprom); |
| | | mt7601u_set_rf_freq_off(dev, eeprom); |
| | | mt7601u_set_rssi_offset(dev, eeprom); |
| | | dev->ee->ref_temp = eeprom[MT_EE_REF_TEMP]; |
| | | dev->ee->lna_gain = eeprom[MT_EE_LNA_GAIN]; |
| | | |
| | | mt7601u_config_tx_power_per_rate(dev, eeprom); |
| | | |
| | | mt7601u_init_tssi_params(dev, eeprom); |
| | | out: |
| | | kfree(eeprom); |
| | | return ret; |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> |
| | | * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> |
| | | * |
| | | * This program is free software; you can redistribute it and/or modify |
| | | * it under the terms of the GNU General Public License version 2 |
| | | * as published by the Free Software Foundation |
| | | * |
| | | * This program is distributed in the hope that it will be useful, |
| | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| | | * GNU General Public License for more details. |
| | | */ |
| | | |
| | | #ifndef __MT7601U_EEPROM_H |
| | | #define __MT7601U_EEPROM_H |
| | | |
| | | struct mt7601u_dev; |
| | | |
| | | #define MT7601U_EE_MAX_VER 0x0c |
| | | #define MT7601U_EEPROM_SIZE 256 |
| | | |
| | | #define MT7601U_DEFAULT_TX_POWER 6 |
| | | |
| | | enum mt76_eeprom_field { |
| | | MT_EE_CHIP_ID = 0x00, |
| | | MT_EE_VERSION_FAE = 0x02, |
| | | MT_EE_VERSION_EE = 0x03, |
| | | MT_EE_MAC_ADDR = 0x04, |
| | | MT_EE_NIC_CONF_0 = 0x34, |
| | | MT_EE_NIC_CONF_1 = 0x36, |
| | | MT_EE_COUNTRY_REGION = 0x39, |
| | | MT_EE_FREQ_OFFSET = 0x3a, |
| | | MT_EE_NIC_CONF_2 = 0x42, |
| | | |
| | | MT_EE_LNA_GAIN = 0x44, |
| | | MT_EE_RSSI_OFFSET = 0x46, |
| | | |
| | | MT_EE_TX_POWER_DELTA_BW40 = 0x50, |
| | | MT_EE_TX_POWER_OFFSET = 0x52, |
| | | |
| | | MT_EE_TX_TSSI_SLOPE = 0x6e, |
| | | MT_EE_TX_TSSI_OFFSET_GROUP = 0x6f, |
| | | MT_EE_TX_TSSI_OFFSET = 0x76, |
| | | |
| | | MT_EE_TX_TSSI_TARGET_POWER = 0xd0, |
| | | MT_EE_REF_TEMP = 0xd1, |
| | | MT_EE_FREQ_OFFSET_COMPENSATION = 0xdb, |
| | | MT_EE_TX_POWER_BYRATE_BASE = 0xde, |
| | | |
| | | MT_EE_USAGE_MAP_START = 0x1e0, |
| | | MT_EE_USAGE_MAP_END = 0x1fc, |
| | | }; |
| | | |
| | | #define MT_EE_NIC_CONF_0_RX_PATH GENMASK(3, 0) |
| | | #define MT_EE_NIC_CONF_0_TX_PATH GENMASK(7, 4) |
| | | #define MT_EE_NIC_CONF_0_BOARD_TYPE GENMASK(13, 12) |
| | | |
| | | #define MT_EE_NIC_CONF_1_HW_RF_CTRL BIT(0) |
| | | #define MT_EE_NIC_CONF_1_TEMP_TX_ALC BIT(1) |
| | | #define MT_EE_NIC_CONF_1_LNA_EXT_2G BIT(2) |
| | | #define MT_EE_NIC_CONF_1_LNA_EXT_5G BIT(3) |
| | | #define MT_EE_NIC_CONF_1_TX_ALC_EN BIT(13) |
| | | |
| | | #define MT_EE_NIC_CONF_2_RX_STREAM GENMASK(3, 0) |
| | | #define MT_EE_NIC_CONF_2_TX_STREAM GENMASK(7, 4) |
| | | #define MT_EE_NIC_CONF_2_HW_ANTDIV BIT(8) |
| | | #define MT_EE_NIC_CONF_2_XTAL_OPTION GENMASK(10, 9) |
| | | #define MT_EE_NIC_CONF_2_TEMP_DISABLE BIT(11) |
| | | #define MT_EE_NIC_CONF_2_COEX_METHOD GENMASK(15, 13) |
| | | |
| | | #define MT_EE_TX_POWER_BYRATE(i) (MT_EE_TX_POWER_BYRATE_BASE + \ |
| | | (i) * 4) |
| | | |
| | | #define MT_EFUSE_USAGE_MAP_SIZE (MT_EE_USAGE_MAP_END - \ |
| | | MT_EE_USAGE_MAP_START + 1) |
| | | |
| | | enum mt7601u_eeprom_access_modes { |
| | | MT_EE_READ = 0, |
| | | MT_EE_PHYSICAL_READ = 1, |
| | | }; |
| | | |
| | | struct power_per_rate { |
| | | u8 raw; /* validated s6 value */ |
| | | s8 bw20; /* sign-extended int */ |
| | | s8 bw40; /* sign-extended int */ |
| | | }; |
| | | |
| | | /* Power per rate - one value per two rates */ |
| | | struct mt7601u_rate_power { |
| | | struct power_per_rate cck[2]; |
| | | struct power_per_rate ofdm[4]; |
| | | struct power_per_rate ht[4]; |
| | | }; |
| | | |
| | | struct reg_channel_bounds { |
| | | u8 start; |
| | | u8 num; |
| | | }; |
| | | |
| | | struct mt7601u_eeprom_params { |
| | | bool tssi_enabled; |
| | | u8 rf_freq_off; |
| | | s8 rssi_offset[2]; |
| | | s8 ref_temp; |
| | | s8 lna_gain; |
| | | |
| | | u8 chan_pwr[14]; |
| | | struct mt7601u_rate_power power_rate_table; |
| | | s8 real_cck_bw20[2]; |
| | | |
| | | /* TSSI stuff - only with internal TX ALC */ |
| | | struct tssi_data { |
| | | int tx0_delta_offset; |
| | | u8 slope; |
| | | u8 offset[3]; |
| | | } tssi_data; |
| | | |
| | | struct reg_channel_bounds reg; |
| | | }; |
| | | |
| | | int mt7601u_eeprom_init(struct mt7601u_dev *dev); |
| | | |
| | | static inline u32 s6_validate(u32 reg) |
| | | { |
| | | WARN_ON(reg & ~GENMASK(5, 0)); |
| | | return reg & GENMASK(5, 0); |
| | | } |
| | | |
| | | static inline int s6_to_int(u32 reg) |
| | | { |
| | | int s6; |
| | | |
| | | s6 = s6_validate(reg); |
| | | if (s6 & BIT(5)) |
| | | s6 -= BIT(6); |
| | | |
| | | return s6; |
| | | } |
| | | |
| | | static inline u32 int_to_s6(int val) |
| | | { |
| | | if (val < -0x20) |
| | | return 0x20; |
| | | if (val > 0x1f) |
| | | return 0x1f; |
| | | |
| | | return val & 0x3f; |
| | | } |
| | | |
| | | #endif |
New file |
| | |
| | | /* |
| | | * (c) Copyright 2002-2010, Ralink Technology, Inc. |
| | | * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> |
| | | * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> |
| | | * |
| | | * This program is free software; you can redistribute it and/or modify |
| | | * it under the terms of the GNU General Public License version 2 |
| | | * as published by the Free Software Foundation |
| | | * |
| | | * This program is distributed in the hope that it will be useful, |
| | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| | | * GNU General Public License for more details. |
| | | */ |
| | | |
| | | #include <linux/version.h> |
| | | |
| | | #include "mt7601u.h" |
| | | #include "eeprom.h" |
| | | #include "trace.h" |
| | | #include "mcu.h" |
| | | |
| | | #include "initvals.h" |
| | | |
| | | static void |
| | | mt7601u_set_wlan_state(struct mt7601u_dev *dev, u32 val, bool enable) |
| | | { |
| | | int i; |
| | | |
| | | /* Note: we don't turn off WLAN_CLK because that makes the device |
| | | * not respond properly on the probe path. |
| | | * In case anyone (PSM?) wants to use this function we can |
| | | * bring the clock stuff back and fixup the probe path. |
| | | */ |
| | | |
| | | if (enable) |
| | | val |= (MT_WLAN_FUN_CTRL_WLAN_EN | |
| | | MT_WLAN_FUN_CTRL_WLAN_CLK_EN); |
| | | else |
| | | val &= ~(MT_WLAN_FUN_CTRL_WLAN_EN); |
| | | |
| | | mt7601u_wr(dev, MT_WLAN_FUN_CTRL, val); |
| | | udelay(20); |
| | | |
| | | if (enable) { |
| | | set_bit(MT7601U_STATE_WLAN_RUNNING, &dev->state); |
| | | } else { |
| | | clear_bit(MT7601U_STATE_WLAN_RUNNING, &dev->state); |
| | | return; |
| | | } |
| | | |
| | | for (i = 200; i; i--) { |
| | | val = mt7601u_rr(dev, MT_CMB_CTRL); |
| | | |
| | | if (val & MT_CMB_CTRL_XTAL_RDY && val & MT_CMB_CTRL_PLL_LD) |
| | | break; |
| | | |
| | | udelay(20); |
| | | } |
| | | |
| | | /* Note: vendor driver tries to disable/enable wlan here and retry |
| | | * but the code which does it is so buggy it must have never |
| | | * triggered, so don't bother. |
| | | */ |
| | | if (!i) |
| | | dev_err(dev->dev, "Error: PLL and XTAL check failed!\n"); |
| | | } |
| | | |
| | | static void mt7601u_chip_onoff(struct mt7601u_dev *dev, bool enable, bool reset) |
| | | { |
| | | u32 val; |
| | | |
| | | mutex_lock(&dev->hw_atomic_mutex); |
| | | |
| | | val = mt7601u_rr(dev, MT_WLAN_FUN_CTRL); |
| | | |
| | | if (reset) { |
| | | val |= MT_WLAN_FUN_CTRL_GPIO_OUT_EN; |
| | | val &= ~MT_WLAN_FUN_CTRL_FRC_WL_ANT_SEL; |
| | | |
| | | if (val & MT_WLAN_FUN_CTRL_WLAN_EN) { |
| | | val |= (MT_WLAN_FUN_CTRL_WLAN_RESET | |
| | | MT_WLAN_FUN_CTRL_WLAN_RESET_RF); |
| | | mt7601u_wr(dev, MT_WLAN_FUN_CTRL, val); |
| | | udelay(20); |
| | | |
| | | val &= ~(MT_WLAN_FUN_CTRL_WLAN_RESET | |
| | | MT_WLAN_FUN_CTRL_WLAN_RESET_RF); |
| | | } |
| | | } |
| | | |
| | | mt7601u_wr(dev, MT_WLAN_FUN_CTRL, val); |
| | | udelay(20); |
| | | |
| | | mt7601u_set_wlan_state(dev, val, enable); |
| | | |
| | | mutex_unlock(&dev->hw_atomic_mutex); |
| | | } |
| | | |
| | | static void mt7601u_reset_csr_bbp(struct mt7601u_dev *dev) |
| | | { |
| | | mt7601u_wr(dev, MT_MAC_SYS_CTRL, (MT_MAC_SYS_CTRL_RESET_CSR | |
| | | MT_MAC_SYS_CTRL_RESET_BBP)); |
| | | mt7601u_wr(dev, MT_USB_DMA_CFG, 0); |
| | | msleep(1); |
| | | mt7601u_wr(dev, MT_MAC_SYS_CTRL, 0); |
| | | } |
| | | |
| | | static void mt7601u_init_usb_dma(struct mt7601u_dev *dev) |
| | | { |
| | | u32 val; |
| | | |
| | | val = MT76_SET(MT_USB_DMA_CFG_RX_BULK_AGG_TOUT, MT_USB_AGGR_TIMEOUT) | |
| | | MT76_SET(MT_USB_DMA_CFG_RX_BULK_AGG_LMT, MT_USB_AGGR_SIZE_LIMIT) | |
| | | MT_USB_DMA_CFG_RX_BULK_EN | |
| | | MT_USB_DMA_CFG_TX_BULK_EN; |
| | | if (dev->in_max_packet == 512) |
| | | val |= MT_USB_DMA_CFG_RX_BULK_AGG_EN; |
| | | mt7601u_wr(dev, MT_USB_DMA_CFG, val); |
| | | |
| | | val |= MT_USB_DMA_CFG_UDMA_RX_WL_DROP; |
| | | mt7601u_wr(dev, MT_USB_DMA_CFG, val); |
| | | val &= ~MT_USB_DMA_CFG_UDMA_RX_WL_DROP; |
| | | mt7601u_wr(dev, MT_USB_DMA_CFG, val); |
| | | } |
| | | |
| | | static int mt7601u_init_bbp(struct mt7601u_dev *dev) |
| | | { |
| | | int ret; |
| | | |
| | | ret = mt7601u_wait_bbp_ready(dev); |
| | | if (ret) |
| | | return ret; |
| | | |
| | | ret = mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_BBP, bbp_common_vals, |
| | | ARRAY_SIZE(bbp_common_vals)); |
| | | if (ret) |
| | | return ret; |
| | | |
| | | return mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_BBP, bbp_chip_vals, |
| | | ARRAY_SIZE(bbp_chip_vals)); |
| | | } |
| | | |
| | | static void |
| | | mt76_init_beacon_offsets(struct mt7601u_dev *dev) |
| | | { |
| | | u16 base = MT_BEACON_BASE; |
| | | u32 regs[4] = {}; |
| | | int i; |
| | | |
| | | for (i = 0; i < 16; i++) { |
| | | u16 addr = dev->beacon_offsets[i]; |
| | | |
| | | regs[i / 4] |= ((addr - base) / 64) << (8 * (i % 4)); |
| | | } |
| | | |
| | | for (i = 0; i < 4; i++) |
| | | mt7601u_wr(dev, MT_BCN_OFFSET(i), regs[i]); |
| | | } |
| | | |
| | | static int mt7601u_write_mac_initvals(struct mt7601u_dev *dev) |
| | | { |
| | | int ret; |
| | | |
| | | ret = mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_WLAN, mac_common_vals, |
| | | ARRAY_SIZE(mac_common_vals)); |
| | | if (ret) |
| | | return ret; |
| | | ret = mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_WLAN, |
| | | mac_chip_vals, ARRAY_SIZE(mac_chip_vals)); |
| | | if (ret) |
| | | return ret; |
| | | |
| | | mt76_init_beacon_offsets(dev); |
| | | |
| | | mt7601u_wr(dev, MT_AUX_CLK_CFG, 0); |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | static int mt7601u_init_wcid_mem(struct mt7601u_dev *dev) |
| | | { |
| | | u32 *vals; |
| | | int i, ret; |
| | | |
| | | vals = kmalloc(sizeof(*vals) * N_WCIDS * 2, GFP_KERNEL); |
| | | if (!vals) |
| | | return -ENOMEM; |
| | | |
| | | for (i = 0; i < N_WCIDS; i++) { |
| | | vals[i * 2] = 0xffffffff; |
| | | vals[i * 2 + 1] = 0x00ffffff; |
| | | } |
| | | |
| | | ret = mt7601u_burst_write_regs(dev, MT_WCID_ADDR_BASE, |
| | | vals, N_WCIDS * 2); |
| | | kfree(vals); |
| | | |
| | | return ret; |
| | | } |
| | | |
| | | static int mt7601u_init_key_mem(struct mt7601u_dev *dev) |
| | | { |
| | | u32 vals[4] = {}; |
| | | |
| | | return mt7601u_burst_write_regs(dev, MT_SKEY_MODE_BASE_0, |
| | | vals, ARRAY_SIZE(vals)); |
| | | } |
| | | |
| | | static int mt7601u_init_wcid_attr_mem(struct mt7601u_dev *dev) |
| | | { |
| | | u32 *vals; |
| | | int i, ret; |
| | | |
| | | vals = kmalloc(sizeof(*vals) * N_WCIDS * 2, GFP_KERNEL); |
| | | if (!vals) |
| | | return -ENOMEM; |
| | | |
| | | for (i = 0; i < N_WCIDS * 2; i++) |
| | | vals[i] = 1; |
| | | |
| | | ret = mt7601u_burst_write_regs(dev, MT_WCID_ATTR_BASE, |
| | | vals, N_WCIDS * 2); |
| | | kfree(vals); |
| | | |
| | | return ret; |
| | | } |
| | | |
| | | static void mt7601u_reset_counters(struct mt7601u_dev *dev) |
| | | { |
| | | mt7601u_rr(dev, MT_RX_STA_CNT0); |
| | | mt7601u_rr(dev, MT_RX_STA_CNT1); |
| | | mt7601u_rr(dev, MT_RX_STA_CNT2); |
| | | mt7601u_rr(dev, MT_TX_STA_CNT0); |
| | | mt7601u_rr(dev, MT_TX_STA_CNT1); |
| | | mt7601u_rr(dev, MT_TX_STA_CNT2); |
| | | } |
| | | |
| | | int mt7601u_mac_start(struct mt7601u_dev *dev) |
| | | { |
| | | mt7601u_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX); |
| | | |
| | | if (!mt76_poll(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_DMA_BUSY | |
| | | MT_WPDMA_GLO_CFG_RX_DMA_BUSY, 0, 200000)) |
| | | return -ETIMEDOUT; |
| | | |
| | | dev->rxfilter = MT_RX_FILTR_CFG_CRC_ERR | |
| | | MT_RX_FILTR_CFG_PHY_ERR | MT_RX_FILTR_CFG_PROMISC | |
| | | MT_RX_FILTR_CFG_VER_ERR | MT_RX_FILTR_CFG_DUP | |
| | | MT_RX_FILTR_CFG_CFACK | MT_RX_FILTR_CFG_CFEND | |
| | | MT_RX_FILTR_CFG_ACK | MT_RX_FILTR_CFG_CTS | |
| | | MT_RX_FILTR_CFG_RTS | MT_RX_FILTR_CFG_PSPOLL | |
| | | MT_RX_FILTR_CFG_BA | MT_RX_FILTR_CFG_CTRL_RSV; |
| | | mt7601u_wr(dev, MT_RX_FILTR_CFG, dev->rxfilter); |
| | | |
| | | mt7601u_wr(dev, MT_MAC_SYS_CTRL, |
| | | MT_MAC_SYS_CTRL_ENABLE_TX | MT_MAC_SYS_CTRL_ENABLE_RX); |
| | | |
| | | if (!mt76_poll(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_DMA_BUSY | |
| | | MT_WPDMA_GLO_CFG_RX_DMA_BUSY, 0, 50)) |
| | | return -ETIMEDOUT; |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | static void mt7601u_mac_stop_hw(struct mt7601u_dev *dev) |
| | | { |
| | | int i, ok; |
| | | |
| | | if (test_bit(MT7601U_STATE_REMOVED, &dev->state)) |
| | | return; |
| | | |
| | | mt76_clear(dev, MT_BEACON_TIME_CFG, MT_BEACON_TIME_CFG_TIMER_EN | |
| | | MT_BEACON_TIME_CFG_SYNC_MODE | MT_BEACON_TIME_CFG_TBTT_EN | |
| | | MT_BEACON_TIME_CFG_BEACON_TX); |
| | | |
| | | if (!mt76_poll(dev, MT_USB_DMA_CFG, MT_USB_DMA_CFG_TX_BUSY, 0, 1000)) |
| | | dev_warn(dev->dev, "Warning: TX DMA did not stop!\n"); |
| | | |
| | | /* Page count on TxQ */ |
| | | i = 200; |
| | | while (i-- && ((mt76_rr(dev, 0x0438) & 0xffffffff) || |
| | | (mt76_rr(dev, 0x0a30) & 0x000000ff) || |
| | | (mt76_rr(dev, 0x0a34) & 0x00ff00ff))) |
| | | msleep(10); |
| | | |
| | | if (!mt76_poll(dev, MT_MAC_STATUS, MT_MAC_STATUS_TX, 0, 1000)) |
| | | dev_warn(dev->dev, "Warning: MAC TX did not stop!\n"); |
| | | |
| | | mt76_clear(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_RX | |
| | | MT_MAC_SYS_CTRL_ENABLE_TX); |
| | | |
| | | /* Page count on RxQ */ |
| | | ok = 0; |
| | | i = 200; |
| | | while (i--) { |
| | | if (!(mt76_rr(dev, MT_RXQ_STA) & 0x00ff0000) && |
| | | !mt76_rr(dev, 0x0a30) && |
| | | !mt76_rr(dev, 0x0a34)) { |
| | | if (ok++ > 5) |
| | | break; |
| | | continue; |
| | | } |
| | | msleep(1); |
| | | } |
| | | |
| | | if (!mt76_poll(dev, MT_MAC_STATUS, MT_MAC_STATUS_RX, 0, 1000)) |
| | | dev_warn(dev->dev, "Warning: MAC RX did not stop!\n"); |
| | | |
| | | if (!mt76_poll(dev, MT_USB_DMA_CFG, MT_USB_DMA_CFG_RX_BUSY, 0, 1000)) |
| | | dev_warn(dev->dev, "Warning: RX DMA did not stop!\n"); |
| | | } |
| | | |
| | | void mt7601u_mac_stop(struct mt7601u_dev *dev) |
| | | { |
| | | mt7601u_mac_stop_hw(dev); |
| | | flush_delayed_work(&dev->stat_work); |
| | | cancel_delayed_work_sync(&dev->stat_work); |
| | | } |
| | | |
| | | static void mt7601u_stop_hardware(struct mt7601u_dev *dev) |
| | | { |
| | | mt7601u_chip_onoff(dev, false, false); |
| | | } |
| | | |
| | | int mt7601u_init_hardware(struct mt7601u_dev *dev) |
| | | { |
| | | static const u16 beacon_offsets[16] = { |
| | | /* 512 byte per beacon */ |
| | | 0xc000, 0xc200, 0xc400, 0xc600, |
| | | 0xc800, 0xca00, 0xcc00, 0xce00, |
| | | 0xd000, 0xd200, 0xd400, 0xd600, |
| | | 0xd800, 0xda00, 0xdc00, 0xde00 |
| | | }; |
| | | int ret; |
| | | |
| | | dev->beacon_offsets = beacon_offsets; |
| | | |
| | | mt7601u_chip_onoff(dev, true, false); |
| | | |
| | | ret = mt7601u_wait_asic_ready(dev); |
| | | if (ret) |
| | | goto err; |
| | | ret = mt7601u_mcu_init(dev); |
| | | if (ret) |
| | | goto err; |
| | | |
| | | if (!mt76_poll_msec(dev, MT_WPDMA_GLO_CFG, |
| | | MT_WPDMA_GLO_CFG_TX_DMA_BUSY | |
| | | MT_WPDMA_GLO_CFG_RX_DMA_BUSY, 0, 100)) { |
| | | ret = -EIO; |
| | | goto err; |
| | | } |
| | | |
| | | /* Wait for ASIC ready after FW load. */ |
| | | ret = mt7601u_wait_asic_ready(dev); |
| | | if (ret) |
| | | goto err; |
| | | |
| | | mt7601u_reset_csr_bbp(dev); |
| | | mt7601u_init_usb_dma(dev); |
| | | |
| | | ret = mt7601u_mcu_cmd_init(dev); |
| | | if (ret) |
| | | goto err; |
| | | ret = mt7601u_dma_init(dev); |
| | | if (ret) |
| | | goto err_mcu; |
| | | ret = mt7601u_write_mac_initvals(dev); |
| | | if (ret) |
| | | goto err_rx; |
| | | |
| | | if (!mt76_poll_msec(dev, MT_MAC_STATUS, |
| | | MT_MAC_STATUS_TX | MT_MAC_STATUS_RX, 0, 100)) { |
| | | ret = -EIO; |
| | | goto err_rx; |
| | | } |
| | | |
| | | ret = mt7601u_init_bbp(dev); |
| | | if (ret) |
| | | goto err_rx; |
| | | ret = mt7601u_init_wcid_mem(dev); |
| | | if (ret) |
| | | goto err_rx; |
| | | ret = mt7601u_init_key_mem(dev); |
| | | if (ret) |
| | | goto err_rx; |
| | | ret = mt7601u_init_wcid_attr_mem(dev); |
| | | if (ret) |
| | | goto err_rx; |
| | | |
| | | mt76_clear(dev, MT_BEACON_TIME_CFG, (MT_BEACON_TIME_CFG_TIMER_EN | |
| | | MT_BEACON_TIME_CFG_SYNC_MODE | |
| | | MT_BEACON_TIME_CFG_TBTT_EN | |
| | | MT_BEACON_TIME_CFG_BEACON_TX)); |
| | | |
| | | mt7601u_reset_counters(dev); |
| | | |
| | | mt7601u_rmw(dev, MT_US_CYC_CFG, MT_US_CYC_CNT, 0x1e); |
| | | |
| | | mt7601u_wr(dev, MT_TXOP_CTRL_CFG, MT76_SET(MT_TXOP_TRUN_EN, 0x3f) | |
| | | MT76_SET(MT_TXOP_EXT_CCA_DLY, 0x58)); |
| | | |
| | | ret = mt7601u_eeprom_init(dev); |
| | | if (ret) |
| | | goto err_rx; |
| | | |
| | | ret = mt7601u_phy_init(dev); |
| | | if (ret) |
| | | goto err_rx; |
| | | |
| | | mt7601u_set_rx_path(dev, 0); |
| | | mt7601u_set_tx_dac(dev, 0); |
| | | |
| | | mt7601u_mac_set_ctrlch(dev, false); |
| | | mt7601u_bbp_set_ctrlch(dev, false); |
| | | mt7601u_bbp_set_bw(dev, MT_BW_20); |
| | | |
| | | return 0; |
| | | |
| | | err_rx: |
| | | mt7601u_dma_cleanup(dev); |
| | | err_mcu: |
| | | mt7601u_mcu_cmd_deinit(dev); |
| | | err: |
| | | mt7601u_chip_onoff(dev, false, false); |
| | | return ret; |
| | | } |
| | | |
| | | void mt7601u_cleanup(struct mt7601u_dev *dev) |
| | | { |
| | | if (!test_and_clear_bit(MT7601U_STATE_INITIALIZED, &dev->state)) |
| | | return; |
| | | |
| | | mt7601u_stop_hardware(dev); |
| | | mt7601u_dma_cleanup(dev); |
| | | mt7601u_mcu_cmd_deinit(dev); |
| | | } |
| | | |
| | | struct mt7601u_dev *mt7601u_alloc_device(struct device *pdev) |
| | | { |
| | | struct ieee80211_hw *hw; |
| | | struct mt7601u_dev *dev; |
| | | |
| | | hw = ieee80211_alloc_hw(sizeof(*dev), &mt7601u_ops); |
| | | if (!hw) |
| | | return NULL; |
| | | |
| | | dev = hw->priv; |
| | | dev->dev = pdev; |
| | | dev->hw = hw; |
| | | mutex_init(&dev->vendor_req_mutex); |
| | | mutex_init(&dev->reg_atomic_mutex); |
| | | mutex_init(&dev->hw_atomic_mutex); |
| | | mutex_init(&dev->mutex); |
| | | spin_lock_init(&dev->tx_lock); |
| | | spin_lock_init(&dev->rx_lock); |
| | | spin_lock_init(&dev->lock); |
| | | spin_lock_init(&dev->mac_lock); |
| | | spin_lock_init(&dev->con_mon_lock); |
| | | atomic_set(&dev->avg_ampdu_len, 1); |
| | | skb_queue_head_init(&dev->tx_skb_done); |
| | | |
| | | dev->stat_wq = alloc_workqueue("mt7601u", WQ_UNBOUND, 0); |
| | | if (!dev->stat_wq) { |
| | | ieee80211_free_hw(hw); |
| | | return NULL; |
| | | } |
| | | |
| | | return dev; |
| | | } |
| | | |
| | | #define CHAN2G(_idx, _freq) { \ |
| | | .band = NL80211_BAND_2GHZ, \ |
| | | .center_freq = (_freq), \ |
| | | .hw_value = (_idx), \ |
| | | .max_power = 30, \ |
| | | } |
| | | |
| | | static const struct ieee80211_channel mt76_channels_2ghz[] = { |
| | | CHAN2G(1, 2412), |
| | | CHAN2G(2, 2417), |
| | | CHAN2G(3, 2422), |
| | | CHAN2G(4, 2427), |
| | | CHAN2G(5, 2432), |
| | | CHAN2G(6, 2437), |
| | | CHAN2G(7, 2442), |
| | | CHAN2G(8, 2447), |
| | | CHAN2G(9, 2452), |
| | | CHAN2G(10, 2457), |
| | | CHAN2G(11, 2462), |
| | | CHAN2G(12, 2467), |
| | | CHAN2G(13, 2472), |
| | | CHAN2G(14, 2484), |
| | | }; |
| | | |
| | | #define CCK_RATE(_idx, _rate) { \ |
| | | .bitrate = _rate, \ |
| | | .flags = IEEE80211_RATE_SHORT_PREAMBLE, \ |
| | | .hw_value = (MT_PHY_TYPE_CCK << 8) | _idx, \ |
| | | .hw_value_short = (MT_PHY_TYPE_CCK << 8) | (8 + _idx), \ |
| | | } |
| | | |
| | | #define OFDM_RATE(_idx, _rate) { \ |
| | | .bitrate = _rate, \ |
| | | .hw_value = (MT_PHY_TYPE_OFDM << 8) | _idx, \ |
| | | .hw_value_short = (MT_PHY_TYPE_OFDM << 8) | _idx, \ |
| | | } |
| | | |
| | | static struct ieee80211_rate mt76_rates[] = { |
| | | CCK_RATE(0, 10), |
| | | CCK_RATE(1, 20), |
| | | CCK_RATE(2, 55), |
| | | CCK_RATE(3, 110), |
| | | OFDM_RATE(0, 60), |
| | | OFDM_RATE(1, 90), |
| | | OFDM_RATE(2, 120), |
| | | OFDM_RATE(3, 180), |
| | | OFDM_RATE(4, 240), |
| | | OFDM_RATE(5, 360), |
| | | OFDM_RATE(6, 480), |
| | | OFDM_RATE(7, 540), |
| | | }; |
| | | |
| | | static int |
| | | mt76_init_sband(struct mt7601u_dev *dev, struct ieee80211_supported_band *sband, |
| | | const struct ieee80211_channel *chan, int n_chan, |
| | | struct ieee80211_rate *rates, int n_rates) |
| | | { |
| | | struct ieee80211_sta_ht_cap *ht_cap; |
| | | void *chanlist; |
| | | int size; |
| | | |
| | | size = n_chan * sizeof(*chan); |
| | | chanlist = devm_kmemdup(dev->dev, chan, size, GFP_KERNEL); |
| | | if (!chanlist) |
| | | return -ENOMEM; |
| | | |
| | | sband->channels = chanlist; |
| | | sband->n_channels = n_chan; |
| | | sband->bitrates = rates; |
| | | sband->n_bitrates = n_rates; |
| | | |
| | | ht_cap = &sband->ht_cap; |
| | | ht_cap->ht_supported = true; |
| | | ht_cap->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | |
| | | IEEE80211_HT_CAP_GRN_FLD | |
| | | IEEE80211_HT_CAP_SGI_20 | |
| | | IEEE80211_HT_CAP_SGI_40 | |
| | | (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT); |
| | | |
| | | ht_cap->mcs.rx_mask[0] = 0xff; |
| | | ht_cap->mcs.rx_mask[4] = 0x1; |
| | | ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; |
| | | ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; |
| | | ht_cap->ampdu_density = IEEE80211_HT_MPDU_DENSITY_2; |
| | | |
| | | dev->chandef.chan = &sband->channels[0]; |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | static int |
| | | mt76_init_sband_2g(struct mt7601u_dev *dev) |
| | | { |
| | | dev->sband_2g = devm_kzalloc(dev->dev, sizeof(*dev->sband_2g), |
| | | GFP_KERNEL); |
| | | dev->hw->wiphy->bands[NL80211_BAND_2GHZ] = dev->sband_2g; |
| | | |
| | | WARN_ON(dev->ee->reg.start - 1 + dev->ee->reg.num > |
| | | ARRAY_SIZE(mt76_channels_2ghz)); |
| | | |
| | | return mt76_init_sband(dev, dev->sband_2g, |
| | | &mt76_channels_2ghz[dev->ee->reg.start - 1], |
| | | dev->ee->reg.num, |
| | | mt76_rates, ARRAY_SIZE(mt76_rates)); |
| | | } |
| | | |
| | | int mt7601u_register_device(struct mt7601u_dev *dev) |
| | | { |
| | | struct ieee80211_hw *hw = dev->hw; |
| | | struct wiphy *wiphy = hw->wiphy; |
| | | int ret; |
| | | |
| | | /* Reserve WCID 0 for mcast - thanks to this APs WCID will go to |
| | | * entry no. 1 like it does in the vendor driver. |
| | | */ |
| | | dev->wcid_mask[0] |= 1; |
| | | |
| | | /* init fake wcid for monitor interfaces */ |
| | | dev->mon_wcid = devm_kmalloc(dev->dev, sizeof(*dev->mon_wcid), |
| | | GFP_KERNEL); |
| | | if (!dev->mon_wcid) |
| | | return -ENOMEM; |
| | | dev->mon_wcid->idx = 0xff; |
| | | dev->mon_wcid->hw_key_idx = -1; |
| | | |
| | | SET_IEEE80211_DEV(hw, dev->dev); |
| | | |
| | | #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0) |
| | | #define ieee80211_hw_set(hw, flag) (hw)->flags |= IEEE80211_HW_ ## flag; |
| | | #endif |
| | | |
| | | hw->queues = 4; |
| | | ieee80211_hw_set(hw, SIGNAL_DBM); |
| | | ieee80211_hw_set(hw, PS_NULLFUNC_STACK); |
| | | ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES); |
| | | ieee80211_hw_set(hw, AMPDU_AGGREGATION); |
| | | #ifdef MAC80211_IS_PATCHED |
| | | ieee80211_hw_set(hw, TX_STATS_EVERY_MPDU); |
| | | #endif |
| | | ieee80211_hw_set(hw, SUPPORTS_RC_TABLE); |
| | | hw->max_rates = 1; |
| | | hw->max_report_rates = 7; |
| | | hw->max_rate_tries = 1; |
| | | |
| | | hw->sta_data_size = sizeof(struct mt76_sta); |
| | | hw->vif_data_size = sizeof(struct mt76_vif); |
| | | |
| | | SET_IEEE80211_PERM_ADDR(hw, dev->macaddr); |
| | | |
| | | wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR; |
| | | wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); |
| | | |
| | | ret = mt76_init_sband_2g(dev); |
| | | if (ret) |
| | | return ret; |
| | | |
| | | INIT_DELAYED_WORK(&dev->mac_work, mt7601u_mac_work); |
| | | INIT_DELAYED_WORK(&dev->stat_work, mt7601u_tx_stat); |
| | | |
| | | ret = ieee80211_register_hw(hw); |
| | | if (ret) |
| | | return ret; |
| | | |
| | | mt7601u_init_debugfs(dev); |
| | | |
| | | return 0; |
| | | } |
New file |
| | |
| | | /* |
| | | * (c) Copyright 2002-2010, Ralink Technology, Inc. |
| | | * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> |
| | | * |
| | | * This program is free software; you can redistribute it and/or modify |
| | | * it under the terms of the GNU General Public License version 2 |
| | | * as published by the Free Software Foundation |
| | | * |
| | | * This program is distributed in the hope that it will be useful, |
| | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| | | * GNU General Public License for more details. |
| | | */ |
| | | |
| | | #ifndef __MT7601U_INITVALS_H |
| | | #define __MT7601U_INITVALS_H |
| | | |
| | | static const struct mt76_reg_pair bbp_common_vals[] = { |
| | | { 65, 0x2c }, |
| | | { 66, 0x38 }, |
| | | { 68, 0x0b }, |
| | | { 69, 0x12 }, |
| | | { 70, 0x0a }, |
| | | { 73, 0x10 }, |
| | | { 81, 0x37 }, |
| | | { 82, 0x62 }, |
| | | { 83, 0x6a }, |
| | | { 84, 0x99 }, |
| | | { 86, 0x00 }, |
| | | { 91, 0x04 }, |
| | | { 92, 0x00 }, |
| | | { 103, 0x00 }, |
| | | { 105, 0x05 }, |
| | | { 106, 0x35 }, |
| | | }; |
| | | |
| | | static const struct mt76_reg_pair bbp_chip_vals[] = { |
| | | { 1, 0x04 }, { 4, 0x40 }, { 20, 0x06 }, { 31, 0x08 }, |
| | | /* CCK Tx Control */ |
| | | { 178, 0xff }, |
| | | /* AGC/Sync controls */ |
| | | { 66, 0x14 }, { 68, 0x8b }, { 69, 0x12 }, { 70, 0x09 }, |
| | | { 73, 0x11 }, { 75, 0x60 }, { 76, 0x44 }, { 84, 0x9a }, |
| | | { 86, 0x38 }, { 91, 0x07 }, { 92, 0x02 }, |
| | | /* Rx Path Controls */ |
| | | { 99, 0x50 }, { 101, 0x00 }, { 103, 0xc0 }, { 104, 0x92 }, |
| | | { 105, 0x3c }, { 106, 0x03 }, { 128, 0x12 }, |
| | | /* Change RXWI content: Gain Report */ |
| | | { 142, 0x04 }, { 143, 0x37 }, |
| | | /* Change RXWI content: Antenna Report */ |
| | | { 142, 0x03 }, { 143, 0x99 }, |
| | | /* Calibration Index Register */ |
| | | /* CCK Receiver Control */ |
| | | { 160, 0xeb }, { 161, 0xc4 }, { 162, 0x77 }, { 163, 0xf9 }, |
| | | { 164, 0x88 }, { 165, 0x80 }, { 166, 0xff }, { 167, 0xe4 }, |
| | | /* Added AGC controls - these AGC/GLRT registers are accessed |
| | | * through R195 and R196. |
| | | */ |
| | | { 195, 0x00 }, { 196, 0x00 }, |
| | | { 195, 0x01 }, { 196, 0x04 }, |
| | | { 195, 0x02 }, { 196, 0x20 }, |
| | | { 195, 0x03 }, { 196, 0x0a }, |
| | | { 195, 0x06 }, { 196, 0x16 }, |
| | | { 195, 0x07 }, { 196, 0x05 }, |
| | | { 195, 0x08 }, { 196, 0x37 }, |
| | | { 195, 0x0a }, { 196, 0x15 }, |
| | | { 195, 0x0b }, { 196, 0x17 }, |
| | | { 195, 0x0c }, { 196, 0x06 }, |
| | | { 195, 0x0d }, { 196, 0x09 }, |
| | | { 195, 0x0e }, { 196, 0x05 }, |
| | | { 195, 0x0f }, { 196, 0x09 }, |
| | | { 195, 0x10 }, { 196, 0x20 }, |
| | | { 195, 0x20 }, { 196, 0x17 }, |
| | | { 195, 0x21 }, { 196, 0x06 }, |
| | | { 195, 0x22 }, { 196, 0x09 }, |
| | | { 195, 0x23 }, { 196, 0x17 }, |
| | | { 195, 0x24 }, { 196, 0x06 }, |
| | | { 195, 0x25 }, { 196, 0x09 }, |
| | | { 195, 0x26 }, { 196, 0x17 }, |
| | | { 195, 0x27 }, { 196, 0x06 }, |
| | | { 195, 0x28 }, { 196, 0x09 }, |
| | | { 195, 0x29 }, { 196, 0x05 }, |
| | | { 195, 0x2a }, { 196, 0x09 }, |
| | | { 195, 0x80 }, { 196, 0x8b }, |
| | | { 195, 0x81 }, { 196, 0x12 }, |
| | | { 195, 0x82 }, { 196, 0x09 }, |
| | | { 195, 0x83 }, { 196, 0x17 }, |
| | | { 195, 0x84 }, { 196, 0x11 }, |
| | | { 195, 0x85 }, { 196, 0x00 }, |
| | | { 195, 0x86 }, { 196, 0x00 }, |
| | | { 195, 0x87 }, { 196, 0x18 }, |
| | | { 195, 0x88 }, { 196, 0x60 }, |
| | | { 195, 0x89 }, { 196, 0x44 }, |
| | | { 195, 0x8a }, { 196, 0x8b }, |
| | | { 195, 0x8b }, { 196, 0x8b }, |
| | | { 195, 0x8c }, { 196, 0x8b }, |
| | | { 195, 0x8d }, { 196, 0x8b }, |
| | | { 195, 0x8e }, { 196, 0x09 }, |
| | | { 195, 0x8f }, { 196, 0x09 }, |
| | | { 195, 0x90 }, { 196, 0x09 }, |
| | | { 195, 0x91 }, { 196, 0x09 }, |
| | | { 195, 0x92 }, { 196, 0x11 }, |
| | | { 195, 0x93 }, { 196, 0x11 }, |
| | | { 195, 0x94 }, { 196, 0x11 }, |
| | | { 195, 0x95 }, { 196, 0x11 }, |
| | | /* PPAD */ |
| | | { 47, 0x80 }, { 60, 0x80 }, { 150, 0xd2 }, { 151, 0x32 }, |
| | | { 152, 0x23 }, { 153, 0x41 }, { 154, 0x00 }, { 155, 0x4f }, |
| | | { 253, 0x7e }, { 195, 0x30 }, { 196, 0x32 }, { 195, 0x31 }, |
| | | { 196, 0x23 }, { 195, 0x32 }, { 196, 0x45 }, { 195, 0x35 }, |
| | | { 196, 0x4a }, { 195, 0x36 }, { 196, 0x5a }, { 195, 0x37 }, |
| | | { 196, 0x5a }, |
| | | }; |
| | | |
| | | static const struct mt76_reg_pair mac_common_vals[] = { |
| | | { MT_LEGACY_BASIC_RATE, 0x0000013f }, |
| | | { MT_HT_BASIC_RATE, 0x00008003 }, |
| | | { MT_MAC_SYS_CTRL, 0x00000000 }, |
| | | { MT_RX_FILTR_CFG, 0x00017f97 }, |
| | | { MT_BKOFF_SLOT_CFG, 0x00000209 }, |
| | | { MT_TX_SW_CFG0, 0x00000000 }, |
| | | { MT_TX_SW_CFG1, 0x00080606 }, |
| | | { MT_TX_LINK_CFG, 0x00001020 }, |
| | | { MT_TX_TIMEOUT_CFG, 0x000a2090 }, |
| | | { MT_MAX_LEN_CFG, 0x00003fff }, |
| | | { MT_PBF_TX_MAX_PCNT, 0x1fbf1f1f }, |
| | | { MT_PBF_RX_MAX_PCNT, 0x0000009f }, |
| | | { MT_TX_RETRY_CFG, 0x47d01f0f }, |
| | | { MT_AUTO_RSP_CFG, 0x00000013 }, |
| | | { MT_CCK_PROT_CFG, 0x05740003 }, |
| | | { MT_OFDM_PROT_CFG, 0x05740003 }, |
| | | { MT_MM40_PROT_CFG, 0x03f44084 }, |
| | | { MT_GF20_PROT_CFG, 0x01744004 }, |
| | | { MT_GF40_PROT_CFG, 0x03f44084 }, |
| | | { MT_MM20_PROT_CFG, 0x01744004 }, |
| | | { MT_TXOP_CTRL_CFG, 0x0000583f }, |
| | | { MT_TX_RTS_CFG, 0x01092b20 }, |
| | | { MT_EXP_ACK_TIME, 0x002400ca }, |
| | | { MT_TXOP_HLDR_ET, 0x00000002 }, |
| | | { MT_XIFS_TIME_CFG, 0x33a41010 }, |
| | | { MT_PWR_PIN_CFG, 0x00000000 }, |
| | | }; |
| | | |
| | | static const struct mt76_reg_pair mac_chip_vals[] = { |
| | | { MT_TSO_CTRL, 0x00006050 }, |
| | | { MT_BCN_OFFSET(0), 0x18100800 }, |
| | | { MT_BCN_OFFSET(1), 0x38302820 }, |
| | | { MT_PBF_SYS_CTRL, 0x00080c00 }, |
| | | { MT_PBF_CFG, 0x7f723c1f }, |
| | | { MT_FCE_PSE_CTRL, 0x00000001 }, |
| | | { MT_PAUSE_ENABLE_CONTROL1, 0x00000000 }, |
| | | { MT_TX0_RF_GAIN_CORR, 0x003b0005 }, |
| | | { MT_TX0_RF_GAIN_ATTEN, 0x00006900 }, |
| | | { MT_TX0_BB_GAIN_ATTEN, 0x00000400 }, |
| | | { MT_TX_ALC_VGA3, 0x00060006 }, |
| | | { MT_TX_SW_CFG0, 0x00000402 }, |
| | | { MT_TX_SW_CFG1, 0x00000000 }, |
| | | { MT_TX_SW_CFG2, 0x00000000 }, |
| | | { MT_HEADER_TRANS_CTRL_REG, 0x00000000 }, |
| | | { MT_FCE_CSO, 0x0000030f }, |
| | | { MT_FCE_PARAMETERS, 0x00256f0f }, |
| | | }; |
| | | |
| | | #endif |
New file |
| | |
| | | /* |
| | | * (c) Copyright 2002-2010, Ralink Technology, Inc. |
| | | * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> |
| | | * |
| | | * This program is free software; you can redistribute it and/or modify |
| | | * it under the terms of the GNU General Public License version 2 |
| | | * as published by the Free Software Foundation |
| | | * |
| | | * This program is distributed in the hope that it will be useful, |
| | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| | | * GNU General Public License for more details. |
| | | */ |
| | | |
| | | #ifndef __MT7601U_PHY_INITVALS_H |
| | | #define __MT7601U_PHY_INITVALS_H |
| | | |
| | | #define RF_REG_PAIR(bank, reg, value) \ |
| | | { MT_MCU_MEMMAP_RF | (bank) << 16 | (reg), value } |
| | | |
| | | static const struct mt76_reg_pair rf_central[] = { |
| | | /* Bank 0 - for central blocks: BG, PLL, XTAL, LO, ADC/DAC */ |
| | | RF_REG_PAIR(0, 0, 0x02), |
| | | RF_REG_PAIR(0, 1, 0x01), |
| | | RF_REG_PAIR(0, 2, 0x11), |
| | | RF_REG_PAIR(0, 3, 0xff), |
| | | RF_REG_PAIR(0, 4, 0x0a), |
| | | RF_REG_PAIR(0, 5, 0x20), |
| | | RF_REG_PAIR(0, 6, 0x00), |
| | | /* B/G */ |
| | | RF_REG_PAIR(0, 7, 0x00), |
| | | RF_REG_PAIR(0, 8, 0x00), |
| | | RF_REG_PAIR(0, 9, 0x00), |
| | | RF_REG_PAIR(0, 10, 0x00), |
| | | RF_REG_PAIR(0, 11, 0x21), |
| | | /* XO */ |
| | | RF_REG_PAIR(0, 13, 0x00), /* 40mhz xtal */ |
| | | /* RF_REG_PAIR(0, 13, 0x13), */ /* 20mhz xtal */ |
| | | RF_REG_PAIR(0, 14, 0x7c), |
| | | RF_REG_PAIR(0, 15, 0x22), |
| | | RF_REG_PAIR(0, 16, 0x80), |
| | | /* PLL */ |
| | | RF_REG_PAIR(0, 17, 0x99), |
| | | RF_REG_PAIR(0, 18, 0x99), |
| | | RF_REG_PAIR(0, 19, 0x09), |
| | | RF_REG_PAIR(0, 20, 0x50), |
| | | RF_REG_PAIR(0, 21, 0xb0), |
| | | RF_REG_PAIR(0, 22, 0x00), |
| | | RF_REG_PAIR(0, 23, 0xc5), |
| | | RF_REG_PAIR(0, 24, 0xfc), |
| | | RF_REG_PAIR(0, 25, 0x40), |
| | | RF_REG_PAIR(0, 26, 0x4d), |
| | | RF_REG_PAIR(0, 27, 0x02), |
| | | RF_REG_PAIR(0, 28, 0x72), |
| | | RF_REG_PAIR(0, 29, 0x01), |
| | | RF_REG_PAIR(0, 30, 0x00), |
| | | RF_REG_PAIR(0, 31, 0x00), |
| | | /* test ports */ |
| | | RF_REG_PAIR(0, 32, 0x00), |
| | | RF_REG_PAIR(0, 33, 0x00), |
| | | RF_REG_PAIR(0, 34, 0x23), |
| | | RF_REG_PAIR(0, 35, 0x01), /* change setting to reduce spurs */ |
| | | RF_REG_PAIR(0, 36, 0x00), |
| | | RF_REG_PAIR(0, 37, 0x00), |
| | | /* ADC/DAC */ |
| | | RF_REG_PAIR(0, 38, 0x00), |
| | | RF_REG_PAIR(0, 39, 0x20), |
| | | RF_REG_PAIR(0, 40, 0x00), |
| | | RF_REG_PAIR(0, 41, 0xd0), |
| | | RF_REG_PAIR(0, 42, 0x1b), |
| | | RF_REG_PAIR(0, 43, 0x02), |
| | | RF_REG_PAIR(0, 44, 0x00), |
| | | }; |
| | | |
| | | static const struct mt76_reg_pair rf_channel[] = { |
| | | RF_REG_PAIR(4, 0, 0x01), |
| | | RF_REG_PAIR(4, 1, 0x00), |
| | | RF_REG_PAIR(4, 2, 0x00), |
| | | RF_REG_PAIR(4, 3, 0x00), |
| | | /* LDO */ |
| | | RF_REG_PAIR(4, 4, 0x00), |
| | | RF_REG_PAIR(4, 5, 0x08), |
| | | RF_REG_PAIR(4, 6, 0x00), |
| | | /* RX */ |
| | | RF_REG_PAIR(4, 7, 0x5b), |
| | | RF_REG_PAIR(4, 8, 0x52), |
| | | RF_REG_PAIR(4, 9, 0xb6), |
| | | RF_REG_PAIR(4, 10, 0x57), |
| | | RF_REG_PAIR(4, 11, 0x33), |
| | | RF_REG_PAIR(4, 12, 0x22), |
| | | RF_REG_PAIR(4, 13, 0x3d), |
| | | RF_REG_PAIR(4, 14, 0x3e), |
| | | RF_REG_PAIR(4, 15, 0x13), |
| | | RF_REG_PAIR(4, 16, 0x22), |
| | | RF_REG_PAIR(4, 17, 0x23), |
| | | RF_REG_PAIR(4, 18, 0x02), |
| | | RF_REG_PAIR(4, 19, 0xa4), |
| | | RF_REG_PAIR(4, 20, 0x01), |
| | | RF_REG_PAIR(4, 21, 0x12), |
| | | RF_REG_PAIR(4, 22, 0x80), |
| | | RF_REG_PAIR(4, 23, 0xb3), |
| | | RF_REG_PAIR(4, 24, 0x00), /* reserved */ |
| | | RF_REG_PAIR(4, 25, 0x00), /* reserved */ |
| | | RF_REG_PAIR(4, 26, 0x00), /* reserved */ |
| | | RF_REG_PAIR(4, 27, 0x00), /* reserved */ |
| | | /* LOGEN */ |
| | | RF_REG_PAIR(4, 28, 0x18), |
| | | RF_REG_PAIR(4, 29, 0xee), |
| | | RF_REG_PAIR(4, 30, 0x6b), |
| | | RF_REG_PAIR(4, 31, 0x31), |
| | | RF_REG_PAIR(4, 32, 0x5d), |
| | | RF_REG_PAIR(4, 33, 0x00), /* reserved */ |
| | | /* TX */ |
| | | RF_REG_PAIR(4, 34, 0x96), |
| | | RF_REG_PAIR(4, 35, 0x55), |
| | | RF_REG_PAIR(4, 36, 0x08), |
| | | RF_REG_PAIR(4, 37, 0xbb), |
| | | RF_REG_PAIR(4, 38, 0xb3), |
| | | RF_REG_PAIR(4, 39, 0xb3), |
| | | RF_REG_PAIR(4, 40, 0x03), |
| | | RF_REG_PAIR(4, 41, 0x00), /* reserved */ |
| | | RF_REG_PAIR(4, 42, 0x00), /* reserved */ |
| | | RF_REG_PAIR(4, 43, 0xc5), |
| | | RF_REG_PAIR(4, 44, 0xc5), |
| | | RF_REG_PAIR(4, 45, 0xc5), |
| | | RF_REG_PAIR(4, 46, 0x07), |
| | | RF_REG_PAIR(4, 47, 0xa8), |
| | | RF_REG_PAIR(4, 48, 0xef), |
| | | RF_REG_PAIR(4, 49, 0x1a), |
| | | /* PA */ |
| | | RF_REG_PAIR(4, 54, 0x07), |
| | | RF_REG_PAIR(4, 55, 0xa7), |
| | | RF_REG_PAIR(4, 56, 0xcc), |
| | | RF_REG_PAIR(4, 57, 0x14), |
| | | RF_REG_PAIR(4, 58, 0x07), |
| | | RF_REG_PAIR(4, 59, 0xa8), |
| | | RF_REG_PAIR(4, 60, 0xd7), |
| | | RF_REG_PAIR(4, 61, 0x10), |
| | | RF_REG_PAIR(4, 62, 0x1c), |
| | | RF_REG_PAIR(4, 63, 0x00), /* reserved */ |
| | | }; |
| | | |
| | | static const struct mt76_reg_pair rf_vga[] = { |
| | | RF_REG_PAIR(5, 0, 0x47), |
| | | RF_REG_PAIR(5, 1, 0x00), |
| | | RF_REG_PAIR(5, 2, 0x00), |
| | | RF_REG_PAIR(5, 3, 0x08), |
| | | RF_REG_PAIR(5, 4, 0x04), |
| | | RF_REG_PAIR(5, 5, 0x20), |
| | | RF_REG_PAIR(5, 6, 0x3a), |
| | | RF_REG_PAIR(5, 7, 0x3a), |
| | | RF_REG_PAIR(5, 8, 0x00), |
| | | RF_REG_PAIR(5, 9, 0x00), |
| | | RF_REG_PAIR(5, 10, 0x10), |
| | | RF_REG_PAIR(5, 11, 0x10), |
| | | RF_REG_PAIR(5, 12, 0x10), |
| | | RF_REG_PAIR(5, 13, 0x10), |
| | | RF_REG_PAIR(5, 14, 0x10), |
| | | RF_REG_PAIR(5, 15, 0x20), |
| | | RF_REG_PAIR(5, 16, 0x22), |
| | | RF_REG_PAIR(5, 17, 0x7c), |
| | | RF_REG_PAIR(5, 18, 0x00), |
| | | RF_REG_PAIR(5, 19, 0x00), |
| | | RF_REG_PAIR(5, 20, 0x00), |
| | | RF_REG_PAIR(5, 21, 0xf1), |
| | | RF_REG_PAIR(5, 22, 0x11), |
| | | RF_REG_PAIR(5, 23, 0x02), |
| | | RF_REG_PAIR(5, 24, 0x41), |
| | | RF_REG_PAIR(5, 25, 0x20), |
| | | RF_REG_PAIR(5, 26, 0x00), |
| | | RF_REG_PAIR(5, 27, 0xd7), |
| | | RF_REG_PAIR(5, 28, 0xa2), |
| | | RF_REG_PAIR(5, 29, 0x20), |
| | | RF_REG_PAIR(5, 30, 0x49), |
| | | RF_REG_PAIR(5, 31, 0x20), |
| | | RF_REG_PAIR(5, 32, 0x04), |
| | | RF_REG_PAIR(5, 33, 0xf1), |
| | | RF_REG_PAIR(5, 34, 0xa1), |
| | | RF_REG_PAIR(5, 35, 0x01), |
| | | RF_REG_PAIR(5, 41, 0x00), |
| | | RF_REG_PAIR(5, 42, 0x00), |
| | | RF_REG_PAIR(5, 43, 0x00), |
| | | RF_REG_PAIR(5, 44, 0x00), |
| | | RF_REG_PAIR(5, 45, 0x00), |
| | | RF_REG_PAIR(5, 46, 0x00), |
| | | RF_REG_PAIR(5, 47, 0x00), |
| | | RF_REG_PAIR(5, 48, 0x00), |
| | | RF_REG_PAIR(5, 49, 0x00), |
| | | RF_REG_PAIR(5, 50, 0x00), |
| | | RF_REG_PAIR(5, 51, 0x00), |
| | | RF_REG_PAIR(5, 52, 0x00), |
| | | RF_REG_PAIR(5, 53, 0x00), |
| | | RF_REG_PAIR(5, 54, 0x00), |
| | | RF_REG_PAIR(5, 55, 0x00), |
| | | RF_REG_PAIR(5, 56, 0x00), |
| | | RF_REG_PAIR(5, 57, 0x00), |
| | | RF_REG_PAIR(5, 58, 0x31), |
| | | RF_REG_PAIR(5, 59, 0x31), |
| | | RF_REG_PAIR(5, 60, 0x0a), |
| | | RF_REG_PAIR(5, 61, 0x02), |
| | | RF_REG_PAIR(5, 62, 0x00), |
| | | RF_REG_PAIR(5, 63, 0x00), |
| | | }; |
| | | |
| | | /* TODO: BBP178 is set to 0xff for "CCK CH14 OBW" which overrides the settings |
| | | * from channel switching. Seems stupid at best. |
| | | */ |
| | | static const struct mt76_reg_pair bbp_high_temp[] = { |
| | | { 75, 0x60 }, |
| | | { 92, 0x02 }, |
| | | { 178, 0xff }, /* For CCK CH14 OBW */ |
| | | { 195, 0x88 }, { 196, 0x60 }, |
| | | }, bbp_high_temp_bw20[] = { |
| | | { 69, 0x12 }, |
| | | { 91, 0x07 }, |
| | | { 195, 0x23 }, { 196, 0x17 }, |
| | | { 195, 0x24 }, { 196, 0x06 }, |
| | | { 195, 0x81 }, { 196, 0x12 }, |
| | | { 195, 0x83 }, { 196, 0x17 }, |
| | | }, bbp_high_temp_bw40[] = { |
| | | { 69, 0x15 }, |
| | | { 91, 0x04 }, |
| | | { 195, 0x23 }, { 196, 0x12 }, |
| | | { 195, 0x24 }, { 196, 0x08 }, |
| | | { 195, 0x81 }, { 196, 0x15 }, |
| | | { 195, 0x83 }, { 196, 0x16 }, |
| | | }, bbp_low_temp[] = { |
| | | { 178, 0xff }, /* For CCK CH14 OBW */ |
| | | }, bbp_low_temp_bw20[] = { |
| | | { 69, 0x12 }, |
| | | { 75, 0x5e }, |
| | | { 91, 0x07 }, |
| | | { 92, 0x02 }, |
| | | { 195, 0x23 }, { 196, 0x17 }, |
| | | { 195, 0x24 }, { 196, 0x06 }, |
| | | { 195, 0x81 }, { 196, 0x12 }, |
| | | { 195, 0x83 }, { 196, 0x17 }, |
| | | { 195, 0x88 }, { 196, 0x5e }, |
| | | }, bbp_low_temp_bw40[] = { |
| | | { 69, 0x15 }, |
| | | { 75, 0x5c }, |
| | | { 91, 0x04 }, |
| | | { 92, 0x03 }, |
| | | { 195, 0x23 }, { 196, 0x10 }, |
| | | { 195, 0x24 }, { 196, 0x08 }, |
| | | { 195, 0x81 }, { 196, 0x15 }, |
| | | { 195, 0x83 }, { 196, 0x16 }, |
| | | { 195, 0x88 }, { 196, 0x5b }, |
| | | }, bbp_normal_temp[] = { |
| | | { 75, 0x60 }, |
| | | { 92, 0x02 }, |
| | | { 178, 0xff }, /* For CCK CH14 OBW */ |
| | | { 195, 0x88 }, { 196, 0x60 }, |
| | | }, bbp_normal_temp_bw20[] = { |
| | | { 69, 0x12 }, |
| | | { 91, 0x07 }, |
| | | { 195, 0x23 }, { 196, 0x17 }, |
| | | { 195, 0x24 }, { 196, 0x06 }, |
| | | { 195, 0x81 }, { 196, 0x12 }, |
| | | { 195, 0x83 }, { 196, 0x17 }, |
| | | }, bbp_normal_temp_bw40[] = { |
| | | { 69, 0x15 }, |
| | | { 91, 0x04 }, |
| | | { 195, 0x23 }, { 196, 0x12 }, |
| | | { 195, 0x24 }, { 196, 0x08 }, |
| | | { 195, 0x81 }, { 196, 0x15 }, |
| | | { 195, 0x83 }, { 196, 0x16 }, |
| | | }; |
| | | |
| | | #define BBP_TABLE(arr) { arr, ARRAY_SIZE(arr), } |
| | | |
| | | static const struct reg_table { |
| | | const struct mt76_reg_pair *regs; |
| | | size_t n; |
| | | } bbp_mode_table[3][3] = { |
| | | { |
| | | BBP_TABLE(bbp_normal_temp_bw20), |
| | | BBP_TABLE(bbp_normal_temp_bw40), |
| | | BBP_TABLE(bbp_normal_temp), |
| | | }, { |
| | | BBP_TABLE(bbp_high_temp_bw20), |
| | | BBP_TABLE(bbp_high_temp_bw40), |
| | | BBP_TABLE(bbp_high_temp), |
| | | }, { |
| | | BBP_TABLE(bbp_low_temp_bw20), |
| | | BBP_TABLE(bbp_low_temp_bw40), |
| | | BBP_TABLE(bbp_low_temp), |
| | | } |
| | | }; |
| | | |
| | | #endif |
New file |
| | |
| | | /* |
| | | * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> |
| | | * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> |
| | | * |
| | | * This program is free software; you can redistribute it and/or modify |
| | | * it under the terms of the GNU General Public License version 2 |
| | | * as published by the Free Software Foundation |
| | | * |
| | | * This program is distributed in the hope that it will be useful, |
| | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| | | * GNU General Public License for more details. |
| | | */ |
| | | |
| | | #include "mt7601u.h" |
| | | #include "trace.h" |
| | | #include <linux/etherdevice.h> |
| | | |
| | | static void |
| | | mt76_mac_process_tx_rate(struct ieee80211_tx_rate *txrate, u16 rate) |
| | | { |
| | | u8 idx = MT76_GET(MT_TXWI_RATE_MCS, rate); |
| | | |
| | | txrate->idx = 0; |
| | | txrate->flags = 0; |
| | | txrate->count = 1; |
| | | |
| | | switch (MT76_GET(MT_TXWI_RATE_PHY_MODE, rate)) { |
| | | case MT_PHY_TYPE_OFDM: |
| | | txrate->idx = idx + 4; |
| | | return; |
| | | case MT_PHY_TYPE_CCK: |
| | | if (idx >= 8) |
| | | idx -= 8; |
| | | |
| | | txrate->idx = idx; |
| | | return; |
| | | case MT_PHY_TYPE_HT_GF: |
| | | txrate->flags |= IEEE80211_TX_RC_GREEN_FIELD; |
| | | /* fall through */ |
| | | case MT_PHY_TYPE_HT: |
| | | txrate->flags |= IEEE80211_TX_RC_MCS; |
| | | txrate->idx = idx; |
| | | break; |
| | | default: |
| | | WARN_ON(1); |
| | | return; |
| | | } |
| | | |
| | | if (MT76_GET(MT_TXWI_RATE_BW, rate) == MT_PHY_BW_40) |
| | | txrate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; |
| | | |
| | | if (rate & MT_TXWI_RATE_SGI) |
| | | txrate->flags |= IEEE80211_TX_RC_SHORT_GI; |
| | | } |
| | | |
| | | static void |
| | | mt76_mac_fill_tx_status(struct mt7601u_dev *dev, struct ieee80211_tx_info *info, |
| | | struct mt76_tx_status *st) |
| | | { |
| | | struct ieee80211_tx_rate *rate = info->status.rates; |
| | | int cur_idx, last_rate; |
| | | int i; |
| | | |
| | | last_rate = min_t(int, st->retry, IEEE80211_TX_MAX_RATES - 1); |
| | | mt76_mac_process_tx_rate(&rate[last_rate], st->rate); |
| | | if (last_rate < IEEE80211_TX_MAX_RATES - 1) |
| | | rate[last_rate + 1].idx = -1; |
| | | |
| | | cur_idx = rate[last_rate].idx + st->retry; |
| | | for (i = 0; i <= last_rate; i++) { |
| | | rate[i].flags = rate[last_rate].flags; |
| | | rate[i].idx = max_t(int, 0, cur_idx - i); |
| | | rate[i].count = 1; |
| | | } |
| | | |
| | | if (last_rate > 0) |
| | | rate[last_rate - 1].count = st->retry + 1 - last_rate; |
| | | |
| | | #ifdef MAC80211_IS_PATCHED |
| | | info->status.ampdu_len = atomic_read(&dev->avg_ampdu_len); |
| | | #else |
| | | info->status.ampdu_len = 1; |
| | | #endif |
| | | info->status.ampdu_ack_len = st->success; |
| | | |
| | | if (st->is_probe) |
| | | info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE; |
| | | |
| | | if (st->aggr) |
| | | info->flags |= IEEE80211_TX_CTL_AMPDU | |
| | | IEEE80211_TX_STAT_AMPDU; |
| | | |
| | | if (!st->ack_req) |
| | | info->flags |= IEEE80211_TX_CTL_NO_ACK; |
| | | else if (st->success) |
| | | info->flags |= IEEE80211_TX_STAT_ACK; |
| | | } |
| | | |
| | | u16 mt76_mac_tx_rate_val(struct mt7601u_dev *dev, |
| | | const struct ieee80211_tx_rate *rate, u8 *nss_val) |
| | | { |
| | | u16 rateval; |
| | | u8 phy, rate_idx; |
| | | u8 nss = 1; |
| | | u8 bw = 0; |
| | | |
| | | if (rate->flags & IEEE80211_TX_RC_MCS) { |
| | | rate_idx = rate->idx; |
| | | nss = 1 + (rate->idx >> 3); |
| | | phy = MT_PHY_TYPE_HT; |
| | | if (rate->flags & IEEE80211_TX_RC_GREEN_FIELD) |
| | | phy = MT_PHY_TYPE_HT_GF; |
| | | if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) |
| | | bw = 1; |
| | | } else { |
| | | const struct ieee80211_rate *r; |
| | | int band = dev->chandef.chan->band; |
| | | u16 val; |
| | | |
| | | r = &dev->hw->wiphy->bands[band]->bitrates[rate->idx]; |
| | | if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) |
| | | val = r->hw_value_short; |
| | | else |
| | | val = r->hw_value; |
| | | |
| | | phy = val >> 8; |
| | | rate_idx = val & 0xff; |
| | | bw = 0; |
| | | } |
| | | |
| | | rateval = MT76_SET(MT_RXWI_RATE_MCS, rate_idx); |
| | | rateval |= MT76_SET(MT_RXWI_RATE_PHY, phy); |
| | | rateval |= MT76_SET(MT_RXWI_RATE_BW, bw); |
| | | if (rate->flags & IEEE80211_TX_RC_SHORT_GI) |
| | | rateval |= MT_RXWI_RATE_SGI; |
| | | |
| | | *nss_val = nss; |
| | | return rateval; |
| | | } |
| | | |
| | | void mt76_mac_wcid_set_rate(struct mt7601u_dev *dev, struct mt76_wcid *wcid, |
| | | const struct ieee80211_tx_rate *rate) |
| | | { |
| | | unsigned long flags; |
| | | |
| | | spin_lock_irqsave(&dev->lock, flags); |
| | | wcid->tx_rate = mt76_mac_tx_rate_val(dev, rate, &wcid->tx_rate_nss); |
| | | wcid->tx_rate_set = true; |
| | | spin_unlock_irqrestore(&dev->lock, flags); |
| | | } |
| | | |
| | | struct mt76_tx_status mt7601u_mac_fetch_tx_status(struct mt7601u_dev *dev) |
| | | { |
| | | struct mt76_tx_status stat = {}; |
| | | u32 val; |
| | | |
| | | val = mt7601u_rr(dev, MT_TX_STAT_FIFO); |
| | | stat.valid = !!(val & MT_TX_STAT_FIFO_VALID); |
| | | stat.success = !!(val & MT_TX_STAT_FIFO_SUCCESS); |
| | | stat.aggr = !!(val & MT_TX_STAT_FIFO_AGGR); |
| | | stat.ack_req = !!(val & MT_TX_STAT_FIFO_ACKREQ); |
| | | stat.pktid = MT76_GET(MT_TX_STAT_FIFO_PID_TYPE, val); |
| | | stat.wcid = MT76_GET(MT_TX_STAT_FIFO_WCID, val); |
| | | stat.rate = MT76_GET(MT_TX_STAT_FIFO_RATE, val); |
| | | |
| | | return stat; |
| | | } |
| | | |
| | | void mt76_send_tx_status(struct mt7601u_dev *dev, struct mt76_tx_status *stat) |
| | | { |
| | | struct ieee80211_tx_info info = {}; |
| | | struct ieee80211_sta *sta = NULL; |
| | | struct mt76_wcid *wcid = NULL; |
| | | void *msta; |
| | | |
| | | rcu_read_lock(); |
| | | if (stat->wcid < ARRAY_SIZE(dev->wcid)) |
| | | wcid = rcu_dereference(dev->wcid[stat->wcid]); |
| | | |
| | | if (wcid) { |
| | | msta = container_of(wcid, struct mt76_sta, wcid); |
| | | sta = container_of(msta, struct ieee80211_sta, |
| | | drv_priv); |
| | | } |
| | | |
| | | mt76_mac_fill_tx_status(dev, &info, stat); |
| | | |
| | | spin_lock_bh(&dev->mac_lock); |
| | | ieee80211_tx_status_noskb(dev->hw, sta, &info); |
| | | spin_unlock_bh(&dev->mac_lock); |
| | | |
| | | rcu_read_unlock(); |
| | | } |
| | | |
| | | void mt7601u_mac_set_protection(struct mt7601u_dev *dev, bool legacy_prot, |
| | | int ht_mode) |
| | | { |
| | | int mode = ht_mode & IEEE80211_HT_OP_MODE_PROTECTION; |
| | | bool non_gf = !!(ht_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); |
| | | u32 prot[6]; |
| | | bool ht_rts[4] = {}; |
| | | int i; |
| | | |
| | | prot[0] = MT_PROT_NAV_SHORT | |
| | | MT_PROT_TXOP_ALLOW_ALL | |
| | | MT_PROT_RTS_THR_EN; |
| | | prot[1] = prot[0]; |
| | | if (legacy_prot) |
| | | prot[1] |= MT_PROT_CTRL_CTS2SELF; |
| | | |
| | | prot[2] = prot[4] = MT_PROT_NAV_SHORT | MT_PROT_TXOP_ALLOW_BW20; |
| | | prot[3] = prot[5] = MT_PROT_NAV_SHORT | MT_PROT_TXOP_ALLOW_ALL; |
| | | |
| | | if (legacy_prot) { |
| | | prot[2] |= MT_PROT_RATE_CCK_11; |
| | | prot[3] |= MT_PROT_RATE_CCK_11; |
| | | prot[4] |= MT_PROT_RATE_CCK_11; |
| | | prot[5] |= MT_PROT_RATE_CCK_11; |
| | | } else { |
| | | prot[2] |= MT_PROT_RATE_OFDM_24; |
| | | prot[3] |= MT_PROT_RATE_DUP_OFDM_24; |
| | | prot[4] |= MT_PROT_RATE_OFDM_24; |
| | | prot[5] |= MT_PROT_RATE_DUP_OFDM_24; |
| | | } |
| | | |
| | | switch (mode) { |
| | | case IEEE80211_HT_OP_MODE_PROTECTION_NONE: |
| | | break; |
| | | |
| | | case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER: |
| | | ht_rts[0] = ht_rts[1] = ht_rts[2] = ht_rts[3] = true; |
| | | break; |
| | | |
| | | case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ: |
| | | ht_rts[1] = ht_rts[3] = true; |
| | | break; |
| | | |
| | | case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED: |
| | | ht_rts[0] = ht_rts[1] = ht_rts[2] = ht_rts[3] = true; |
| | | break; |
| | | } |
| | | |
| | | if (non_gf) |
| | | ht_rts[2] = ht_rts[3] = true; |
| | | |
| | | for (i = 0; i < 4; i++) |
| | | if (ht_rts[i]) |
| | | prot[i + 2] |= MT_PROT_CTRL_RTS_CTS; |
| | | |
| | | for (i = 0; i < 6; i++) |
| | | mt7601u_wr(dev, MT_CCK_PROT_CFG + i * 4, prot[i]); |
| | | } |
| | | |
| | | void mt7601u_mac_set_short_preamble(struct mt7601u_dev *dev, bool short_preamb) |
| | | { |
| | | if (short_preamb) |
| | | mt76_set(dev, MT_AUTO_RSP_CFG, MT_AUTO_RSP_PREAMB_SHORT); |
| | | else |
| | | mt76_clear(dev, MT_AUTO_RSP_CFG, MT_AUTO_RSP_PREAMB_SHORT); |
| | | } |
| | | |
| | | void mt7601u_mac_config_tsf(struct mt7601u_dev *dev, bool enable, int interval) |
| | | { |
| | | u32 val = mt7601u_rr(dev, MT_BEACON_TIME_CFG); |
| | | |
| | | val &= ~(MT_BEACON_TIME_CFG_TIMER_EN | |
| | | MT_BEACON_TIME_CFG_SYNC_MODE | |
| | | MT_BEACON_TIME_CFG_TBTT_EN); |
| | | |
| | | if (!enable) { |
| | | mt7601u_wr(dev, MT_BEACON_TIME_CFG, val); |
| | | return; |
| | | } |
| | | |
| | | val &= ~MT_BEACON_TIME_CFG_INTVAL; |
| | | val |= MT76_SET(MT_BEACON_TIME_CFG_INTVAL, interval << 4) | |
| | | MT_BEACON_TIME_CFG_TIMER_EN | |
| | | MT_BEACON_TIME_CFG_SYNC_MODE | |
| | | MT_BEACON_TIME_CFG_TBTT_EN; |
| | | } |
| | | |
| | | static void mt7601u_check_mac_err(struct mt7601u_dev *dev) |
| | | { |
| | | u32 val = mt7601u_rr(dev, 0x10f4); |
| | | |
| | | if (!(val & BIT(29)) || !(val & (BIT(7) | BIT(5)))) |
| | | return; |
| | | |
| | | dev_err(dev->dev, "Error: MAC specific condition occurred\n"); |
| | | |
| | | mt76_set(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_RESET_CSR); |
| | | udelay(10); |
| | | mt76_clear(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_RESET_CSR); |
| | | } |
| | | |
| | | void mt7601u_mac_work(struct work_struct *work) |
| | | { |
| | | struct mt7601u_dev *dev = container_of(work, struct mt7601u_dev, |
| | | mac_work.work); |
| | | struct { |
| | | u32 addr_base; |
| | | u32 span; |
| | | u64 *stat_base; |
| | | } spans[] = { |
| | | { MT_RX_STA_CNT0, 3, dev->stats.rx_stat }, |
| | | { MT_TX_STA_CNT0, 3, dev->stats.tx_stat }, |
| | | { MT_TX_AGG_STAT, 1, dev->stats.aggr_stat }, |
| | | { MT_MPDU_DENSITY_CNT, 1, dev->stats.zero_len_del }, |
| | | { MT_TX_AGG_CNT_BASE0, 8, &dev->stats.aggr_n[0] }, |
| | | { MT_TX_AGG_CNT_BASE1, 8, &dev->stats.aggr_n[16] }, |
| | | }; |
| | | u32 sum, n; |
| | | int i, j, k; |
| | | |
| | | /* Note: using MCU_RANDOM_READ is actually slower then reading all the |
| | | * registers by hand. MCU takes ca. 20ms to complete read of 24 |
| | | * registers while reading them one by one will takes roughly |
| | | * 24*200us =~ 5ms. |
| | | */ |
| | | |
| | | k = 0; |
| | | n = 0; |
| | | sum = 0; |
| | | for (i = 0; i < ARRAY_SIZE(spans); i++) |
| | | for (j = 0; j < spans[i].span; j++) { |
| | | u32 val = mt7601u_rr(dev, spans[i].addr_base + j * 4); |
| | | |
| | | spans[i].stat_base[j * 2] += val & 0xffff; |
| | | spans[i].stat_base[j * 2 + 1] += val >> 16; |
| | | |
| | | /* Calculate average AMPDU length */ |
| | | if (spans[i].addr_base != MT_TX_AGG_CNT_BASE0 && |
| | | spans[i].addr_base != MT_TX_AGG_CNT_BASE1) |
| | | continue; |
| | | |
| | | n += (val >> 16) + (val & 0xffff); |
| | | sum += (val & 0xffff) * (1 + k * 2) + |
| | | (val >> 16) * (2 + k * 2); |
| | | k++; |
| | | } |
| | | |
| | | atomic_set(&dev->avg_ampdu_len, n ? DIV_ROUND_CLOSEST(sum, n) : 1); |
| | | |
| | | mt7601u_check_mac_err(dev); |
| | | |
| | | ieee80211_queue_delayed_work(dev->hw, &dev->mac_work, 10 * HZ); |
| | | } |
| | | |
| | | void |
| | | mt7601u_mac_wcid_setup(struct mt7601u_dev *dev, u8 idx, u8 vif_idx, u8 *mac) |
| | | { |
| | | u8 zmac[ETH_ALEN] = {}; |
| | | u32 attr; |
| | | |
| | | attr = MT76_SET(MT_WCID_ATTR_BSS_IDX, vif_idx & 7) | |
| | | MT76_SET(MT_WCID_ATTR_BSS_IDX_EXT, !!(vif_idx & 8)); |
| | | |
| | | mt76_wr(dev, MT_WCID_ATTR(idx), attr); |
| | | |
| | | if (mac) |
| | | memcpy(zmac, mac, sizeof(zmac)); |
| | | |
| | | mt7601u_addr_wr(dev, MT_WCID_ADDR(idx), zmac); |
| | | } |
| | | |
| | | void mt7601u_mac_set_ampdu_factor(struct mt7601u_dev *dev) |
| | | { |
| | | struct ieee80211_sta *sta; |
| | | struct mt76_wcid *wcid; |
| | | void *msta; |
| | | u8 min_factor = 3; |
| | | int i; |
| | | |
| | | rcu_read_lock(); |
| | | for (i = 0; i < ARRAY_SIZE(dev->wcid); i++) { |
| | | wcid = rcu_dereference(dev->wcid[i]); |
| | | if (!wcid) |
| | | continue; |
| | | |
| | | msta = container_of(wcid, struct mt76_sta, wcid); |
| | | sta = container_of(msta, struct ieee80211_sta, drv_priv); |
| | | |
| | | min_factor = min(min_factor, sta->ht_cap.ampdu_factor); |
| | | } |
| | | rcu_read_unlock(); |
| | | |
| | | mt7601u_wr(dev, MT_MAX_LEN_CFG, 0xa0fff | |
| | | MT76_SET(MT_MAX_LEN_CFG_AMPDU, min_factor)); |
| | | } |
| | | |
| | | static void |
| | | mt76_mac_process_rate(struct ieee80211_rx_status *status, u16 rate) |
| | | { |
| | | u8 idx = MT76_GET(MT_RXWI_RATE_MCS, rate); |
| | | |
| | | switch (MT76_GET(MT_RXWI_RATE_PHY, rate)) { |
| | | case MT_PHY_TYPE_OFDM: |
| | | if (WARN_ON(idx >= 8)) |
| | | idx = 0; |
| | | idx += 4; |
| | | |
| | | status->rate_idx = idx; |
| | | return; |
| | | case MT_PHY_TYPE_CCK: |
| | | if (idx >= 8) { |
| | | idx -= 8; |
| | | status->flag |= RX_FLAG_SHORTPRE; |
| | | } |
| | | |
| | | if (WARN_ON(idx >= 4)) |
| | | idx = 0; |
| | | |
| | | status->rate_idx = idx; |
| | | return; |
| | | case MT_PHY_TYPE_HT_GF: |
| | | status->flag |= RX_FLAG_HT_GF; |
| | | /* fall through */ |
| | | case MT_PHY_TYPE_HT: |
| | | status->flag |= RX_FLAG_HT; |
| | | status->rate_idx = idx; |
| | | break; |
| | | default: |
| | | WARN_ON(1); |
| | | return; |
| | | } |
| | | |
| | | if (rate & MT_RXWI_RATE_SGI) |
| | | status->flag |= RX_FLAG_SHORT_GI; |
| | | |
| | | if (rate & MT_RXWI_RATE_STBC) |
| | | status->flag |= 1 << RX_FLAG_STBC_SHIFT; |
| | | |
| | | if (rate & MT_RXWI_RATE_BW) |
| | | status->flag |= RX_FLAG_40MHZ; |
| | | } |
| | | |
| | | static void |
| | | mt7601u_rx_monitor_beacon(struct mt7601u_dev *dev, struct mt7601u_rxwi *rxwi, |
| | | u16 rate, int rssi) |
| | | { |
| | | dev->bcn_freq_off = rxwi->freq_off; |
| | | dev->bcn_phy_mode = MT76_GET(MT_RXWI_RATE_PHY, rate); |
| | | dev->avg_rssi = (dev->avg_rssi * 15) / 16 + (rssi << 8); |
| | | } |
| | | |
| | | static int |
| | | mt7601u_rx_is_our_beacon(struct mt7601u_dev *dev, u8 *data) |
| | | { |
| | | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)data; |
| | | |
| | | return ieee80211_is_beacon(hdr->frame_control) && |
| | | ether_addr_equal(hdr->addr2, dev->ap_bssid); |
| | | } |
| | | |
| | | u32 mt76_mac_process_rx(struct mt7601u_dev *dev, struct sk_buff *skb, |
| | | u8 *data, void *rxi) |
| | | { |
| | | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); |
| | | struct mt7601u_rxwi *rxwi = rxi; |
| | | u32 len, ctl = le32_to_cpu(rxwi->ctl); |
| | | u16 rate = le16_to_cpu(rxwi->rate); |
| | | int rssi; |
| | | |
| | | len = MT76_GET(MT_RXWI_CTL_MPDU_LEN, ctl); |
| | | if (len < 10) |
| | | return 0; |
| | | |
| | | if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_DECRYPT)) { |
| | | status->flag |= RX_FLAG_DECRYPTED; |
| | | status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED; |
| | | } |
| | | |
| | | status->chains = BIT(0); |
| | | rssi = mt7601u_phy_get_rssi(dev, rxwi, rate); |
| | | status->chain_signal[0] = status->signal = rssi; |
| | | status->freq = dev->chandef.chan->center_freq; |
| | | status->band = dev->chandef.chan->band; |
| | | |
| | | mt76_mac_process_rate(status, rate); |
| | | |
| | | spin_lock_bh(&dev->con_mon_lock); |
| | | if (mt7601u_rx_is_our_beacon(dev, data)) |
| | | mt7601u_rx_monitor_beacon(dev, rxwi, rate, rssi); |
| | | else if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_U2M)) |
| | | dev->avg_rssi = (dev->avg_rssi * 15) / 16 + (rssi << 8); |
| | | spin_unlock_bh(&dev->con_mon_lock); |
| | | |
| | | return len; |
| | | } |
| | | |
| | | static enum mt76_cipher_type |
| | | mt76_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data) |
| | | { |
| | | memset(key_data, 0, 32); |
| | | if (!key) |
| | | return MT_CIPHER_NONE; |
| | | |
| | | if (key->keylen > 32) |
| | | return MT_CIPHER_NONE; |
| | | |
| | | memcpy(key_data, key->key, key->keylen); |
| | | |
| | | switch (key->cipher) { |
| | | case WLAN_CIPHER_SUITE_WEP40: |
| | | return MT_CIPHER_WEP40; |
| | | case WLAN_CIPHER_SUITE_WEP104: |
| | | return MT_CIPHER_WEP104; |
| | | case WLAN_CIPHER_SUITE_TKIP: |
| | | return MT_CIPHER_TKIP; |
| | | case WLAN_CIPHER_SUITE_CCMP: |
| | | return MT_CIPHER_AES_CCMP; |
| | | default: |
| | | return MT_CIPHER_NONE; |
| | | } |
| | | } |
| | | |
| | | int mt76_mac_wcid_set_key(struct mt7601u_dev *dev, u8 idx, |
| | | struct ieee80211_key_conf *key) |
| | | { |
| | | enum mt76_cipher_type cipher; |
| | | u8 key_data[32]; |
| | | u8 iv_data[8]; |
| | | u32 val; |
| | | |
| | | cipher = mt76_mac_get_key_info(key, key_data); |
| | | if (cipher == MT_CIPHER_NONE && key) |
| | | return -EINVAL; |
| | | |
| | | trace_set_key(dev, idx); |
| | | |
| | | mt7601u_wr_copy(dev, MT_WCID_KEY(idx), key_data, sizeof(key_data)); |
| | | |
| | | memset(iv_data, 0, sizeof(iv_data)); |
| | | if (key) { |
| | | iv_data[3] = key->keyidx << 6; |
| | | if (cipher >= MT_CIPHER_TKIP) { |
| | | /* Note: start with 1 to comply with spec, |
| | | * (see comment on common/cmm_wpa.c:4291). |
| | | */ |
| | | iv_data[0] |= 1; |
| | | iv_data[3] |= 0x20; |
| | | } |
| | | } |
| | | mt7601u_wr_copy(dev, MT_WCID_IV(idx), iv_data, sizeof(iv_data)); |
| | | |
| | | val = mt7601u_rr(dev, MT_WCID_ATTR(idx)); |
| | | val &= ~MT_WCID_ATTR_PKEY_MODE & ~MT_WCID_ATTR_PKEY_MODE_EXT; |
| | | val |= MT76_SET(MT_WCID_ATTR_PKEY_MODE, cipher & 7) | |
| | | MT76_SET(MT_WCID_ATTR_PKEY_MODE_EXT, cipher >> 3); |
| | | val &= ~MT_WCID_ATTR_PAIRWISE; |
| | | val |= MT_WCID_ATTR_PAIRWISE * |
| | | !!(key && key->flags & IEEE80211_KEY_FLAG_PAIRWISE); |
| | | mt7601u_wr(dev, MT_WCID_ATTR(idx), val); |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | int mt76_mac_shared_key_setup(struct mt7601u_dev *dev, u8 vif_idx, u8 key_idx, |
| | | struct ieee80211_key_conf *key) |
| | | { |
| | | enum mt76_cipher_type cipher; |
| | | u8 key_data[32]; |
| | | u32 val; |
| | | |
| | | cipher = mt76_mac_get_key_info(key, key_data); |
| | | if (cipher == MT_CIPHER_NONE && key) |
| | | return -EINVAL; |
| | | |
| | | trace_set_shared_key(dev, vif_idx, key_idx); |
| | | |
| | | mt7601u_wr_copy(dev, MT_SKEY(vif_idx, key_idx), |
| | | key_data, sizeof(key_data)); |
| | | |
| | | val = mt76_rr(dev, MT_SKEY_MODE(vif_idx)); |
| | | val &= ~(MT_SKEY_MODE_MASK << MT_SKEY_MODE_SHIFT(vif_idx, key_idx)); |
| | | val |= cipher << MT_SKEY_MODE_SHIFT(vif_idx, key_idx); |
| | | mt76_wr(dev, MT_SKEY_MODE(vif_idx), val); |
| | | |
| | | return 0; |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> |
| | | * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> |
| | | * |
| | | * This program is free software; you can redistribute it and/or modify |
| | | * it under the terms of the GNU General Public License version 2 |
| | | * as published by the Free Software Foundation |
| | | * |
| | | * This program is distributed in the hope that it will be useful, |
| | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| | | * GNU General Public License for more details. |
| | | */ |
| | | |
| | | #ifndef __MT76_MAC_H |
| | | #define __MT76_MAC_H |
| | | |
| | | struct mt76_tx_status { |
| | | u8 valid:1; |
| | | u8 success:1; |
| | | u8 aggr:1; |
| | | u8 ack_req:1; |
| | | u8 is_probe:1; |
| | | u8 wcid; |
| | | u8 pktid; |
| | | u8 retry; |
| | | u16 rate; |
| | | } __packed __aligned(2); |
| | | |
| | | /* Note: values in original "RSSI" and "SNR" fields are not actually what they |
| | | * are called for MT7601U, names used by this driver are educated guesses |
| | | * (see vendor mac/ral_omac.c). |
| | | */ |
| | | struct mt7601u_rxwi { |
| | | __le32 rxinfo; |
| | | |
| | | __le32 ctl; |
| | | |
| | | __le16 frag_sn; |
| | | __le16 rate; |
| | | |
| | | u8 unknown; |
| | | u8 zero[3]; |
| | | |
| | | u8 snr; |
| | | u8 ant; |
| | | u8 gain; |
| | | u8 freq_off; |
| | | |
| | | __le32 resv2; |
| | | __le32 expert_ant; |
| | | } __packed __aligned(4); |
| | | |
| | | #define MT_RXINFO_BA BIT(0) |
| | | #define MT_RXINFO_DATA BIT(1) |
| | | #define MT_RXINFO_NULL BIT(2) |
| | | #define MT_RXINFO_FRAG BIT(3) |
| | | #define MT_RXINFO_U2M BIT(4) |
| | | #define MT_RXINFO_MULTICAST BIT(5) |
| | | #define MT_RXINFO_BROADCAST BIT(6) |
| | | #define MT_RXINFO_MYBSS BIT(7) |
| | | #define MT_RXINFO_CRCERR BIT(8) |
| | | #define MT_RXINFO_ICVERR BIT(9) |
| | | #define MT_RXINFO_MICERR BIT(10) |
| | | #define MT_RXINFO_AMSDU BIT(11) |
| | | #define MT_RXINFO_HTC BIT(12) |
| | | #define MT_RXINFO_RSSI BIT(13) |
| | | #define MT_RXINFO_L2PAD BIT(14) |
| | | #define MT_RXINFO_AMPDU BIT(15) |
| | | #define MT_RXINFO_DECRYPT BIT(16) |
| | | #define MT_RXINFO_BSSIDX3 BIT(17) |
| | | #define MT_RXINFO_WAPI_KEY BIT(18) |
| | | #define MT_RXINFO_PN_LEN GENMASK(21, 19) |
| | | #define MT_RXINFO_SW_PKT_80211 BIT(22) |
| | | #define MT_RXINFO_TCP_SUM_BYPASS BIT(28) |
| | | #define MT_RXINFO_IP_SUM_BYPASS BIT(29) |
| | | #define MT_RXINFO_TCP_SUM_ERR BIT(30) |
| | | #define MT_RXINFO_IP_SUM_ERR BIT(31) |
| | | |
| | | #define MT_RXWI_CTL_WCID GENMASK(7, 0) |
| | | #define MT_RXWI_CTL_KEY_IDX GENMASK(9, 8) |
| | | #define MT_RXWI_CTL_BSS_IDX GENMASK(12, 10) |
| | | #define MT_RXWI_CTL_UDF GENMASK(15, 13) |
| | | #define MT_RXWI_CTL_MPDU_LEN GENMASK(27, 16) |
| | | #define MT_RXWI_CTL_TID GENMASK(31, 28) |
| | | |
| | | #define MT_RXWI_FRAG GENMASK(3, 0) |
| | | #define MT_RXWI_SN GENMASK(15, 4) |
| | | |
| | | #define MT_RXWI_RATE_MCS GENMASK(6, 0) |
| | | #define MT_RXWI_RATE_BW BIT(7) |
| | | #define MT_RXWI_RATE_SGI BIT(8) |
| | | #define MT_RXWI_RATE_STBC GENMASK(10, 9) |
| | | #define MT_RXWI_RATE_ETXBF BIT(11) |
| | | #define MT_RXWI_RATE_SND BIT(12) |
| | | #define MT_RXWI_RATE_ITXBF BIT(13) |
| | | #define MT_RXWI_RATE_PHY GENMASK(15, 14) |
| | | |
| | | #define MT_RXWI_GAIN_RSSI_VAL GENMASK(5, 0) |
| | | #define MT_RXWI_GAIN_RSSI_LNA_ID GENMASK(7, 6) |
| | | #define MT_RXWI_ANT_AUX_LNA BIT(7) |
| | | |
| | | #define MT_RXWI_EANT_ENC_ANT_ID GENMASK(7, 0) |
| | | |
| | | enum mt76_phy_type { |
| | | MT_PHY_TYPE_CCK, |
| | | MT_PHY_TYPE_OFDM, |
| | | MT_PHY_TYPE_HT, |
| | | MT_PHY_TYPE_HT_GF, |
| | | }; |
| | | |
| | | enum mt76_phy_bandwidth { |
| | | MT_PHY_BW_20, |
| | | MT_PHY_BW_40, |
| | | }; |
| | | |
| | | struct mt76_txwi { |
| | | __le16 flags; |
| | | __le16 rate_ctl; |
| | | |
| | | u8 ack_ctl; |
| | | u8 wcid; |
| | | __le16 len_ctl; |
| | | |
| | | __le32 iv; |
| | | |
| | | __le32 eiv; |
| | | |
| | | u8 aid; |
| | | u8 txstream; |
| | | __le16 ctl; |
| | | } __packed __aligned(4); |
| | | |
| | | #define MT_TXWI_FLAGS_FRAG BIT(0) |
| | | #define MT_TXWI_FLAGS_MMPS BIT(1) |
| | | #define MT_TXWI_FLAGS_CFACK BIT(2) |
| | | #define MT_TXWI_FLAGS_TS BIT(3) |
| | | #define MT_TXWI_FLAGS_AMPDU BIT(4) |
| | | #define MT_TXWI_FLAGS_MPDU_DENSITY GENMASK(7, 5) |
| | | #define MT_TXWI_FLAGS_TXOP GENMASK(9, 8) |
| | | #define MT_TXWI_FLAGS_CWMIN GENMASK(12, 10) |
| | | #define MT_TXWI_FLAGS_NO_RATE_FALLBACK BIT(13) |
| | | #define MT_TXWI_FLAGS_TX_RPT BIT(14) |
| | | #define MT_TXWI_FLAGS_TX_RATE_LUT BIT(15) |
| | | |
| | | #define MT_TXWI_RATE_MCS GENMASK(6, 0) |
| | | #define MT_TXWI_RATE_BW BIT(7) |
| | | #define MT_TXWI_RATE_SGI BIT(8) |
| | | #define MT_TXWI_RATE_STBC GENMASK(10, 9) |
| | | #define MT_TXWI_RATE_PHY_MODE GENMASK(15, 14) |
| | | |
| | | #define MT_TXWI_ACK_CTL_REQ BIT(0) |
| | | #define MT_TXWI_ACK_CTL_NSEQ BIT(1) |
| | | #define MT_TXWI_ACK_CTL_BA_WINDOW GENMASK(7, 2) |
| | | |
| | | #define MT_TXWI_LEN_BYTE_CNT GENMASK(11, 0) |
| | | #define MT_TXWI_LEN_PKTID GENMASK(15, 12) |
| | | |
| | | #define MT_TXWI_CTL_TX_POWER_ADJ GENMASK(3, 0) |
| | | #define MT_TXWI_CTL_CHAN_CHECK_PKT BIT(4) |
| | | #define MT_TXWI_CTL_PIFS_REV BIT(6) |
| | | |
| | | u32 mt76_mac_process_rx(struct mt7601u_dev *dev, struct sk_buff *skb, |
| | | u8 *data, void *rxi); |
| | | int mt76_mac_wcid_set_key(struct mt7601u_dev *dev, u8 idx, |
| | | struct ieee80211_key_conf *key); |
| | | void mt76_mac_wcid_set_rate(struct mt7601u_dev *dev, struct mt76_wcid *wcid, |
| | | const struct ieee80211_tx_rate *rate); |
| | | |
| | | int mt76_mac_shared_key_setup(struct mt7601u_dev *dev, u8 vif_idx, u8 key_idx, |
| | | struct ieee80211_key_conf *key); |
| | | u16 mt76_mac_tx_rate_val(struct mt7601u_dev *dev, |
| | | const struct ieee80211_tx_rate *rate, u8 *nss_val); |
| | | struct mt76_tx_status |
| | | mt7601u_mac_fetch_tx_status(struct mt7601u_dev *dev); |
| | | void mt76_send_tx_status(struct mt7601u_dev *dev, struct mt76_tx_status *stat); |
| | | |
| | | #endif |
New file |
| | |
| | | /* |
| | | * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> |
| | | * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> |
| | | * |
| | | * This program is free software; you can redistribute it and/or modify |
| | | * it under the terms of the GNU General Public License version 2 |
| | | * as published by the Free Software Foundation |
| | | * |
| | | * This program is distributed in the hope that it will be useful, |
| | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| | | * GNU General Public License for more details. |
| | | */ |
| | | |
| | | #include "mt7601u.h" |
| | | #include "mac.h" |
| | | #include <linux/etherdevice.h> |
| | | #include <linux/version.h> |
| | | |
| | | #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0) |
| | | #error Your kernel is too old, please upgrade to at least 3.19 |
| | | #endif |
| | | |
| | | static int mt7601u_start(struct ieee80211_hw *hw) |
| | | { |
| | | struct mt7601u_dev *dev = hw->priv; |
| | | int ret; |
| | | |
| | | mutex_lock(&dev->mutex); |
| | | |
| | | ret = mt7601u_mac_start(dev); |
| | | if (ret) |
| | | goto out; |
| | | |
| | | ieee80211_queue_delayed_work(dev->hw, &dev->mac_work, |
| | | MT_CALIBRATE_INTERVAL); |
| | | ieee80211_queue_delayed_work(dev->hw, &dev->cal_work, |
| | | MT_CALIBRATE_INTERVAL); |
| | | out: |
| | | mutex_unlock(&dev->mutex); |
| | | return ret; |
| | | } |
| | | |
| | | static void mt7601u_stop(struct ieee80211_hw *hw) |
| | | { |
| | | struct mt7601u_dev *dev = hw->priv; |
| | | |
| | | mutex_lock(&dev->mutex); |
| | | |
| | | cancel_delayed_work_sync(&dev->cal_work); |
| | | cancel_delayed_work_sync(&dev->mac_work); |
| | | mt7601u_mac_stop(dev); |
| | | |
| | | mutex_unlock(&dev->mutex); |
| | | } |
| | | |
| | | static int mt7601u_add_interface(struct ieee80211_hw *hw, |
| | | struct ieee80211_vif *vif) |
| | | { |
| | | struct mt7601u_dev *dev = hw->priv; |
| | | struct mt76_vif *mvif = (struct mt76_vif *) vif->drv_priv; |
| | | unsigned int idx = 0; |
| | | unsigned int wcid = GROUP_WCID(idx); |
| | | |
| | | /* Note: for AP do the AP-STA things mt76 does: |
| | | * - beacon offsets |
| | | * - do mac address tricks |
| | | * - shift vif idx |
| | | */ |
| | | mvif->idx = idx; |
| | | |
| | | if (dev->wcid_mask[wcid / BITS_PER_LONG] & BIT(wcid % BITS_PER_LONG)) |
| | | return -ENOSPC; |
| | | dev->wcid_mask[wcid / BITS_PER_LONG] |= BIT(wcid % BITS_PER_LONG); |
| | | mvif->group_wcid.idx = wcid; |
| | | mvif->group_wcid.hw_key_idx = -1; |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | static void mt7601u_remove_interface(struct ieee80211_hw *hw, |
| | | struct ieee80211_vif *vif) |
| | | { |
| | | struct mt7601u_dev *dev = hw->priv; |
| | | struct mt76_vif *mvif = (struct mt76_vif *) vif->drv_priv; |
| | | unsigned int wcid = mvif->group_wcid.idx; |
| | | |
| | | dev->wcid_mask[wcid / BITS_PER_LONG] &= ~BIT(wcid % BITS_PER_LONG); |
| | | } |
| | | |
| | | static int mt7601u_config(struct ieee80211_hw *hw, u32 changed) |
| | | { |
| | | struct mt7601u_dev *dev = hw->priv; |
| | | int ret = 0; |
| | | |
| | | mutex_lock(&dev->mutex); |
| | | |
| | | if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { |
| | | ieee80211_stop_queues(hw); |
| | | ret = mt7601u_phy_set_channel(dev, &hw->conf.chandef); |
| | | ieee80211_wake_queues(hw); |
| | | } |
| | | |
| | | mutex_unlock(&dev->mutex); |
| | | |
| | | return ret; |
| | | } |
| | | |
| | | static void |
| | | mt76_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, |
| | | unsigned int *total_flags, u64 multicast) |
| | | { |
| | | struct mt7601u_dev *dev = hw->priv; |
| | | u32 flags = 0; |
| | | |
| | | #define MT76_FILTER(_flag, _hw) do { \ |
| | | flags |= *total_flags & FIF_##_flag; \ |
| | | dev->rxfilter &= ~(_hw); \ |
| | | dev->rxfilter |= !(flags & FIF_##_flag) * (_hw); \ |
| | | } while (0) |
| | | |
| | | mutex_lock(&dev->mutex); |
| | | |
| | | dev->rxfilter &= ~MT_RX_FILTR_CFG_OTHER_BSS; |
| | | |
| | | MT76_FILTER(OTHER_BSS, MT_RX_FILTR_CFG_PROMISC); |
| | | MT76_FILTER(FCSFAIL, MT_RX_FILTR_CFG_CRC_ERR); |
| | | MT76_FILTER(PLCPFAIL, MT_RX_FILTR_CFG_PHY_ERR); |
| | | MT76_FILTER(CONTROL, MT_RX_FILTR_CFG_ACK | |
| | | MT_RX_FILTR_CFG_CTS | |
| | | MT_RX_FILTR_CFG_CFEND | |
| | | MT_RX_FILTR_CFG_CFACK | |
| | | MT_RX_FILTR_CFG_BA | |
| | | MT_RX_FILTR_CFG_CTRL_RSV); |
| | | MT76_FILTER(PSPOLL, MT_RX_FILTR_CFG_PSPOLL); |
| | | |
| | | *total_flags = flags; |
| | | mt76_wr(dev, MT_RX_FILTR_CFG, dev->rxfilter); |
| | | |
| | | mutex_unlock(&dev->mutex); |
| | | } |
| | | |
| | | static void |
| | | mt7601u_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
| | | struct ieee80211_bss_conf *info, u32 changed) |
| | | { |
| | | struct mt7601u_dev *dev = hw->priv; |
| | | |
| | | mutex_lock(&dev->mutex); |
| | | |
| | | if (changed & BSS_CHANGED_ASSOC) |
| | | mt7601u_phy_con_cal_onoff(dev, info); |
| | | |
| | | if (changed & BSS_CHANGED_BSSID) { |
| | | mt7601u_addr_wr(dev, MT_MAC_BSSID_DW0, info->bssid); |
| | | |
| | | /* Note: this is a hack because beacon_int is not changed |
| | | * on leave nor is any more appropriate event generated. |
| | | * rt2x00 doesn't seem to be bothered though. |
| | | */ |
| | | if (is_zero_ether_addr(info->bssid)) |
| | | mt7601u_mac_config_tsf(dev, false, 0); |
| | | } |
| | | |
| | | if (changed & BSS_CHANGED_BASIC_RATES) { |
| | | mt7601u_wr(dev, MT_LEGACY_BASIC_RATE, info->basic_rates); |
| | | mt7601u_wr(dev, MT_HT_FBK_CFG0, 0x65432100); |
| | | mt7601u_wr(dev, MT_HT_FBK_CFG1, 0xedcba980); |
| | | mt7601u_wr(dev, MT_LG_FBK_CFG0, 0xedcba988); |
| | | mt7601u_wr(dev, MT_LG_FBK_CFG1, 0x00002100); |
| | | } |
| | | |
| | | if (changed & BSS_CHANGED_BEACON_INT) |
| | | mt7601u_mac_config_tsf(dev, true, info->beacon_int); |
| | | |
| | | if (changed & BSS_CHANGED_HT || changed & BSS_CHANGED_ERP_CTS_PROT) |
| | | mt7601u_mac_set_protection(dev, info->use_cts_prot, |
| | | info->ht_operation_mode); |
| | | |
| | | if (changed & BSS_CHANGED_ERP_PREAMBLE) |
| | | mt7601u_mac_set_short_preamble(dev, info->use_short_preamble); |
| | | |
| | | if (changed & BSS_CHANGED_ERP_SLOT) { |
| | | int slottime = info->use_short_slot ? 9 : 20; |
| | | |
| | | mt76_rmw_field(dev, MT_BKOFF_SLOT_CFG, |
| | | MT_BKOFF_SLOT_CFG_SLOTTIME, slottime); |
| | | } |
| | | |
| | | if (changed & BSS_CHANGED_ASSOC) |
| | | mt7601u_phy_recalibrate_after_assoc(dev); |
| | | |
| | | mutex_unlock(&dev->mutex); |
| | | } |
| | | |
| | | static int |
| | | mt76_wcid_alloc(struct mt7601u_dev *dev) |
| | | { |
| | | int i, idx = 0; |
| | | |
| | | for (i = 0; i < ARRAY_SIZE(dev->wcid_mask); i++) { |
| | | idx = ffs(~dev->wcid_mask[i]); |
| | | if (!idx) |
| | | continue; |
| | | |
| | | idx--; |
| | | dev->wcid_mask[i] |= BIT(idx); |
| | | break; |
| | | } |
| | | |
| | | idx = i * BITS_PER_LONG + idx; |
| | | if (idx > 119) |
| | | return -1; |
| | | |
| | | return idx; |
| | | } |
| | | |
| | | static int |
| | | mt7601u_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
| | | struct ieee80211_sta *sta) |
| | | { |
| | | struct mt7601u_dev *dev = hw->priv; |
| | | struct mt76_sta *msta = (struct mt76_sta *) sta->drv_priv; |
| | | struct mt76_vif *mvif = (struct mt76_vif *) vif->drv_priv; |
| | | int ret = 0; |
| | | int idx = 0; |
| | | |
| | | mutex_lock(&dev->mutex); |
| | | |
| | | idx = mt76_wcid_alloc(dev); |
| | | if (idx < 0) { |
| | | ret = -ENOSPC; |
| | | goto out; |
| | | } |
| | | |
| | | msta->wcid.idx = idx; |
| | | msta->wcid.hw_key_idx = -1; |
| | | mt7601u_mac_wcid_setup(dev, idx, mvif->idx, sta->addr); |
| | | mt76_clear(dev, MT_WCID_DROP(idx), MT_WCID_DROP_MASK(idx)); |
| | | rcu_assign_pointer(dev->wcid[idx], &msta->wcid); |
| | | mt7601u_mac_set_ampdu_factor(dev); |
| | | |
| | | out: |
| | | mutex_unlock(&dev->mutex); |
| | | |
| | | return ret; |
| | | } |
| | | |
| | | static int |
| | | mt7601u_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
| | | struct ieee80211_sta *sta) |
| | | { |
| | | struct mt7601u_dev *dev = hw->priv; |
| | | struct mt76_sta *msta = (struct mt76_sta *) sta->drv_priv; |
| | | int idx = msta->wcid.idx; |
| | | |
| | | mutex_lock(&dev->mutex); |
| | | rcu_assign_pointer(dev->wcid[idx], NULL); |
| | | mt76_set(dev, MT_WCID_DROP(idx), MT_WCID_DROP_MASK(idx)); |
| | | dev->wcid_mask[idx / BITS_PER_LONG] &= ~BIT(idx % BITS_PER_LONG); |
| | | mt7601u_mac_wcid_setup(dev, idx, 0, NULL); |
| | | mt7601u_mac_set_ampdu_factor(dev); |
| | | mutex_unlock(&dev->mutex); |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | static void |
| | | mt7601u_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
| | | enum sta_notify_cmd cmd, struct ieee80211_sta *sta) |
| | | { |
| | | } |
| | | |
| | | static void |
| | | mt7601u_sw_scan(struct ieee80211_hw *hw, |
| | | struct ieee80211_vif *vif, |
| | | const u8 *mac_addr) |
| | | { |
| | | struct mt7601u_dev *dev = hw->priv; |
| | | |
| | | mt7601u_agc_save(dev); |
| | | set_bit(MT7601U_STATE_SCANNING, &dev->state); |
| | | } |
| | | |
| | | static void |
| | | mt7601u_sw_scan_complete(struct ieee80211_hw *hw, |
| | | struct ieee80211_vif *vif) |
| | | { |
| | | struct mt7601u_dev *dev = hw->priv; |
| | | |
| | | mt7601u_agc_restore(dev); |
| | | clear_bit(MT7601U_STATE_SCANNING, &dev->state); |
| | | } |
| | | |
| | | static int |
| | | mt7601u_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, |
| | | struct ieee80211_vif *vif, struct ieee80211_sta *sta, |
| | | struct ieee80211_key_conf *key) |
| | | { |
| | | struct mt7601u_dev *dev = hw->priv; |
| | | struct mt76_vif *mvif = (struct mt76_vif *) vif->drv_priv; |
| | | struct mt76_sta *msta = sta ? (struct mt76_sta *) sta->drv_priv : NULL; |
| | | struct mt76_wcid *wcid = msta ? &msta->wcid : &mvif->group_wcid; |
| | | int idx = key->keyidx; |
| | | int ret; |
| | | |
| | | if (cmd == SET_KEY) { |
| | | key->hw_key_idx = wcid->idx; |
| | | wcid->hw_key_idx = idx; |
| | | } else { |
| | | if (idx == wcid->hw_key_idx) |
| | | wcid->hw_key_idx = -1; |
| | | |
| | | key = NULL; |
| | | } |
| | | |
| | | if (!msta) { |
| | | if (key || wcid->hw_key_idx == idx) { |
| | | ret = mt76_mac_wcid_set_key(dev, wcid->idx, key); |
| | | if (ret) |
| | | return ret; |
| | | } |
| | | |
| | | return mt76_mac_shared_key_setup(dev, mvif->idx, idx, key); |
| | | } |
| | | |
| | | return mt76_mac_wcid_set_key(dev, msta->wcid.idx, key); |
| | | } |
| | | |
| | | static int mt7601u_set_rts_threshold(struct ieee80211_hw *hw, u32 value) |
| | | { |
| | | struct mt7601u_dev *dev = hw->priv; |
| | | |
| | | mt76_rmw_field(dev, MT_TX_RTS_CFG, MT_TX_RTS_CFG_THRESH, value); |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | static int |
| | | mt76_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
| | | #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0) |
| | | struct ieee80211_ampdu_params *params |
| | | #else |
| | | enum ieee80211_ampdu_mlme_action action, |
| | | struct ieee80211_sta *sta, u16 tid, u16 *ssn, u8 buf_size |
| | | #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0) |
| | | , bool amsdu |
| | | #endif |
| | | #endif |
| | | ) |
| | | { |
| | | #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0) |
| | | enum ieee80211_ampdu_mlme_action action = params->action; |
| | | struct ieee80211_sta *sta = params->sta; |
| | | u16 *ssn = ¶ms->ssn; |
| | | u16 tid = params->tid; |
| | | #endif |
| | | struct mt7601u_dev *dev = hw->priv; |
| | | struct mt76_sta *msta = (struct mt76_sta *) sta->drv_priv; |
| | | |
| | | WARN_ON(msta->wcid.idx > GROUP_WCID(0)); |
| | | |
| | | switch (action) { |
| | | case IEEE80211_AMPDU_RX_START: |
| | | mt76_set(dev, MT_WCID_ADDR(msta->wcid.idx) + 4, BIT(16 + tid)); |
| | | break; |
| | | case IEEE80211_AMPDU_RX_STOP: |
| | | mt76_clear(dev, MT_WCID_ADDR(msta->wcid.idx) + 4, |
| | | BIT(16 + tid)); |
| | | break; |
| | | case IEEE80211_AMPDU_TX_OPERATIONAL: |
| | | ieee80211_send_bar(vif, sta->addr, tid, msta->agg_ssn[tid]); |
| | | break; |
| | | case IEEE80211_AMPDU_TX_STOP_FLUSH: |
| | | case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: |
| | | break; |
| | | case IEEE80211_AMPDU_TX_START: |
| | | msta->agg_ssn[tid] = *ssn << 4; |
| | | ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); |
| | | break; |
| | | case IEEE80211_AMPDU_TX_STOP_CONT: |
| | | ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); |
| | | break; |
| | | } |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | static void |
| | | mt76_sta_rate_tbl_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
| | | struct ieee80211_sta *sta) |
| | | { |
| | | struct mt7601u_dev *dev = hw->priv; |
| | | struct mt76_sta *msta = (struct mt76_sta *) sta->drv_priv; |
| | | struct ieee80211_sta_rates *rates; |
| | | struct ieee80211_tx_rate rate = {}; |
| | | |
| | | rcu_read_lock(); |
| | | rates = rcu_dereference(sta->rates); |
| | | |
| | | if (!rates) |
| | | goto out; |
| | | |
| | | rate.idx = rates->rate[0].idx; |
| | | rate.flags = rates->rate[0].flags; |
| | | mt76_mac_wcid_set_rate(dev, &msta->wcid, &rate); |
| | | |
| | | out: |
| | | rcu_read_unlock(); |
| | | } |
| | | |
| | | const struct ieee80211_ops mt7601u_ops = { |
| | | .tx = mt7601u_tx, |
| | | .start = mt7601u_start, |
| | | .stop = mt7601u_stop, |
| | | .add_interface = mt7601u_add_interface, |
| | | .remove_interface = mt7601u_remove_interface, |
| | | .config = mt7601u_config, |
| | | .configure_filter = mt76_configure_filter, |
| | | .bss_info_changed = mt7601u_bss_info_changed, |
| | | .sta_add = mt7601u_sta_add, |
| | | .sta_remove = mt7601u_sta_remove, |
| | | .sta_notify = mt7601u_sta_notify, |
| | | .set_key = mt7601u_set_key, |
| | | .conf_tx = mt7601u_conf_tx, |
| | | .sw_scan_start = mt7601u_sw_scan, |
| | | .sw_scan_complete = mt7601u_sw_scan_complete, |
| | | /* .flush = mt7601u_flush,*/ |
| | | .ampdu_action = mt76_ampdu_action, |
| | | .sta_rate_tbl_update = mt76_sta_rate_tbl_update, |
| | | .set_rts_threshold = mt7601u_set_rts_threshold, |
| | | }; |
New file |
| | |
| | | /* |
| | | * (c) Copyright 2002-2010, Ralink Technology, Inc. |
| | | * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> |
| | | * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> |
| | | * |
| | | * This program is free software; you can redistribute it and/or modify |
| | | * it under the terms of the GNU General Public License version 2 |
| | | * as published by the Free Software Foundation |
| | | * |
| | | * This program is distributed in the hope that it will be useful, |
| | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| | | * GNU General Public License for more details. |
| | | */ |
| | | |
| | | #include <linux/kernel.h> |
| | | #include <linux/firmware.h> |
| | | #include <linux/delay.h> |
| | | #include <linux/usb.h> |
| | | #include <linux/skbuff.h> |
| | | |
| | | #include "mt7601u.h" |
| | | #include "dma.h" |
| | | #include "mcu.h" |
| | | #include "usb.h" |
| | | #include "trace.h" |
| | | |
| | | #define MCU_FW_URB_MAX_PAYLOAD 0x3800 |
| | | #define MCU_FW_URB_SIZE (MCU_FW_URB_MAX_PAYLOAD + 12) |
| | | #define MCU_RESP_URB_SIZE 1024 |
| | | |
| | | static inline int firmware_running(struct mt7601u_dev *dev) |
| | | { |
| | | return mt7601u_rr(dev, MT_MCU_COM_REG0) == 1; |
| | | } |
| | | |
| | | static inline void skb_put_le32(struct sk_buff *skb, u32 val) |
| | | { |
| | | put_unaligned_le32(val, skb_put(skb, 4)); |
| | | } |
| | | |
| | | static inline void mt7601u_dma_skb_wrap_cmd(struct sk_buff *skb, |
| | | u8 seq, enum mcu_cmd cmd) |
| | | { |
| | | WARN_ON(mt7601u_dma_skb_wrap(skb, CPU_TX_PORT, DMA_COMMAND, |
| | | MT76_SET(MT_TXD_CMD_INFO_SEQ, seq) | |
| | | MT76_SET(MT_TXD_CMD_INFO_TYPE, cmd))); |
| | | } |
| | | |
| | | static inline void trace_mt_mcu_msg_send_cs(struct mt7601u_dev *dev, |
| | | struct sk_buff *skb, bool need_resp) |
| | | { |
| | | u32 i, csum = 0; |
| | | |
| | | for (i = 0; i < skb->len / 4; i++) |
| | | csum ^= get_unaligned_le32(skb->data + i * 4); |
| | | |
| | | trace_mt_mcu_msg_send(dev, skb, csum, need_resp); |
| | | } |
| | | |
| | | static struct sk_buff * |
| | | mt7601u_mcu_msg_alloc(struct mt7601u_dev *dev, const void *data, int len) |
| | | { |
| | | struct sk_buff *skb; |
| | | |
| | | WARN_ON(len % 4); /* if length is not divisible by 4 we need to pad */ |
| | | |
| | | skb = alloc_skb(len + MT_DMA_HDR_LEN + 4, GFP_KERNEL); |
| | | skb_reserve(skb, MT_DMA_HDR_LEN); |
| | | memcpy(skb_put(skb, len), data, len); |
| | | |
| | | return skb; |
| | | } |
| | | |
| | | static int mt7601u_mcu_wait_resp(struct mt7601u_dev *dev, u8 seq) |
| | | { |
| | | struct urb *urb = dev->mcu.resp.urb; |
| | | u32 rxfce; |
| | | int urb_status, ret, i = 5; |
| | | |
| | | while (i--) { |
| | | if (!wait_for_completion_timeout(&dev->mcu.resp_cmpl, |
| | | msecs_to_jiffies(300))) { |
| | | dev_warn(dev->dev, "Warning: %s retrying\n", __func__); |
| | | continue; |
| | | } |
| | | |
| | | /* Make copies of important data before reusing the urb */ |
| | | rxfce = get_unaligned_le32(dev->mcu.resp.buf); |
| | | urb_status = urb->status * mt7601u_urb_has_error(urb); |
| | | |
| | | ret = mt7601u_usb_submit_buf(dev, USB_DIR_IN, MT_EP_IN_CMD_RESP, |
| | | &dev->mcu.resp, GFP_KERNEL, |
| | | mt7601u_complete_urb, |
| | | &dev->mcu.resp_cmpl); |
| | | if (ret) |
| | | return ret; |
| | | |
| | | if (urb_status) |
| | | dev_err(dev->dev, "Error: MCU resp urb failed:%d\n", |
| | | urb_status); |
| | | |
| | | if (MT76_GET(MT_RXD_CMD_INFO_CMD_SEQ, rxfce) == seq && |
| | | MT76_GET(MT_RXD_CMD_INFO_EVT_TYPE, rxfce) == CMD_DONE) |
| | | return 0; |
| | | |
| | | dev_err(dev->dev, "Error: MCU resp evt:%hhx seq:%hhx-%hhx!\n", |
| | | MT76_GET(MT_RXD_CMD_INFO_EVT_TYPE, rxfce), |
| | | seq, MT76_GET(MT_RXD_CMD_INFO_CMD_SEQ, rxfce)); |
| | | } |
| | | |
| | | dev_err(dev->dev, "Error: %s timed out\n", __func__); |
| | | return -ETIMEDOUT; |
| | | } |
| | | |
| | | static int |
| | | mt7601u_mcu_msg_send(struct mt7601u_dev *dev, struct sk_buff *skb, |
| | | enum mcu_cmd cmd, bool wait_resp) |
| | | { |
| | | struct usb_device *usb_dev = mt7601u_to_usb_dev(dev); |
| | | unsigned cmd_pipe = usb_sndbulkpipe(usb_dev, |
| | | dev->out_eps[MT_EP_OUT_INBAND_CMD]); |
| | | int sent, ret; |
| | | u8 seq = 0; |
| | | |
| | | if (test_bit(MT7601U_STATE_REMOVED, &dev->state)) |
| | | return 0; |
| | | |
| | | mutex_lock(&dev->mcu.mutex); |
| | | |
| | | if (wait_resp) |
| | | while (!seq) |
| | | seq = ++dev->mcu.msg_seq & 0xf; |
| | | |
| | | mt7601u_dma_skb_wrap_cmd(skb, seq, cmd); |
| | | |
| | | if (dev->mcu.resp_cmpl.done) |
| | | dev_err(dev->dev, "Error: MCU response pre-completed!\n"); |
| | | |
| | | trace_mt_mcu_msg_send_cs(dev, skb, wait_resp); |
| | | trace_mt_submit_urb_sync(dev, cmd_pipe, skb->len); |
| | | ret = usb_bulk_msg(usb_dev, cmd_pipe, skb->data, skb->len, &sent, 500); |
| | | if (ret) { |
| | | dev_err(dev->dev, "Error: send MCU cmd failed:%d\n", ret); |
| | | goto out; |
| | | } |
| | | if (sent != skb->len) |
| | | dev_err(dev->dev, "Error: %s sent != skb->len\n", __func__); |
| | | |
| | | if (wait_resp) |
| | | ret = mt7601u_mcu_wait_resp(dev, seq); |
| | | out: |
| | | mutex_unlock(&dev->mcu.mutex); |
| | | |
| | | consume_skb(skb); |
| | | |
| | | return ret; |
| | | } |
| | | |
| | | static int mt7601u_mcu_function_select(struct mt7601u_dev *dev, |
| | | enum mcu_function func, u32 val) |
| | | { |
| | | struct sk_buff *skb; |
| | | struct { |
| | | __le32 id; |
| | | __le32 value; |
| | | } __packed __aligned(4) msg = { |
| | | .id = cpu_to_le32(func), |
| | | .value = cpu_to_le32(val), |
| | | }; |
| | | |
| | | skb = mt7601u_mcu_msg_alloc(dev, &msg, sizeof(msg)); |
| | | return mt7601u_mcu_msg_send(dev, skb, CMD_FUN_SET_OP, func == 5); |
| | | } |
| | | |
| | | int mt7601u_mcu_tssi_read_kick(struct mt7601u_dev *dev, int use_hvga) |
| | | { |
| | | int ret; |
| | | |
| | | if (!test_bit(MT7601U_STATE_MCU_RUNNING, &dev->state)) |
| | | return 0; |
| | | |
| | | ret = mt7601u_mcu_function_select(dev, ATOMIC_TSSI_SETTING, |
| | | use_hvga); |
| | | if (ret) { |
| | | dev_warn(dev->dev, "Warning: MCU TSSI read kick failed\n"); |
| | | return ret; |
| | | } |
| | | |
| | | dev->tssi_read_trig = true; |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | int |
| | | mt7601u_mcu_calibrate(struct mt7601u_dev *dev, enum mcu_calibrate cal, u32 val) |
| | | { |
| | | struct sk_buff *skb; |
| | | struct { |
| | | __le32 id; |
| | | __le32 value; |
| | | } __packed __aligned(4) msg = { |
| | | .id = cpu_to_le32(cal), |
| | | .value = cpu_to_le32(val), |
| | | }; |
| | | |
| | | skb = mt7601u_mcu_msg_alloc(dev, &msg, sizeof(msg)); |
| | | return mt7601u_mcu_msg_send(dev, skb, CMD_CALIBRATION_OP, true); |
| | | } |
| | | |
| | | int mt7601u_write_reg_pairs(struct mt7601u_dev *dev, u32 base, |
| | | const struct mt76_reg_pair *data, int n) |
| | | { |
| | | const int max_vals_per_cmd = INBAND_PACKET_MAX_LEN / 8; |
| | | struct sk_buff *skb; |
| | | int cnt, i, ret; |
| | | |
| | | if (!n) |
| | | return 0; |
| | | |
| | | cnt = min(max_vals_per_cmd, n); |
| | | |
| | | skb = alloc_skb(cnt * 8 + MT_DMA_HDR_LEN + 4, GFP_KERNEL); |
| | | if (!skb) |
| | | return -ENOMEM; |
| | | skb_reserve(skb, MT_DMA_HDR_LEN); |
| | | |
| | | for (i = 0; i < cnt; i++) { |
| | | skb_put_le32(skb, base + data[i].reg); |
| | | skb_put_le32(skb, data[i].value); |
| | | } |
| | | |
| | | ret = mt7601u_mcu_msg_send(dev, skb, CMD_RANDOM_WRITE, cnt == n); |
| | | if (ret) |
| | | return ret; |
| | | |
| | | return mt7601u_write_reg_pairs(dev, base, data + cnt, n - cnt); |
| | | } |
| | | |
| | | int mt7601u_burst_write_regs(struct mt7601u_dev *dev, u32 offset, |
| | | const u32 *data, int n) |
| | | { |
| | | const int max_regs_per_cmd = INBAND_PACKET_MAX_LEN / 4 - 1; |
| | | struct sk_buff *skb; |
| | | int cnt, i, ret; |
| | | |
| | | if (!n) |
| | | return 0; |
| | | |
| | | cnt = min(max_regs_per_cmd, n); |
| | | |
| | | skb = alloc_skb(cnt * 4 + MT_DMA_HDR_LEN + 4, GFP_KERNEL); |
| | | if (!skb) |
| | | return -ENOMEM; |
| | | skb_reserve(skb, MT_DMA_HDR_LEN); |
| | | |
| | | skb_put_le32(skb, MT_MCU_MEMMAP_WLAN + offset); |
| | | for (i = 0; i < cnt; i++) |
| | | skb_put_le32(skb, data[i]); |
| | | |
| | | ret = mt7601u_mcu_msg_send(dev, skb, CMD_BURST_WRITE, cnt == n); |
| | | if (ret) |
| | | return ret; |
| | | |
| | | return mt7601u_burst_write_regs(dev, offset + cnt * 4, |
| | | data + cnt, n - cnt); |
| | | } |
| | | |
| | | struct mt76_fw_header { |
| | | __le32 ilm_len; |
| | | __le32 dlm_len; |
| | | __le16 build_ver; |
| | | __le16 fw_ver; |
| | | u8 pad[4]; |
| | | char build_time[16]; |
| | | }; |
| | | |
| | | struct mt76_fw { |
| | | struct mt76_fw_header hdr; |
| | | u8 ivb[MT_MCU_IVB_SIZE]; |
| | | u8 ilm[]; |
| | | }; |
| | | |
| | | static int __mt7601u_dma_fw(struct mt7601u_dev *dev, |
| | | const struct mt7601u_dma_buf *dma_buf, |
| | | const void *data, u32 len, u32 dst_addr) |
| | | { |
| | | DECLARE_COMPLETION_ONSTACK(cmpl); |
| | | struct mt7601u_dma_buf buf = *dma_buf; /* we need to fake length */ |
| | | __le32 reg; |
| | | u32 val; |
| | | int ret; |
| | | |
| | | reg = cpu_to_le32(MT76_SET(MT_TXD_INFO_TYPE, DMA_PACKET) | |
| | | MT76_SET(MT_TXD_INFO_D_PORT, CPU_TX_PORT) | |
| | | MT76_SET(MT_TXD_INFO_LEN, len)); |
| | | memcpy(buf.buf, ®, sizeof(reg)); |
| | | memcpy(buf.buf + sizeof(reg), data, len); |
| | | memset(buf.buf + sizeof(reg) + len, 0, 8); |
| | | |
| | | ret = mt7601u_vendor_single_wr(dev, MT_VEND_WRITE_FCE, |
| | | MT_FCE_DMA_ADDR, dst_addr); |
| | | if (ret) |
| | | return ret; |
| | | len = roundup(len, 4); |
| | | ret = mt7601u_vendor_single_wr(dev, MT_VEND_WRITE_FCE, |
| | | MT_FCE_DMA_LEN, len << 16); |
| | | if (ret) |
| | | return ret; |
| | | |
| | | buf.len = MT_DMA_HDR_LEN + len + 4; |
| | | ret = mt7601u_usb_submit_buf(dev, USB_DIR_OUT, MT_EP_OUT_INBAND_CMD, |
| | | &buf, GFP_KERNEL, |
| | | mt7601u_complete_urb, &cmpl); |
| | | if (ret) |
| | | return ret; |
| | | |
| | | if (!wait_for_completion_timeout(&cmpl, msecs_to_jiffies(1000))) { |
| | | dev_err(dev->dev, "Error: firmware upload timed out\n"); |
| | | usb_kill_urb(buf.urb); |
| | | return -ETIMEDOUT; |
| | | } |
| | | if (mt7601u_urb_has_error(buf.urb)) { |
| | | dev_err(dev->dev, "Error: firmware upload urb failed:%d\n", |
| | | buf.urb->status); |
| | | return buf.urb->status; |
| | | } |
| | | |
| | | val = mt7601u_rr(dev, MT_TX_CPU_FROM_FCE_CPU_DESC_IDX); |
| | | val++; |
| | | mt7601u_wr(dev, MT_TX_CPU_FROM_FCE_CPU_DESC_IDX, val); |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | static int |
| | | mt7601u_dma_fw(struct mt7601u_dev *dev, struct mt7601u_dma_buf *dma_buf, |
| | | const void *data, int len, u32 dst_addr) |
| | | { |
| | | int n, ret; |
| | | |
| | | if (len == 0) |
| | | return 0; |
| | | |
| | | n = min(MCU_FW_URB_MAX_PAYLOAD, len); |
| | | ret = __mt7601u_dma_fw(dev, dma_buf, data, n, dst_addr); |
| | | if (ret) |
| | | return ret; |
| | | |
| | | if (!mt76_poll_msec(dev, MT_MCU_COM_REG1, BIT(31), BIT(31), 500)) |
| | | return -ETIMEDOUT; |
| | | |
| | | return mt7601u_dma_fw(dev, dma_buf, data + n, len - n, dst_addr + n); |
| | | } |
| | | |
| | | static int |
| | | mt7601u_upload_firmware(struct mt7601u_dev *dev, const struct mt76_fw *fw) |
| | | { |
| | | struct mt7601u_dma_buf dma_buf; |
| | | void *ivb; |
| | | u32 ilm_len, dlm_len; |
| | | int i, ret; |
| | | |
| | | ivb = kmemdup(fw->ivb, sizeof(fw->ivb), GFP_KERNEL); |
| | | if (!ivb) |
| | | return -ENOMEM; |
| | | if (mt7601u_usb_alloc_buf(dev, MCU_FW_URB_SIZE, &dma_buf)) { |
| | | ret = -ENOMEM; |
| | | goto error; |
| | | } |
| | | |
| | | ilm_len = le32_to_cpu(fw->hdr.ilm_len) - sizeof(fw->ivb); |
| | | dev_dbg(dev->dev, "loading FW - ILM %u + IVB %zu\n", |
| | | ilm_len, sizeof(fw->ivb)); |
| | | ret = mt7601u_dma_fw(dev, &dma_buf, fw->ilm, ilm_len, sizeof(fw->ivb)); |
| | | if (ret) |
| | | goto error; |
| | | |
| | | dlm_len = le32_to_cpu(fw->hdr.dlm_len); |
| | | dev_dbg(dev->dev, "loading FW - DLM %u\n", dlm_len); |
| | | ret = mt7601u_dma_fw(dev, &dma_buf, fw->ilm + ilm_len, |
| | | dlm_len, MT_MCU_DLM_OFFSET); |
| | | if (ret) |
| | | goto error; |
| | | |
| | | ret = mt7601u_vendor_request(dev, MT_VEND_DEV_MODE, USB_DIR_OUT, |
| | | 0x12, 0, ivb, sizeof(fw->ivb)); |
| | | if (ret < 0) |
| | | goto error; |
| | | ret = 0; |
| | | |
| | | for (i = 100; i && !firmware_running(dev); i--) |
| | | msleep(10); |
| | | if (!i) { |
| | | ret = -ETIMEDOUT; |
| | | goto error; |
| | | } |
| | | |
| | | dev_dbg(dev->dev, "Firmware running!\n"); |
| | | error: |
| | | kfree(ivb); |
| | | mt7601u_usb_free_buf(dev, &dma_buf); |
| | | |
| | | return ret; |
| | | } |
| | | |
| | | static int mt7601u_load_firmware(struct mt7601u_dev *dev) |
| | | { |
| | | const struct firmware *fw; |
| | | const struct mt76_fw_header *hdr; |
| | | int len, ret; |
| | | u32 val; |
| | | |
| | | mt7601u_wr(dev, MT_USB_DMA_CFG, (MT_USB_DMA_CFG_RX_BULK_EN | |
| | | MT_USB_DMA_CFG_TX_BULK_EN)); |
| | | |
| | | if (firmware_running(dev)) |
| | | return 0; |
| | | |
| | | ret = request_firmware(&fw, MT7601U_FIRMWARE, dev->dev); |
| | | if (ret) |
| | | return ret; |
| | | |
| | | if (!fw || !fw->data || fw->size < sizeof(*hdr)) |
| | | goto err_inv_fw; |
| | | |
| | | hdr = (const struct mt76_fw_header *) fw->data; |
| | | |
| | | if (le32_to_cpu(hdr->ilm_len) <= MT_MCU_IVB_SIZE) |
| | | goto err_inv_fw; |
| | | |
| | | len = sizeof(*hdr); |
| | | len += le32_to_cpu(hdr->ilm_len); |
| | | len += le32_to_cpu(hdr->dlm_len); |
| | | |
| | | if (fw->size != len) |
| | | goto err_inv_fw; |
| | | |
| | | val = le16_to_cpu(hdr->fw_ver); |
| | | dev_info(dev->dev, |
| | | "Firmware Version: %d.%d.%02d Build: %x Build time: %.16s\n", |
| | | (val >> 12) & 0xf, (val >> 8) & 0xf, val & 0xf, |
| | | le16_to_cpu(hdr->build_ver), hdr->build_time); |
| | | |
| | | len = le32_to_cpu(hdr->ilm_len); |
| | | |
| | | mt7601u_wr(dev, 0x94c, 0); |
| | | mt7601u_wr(dev, MT_FCE_PSE_CTRL, 0); |
| | | |
| | | mt7601u_vendor_reset(dev); |
| | | msleep(5); |
| | | |
| | | mt7601u_wr(dev, 0xa44, 0); |
| | | mt7601u_wr(dev, 0x230, 0x84210); |
| | | mt7601u_wr(dev, 0x400, 0x80c00); |
| | | mt7601u_wr(dev, 0x800, 1); |
| | | |
| | | mt7601u_rmw(dev, MT_PBF_CFG, 0, (MT_PBF_CFG_TX0Q_EN | |
| | | MT_PBF_CFG_TX1Q_EN | |
| | | MT_PBF_CFG_TX2Q_EN | |
| | | MT_PBF_CFG_TX3Q_EN)); |
| | | |
| | | mt7601u_wr(dev, MT_FCE_PSE_CTRL, 1); |
| | | |
| | | mt7601u_wr(dev, MT_USB_DMA_CFG, (MT_USB_DMA_CFG_RX_BULK_EN | |
| | | MT_USB_DMA_CFG_TX_BULK_EN)); |
| | | val = mt76_set(dev, MT_USB_DMA_CFG, MT_USB_DMA_CFG_TX_CLR); |
| | | val &= ~MT_USB_DMA_CFG_TX_CLR; |
| | | mt7601u_wr(dev, MT_USB_DMA_CFG, val); |
| | | |
| | | /* FCE tx_fs_base_ptr */ |
| | | mt7601u_wr(dev, MT_TX_CPU_FROM_FCE_BASE_PTR, 0x400230); |
| | | /* FCE tx_fs_max_cnt */ |
| | | mt7601u_wr(dev, MT_TX_CPU_FROM_FCE_MAX_COUNT, 1); |
| | | /* FCE pdma enable */ |
| | | mt7601u_wr(dev, MT_FCE_PDMA_GLOBAL_CONF, 0x44); |
| | | /* FCE skip_fs_en */ |
| | | mt7601u_wr(dev, MT_FCE_SKIP_FS, 3); |
| | | |
| | | ret = mt7601u_upload_firmware(dev, (const struct mt76_fw *)fw->data); |
| | | |
| | | release_firmware(fw); |
| | | |
| | | return ret; |
| | | |
| | | err_inv_fw: |
| | | dev_err(dev->dev, "Invalid firmware image\n"); |
| | | release_firmware(fw); |
| | | return -ENOENT; |
| | | } |
| | | |
| | | int mt7601u_mcu_init(struct mt7601u_dev *dev) |
| | | { |
| | | int ret; |
| | | |
| | | mutex_init(&dev->mcu.mutex); |
| | | |
| | | ret = mt7601u_load_firmware(dev); |
| | | if (ret) |
| | | return ret; |
| | | |
| | | set_bit(MT7601U_STATE_MCU_RUNNING, &dev->state); |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | int mt7601u_mcu_cmd_init(struct mt7601u_dev *dev) |
| | | { |
| | | int ret; |
| | | |
| | | ret = mt7601u_mcu_function_select(dev, Q_SELECT, 1); |
| | | if (ret) |
| | | return ret; |
| | | |
| | | init_completion(&dev->mcu.resp_cmpl); |
| | | if (mt7601u_usb_alloc_buf(dev, MCU_RESP_URB_SIZE, &dev->mcu.resp)) { |
| | | mt7601u_usb_free_buf(dev, &dev->mcu.resp); |
| | | return -ENOMEM; |
| | | } |
| | | |
| | | ret = mt7601u_usb_submit_buf(dev, USB_DIR_IN, MT_EP_IN_CMD_RESP, |
| | | &dev->mcu.resp, GFP_KERNEL, |
| | | mt7601u_complete_urb, &dev->mcu.resp_cmpl); |
| | | if (ret) { |
| | | mt7601u_usb_free_buf(dev, &dev->mcu.resp); |
| | | return ret; |
| | | } |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | void mt7601u_mcu_cmd_deinit(struct mt7601u_dev *dev) |
| | | { |
| | | usb_kill_urb(dev->mcu.resp.urb); |
| | | mt7601u_usb_free_buf(dev, &dev->mcu.resp); |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> |
| | | * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> |
| | | * |
| | | * This program is free software; you can redistribute it and/or modify |
| | | * it under the terms of the GNU General Public License version 2 |
| | | * as published by the Free Software Foundation |
| | | * |
| | | * This program is distributed in the hope that it will be useful, |
| | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| | | * GNU General Public License for more details. |
| | | */ |
| | | |
| | | #ifndef __MT7601U_MCU_H |
| | | #define __MT7601U_MCU_H |
| | | |
| | | struct mt7601u_dev; |
| | | |
| | | /* Register definitions */ |
| | | #define MT_MCU_RESET_CTL 0x070C |
| | | #define MT_MCU_INT_LEVEL 0x0718 |
| | | #define MT_MCU_COM_REG0 0x0730 |
| | | #define MT_MCU_COM_REG1 0x0734 |
| | | #define MT_MCU_COM_REG2 0x0738 |
| | | #define MT_MCU_COM_REG3 0x073C |
| | | |
| | | #define MT_MCU_IVB_SIZE 0x40 |
| | | #define MT_MCU_DLM_OFFSET 0x80000 |
| | | |
| | | #define MT_MCU_MEMMAP_WLAN 0x00410000 |
| | | #define MT_MCU_MEMMAP_BBP 0x40000000 |
| | | #define MT_MCU_MEMMAP_RF 0x80000000 |
| | | |
| | | #define INBAND_PACKET_MAX_LEN 192 |
| | | |
| | | enum mcu_cmd { |
| | | CMD_FUN_SET_OP = 1, |
| | | CMD_LOAD_CR = 2, |
| | | CMD_INIT_GAIN_OP = 3, |
| | | CMD_DYNC_VGA_OP = 6, |
| | | CMD_TDLS_CH_SW = 7, |
| | | CMD_BURST_WRITE = 8, |
| | | CMD_READ_MODIFY_WRITE = 9, |
| | | CMD_RANDOM_READ = 10, |
| | | CMD_BURST_READ = 11, |
| | | CMD_RANDOM_WRITE = 12, |
| | | CMD_LED_MODE_OP = 16, |
| | | CMD_POWER_SAVING_OP = 20, |
| | | CMD_WOW_CONFIG = 21, |
| | | CMD_WOW_QUERY = 22, |
| | | CMD_WOW_FEATURE = 24, |
| | | CMD_CARRIER_DETECT_OP = 28, |
| | | CMD_RADOR_DETECT_OP = 29, |
| | | CMD_SWITCH_CHANNEL_OP = 30, |
| | | CMD_CALIBRATION_OP = 31, |
| | | CMD_BEACON_OP = 32, |
| | | CMD_ANTENNA_OP = 33, |
| | | }; |
| | | |
| | | enum mcu_function { |
| | | Q_SELECT = 1, |
| | | ATOMIC_TSSI_SETTING = 5, |
| | | }; |
| | | |
| | | enum mcu_power_mode { |
| | | RADIO_OFF = 0x30, |
| | | RADIO_ON = 0x31, |
| | | RADIO_OFF_AUTO_WAKEUP = 0x32, |
| | | RADIO_OFF_ADVANCE = 0x33, |
| | | RADIO_ON_ADVANCE = 0x34, |
| | | }; |
| | | |
| | | enum mcu_calibrate { |
| | | MCU_CAL_R = 1, |
| | | MCU_CAL_DCOC, |
| | | MCU_CAL_LC, |
| | | MCU_CAL_LOFT, |
| | | MCU_CAL_TXIQ, |
| | | MCU_CAL_BW, |
| | | MCU_CAL_DPD, |
| | | MCU_CAL_RXIQ, |
| | | MCU_CAL_TXDCOC, |
| | | }; |
| | | |
| | | int mt7601u_mcu_init(struct mt7601u_dev *dev); |
| | | int mt7601u_mcu_cmd_init(struct mt7601u_dev *dev); |
| | | void mt7601u_mcu_cmd_deinit(struct mt7601u_dev *dev); |
| | | |
| | | int |
| | | mt7601u_mcu_calibrate(struct mt7601u_dev *dev, enum mcu_calibrate cal, u32 val); |
| | | int mt7601u_mcu_tssi_read_kick(struct mt7601u_dev *dev, int use_hvga); |
| | | |
| | | #endif |
New file |
| | |
| | | /* |
| | | * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> |
| | | * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> |
| | | * |
| | | * This program is free software; you can redistribute it and/or modify |
| | | * it under the terms of the GNU General Public License version 2 |
| | | * as published by the Free Software Foundation |
| | | * |
| | | * This program is distributed in the hope that it will be useful, |
| | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| | | * GNU General Public License for more details. |
| | | */ |
| | | |
| | | #ifndef MT7601U_H |
| | | #define MT7601U_H |
| | | |
| | | #include <linux/kernel.h> |
| | | #include <linux/device.h> |
| | | #include <linux/mutex.h> |
| | | #include <linux/usb.h> |
| | | #include <linux/completion.h> |
| | | #include <net/mac80211.h> |
| | | #include <linux/debugfs.h> |
| | | |
| | | #include "regs.h" |
| | | #include "util.h" |
| | | |
| | | #define MT_CALIBRATE_INTERVAL (4 * HZ) |
| | | |
| | | #define MT_FREQ_CAL_INIT_DELAY (30 * HZ) |
| | | #define MT_FREQ_CAL_CHECK_INTERVAL (10 * HZ) |
| | | #define MT_FREQ_CAL_ADJ_INTERVAL (HZ / 2) |
| | | |
| | | #define MT_BBP_REG_VERSION 0x00 |
| | | |
| | | #define MT_USB_AGGR_SIZE_LIMIT 28 /* * 1024B */ |
| | | #define MT_USB_AGGR_TIMEOUT 0x80 /* * 33ns */ |
| | | #define MT_RX_ORDER 3 |
| | | #define MT_RX_URB_SIZE (PAGE_SIZE << MT_RX_ORDER) |
| | | |
| | | struct mt7601u_dma_buf { |
| | | struct urb *urb; |
| | | void *buf; |
| | | dma_addr_t dma; |
| | | size_t len; |
| | | }; |
| | | |
| | | struct mt7601u_mcu { |
| | | struct mutex mutex; |
| | | |
| | | u8 msg_seq; |
| | | |
| | | struct mt7601u_dma_buf resp; |
| | | struct completion resp_cmpl; |
| | | }; |
| | | |
| | | struct mt7601u_freq_cal { |
| | | struct delayed_work work; |
| | | u8 freq; |
| | | bool enabled; |
| | | bool adjusting; |
| | | }; |
| | | |
| | | struct mac_stats { |
| | | u64 rx_stat[6]; |
| | | u64 tx_stat[6]; |
| | | u64 aggr_stat[2]; |
| | | u64 aggr_n[32]; |
| | | u64 zero_len_del[2]; |
| | | }; |
| | | |
| | | #define N_RX_ENTRIES 16 |
| | | struct mt7601u_rx_queue { |
| | | struct mt7601u_dev *dev; |
| | | |
| | | struct mt7601u_dma_buf_rx { |
| | | struct urb *urb; |
| | | struct page *p; |
| | | } e[N_RX_ENTRIES]; |
| | | |
| | | unsigned int start; |
| | | unsigned int end; |
| | | unsigned int entries; |
| | | unsigned int pending; |
| | | }; |
| | | |
| | | #define N_TX_ENTRIES 64 |
| | | |
| | | struct mt7601u_tx_queue { |
| | | struct mt7601u_dev *dev; |
| | | |
| | | struct mt7601u_dma_buf_tx { |
| | | struct urb *urb; |
| | | struct sk_buff *skb; |
| | | } e[N_TX_ENTRIES]; |
| | | |
| | | unsigned int start; |
| | | unsigned int end; |
| | | unsigned int entries; |
| | | unsigned int used; |
| | | unsigned int fifo_seq; |
| | | }; |
| | | |
| | | /* WCID allocation: |
| | | * 0: mcast wcid |
| | | * 1: bssid wcid |
| | | * 1...: STAs |
| | | * ...7e: group wcids |
| | | * 7f: reserved |
| | | */ |
| | | #define N_WCIDS 128 |
| | | #define GROUP_WCID(idx) (N_WCIDS - 2 - idx) |
| | | |
| | | struct mt7601u_eeprom_params; |
| | | |
| | | #define MT_EE_TEMPERATURE_SLOPE 39 |
| | | #define MT_FREQ_OFFSET_INVALID -128 |
| | | |
| | | enum mt_temp_mode { |
| | | MT_TEMP_MODE_NORMAL, |
| | | MT_TEMP_MODE_HIGH, |
| | | MT_TEMP_MODE_LOW, |
| | | }; |
| | | |
| | | enum mt_bw { |
| | | MT_BW_20, |
| | | MT_BW_40, |
| | | }; |
| | | |
| | | enum { |
| | | MT7601U_STATE_INITIALIZED, |
| | | MT7601U_STATE_REMOVED, |
| | | MT7601U_STATE_WLAN_RUNNING, |
| | | MT7601U_STATE_MCU_RUNNING, |
| | | MT7601U_STATE_SCANNING, |
| | | MT7601U_STATE_READING_STATS, |
| | | MT7601U_STATE_MORE_STATS, |
| | | }; |
| | | |
| | | /** |
| | | * struct mt7601u_dev - adapter structure |
| | | * @lock: protects @wcid->tx_rate. |
| | | * @mac_lock: locks out mac80211's tx status and rx paths. |
| | | * @tx_lock: protects @tx_q and changes of MT7601U_STATE_*_STATS |
| | | * flags in @state. |
| | | * @rx_lock: protects @rx_q. |
| | | * @con_mon_lock: protects @ap_bssid, @bcn_*, @avg_rssi. |
| | | * @mutex: ensures exclusive access from mac80211 callbacks. |
| | | * @vendor_req_mutex: protects @vend_buf, ensures atomicity of split writes. |
| | | * @reg_atomic_mutex: ensures atomicity of indirect register accesses |
| | | * (accesses to RF and BBP). |
| | | * @hw_atomic_mutex: ensures exclusive access to HW during critical |
| | | * operations (power management, channel switch). |
| | | */ |
| | | struct mt7601u_dev { |
| | | struct ieee80211_hw *hw; |
| | | struct device *dev; |
| | | |
| | | unsigned long state; |
| | | |
| | | struct mutex mutex; |
| | | |
| | | unsigned long wcid_mask[N_WCIDS / BITS_PER_LONG]; |
| | | |
| | | struct cfg80211_chan_def chandef; |
| | | struct ieee80211_supported_band *sband_2g; |
| | | |
| | | struct mt7601u_mcu mcu; |
| | | |
| | | struct delayed_work cal_work; |
| | | struct delayed_work mac_work; |
| | | |
| | | struct workqueue_struct *stat_wq; |
| | | struct delayed_work stat_work; |
| | | |
| | | struct mt76_wcid *mon_wcid; |
| | | struct mt76_wcid __rcu *wcid[N_WCIDS]; |
| | | |
| | | spinlock_t lock; |
| | | spinlock_t mac_lock; |
| | | |
| | | const u16 *beacon_offsets; |
| | | |
| | | u8 macaddr[ETH_ALEN]; |
| | | struct mt7601u_eeprom_params *ee; |
| | | |
| | | struct mutex vendor_req_mutex; |
| | | void *vend_buf; |
| | | |
| | | struct mutex reg_atomic_mutex; |
| | | struct mutex hw_atomic_mutex; |
| | | |
| | | u32 rxfilter; |
| | | u32 debugfs_reg; |
| | | |
| | | u8 out_eps[8]; |
| | | u8 in_eps[8]; |
| | | u16 out_max_packet; |
| | | u16 in_max_packet; |
| | | |
| | | /* TX */ |
| | | spinlock_t tx_lock; |
| | | struct tasklet_struct tx_tasklet; |
| | | struct mt7601u_tx_queue *tx_q; |
| | | struct sk_buff_head tx_skb_done; |
| | | |
| | | atomic_t avg_ampdu_len; |
| | | |
| | | /* RX */ |
| | | spinlock_t rx_lock; |
| | | struct tasklet_struct rx_tasklet; |
| | | struct mt7601u_rx_queue rx_q; |
| | | |
| | | /* Connection monitoring things */ |
| | | spinlock_t con_mon_lock; |
| | | u8 ap_bssid[ETH_ALEN]; |
| | | |
| | | s8 bcn_freq_off; |
| | | u8 bcn_phy_mode; |
| | | |
| | | int avg_rssi; /* starts at 0 and converges */ |
| | | |
| | | u8 agc_save; |
| | | |
| | | struct mt7601u_freq_cal freq_cal; |
| | | |
| | | bool tssi_read_trig; |
| | | |
| | | s8 tssi_init; |
| | | s8 tssi_init_hvga; |
| | | s16 tssi_init_hvga_offset_db; |
| | | |
| | | int prev_pwr_diff; |
| | | |
| | | enum mt_temp_mode temp_mode; |
| | | int curr_temp; |
| | | int dpd_temp; |
| | | s8 raw_temp; |
| | | bool pll_lock_protect; |
| | | |
| | | u8 bw; |
| | | bool chan_ext_below; |
| | | |
| | | /* PA mode */ |
| | | u32 rf_pa_mode[2]; |
| | | |
| | | struct mac_stats stats; |
| | | }; |
| | | |
| | | struct mt7601u_tssi_params { |
| | | char tssi0; |
| | | int trgt_power; |
| | | }; |
| | | |
| | | struct mt76_wcid { |
| | | u8 idx; |
| | | u8 hw_key_idx; |
| | | |
| | | u16 tx_rate; |
| | | bool tx_rate_set; |
| | | u8 tx_rate_nss; |
| | | }; |
| | | |
| | | struct mt76_vif { |
| | | u8 idx; |
| | | |
| | | struct mt76_wcid group_wcid; |
| | | }; |
| | | |
| | | struct mt76_sta { |
| | | struct mt76_wcid wcid; |
| | | u16 agg_ssn[IEEE80211_NUM_TIDS]; |
| | | }; |
| | | |
| | | struct mt76_reg_pair { |
| | | u32 reg; |
| | | u32 value; |
| | | }; |
| | | |
| | | struct mt7601u_rxwi; |
| | | |
| | | extern const struct ieee80211_ops mt7601u_ops; |
| | | |
| | | void mt7601u_init_debugfs(struct mt7601u_dev *dev); |
| | | |
| | | u32 mt7601u_rr(struct mt7601u_dev *dev, u32 offset); |
| | | void mt7601u_wr(struct mt7601u_dev *dev, u32 offset, u32 val); |
| | | u32 mt7601u_rmw(struct mt7601u_dev *dev, u32 offset, u32 mask, u32 val); |
| | | u32 mt7601u_rmc(struct mt7601u_dev *dev, u32 offset, u32 mask, u32 val); |
| | | void mt7601u_wr_copy(struct mt7601u_dev *dev, u32 offset, |
| | | const void *data, int len); |
| | | |
| | | int mt7601u_wait_asic_ready(struct mt7601u_dev *dev); |
| | | bool mt76_poll(struct mt7601u_dev *dev, u32 offset, u32 mask, u32 val, |
| | | int timeout); |
| | | bool mt76_poll_msec(struct mt7601u_dev *dev, u32 offset, u32 mask, u32 val, |
| | | int timeout); |
| | | |
| | | /* Compatibility with mt76 */ |
| | | #define mt76_rmw_field(_dev, _reg, _field, _val) \ |
| | | mt76_rmw(_dev, _reg, _field, MT76_SET(_field, _val)) |
| | | |
| | | static inline u32 mt76_rr(struct mt7601u_dev *dev, u32 offset) |
| | | { |
| | | return mt7601u_rr(dev, offset); |
| | | } |
| | | |
| | | static inline void mt76_wr(struct mt7601u_dev *dev, u32 offset, u32 val) |
| | | { |
| | | return mt7601u_wr(dev, offset, val); |
| | | } |
| | | |
| | | static inline u32 |
| | | mt76_rmw(struct mt7601u_dev *dev, u32 offset, u32 mask, u32 val) |
| | | { |
| | | return mt7601u_rmw(dev, offset, mask, val); |
| | | } |
| | | |
| | | static inline u32 mt76_set(struct mt7601u_dev *dev, u32 offset, u32 val) |
| | | { |
| | | return mt76_rmw(dev, offset, 0, val); |
| | | } |
| | | |
| | | static inline u32 mt76_clear(struct mt7601u_dev *dev, u32 offset, u32 val) |
| | | { |
| | | return mt76_rmw(dev, offset, val, 0); |
| | | } |
| | | |
| | | int mt7601u_write_reg_pairs(struct mt7601u_dev *dev, u32 base, |
| | | const struct mt76_reg_pair *data, int len); |
| | | int mt7601u_burst_write_regs(struct mt7601u_dev *dev, u32 offset, |
| | | const u32 *data, int n); |
| | | void mt7601u_addr_wr(struct mt7601u_dev *dev, const u32 offset, const u8 *addr); |
| | | |
| | | /* Init */ |
| | | struct mt7601u_dev *mt7601u_alloc_device(struct device *dev); |
| | | int mt7601u_init_hardware(struct mt7601u_dev *dev); |
| | | int mt7601u_register_device(struct mt7601u_dev *dev); |
| | | void mt7601u_cleanup(struct mt7601u_dev *dev); |
| | | |
| | | int mt7601u_mac_start(struct mt7601u_dev *dev); |
| | | void mt7601u_mac_stop(struct mt7601u_dev *dev); |
| | | |
| | | /* PHY */ |
| | | int mt7601u_phy_init(struct mt7601u_dev *dev); |
| | | int mt7601u_wait_bbp_ready(struct mt7601u_dev *dev); |
| | | void mt7601u_set_rx_path(struct mt7601u_dev *dev, u8 path); |
| | | void mt7601u_set_tx_dac(struct mt7601u_dev *dev, u8 path); |
| | | int mt7601u_bbp_set_bw(struct mt7601u_dev *dev, int bw); |
| | | void mt7601u_agc_save(struct mt7601u_dev *dev); |
| | | void mt7601u_agc_restore(struct mt7601u_dev *dev); |
| | | int mt7601u_phy_set_channel(struct mt7601u_dev *dev, |
| | | struct cfg80211_chan_def *chandef); |
| | | void mt7601u_phy_recalibrate_after_assoc(struct mt7601u_dev *dev); |
| | | int mt7601u_phy_get_rssi(struct mt7601u_dev *dev, |
| | | struct mt7601u_rxwi *rxwi, u16 rate); |
| | | void mt7601u_phy_con_cal_onoff(struct mt7601u_dev *dev, |
| | | struct ieee80211_bss_conf *info); |
| | | |
| | | /* MAC */ |
| | | void mt7601u_mac_work(struct work_struct *work); |
| | | void mt7601u_mac_set_protection(struct mt7601u_dev *dev, bool legacy_prot, |
| | | int ht_mode); |
| | | void mt7601u_mac_set_short_preamble(struct mt7601u_dev *dev, bool short_preamb); |
| | | void mt7601u_mac_config_tsf(struct mt7601u_dev *dev, bool enable, int interval); |
| | | void |
| | | mt7601u_mac_wcid_setup(struct mt7601u_dev *dev, u8 idx, u8 vif_idx, u8 *mac); |
| | | void mt7601u_mac_set_ampdu_factor(struct mt7601u_dev *dev); |
| | | |
| | | /* TX */ |
| | | void mt7601u_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, |
| | | struct sk_buff *skb); |
| | | int mt7601u_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
| | | u16 queue, const struct ieee80211_tx_queue_params *params); |
| | | void mt7601u_tx_status(struct mt7601u_dev *dev, struct sk_buff *skb); |
| | | void mt7601u_tx_stat(struct work_struct *work); |
| | | |
| | | /* util */ |
| | | void mt76_remove_hdr_pad(struct sk_buff *skb); |
| | | int mt76_insert_hdr_pad(struct sk_buff *skb); |
| | | |
| | | u32 mt7601u_bbp_set_ctrlch(struct mt7601u_dev *dev, bool below); |
| | | |
| | | static inline u32 mt7601u_mac_set_ctrlch(struct mt7601u_dev *dev, bool below) |
| | | { |
| | | return mt7601u_rmc(dev, MT_TX_BAND_CFG, 1, below); |
| | | } |
| | | |
| | | int mt7601u_dma_init(struct mt7601u_dev *dev); |
| | | void mt7601u_dma_cleanup(struct mt7601u_dev *dev); |
| | | |
| | | int mt7601u_dma_enqueue_tx(struct mt7601u_dev *dev, struct sk_buff *skb, |
| | | struct mt76_wcid *wcid, int hw_q); |
| | | |
| | | #endif |
New file |
| | |
| | | /* |
| | | * (c) Copyright 2002-2010, Ralink Technology, Inc. |
| | | * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> |
| | | * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> |
| | | * |
| | | * This program is free software; you can redistribute it and/or modify |
| | | * it under the terms of the GNU General Public License version 2 |
| | | * as published by the Free Software Foundation |
| | | * |
| | | * This program is distributed in the hope that it will be useful, |
| | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| | | * GNU General Public License for more details. |
| | | */ |
| | | |
| | | #include "mt7601u.h" |
| | | #include "mcu.h" |
| | | #include "eeprom.h" |
| | | #include "trace.h" |
| | | #include "initvals_phy.h" |
| | | |
| | | #include <linux/etherdevice.h> |
| | | |
| | | static void mt7601u_agc_reset(struct mt7601u_dev *dev); |
| | | |
| | | static int |
| | | mt7601u_rf_wr(struct mt7601u_dev *dev, u8 bank, u8 offset, u8 value) |
| | | { |
| | | int ret = 0; |
| | | |
| | | if (WARN_ON(!test_bit(MT7601U_STATE_WLAN_RUNNING, &dev->state)) || |
| | | WARN_ON(offset > 63)) |
| | | return -EINVAL; |
| | | if (test_bit(MT7601U_STATE_REMOVED, &dev->state)) |
| | | return 0; |
| | | |
| | | mutex_lock(&dev->reg_atomic_mutex); |
| | | |
| | | if (!mt76_poll(dev, MT_RF_CSR_CFG, MT_RF_CSR_CFG_KICK, 0, 100)) { |
| | | ret = -ETIMEDOUT; |
| | | goto out; |
| | | } |
| | | |
| | | mt7601u_wr(dev, MT_RF_CSR_CFG, MT76_SET(MT_RF_CSR_CFG_DATA, value) | |
| | | MT76_SET(MT_RF_CSR_CFG_REG_BANK, bank) | |
| | | MT76_SET(MT_RF_CSR_CFG_REG_ID, offset) | |
| | | MT_RF_CSR_CFG_WR | |
| | | MT_RF_CSR_CFG_KICK); |
| | | trace_rf_write(dev, bank, offset, value); |
| | | out: |
| | | mutex_unlock(&dev->reg_atomic_mutex); |
| | | |
| | | if (ret < 0) |
| | | dev_err(dev->dev, "Error: RF write %02hhx:%02hhx failed:%d!!\n", |
| | | bank, offset, ret); |
| | | |
| | | return ret; |
| | | } |
| | | |
| | | static int |
| | | mt7601u_rf_rr(struct mt7601u_dev *dev, u8 bank, u8 offset) |
| | | { |
| | | int ret = -ETIMEDOUT; |
| | | u32 val; |
| | | |
| | | if (WARN_ON(!test_bit(MT7601U_STATE_WLAN_RUNNING, &dev->state)) || |
| | | WARN_ON(offset > 63)) |
| | | return -EINVAL; |
| | | if (test_bit(MT7601U_STATE_REMOVED, &dev->state)) |
| | | return 0xff; |
| | | |
| | | mutex_lock(&dev->reg_atomic_mutex); |
| | | |
| | | if (!mt76_poll(dev, MT_RF_CSR_CFG, MT_RF_CSR_CFG_KICK, 0, 100)) |
| | | goto out; |
| | | |
| | | mt7601u_wr(dev, MT_RF_CSR_CFG, MT76_SET(MT_RF_CSR_CFG_REG_BANK, bank) | |
| | | MT76_SET(MT_RF_CSR_CFG_REG_ID, offset) | |
| | | MT_RF_CSR_CFG_KICK); |
| | | |
| | | if (!mt76_poll(dev, MT_RF_CSR_CFG, MT_RF_CSR_CFG_KICK, 0, 100)) |
| | | goto out; |
| | | |
| | | val = mt7601u_rr(dev, MT_RF_CSR_CFG); |
| | | if (MT76_GET(MT_RF_CSR_CFG_REG_ID, val) == offset && |
| | | MT76_GET(MT_RF_CSR_CFG_REG_BANK, val) == bank) { |
| | | ret = MT76_GET(MT_RF_CSR_CFG_DATA, val); |
| | | trace_rf_read(dev, bank, offset, ret); |
| | | } |
| | | out: |
| | | mutex_unlock(&dev->reg_atomic_mutex); |
| | | |
| | | if (ret < 0) |
| | | dev_err(dev->dev, "Error: RF read %02hhx:%02hhx failed:%d!!\n", |
| | | bank, offset, ret); |
| | | |
| | | return ret; |
| | | } |
| | | |
| | | static int |
| | | mt7601u_rf_rmw(struct mt7601u_dev *dev, u8 bank, u8 offset, u8 mask, u8 val) |
| | | { |
| | | int ret; |
| | | |
| | | ret = mt7601u_rf_rr(dev, bank, offset); |
| | | if (ret < 0) |
| | | return ret; |
| | | val |= ret & ~mask; |
| | | ret = mt7601u_rf_wr(dev, bank, offset, val); |
| | | if (ret) |
| | | return ret; |
| | | |
| | | return val; |
| | | } |
| | | |
| | | static int |
| | | mt7601u_rf_set(struct mt7601u_dev *dev, u8 bank, u8 offset, u8 val) |
| | | { |
| | | return mt7601u_rf_rmw(dev, bank, offset, 0, val); |
| | | } |
| | | |
| | | static int |
| | | mt7601u_rf_clear(struct mt7601u_dev *dev, u8 bank, u8 offset, u8 mask) |
| | | { |
| | | return mt7601u_rf_rmw(dev, bank, offset, mask, 0); |
| | | } |
| | | |
| | | static void mt7601u_bbp_wr(struct mt7601u_dev *dev, u8 offset, u8 val) |
| | | { |
| | | if (WARN_ON(!test_bit(MT7601U_STATE_WLAN_RUNNING, &dev->state)) || |
| | | test_bit(MT7601U_STATE_REMOVED, &dev->state)) |
| | | return; |
| | | |
| | | mutex_lock(&dev->reg_atomic_mutex); |
| | | |
| | | if (!mt76_poll(dev, MT_BBP_CSR_CFG, MT_BBP_CSR_CFG_BUSY, 0, 1000)) { |
| | | dev_err(dev->dev, "Error: BBP write %02hhx failed!!\n", offset); |
| | | goto out; |
| | | } |
| | | |
| | | mt7601u_wr(dev, MT_BBP_CSR_CFG, |
| | | MT76_SET(MT_BBP_CSR_CFG_VAL, val) | |
| | | MT76_SET(MT_BBP_CSR_CFG_REG_NUM, offset) | |
| | | MT_BBP_CSR_CFG_RW_MODE | MT_BBP_CSR_CFG_BUSY); |
| | | trace_bbp_write(dev, offset, val); |
| | | out: |
| | | mutex_unlock(&dev->reg_atomic_mutex); |
| | | } |
| | | |
| | | static int mt7601u_bbp_rr(struct mt7601u_dev *dev, u8 offset) |
| | | { |
| | | u32 val; |
| | | int ret = -ETIMEDOUT; |
| | | |
| | | if (WARN_ON(!test_bit(MT7601U_STATE_WLAN_RUNNING, &dev->state))) |
| | | return -EINVAL; |
| | | if (test_bit(MT7601U_STATE_REMOVED, &dev->state)) |
| | | return 0xff; |
| | | |
| | | mutex_lock(&dev->reg_atomic_mutex); |
| | | |
| | | if (!mt76_poll(dev, MT_BBP_CSR_CFG, MT_BBP_CSR_CFG_BUSY, 0, 1000)) |
| | | goto out; |
| | | |
| | | mt7601u_wr(dev, MT_BBP_CSR_CFG, |
| | | MT76_SET(MT_BBP_CSR_CFG_REG_NUM, offset) | |
| | | MT_BBP_CSR_CFG_RW_MODE | MT_BBP_CSR_CFG_BUSY | |
| | | MT_BBP_CSR_CFG_READ); |
| | | |
| | | if (!mt76_poll(dev, MT_BBP_CSR_CFG, MT_BBP_CSR_CFG_BUSY, 0, 1000)) |
| | | goto out; |
| | | |
| | | val = mt7601u_rr(dev, MT_BBP_CSR_CFG); |
| | | if (MT76_GET(MT_BBP_CSR_CFG_REG_NUM, val) == offset) { |
| | | ret = MT76_GET(MT_BBP_CSR_CFG_VAL, val); |
| | | trace_bbp_read(dev, offset, ret); |
| | | } |
| | | out: |
| | | mutex_unlock(&dev->reg_atomic_mutex); |
| | | |
| | | if (ret < 0) |
| | | dev_err(dev->dev, "Error: BBP read %02hhx failed:%d!!\n", |
| | | offset, ret); |
| | | |
| | | return ret; |
| | | } |
| | | |
| | | static int mt7601u_bbp_rmw(struct mt7601u_dev *dev, u8 offset, u8 mask, u8 val) |
| | | { |
| | | int ret; |
| | | |
| | | ret = mt7601u_bbp_rr(dev, offset); |
| | | if (ret < 0) |
| | | return ret; |
| | | val |= ret & ~mask; |
| | | mt7601u_bbp_wr(dev, offset, val); |
| | | |
| | | return val; |
| | | } |
| | | |
| | | static u8 mt7601u_bbp_rmc(struct mt7601u_dev *dev, u8 offset, u8 mask, u8 val) |
| | | { |
| | | int ret; |
| | | |
| | | ret = mt7601u_bbp_rr(dev, offset); |
| | | if (ret < 0) |
| | | return ret; |
| | | val |= ret & ~mask; |
| | | if (ret != val) |
| | | mt7601u_bbp_wr(dev, offset, val); |
| | | |
| | | return val; |
| | | } |
| | | |
| | | int mt7601u_wait_bbp_ready(struct mt7601u_dev *dev) |
| | | { |
| | | int i = 20; |
| | | u8 val; |
| | | |
| | | do { |
| | | val = mt7601u_bbp_rr(dev, MT_BBP_REG_VERSION); |
| | | if (val && ~val) |
| | | break; |
| | | } while (--i); |
| | | |
| | | if (!i) { |
| | | dev_err(dev->dev, "Error: BBP is not ready\n"); |
| | | return -EIO; |
| | | } |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | u32 mt7601u_bbp_set_ctrlch(struct mt7601u_dev *dev, bool below) |
| | | { |
| | | return mt7601u_bbp_rmc(dev, 3, 0x20, below ? 0x20 : 0); |
| | | } |
| | | |
| | | int mt7601u_phy_get_rssi(struct mt7601u_dev *dev, |
| | | struct mt7601u_rxwi *rxwi, u16 rate) |
| | | { |
| | | static const s8 lna[2][2][3] = { |
| | | /* main LNA */ { |
| | | /* bw20 */ { -2, 15, 33 }, |
| | | /* bw40 */ { 0, 16, 34 } |
| | | }, |
| | | /* aux LNA */ { |
| | | /* bw20 */ { -2, 15, 33 }, |
| | | /* bw40 */ { -2, 16, 34 } |
| | | } |
| | | }; |
| | | int bw = MT76_GET(MT_RXWI_RATE_BW, rate); |
| | | int aux_lna = MT76_GET(MT_RXWI_ANT_AUX_LNA, rxwi->ant); |
| | | int lna_id = MT76_GET(MT_RXWI_GAIN_RSSI_LNA_ID, rxwi->gain); |
| | | int val; |
| | | |
| | | if (lna_id) /* LNA id can be 0, 2, 3. */ |
| | | lna_id--; |
| | | |
| | | val = 8; |
| | | val -= lna[aux_lna][bw][lna_id]; |
| | | val -= MT76_GET(MT_RXWI_GAIN_RSSI_VAL, rxwi->gain); |
| | | val -= dev->ee->lna_gain; |
| | | val -= dev->ee->rssi_offset[0]; |
| | | |
| | | return val; |
| | | } |
| | | |
| | | static void mt7601u_vco_cal(struct mt7601u_dev *dev) |
| | | { |
| | | mt7601u_rf_wr(dev, 0, 4, 0x0a); |
| | | mt7601u_rf_wr(dev, 0, 5, 0x20); |
| | | mt7601u_rf_set(dev, 0, 4, BIT(7)); |
| | | msleep(2); |
| | | } |
| | | |
| | | static int mt7601u_set_bw_filter(struct mt7601u_dev *dev, bool cal) |
| | | { |
| | | u32 filter = 0; |
| | | int ret; |
| | | |
| | | if (!cal) |
| | | filter |= 0x10000; |
| | | if (dev->bw != MT_BW_20) |
| | | filter |= 0x00100; |
| | | |
| | | /* TX */ |
| | | ret = mt7601u_mcu_calibrate(dev, MCU_CAL_BW, filter | 1); |
| | | if (ret) |
| | | return ret; |
| | | /* RX */ |
| | | return mt7601u_mcu_calibrate(dev, MCU_CAL_BW, filter); |
| | | } |
| | | |
| | | static int mt7601u_load_bbp_temp_table_bw(struct mt7601u_dev *dev) |
| | | { |
| | | const struct reg_table *t; |
| | | |
| | | if (WARN_ON(dev->temp_mode > MT_TEMP_MODE_LOW)) |
| | | return -EINVAL; |
| | | |
| | | t = &bbp_mode_table[dev->temp_mode][dev->bw]; |
| | | |
| | | return mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_BBP, t->regs, t->n); |
| | | } |
| | | |
| | | static int mt7601u_bbp_temp(struct mt7601u_dev *dev, int mode, const char *name) |
| | | { |
| | | const struct reg_table *t; |
| | | int ret; |
| | | |
| | | if (dev->temp_mode == mode) |
| | | return 0; |
| | | |
| | | dev->temp_mode = mode; |
| | | trace_temp_mode(dev, mode); |
| | | |
| | | t = bbp_mode_table[dev->temp_mode]; |
| | | ret = mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_BBP, |
| | | t[2].regs, t[2].n); |
| | | if (ret) |
| | | return ret; |
| | | |
| | | return mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_BBP, |
| | | t[dev->bw].regs, t[dev->bw].n); |
| | | } |
| | | |
| | | static void mt7601u_apply_ch14_fixup(struct mt7601u_dev *dev, int hw_chan) |
| | | { |
| | | struct mt7601u_rate_power *t = &dev->ee->power_rate_table; |
| | | |
| | | if (hw_chan != 14 || dev->bw != MT_BW_20) { |
| | | mt7601u_bbp_rmw(dev, 4, 0x20, 0); |
| | | mt7601u_bbp_wr(dev, 178, 0xff); |
| | | |
| | | t->cck[0].bw20 = dev->ee->real_cck_bw20[0]; |
| | | t->cck[1].bw20 = dev->ee->real_cck_bw20[1]; |
| | | } else { /* Apply CH14 OBW fixup */ |
| | | mt7601u_bbp_wr(dev, 4, 0x60); |
| | | mt7601u_bbp_wr(dev, 178, 0); |
| | | |
| | | /* Note: vendor code is buggy here for negative values */ |
| | | t->cck[0].bw20 = dev->ee->real_cck_bw20[0] - 2; |
| | | t->cck[1].bw20 = dev->ee->real_cck_bw20[1] - 2; |
| | | } |
| | | } |
| | | |
| | | static int __mt7601u_phy_set_channel(struct mt7601u_dev *dev, |
| | | struct cfg80211_chan_def *chandef) |
| | | { |
| | | #define FREQ_PLAN_REGS 4 |
| | | static const u8 freq_plan[14][FREQ_PLAN_REGS] = { |
| | | { 0x99, 0x99, 0x09, 0x50 }, |
| | | { 0x46, 0x44, 0x0a, 0x50 }, |
| | | { 0xec, 0xee, 0x0a, 0x50 }, |
| | | { 0x99, 0x99, 0x0b, 0x50 }, |
| | | { 0x46, 0x44, 0x08, 0x51 }, |
| | | { 0xec, 0xee, 0x08, 0x51 }, |
| | | { 0x99, 0x99, 0x09, 0x51 }, |
| | | { 0x46, 0x44, 0x0a, 0x51 }, |
| | | { 0xec, 0xee, 0x0a, 0x51 }, |
| | | { 0x99, 0x99, 0x0b, 0x51 }, |
| | | { 0x46, 0x44, 0x08, 0x52 }, |
| | | { 0xec, 0xee, 0x08, 0x52 }, |
| | | { 0x99, 0x99, 0x09, 0x52 }, |
| | | { 0x33, 0x33, 0x0b, 0x52 }, |
| | | }; |
| | | struct mt76_reg_pair channel_freq_plan[FREQ_PLAN_REGS] = { |
| | | { 17, 0 }, { 18, 0 }, { 19, 0 }, { 20, 0 }, |
| | | }; |
| | | struct mt76_reg_pair bbp_settings[3] = { |
| | | { 62, 0x37 - dev->ee->lna_gain }, |
| | | { 63, 0x37 - dev->ee->lna_gain }, |
| | | { 64, 0x37 - dev->ee->lna_gain }, |
| | | }; |
| | | |
| | | struct ieee80211_channel *chan = chandef->chan; |
| | | enum nl80211_channel_type chan_type = |
| | | cfg80211_get_chandef_type(chandef); |
| | | struct mt7601u_rate_power *t = &dev->ee->power_rate_table; |
| | | int chan_idx; |
| | | bool chan_ext_below; |
| | | u8 bw; |
| | | int i, ret; |
| | | |
| | | bw = MT_BW_20; |
| | | chan_ext_below = (chan_type == NL80211_CHAN_HT40MINUS); |
| | | chan_idx = chan->hw_value - 1; |
| | | |
| | | if (chandef->width == NL80211_CHAN_WIDTH_40) { |
| | | bw = MT_BW_40; |
| | | |
| | | if (chan_idx > 1 && chan_type == NL80211_CHAN_HT40MINUS) |
| | | chan_idx -= 2; |
| | | else if (chan_idx < 12 && chan_type == NL80211_CHAN_HT40PLUS) |
| | | chan_idx += 2; |
| | | else |
| | | dev_err(dev->dev, "Error: invalid 40MHz channel!!\n"); |
| | | } |
| | | |
| | | if (bw != dev->bw || chan_ext_below != dev->chan_ext_below) { |
| | | dev_dbg(dev->dev, "Info: switching HT mode bw:%d below:%d\n", |
| | | bw, chan_ext_below); |
| | | |
| | | mt7601u_bbp_set_bw(dev, bw); |
| | | |
| | | mt7601u_bbp_set_ctrlch(dev, chan_ext_below); |
| | | mt7601u_mac_set_ctrlch(dev, chan_ext_below); |
| | | dev->chan_ext_below = chan_ext_below; |
| | | } |
| | | |
| | | for (i = 0; i < FREQ_PLAN_REGS; i++) |
| | | channel_freq_plan[i].value = freq_plan[chan_idx][i]; |
| | | |
| | | ret = mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_RF, |
| | | channel_freq_plan, FREQ_PLAN_REGS); |
| | | if (ret) |
| | | return ret; |
| | | |
| | | mt7601u_rmw(dev, MT_TX_ALC_CFG_0, 0x3f3f, |
| | | dev->ee->chan_pwr[chan_idx] & 0x3f); |
| | | |
| | | ret = mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_BBP, |
| | | bbp_settings, ARRAY_SIZE(bbp_settings)); |
| | | if (ret) |
| | | return ret; |
| | | |
| | | mt7601u_vco_cal(dev); |
| | | mt7601u_bbp_set_bw(dev, bw); |
| | | ret = mt7601u_set_bw_filter(dev, false); |
| | | if (ret) |
| | | return ret; |
| | | |
| | | mt7601u_apply_ch14_fixup(dev, chan->hw_value); |
| | | mt7601u_wr(dev, MT_TX_PWR_CFG_0, int_to_s6(t->ofdm[1].bw20) << 24 | |
| | | int_to_s6(t->ofdm[0].bw20) << 16 | |
| | | int_to_s6(t->cck[1].bw20) << 8 | |
| | | int_to_s6(t->cck[0].bw20)); |
| | | |
| | | if (test_bit(MT7601U_STATE_SCANNING, &dev->state)) |
| | | mt7601u_agc_reset(dev); |
| | | |
| | | dev->chandef = *chandef; |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | int mt7601u_phy_set_channel(struct mt7601u_dev *dev, |
| | | struct cfg80211_chan_def *chandef) |
| | | { |
| | | int ret; |
| | | |
| | | cancel_delayed_work_sync(&dev->cal_work); |
| | | cancel_delayed_work_sync(&dev->freq_cal.work); |
| | | |
| | | mutex_lock(&dev->hw_atomic_mutex); |
| | | ret = __mt7601u_phy_set_channel(dev, chandef); |
| | | mutex_unlock(&dev->hw_atomic_mutex); |
| | | if (ret) |
| | | return ret; |
| | | |
| | | if (test_bit(MT7601U_STATE_SCANNING, &dev->state)) |
| | | return 0; |
| | | |
| | | ieee80211_queue_delayed_work(dev->hw, &dev->cal_work, |
| | | MT_CALIBRATE_INTERVAL); |
| | | if (dev->freq_cal.enabled) |
| | | ieee80211_queue_delayed_work(dev->hw, &dev->freq_cal.work, |
| | | MT_FREQ_CAL_INIT_DELAY); |
| | | return 0; |
| | | } |
| | | |
| | | #define BBP_R47_FLAG GENMASK(2, 0) |
| | | #define BBP_R47_F_TSSI 0 |
| | | #define BBP_R47_F_PKT_T 1 |
| | | #define BBP_R47_F_TX_RATE 2 |
| | | #define BBP_R47_F_TEMP 4 |
| | | /** |
| | | * mt7601u_bbp_r47_get - read value through BBP R47/R49 pair |
| | | * @dev: pointer to adapter structure |
| | | * @reg: value of BBP R47 before the operation |
| | | * @flag: one of the BBP_R47_F_* flags |
| | | * |
| | | * Convenience helper for reading values through BBP R47/R49 pair. |
| | | * Takes old value of BBP R47 as @reg, because callers usually have it |
| | | * cached already. |
| | | * |
| | | * Return: value of BBP R49. |
| | | */ |
| | | static u8 mt7601u_bbp_r47_get(struct mt7601u_dev *dev, u8 reg, u8 flag) |
| | | { |
| | | flag |= reg & ~BBP_R47_FLAG; |
| | | mt7601u_bbp_wr(dev, 47, flag); |
| | | usleep_range(500, 700); |
| | | return mt7601u_bbp_rr(dev, 49); |
| | | } |
| | | |
| | | static s8 mt7601u_read_bootup_temp(struct mt7601u_dev *dev) |
| | | { |
| | | u8 bbp_val, temp; |
| | | u32 rf_bp, rf_set; |
| | | int i; |
| | | |
| | | rf_set = mt7601u_rr(dev, MT_RF_SETTING_0); |
| | | rf_bp = mt7601u_rr(dev, MT_RF_BYPASS_0); |
| | | |
| | | mt7601u_wr(dev, MT_RF_BYPASS_0, 0); |
| | | mt7601u_wr(dev, MT_RF_SETTING_0, 0x00000010); |
| | | mt7601u_wr(dev, MT_RF_BYPASS_0, 0x00000010); |
| | | |
| | | bbp_val = mt7601u_bbp_rmw(dev, 47, 0, 0x10); |
| | | |
| | | mt7601u_bbp_wr(dev, 22, 0x40); |
| | | |
| | | for (i = 100; i && (bbp_val & 0x10); i--) |
| | | bbp_val = mt7601u_bbp_rr(dev, 47); |
| | | |
| | | temp = mt7601u_bbp_r47_get(dev, bbp_val, BBP_R47_F_TEMP); |
| | | |
| | | mt7601u_bbp_wr(dev, 22, 0); |
| | | |
| | | bbp_val = mt7601u_bbp_rr(dev, 21); |
| | | bbp_val |= 0x02; |
| | | mt7601u_bbp_wr(dev, 21, bbp_val); |
| | | bbp_val &= ~0x02; |
| | | mt7601u_bbp_wr(dev, 21, bbp_val); |
| | | |
| | | mt7601u_wr(dev, MT_RF_BYPASS_0, 0); |
| | | mt7601u_wr(dev, MT_RF_SETTING_0, rf_set); |
| | | mt7601u_wr(dev, MT_RF_BYPASS_0, rf_bp); |
| | | |
| | | trace_read_temp(dev, temp); |
| | | return temp; |
| | | } |
| | | |
| | | static s8 mt7601u_read_temp(struct mt7601u_dev *dev) |
| | | { |
| | | int i; |
| | | u8 val; |
| | | s8 temp; |
| | | |
| | | val = mt7601u_bbp_rmw(dev, 47, 0x7f, 0x10); |
| | | |
| | | /* Note: this rarely succeeds, temp can change even if it fails. */ |
| | | for (i = 100; i && (val & 0x10); i--) |
| | | val = mt7601u_bbp_rr(dev, 47); |
| | | |
| | | temp = mt7601u_bbp_r47_get(dev, val, BBP_R47_F_TEMP); |
| | | |
| | | trace_read_temp(dev, temp); |
| | | return temp; |
| | | } |
| | | |
| | | static void mt7601u_rxdc_cal(struct mt7601u_dev *dev) |
| | | { |
| | | static const struct mt76_reg_pair intro[] = { |
| | | { 158, 0x8d }, { 159, 0xfc }, |
| | | { 158, 0x8c }, { 159, 0x4c }, |
| | | }, outro[] = { |
| | | { 158, 0x8d }, { 159, 0xe0 }, |
| | | }; |
| | | u32 mac_ctrl; |
| | | int i, ret; |
| | | |
| | | mac_ctrl = mt7601u_rr(dev, MT_MAC_SYS_CTRL); |
| | | mt7601u_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_RX); |
| | | |
| | | ret = mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_BBP, |
| | | intro, ARRAY_SIZE(intro)); |
| | | if (ret) |
| | | dev_err(dev->dev, "%s intro failed:%d\n", __func__, ret); |
| | | |
| | | for (i = 20; i; i--) { |
| | | usleep_range(300, 500); |
| | | |
| | | mt7601u_bbp_wr(dev, 158, 0x8c); |
| | | if (mt7601u_bbp_rr(dev, 159) == 0x0c) |
| | | break; |
| | | } |
| | | if (!i) |
| | | dev_err(dev->dev, "%s timed out\n", __func__); |
| | | |
| | | mt7601u_wr(dev, MT_MAC_SYS_CTRL, 0); |
| | | |
| | | ret = mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_BBP, |
| | | outro, ARRAY_SIZE(outro)); |
| | | if (ret) |
| | | dev_err(dev->dev, "%s outro failed:%d\n", __func__, ret); |
| | | |
| | | mt7601u_wr(dev, MT_MAC_SYS_CTRL, mac_ctrl); |
| | | } |
| | | |
| | | void mt7601u_phy_recalibrate_after_assoc(struct mt7601u_dev *dev) |
| | | { |
| | | mt7601u_mcu_calibrate(dev, MCU_CAL_DPD, dev->curr_temp); |
| | | |
| | | mt7601u_rxdc_cal(dev); |
| | | } |
| | | |
| | | /* Note: function copied from vendor driver */ |
| | | static s16 lin2dBd(u16 linear) |
| | | { |
| | | short exp = 0; |
| | | unsigned int mantisa; |
| | | int app, dBd; |
| | | |
| | | if (WARN_ON(!linear)) |
| | | return -10000; |
| | | |
| | | mantisa = linear; |
| | | |
| | | exp = fls(mantisa) - 16; |
| | | if (exp > 0) |
| | | mantisa >>= exp; |
| | | else |
| | | mantisa <<= abs(exp); |
| | | |
| | | if (mantisa <= 0xb800) |
| | | app = (mantisa + (mantisa >> 3) + (mantisa >> 4) - 0x9600); |
| | | else |
| | | app = (mantisa - (mantisa >> 3) - (mantisa >> 6) - 0x5a00); |
| | | if (app < 0) |
| | | app = 0; |
| | | |
| | | dBd = ((15 + exp) << 15) + app; |
| | | dBd = (dBd << 2) + (dBd << 1) + (dBd >> 6) + (dBd >> 7); |
| | | dBd = (dBd >> 10); |
| | | |
| | | return dBd; |
| | | } |
| | | |
| | | static void |
| | | mt7601u_set_initial_tssi(struct mt7601u_dev *dev, s16 tssi_db, s16 tssi_hvga_db) |
| | | { |
| | | struct tssi_data *d = &dev->ee->tssi_data; |
| | | int init_offset; |
| | | |
| | | init_offset = -((tssi_db * d->slope + d->offset[1]) / 4096) + 10; |
| | | |
| | | mt76_rmw(dev, MT_TX_ALC_CFG_1, MT_TX_ALC_CFG_1_TEMP_COMP, |
| | | int_to_s6(init_offset) & MT_TX_ALC_CFG_1_TEMP_COMP); |
| | | } |
| | | |
| | | static void mt7601u_tssi_dc_gain_cal(struct mt7601u_dev *dev) |
| | | { |
| | | u8 rf_vga, rf_mixer, bbp_r47; |
| | | int i, j; |
| | | s8 res[4]; |
| | | s16 tssi_init_db, tssi_init_hvga_db; |
| | | |
| | | mt7601u_wr(dev, MT_RF_SETTING_0, 0x00000030); |
| | | mt7601u_wr(dev, MT_RF_BYPASS_0, 0x000c0030); |
| | | mt7601u_wr(dev, MT_MAC_SYS_CTRL, 0); |
| | | |
| | | mt7601u_bbp_wr(dev, 58, 0); |
| | | mt7601u_bbp_wr(dev, 241, 0x2); |
| | | mt7601u_bbp_wr(dev, 23, 0x8); |
| | | bbp_r47 = mt7601u_bbp_rr(dev, 47); |
| | | |
| | | /* Set VGA gain */ |
| | | rf_vga = mt7601u_rf_rr(dev, 5, 3); |
| | | mt7601u_rf_wr(dev, 5, 3, 8); |
| | | |
| | | /* Mixer disable */ |
| | | rf_mixer = mt7601u_rf_rr(dev, 4, 39); |
| | | mt7601u_rf_wr(dev, 4, 39, 0); |
| | | |
| | | for (i = 0; i < 4; i++) { |
| | | mt7601u_rf_wr(dev, 4, 39, (i & 1) ? rf_mixer : 0); |
| | | |
| | | mt7601u_bbp_wr(dev, 23, (i < 2) ? 0x08 : 0x02); |
| | | mt7601u_rf_wr(dev, 5, 3, (i < 2) ? 0x08 : 0x11); |
| | | |
| | | /* BBP TSSI initial and soft reset */ |
| | | mt7601u_bbp_wr(dev, 22, 0); |
| | | mt7601u_bbp_wr(dev, 244, 0); |
| | | |
| | | mt7601u_bbp_wr(dev, 21, 1); |
| | | udelay(1); |
| | | mt7601u_bbp_wr(dev, 21, 0); |
| | | |
| | | /* TSSI measurement */ |
| | | mt7601u_bbp_wr(dev, 47, 0x50); |
| | | mt7601u_bbp_wr(dev, (i & 1) ? 244 : 22, (i & 1) ? 0x31 : 0x40); |
| | | |
| | | for (j = 20; j; j--) |
| | | if (!(mt7601u_bbp_rr(dev, 47) & 0x10)) |
| | | break; |
| | | if (!j) |
| | | dev_err(dev->dev, "%s timed out\n", __func__); |
| | | |
| | | /* TSSI read */ |
| | | mt7601u_bbp_wr(dev, 47, 0x40); |
| | | res[i] = mt7601u_bbp_rr(dev, 49); |
| | | } |
| | | |
| | | tssi_init_db = lin2dBd((short)res[1] - res[0]); |
| | | tssi_init_hvga_db = lin2dBd(((short)res[3] - res[2]) * 4); |
| | | dev->tssi_init = res[0]; |
| | | dev->tssi_init_hvga = res[2]; |
| | | dev->tssi_init_hvga_offset_db = tssi_init_hvga_db - tssi_init_db; |
| | | |
| | | dev_dbg(dev->dev, |
| | | "TSSI_init:%hhx db:%hx hvga:%hhx hvga_db:%hx off_db:%hx\n", |
| | | dev->tssi_init, tssi_init_db, dev->tssi_init_hvga, |
| | | tssi_init_hvga_db, dev->tssi_init_hvga_offset_db); |
| | | |
| | | mt7601u_bbp_wr(dev, 22, 0); |
| | | mt7601u_bbp_wr(dev, 244, 0); |
| | | |
| | | mt7601u_bbp_wr(dev, 21, 1); |
| | | udelay(1); |
| | | mt7601u_bbp_wr(dev, 21, 0); |
| | | |
| | | mt7601u_wr(dev, MT_RF_BYPASS_0, 0); |
| | | mt7601u_wr(dev, MT_RF_SETTING_0, 0); |
| | | |
| | | mt7601u_rf_wr(dev, 5, 3, rf_vga); |
| | | mt7601u_rf_wr(dev, 4, 39, rf_mixer); |
| | | mt7601u_bbp_wr(dev, 47, bbp_r47); |
| | | |
| | | mt7601u_set_initial_tssi(dev, tssi_init_db, tssi_init_hvga_db); |
| | | } |
| | | |
| | | static int mt7601u_temp_comp(struct mt7601u_dev *dev, bool on) |
| | | { |
| | | int ret, temp, hi_temp = 400, lo_temp = -200; |
| | | |
| | | temp = (dev->raw_temp - dev->ee->ref_temp) * MT_EE_TEMPERATURE_SLOPE; |
| | | dev->curr_temp = temp; |
| | | |
| | | /* DPD Calibration */ |
| | | if (temp - dev->dpd_temp > 450 || temp - dev->dpd_temp < -450) { |
| | | dev->dpd_temp = temp; |
| | | |
| | | ret = mt7601u_mcu_calibrate(dev, MCU_CAL_DPD, dev->dpd_temp); |
| | | if (ret) |
| | | return ret; |
| | | |
| | | mt7601u_vco_cal(dev); |
| | | |
| | | dev_dbg(dev->dev, "Recalibrate DPD\n"); |
| | | } |
| | | |
| | | /* PLL Lock Protect */ |
| | | if (temp < -50 && !dev->pll_lock_protect) { /* < 20C */ |
| | | dev->pll_lock_protect = true; |
| | | |
| | | mt7601u_rf_wr(dev, 4, 4, 6); |
| | | mt7601u_rf_clear(dev, 4, 10, 0x30); |
| | | |
| | | dev_dbg(dev->dev, "PLL lock protect on - too cold\n"); |
| | | } else if (temp > 50 && dev->pll_lock_protect) { /* > 30C */ |
| | | dev->pll_lock_protect = false; |
| | | |
| | | mt7601u_rf_wr(dev, 4, 4, 0); |
| | | mt7601u_rf_rmw(dev, 4, 10, 0x30, 0x10); |
| | | |
| | | dev_dbg(dev->dev, "PLL lock protect off\n"); |
| | | } |
| | | |
| | | if (on) { |
| | | hi_temp -= 50; |
| | | lo_temp -= 50; |
| | | } |
| | | |
| | | /* BBP CR for H, L, N temperature */ |
| | | if (temp > hi_temp) |
| | | return mt7601u_bbp_temp(dev, MT_TEMP_MODE_HIGH, "high"); |
| | | else if (temp > lo_temp) |
| | | return mt7601u_bbp_temp(dev, MT_TEMP_MODE_NORMAL, "normal"); |
| | | else |
| | | return mt7601u_bbp_temp(dev, MT_TEMP_MODE_LOW, "low"); |
| | | } |
| | | |
| | | /* Note: this is used only with TSSI, we can just use trgt_pwr from eeprom. */ |
| | | static int mt7601u_current_tx_power(struct mt7601u_dev *dev) |
| | | { |
| | | return dev->ee->chan_pwr[dev->chandef.chan->hw_value - 1]; |
| | | } |
| | | |
| | | static bool mt7601u_use_hvga(struct mt7601u_dev *dev) |
| | | { |
| | | return !(mt7601u_current_tx_power(dev) > 20); |
| | | } |
| | | |
| | | static s16 |
| | | mt7601u_phy_rf_pa_mode_val(struct mt7601u_dev *dev, int phy_mode, int tx_rate) |
| | | { |
| | | static const s16 decode_tb[] = { 0, 8847, -5734, -5734 }; |
| | | u32 reg; |
| | | |
| | | switch (phy_mode) { |
| | | case MT_PHY_TYPE_OFDM: |
| | | tx_rate += 4; |
| | | case MT_PHY_TYPE_CCK: |
| | | reg = dev->rf_pa_mode[0]; |
| | | break; |
| | | default: |
| | | reg = dev->rf_pa_mode[1]; |
| | | break; |
| | | } |
| | | |
| | | return decode_tb[(reg >> (tx_rate * 2)) & 0x3]; |
| | | } |
| | | |
| | | static struct mt7601u_tssi_params |
| | | mt7601u_tssi_params_get(struct mt7601u_dev *dev) |
| | | { |
| | | static const u8 ofdm_pkt2rate[8] = { 6, 4, 2, 0, 7, 5, 3, 1 }; |
| | | static const int static_power[4] = { 0, -49152, -98304, 49152 }; |
| | | struct mt7601u_tssi_params p; |
| | | u8 bbp_r47, pkt_type, tx_rate; |
| | | struct power_per_rate *rate_table; |
| | | |
| | | bbp_r47 = mt7601u_bbp_rr(dev, 47); |
| | | |
| | | p.tssi0 = mt7601u_bbp_r47_get(dev, bbp_r47, BBP_R47_F_TSSI); |
| | | dev->raw_temp = mt7601u_bbp_r47_get(dev, bbp_r47, BBP_R47_F_TEMP); |
| | | pkt_type = mt7601u_bbp_r47_get(dev, bbp_r47, BBP_R47_F_PKT_T); |
| | | |
| | | p.trgt_power = mt7601u_current_tx_power(dev); |
| | | |
| | | switch (pkt_type & 0x03) { |
| | | case MT_PHY_TYPE_CCK: |
| | | tx_rate = (pkt_type >> 4) & 0x03; |
| | | rate_table = dev->ee->power_rate_table.cck; |
| | | break; |
| | | |
| | | case MT_PHY_TYPE_OFDM: |
| | | tx_rate = ofdm_pkt2rate[(pkt_type >> 4) & 0x07]; |
| | | rate_table = dev->ee->power_rate_table.ofdm; |
| | | break; |
| | | |
| | | default: |
| | | tx_rate = mt7601u_bbp_r47_get(dev, bbp_r47, BBP_R47_F_TX_RATE); |
| | | tx_rate &= 0x7f; |
| | | rate_table = dev->ee->power_rate_table.ht; |
| | | break; |
| | | } |
| | | |
| | | if (dev->bw == MT_BW_20) |
| | | p.trgt_power += rate_table[tx_rate / 2].bw20; |
| | | else |
| | | p.trgt_power += rate_table[tx_rate / 2].bw40; |
| | | |
| | | p.trgt_power <<= 12; |
| | | |
| | | dev_dbg(dev->dev, "tx_rate:%02hhx pwr:%08x\n", tx_rate, p.trgt_power); |
| | | |
| | | p.trgt_power += mt7601u_phy_rf_pa_mode_val(dev, pkt_type & 0x03, |
| | | tx_rate); |
| | | |
| | | /* Channel 14, cck, bw20 */ |
| | | if ((pkt_type & 0x03) == MT_PHY_TYPE_CCK) { |
| | | if (mt7601u_bbp_rr(dev, 4) & 0x20) |
| | | p.trgt_power += mt7601u_bbp_rr(dev, 178) ? 18022 : 9830; |
| | | else |
| | | p.trgt_power += mt7601u_bbp_rr(dev, 178) ? 819 : 24576; |
| | | } |
| | | |
| | | p.trgt_power += static_power[mt7601u_bbp_rr(dev, 1) & 0x03]; |
| | | |
| | | p.trgt_power += dev->ee->tssi_data.tx0_delta_offset; |
| | | |
| | | dev_dbg(dev->dev, |
| | | "tssi:%02hhx t_power:%08x temp:%02hhx pkt_type:%02hhx\n", |
| | | p.tssi0, p.trgt_power, dev->raw_temp, pkt_type); |
| | | |
| | | return p; |
| | | } |
| | | |
| | | static bool mt7601u_tssi_read_ready(struct mt7601u_dev *dev) |
| | | { |
| | | return !(mt7601u_bbp_rr(dev, 47) & 0x10); |
| | | } |
| | | |
| | | static int mt7601u_tssi_cal(struct mt7601u_dev *dev) |
| | | { |
| | | struct mt7601u_tssi_params params; |
| | | int curr_pwr, diff_pwr; |
| | | char tssi_offset; |
| | | s8 tssi_init; |
| | | s16 tssi_m_dc, tssi_db; |
| | | bool hvga; |
| | | u32 val; |
| | | |
| | | if (!dev->ee->tssi_enabled) |
| | | return 0; |
| | | |
| | | hvga = mt7601u_use_hvga(dev); |
| | | if (!dev->tssi_read_trig) |
| | | return mt7601u_mcu_tssi_read_kick(dev, hvga); |
| | | |
| | | if (!mt7601u_tssi_read_ready(dev)) |
| | | return 0; |
| | | |
| | | params = mt7601u_tssi_params_get(dev); |
| | | |
| | | tssi_init = (hvga ? dev->tssi_init_hvga : dev->tssi_init); |
| | | tssi_m_dc = params.tssi0 - tssi_init; |
| | | tssi_db = lin2dBd(tssi_m_dc); |
| | | dev_dbg(dev->dev, "tssi dc:%04hx db:%04hx hvga:%d\n", |
| | | tssi_m_dc, tssi_db, hvga); |
| | | |
| | | if (dev->chandef.chan->hw_value < 5) |
| | | tssi_offset = dev->ee->tssi_data.offset[0]; |
| | | else if (dev->chandef.chan->hw_value < 9) |
| | | tssi_offset = dev->ee->tssi_data.offset[1]; |
| | | else |
| | | tssi_offset = dev->ee->tssi_data.offset[2]; |
| | | |
| | | if (hvga) |
| | | tssi_db -= dev->tssi_init_hvga_offset_db; |
| | | |
| | | curr_pwr = tssi_db * dev->ee->tssi_data.slope + (tssi_offset << 9); |
| | | diff_pwr = params.trgt_power - curr_pwr; |
| | | dev_dbg(dev->dev, "Power curr:%08x diff:%08x\n", curr_pwr, diff_pwr); |
| | | |
| | | if (params.tssi0 > 126 && diff_pwr > 0) { |
| | | dev_err(dev->dev, "Error: TSSI upper saturation\n"); |
| | | diff_pwr = 0; |
| | | } |
| | | if (params.tssi0 - tssi_init < 1 && diff_pwr < 0) { |
| | | dev_err(dev->dev, "Error: TSSI lower saturation\n"); |
| | | diff_pwr = 0; |
| | | } |
| | | |
| | | if ((dev->prev_pwr_diff ^ diff_pwr) < 0 && abs(diff_pwr) < 4096 && |
| | | (abs(diff_pwr) > abs(dev->prev_pwr_diff) || |
| | | (diff_pwr > 0 && diff_pwr == -dev->prev_pwr_diff))) |
| | | diff_pwr = 0; |
| | | else |
| | | dev->prev_pwr_diff = diff_pwr; |
| | | |
| | | diff_pwr += (diff_pwr > 0) ? 2048 : -2048; |
| | | diff_pwr /= 4096; |
| | | |
| | | dev_dbg(dev->dev, "final diff: %08x\n", diff_pwr); |
| | | |
| | | val = mt7601u_rr(dev, MT_TX_ALC_CFG_1); |
| | | curr_pwr = s6_to_int(MT76_GET(MT_TX_ALC_CFG_1_TEMP_COMP, val)); |
| | | diff_pwr += curr_pwr; |
| | | val = (val & ~MT_TX_ALC_CFG_1_TEMP_COMP) | int_to_s6(diff_pwr); |
| | | mt7601u_wr(dev, MT_TX_ALC_CFG_1, val); |
| | | |
| | | return mt7601u_mcu_tssi_read_kick(dev, hvga); |
| | | } |
| | | |
| | | static u8 mt7601u_agc_default(struct mt7601u_dev *dev) |
| | | { |
| | | return (dev->ee->lna_gain - 8) * 2 + 0x34; |
| | | } |
| | | |
| | | static void mt7601u_agc_reset(struct mt7601u_dev *dev) |
| | | { |
| | | u8 agc = mt7601u_agc_default(dev); |
| | | |
| | | mt7601u_bbp_wr(dev, 66, agc); |
| | | } |
| | | |
| | | void mt7601u_agc_save(struct mt7601u_dev *dev) |
| | | { |
| | | dev->agc_save = mt7601u_bbp_rr(dev, 66); |
| | | } |
| | | |
| | | void mt7601u_agc_restore(struct mt7601u_dev *dev) |
| | | { |
| | | mt7601u_bbp_wr(dev, 66, dev->agc_save); |
| | | } |
| | | |
| | | static void mt7601u_agc_tune(struct mt7601u_dev *dev) |
| | | { |
| | | u8 val = mt7601u_agc_default(dev); |
| | | |
| | | if (test_bit(MT7601U_STATE_SCANNING, &dev->state)) |
| | | return; |
| | | |
| | | /* Note: only in STA mode and not dozing; perhaps do this only if |
| | | * there is enough rssi updates since last run? |
| | | * Rssi updates are only on beacons and U2M so should work... |
| | | */ |
| | | spin_lock_bh(&dev->con_mon_lock); |
| | | if (dev->avg_rssi <= -70) |
| | | val -= 0x20; |
| | | else if (dev->avg_rssi <= -60) |
| | | val -= 0x10; |
| | | spin_unlock_bh(&dev->con_mon_lock); |
| | | |
| | | if (val != mt7601u_bbp_rr(dev, 66)) |
| | | mt7601u_bbp_wr(dev, 66, val); |
| | | |
| | | /* TODO: also if lost a lot of beacons try resetting |
| | | * (see RTMPSetAGCInitValue() call in mlme.c). |
| | | */ |
| | | } |
| | | |
| | | static void mt7601u_phy_calibrate(struct work_struct *work) |
| | | { |
| | | struct mt7601u_dev *dev = container_of(work, struct mt7601u_dev, |
| | | cal_work.work); |
| | | |
| | | mt7601u_agc_tune(dev); |
| | | mt7601u_tssi_cal(dev); |
| | | /* If TSSI calibration was run it already updated temperature. */ |
| | | if (!dev->ee->tssi_enabled) |
| | | dev->raw_temp = mt7601u_read_temp(dev); |
| | | mt7601u_temp_comp(dev, true); /* TODO: find right value for @on */ |
| | | |
| | | ieee80211_queue_delayed_work(dev->hw, &dev->cal_work, |
| | | MT_CALIBRATE_INTERVAL); |
| | | } |
| | | |
| | | static unsigned long |
| | | __mt7601u_phy_freq_cal(struct mt7601u_dev *dev, s8 last_offset, u8 phy_mode) |
| | | { |
| | | u8 activate_threshold, deactivate_threshold; |
| | | |
| | | trace_freq_cal_offset(dev, phy_mode, last_offset); |
| | | |
| | | /* No beacons received - reschedule soon */ |
| | | if (last_offset == MT_FREQ_OFFSET_INVALID) |
| | | return MT_FREQ_CAL_ADJ_INTERVAL; |
| | | |
| | | switch (phy_mode) { |
| | | case MT_PHY_TYPE_CCK: |
| | | activate_threshold = 19; |
| | | deactivate_threshold = 5; |
| | | break; |
| | | case MT_PHY_TYPE_OFDM: |
| | | activate_threshold = 102; |
| | | deactivate_threshold = 32; |
| | | break; |
| | | case MT_PHY_TYPE_HT: |
| | | case MT_PHY_TYPE_HT_GF: |
| | | activate_threshold = 82; |
| | | deactivate_threshold = 20; |
| | | break; |
| | | default: |
| | | WARN_ON(1); |
| | | return MT_FREQ_CAL_CHECK_INTERVAL; |
| | | } |
| | | |
| | | if (abs(last_offset) >= activate_threshold) |
| | | dev->freq_cal.adjusting = true; |
| | | else if (abs(last_offset) <= deactivate_threshold) |
| | | dev->freq_cal.adjusting = false; |
| | | |
| | | if (!dev->freq_cal.adjusting) |
| | | return MT_FREQ_CAL_CHECK_INTERVAL; |
| | | |
| | | if (last_offset > deactivate_threshold) { |
| | | if (dev->freq_cal.freq > 0) |
| | | dev->freq_cal.freq--; |
| | | else |
| | | dev->freq_cal.adjusting = false; |
| | | } else if (last_offset < -deactivate_threshold) { |
| | | if (dev->freq_cal.freq < 0xbf) |
| | | dev->freq_cal.freq++; |
| | | else |
| | | dev->freq_cal.adjusting = false; |
| | | } |
| | | |
| | | trace_freq_cal_adjust(dev, dev->freq_cal.freq); |
| | | mt7601u_rf_wr(dev, 0, 12, dev->freq_cal.freq); |
| | | mt7601u_vco_cal(dev); |
| | | |
| | | return dev->freq_cal.adjusting ? MT_FREQ_CAL_ADJ_INTERVAL : |
| | | MT_FREQ_CAL_CHECK_INTERVAL; |
| | | } |
| | | |
| | | static void mt7601u_phy_freq_cal(struct work_struct *work) |
| | | { |
| | | struct mt7601u_dev *dev = container_of(work, struct mt7601u_dev, |
| | | freq_cal.work.work); |
| | | s8 last_offset; |
| | | u8 phy_mode; |
| | | unsigned long delay; |
| | | |
| | | spin_lock_bh(&dev->con_mon_lock); |
| | | last_offset = dev->bcn_freq_off; |
| | | phy_mode = dev->bcn_phy_mode; |
| | | spin_unlock_bh(&dev->con_mon_lock); |
| | | |
| | | delay = __mt7601u_phy_freq_cal(dev, last_offset, phy_mode); |
| | | ieee80211_queue_delayed_work(dev->hw, &dev->freq_cal.work, delay); |
| | | |
| | | spin_lock_bh(&dev->con_mon_lock); |
| | | dev->bcn_freq_off = MT_FREQ_OFFSET_INVALID; |
| | | spin_unlock_bh(&dev->con_mon_lock); |
| | | } |
| | | |
| | | void mt7601u_phy_con_cal_onoff(struct mt7601u_dev *dev, |
| | | struct ieee80211_bss_conf *info) |
| | | { |
| | | if (!info->assoc) |
| | | cancel_delayed_work_sync(&dev->freq_cal.work); |
| | | |
| | | /* Start/stop collecting beacon data */ |
| | | spin_lock_bh(&dev->con_mon_lock); |
| | | ether_addr_copy(dev->ap_bssid, info->bssid); |
| | | dev->avg_rssi = 0; |
| | | dev->bcn_freq_off = MT_FREQ_OFFSET_INVALID; |
| | | spin_unlock_bh(&dev->con_mon_lock); |
| | | |
| | | dev->freq_cal.freq = dev->ee->rf_freq_off; |
| | | dev->freq_cal.enabled = info->assoc; |
| | | dev->freq_cal.adjusting = false; |
| | | |
| | | if (info->assoc) |
| | | ieee80211_queue_delayed_work(dev->hw, &dev->freq_cal.work, |
| | | MT_FREQ_CAL_INIT_DELAY); |
| | | } |
| | | |
| | | static int mt7601u_init_cal(struct mt7601u_dev *dev) |
| | | { |
| | | u32 mac_ctrl; |
| | | int ret; |
| | | |
| | | dev->raw_temp = mt7601u_read_bootup_temp(dev); |
| | | dev->curr_temp = (dev->raw_temp - dev->ee->ref_temp) * |
| | | MT_EE_TEMPERATURE_SLOPE; |
| | | dev->dpd_temp = dev->curr_temp; |
| | | |
| | | mac_ctrl = mt7601u_rr(dev, MT_MAC_SYS_CTRL); |
| | | |
| | | ret = mt7601u_mcu_calibrate(dev, MCU_CAL_R, 0); |
| | | if (ret) |
| | | return ret; |
| | | |
| | | ret = mt7601u_rf_rr(dev, 0, 4); |
| | | if (ret < 0) |
| | | return ret; |
| | | ret |= 0x80; |
| | | ret = mt7601u_rf_wr(dev, 0, 4, ret); |
| | | if (ret) |
| | | return ret; |
| | | msleep(2); |
| | | |
| | | ret = mt7601u_mcu_calibrate(dev, MCU_CAL_TXDCOC, 0); |
| | | if (ret) |
| | | return ret; |
| | | |
| | | mt7601u_rxdc_cal(dev); |
| | | |
| | | ret = mt7601u_set_bw_filter(dev, true); |
| | | if (ret) |
| | | return ret; |
| | | ret = mt7601u_mcu_calibrate(dev, MCU_CAL_LOFT, 0); |
| | | if (ret) |
| | | return ret; |
| | | ret = mt7601u_mcu_calibrate(dev, MCU_CAL_TXIQ, 0); |
| | | if (ret) |
| | | return ret; |
| | | ret = mt7601u_mcu_calibrate(dev, MCU_CAL_RXIQ, 0); |
| | | if (ret) |
| | | return ret; |
| | | ret = mt7601u_mcu_calibrate(dev, MCU_CAL_DPD, dev->dpd_temp); |
| | | if (ret) |
| | | return ret; |
| | | |
| | | mt7601u_rxdc_cal(dev); |
| | | |
| | | mt7601u_tssi_dc_gain_cal(dev); |
| | | |
| | | mt7601u_wr(dev, MT_MAC_SYS_CTRL, mac_ctrl); |
| | | |
| | | mt7601u_temp_comp(dev, true); |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | int mt7601u_bbp_set_bw(struct mt7601u_dev *dev, int bw) |
| | | { |
| | | u32 val, old; |
| | | |
| | | if (bw == dev->bw) { |
| | | /* Vendor driver does the rmc even when no change is needed. */ |
| | | mt7601u_bbp_rmc(dev, 4, 0x18, bw == MT_BW_20 ? 0 : 0x10); |
| | | |
| | | return 0; |
| | | } |
| | | dev->bw = bw; |
| | | |
| | | /* Stop MAC for the time of bw change */ |
| | | old = mt7601u_rr(dev, MT_MAC_SYS_CTRL); |
| | | val = old & ~(MT_MAC_SYS_CTRL_ENABLE_TX | MT_MAC_SYS_CTRL_ENABLE_RX); |
| | | mt7601u_wr(dev, MT_MAC_SYS_CTRL, val); |
| | | mt76_poll(dev, MT_MAC_STATUS, MT_MAC_STATUS_TX | MT_MAC_STATUS_RX, |
| | | 0, 500000); |
| | | |
| | | mt7601u_bbp_rmc(dev, 4, 0x18, bw == MT_BW_20 ? 0 : 0x10); |
| | | |
| | | mt7601u_wr(dev, MT_MAC_SYS_CTRL, old); |
| | | |
| | | return mt7601u_load_bbp_temp_table_bw(dev); |
| | | } |
| | | |
| | | /** |
| | | * mt7601u_set_rx_path - set rx path in BBP |
| | | * @dev: pointer to adapter structure |
| | | * @path: rx path to set values are 0-based |
| | | */ |
| | | void mt7601u_set_rx_path(struct mt7601u_dev *dev, u8 path) |
| | | { |
| | | mt7601u_bbp_rmw(dev, 3, 0x18, path << 3); |
| | | } |
| | | |
| | | /** |
| | | * mt7601u_set_tx_dac - set which tx DAC to use |
| | | * @dev: pointer to adapter structure |
| | | * @path: DAC index, values are 0-based |
| | | */ |
| | | void mt7601u_set_tx_dac(struct mt7601u_dev *dev, u8 dac) |
| | | { |
| | | mt7601u_bbp_rmc(dev, 1, 0x18, dac << 3); |
| | | } |
| | | |
| | | int mt7601u_phy_init(struct mt7601u_dev *dev) |
| | | { |
| | | int ret; |
| | | |
| | | dev->rf_pa_mode[0] = mt7601u_rr(dev, MT_RF_PA_MODE_CFG0); |
| | | dev->rf_pa_mode[1] = mt7601u_rr(dev, MT_RF_PA_MODE_CFG1); |
| | | |
| | | ret = mt7601u_rf_wr(dev, 0, 12, dev->ee->rf_freq_off); |
| | | if (ret) |
| | | return ret; |
| | | ret = mt7601u_write_reg_pairs(dev, 0, rf_central, |
| | | ARRAY_SIZE(rf_central)); |
| | | if (ret) |
| | | return ret; |
| | | ret = mt7601u_write_reg_pairs(dev, 0, rf_channel, |
| | | ARRAY_SIZE(rf_channel)); |
| | | if (ret) |
| | | return ret; |
| | | ret = mt7601u_write_reg_pairs(dev, 0, rf_vga, ARRAY_SIZE(rf_vga)); |
| | | if (ret) |
| | | return ret; |
| | | |
| | | ret = mt7601u_init_cal(dev); |
| | | if (ret) |
| | | return ret; |
| | | |
| | | dev->prev_pwr_diff = 100; |
| | | |
| | | INIT_DELAYED_WORK(&dev->cal_work, mt7601u_phy_calibrate); |
| | | INIT_DELAYED_WORK(&dev->freq_cal.work, mt7601u_phy_freq_cal); |
| | | |
| | | return 0; |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> |
| | | * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> |
| | | * |
| | | * This program is free software; you can redistribute it and/or modify |
| | | * it under the terms of the GNU General Public License version 2 |
| | | * as published by the Free Software Foundation |
| | | * |
| | | * This program is distributed in the hope that it will be useful, |
| | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| | | * GNU General Public License for more details. |
| | | */ |
| | | |
| | | #ifndef __MT76_REGS_H |
| | | #define __MT76_REGS_H |
| | | |
| | | #include <linux/bitops.h> |
| | | |
| | | #ifndef GENMASK |
| | | #define GENMASK(h, l) (((U32_C(1) << ((h) - (l) + 1)) - 1) << (l)) |
| | | #endif |
| | | |
| | | #define MT_ASIC_VERSION 0x0000 |
| | | |
| | | #define MT76XX_REV_E3 0x22 |
| | | #define MT76XX_REV_E4 0x33 |
| | | |
| | | #define MT_CMB_CTRL 0x0020 |
| | | #define MT_CMB_CTRL_XTAL_RDY BIT(22) |
| | | #define MT_CMB_CTRL_PLL_LD BIT(23) |
| | | |
| | | #define MT_EFUSE_CTRL 0x0024 |
| | | #define MT_EFUSE_CTRL_AOUT GENMASK(5, 0) |
| | | #define MT_EFUSE_CTRL_MODE GENMASK(7, 6) |
| | | #define MT_EFUSE_CTRL_LDO_OFF_TIME GENMASK(13, 8) |
| | | #define MT_EFUSE_CTRL_LDO_ON_TIME GENMASK(15, 14) |
| | | #define MT_EFUSE_CTRL_AIN GENMASK(25, 16) |
| | | #define MT_EFUSE_CTRL_KICK BIT(30) |
| | | #define MT_EFUSE_CTRL_SEL BIT(31) |
| | | |
| | | #define MT_EFUSE_DATA_BASE 0x0028 |
| | | #define MT_EFUSE_DATA(_n) (MT_EFUSE_DATA_BASE + ((_n) << 2)) |
| | | |
| | | #define MT_COEXCFG0 0x0040 |
| | | #define MT_COEXCFG0_COEX_EN BIT(0) |
| | | |
| | | #define MT_WLAN_FUN_CTRL 0x0080 |
| | | #define MT_WLAN_FUN_CTRL_WLAN_EN BIT(0) |
| | | #define MT_WLAN_FUN_CTRL_WLAN_CLK_EN BIT(1) |
| | | #define MT_WLAN_FUN_CTRL_WLAN_RESET_RF BIT(2) |
| | | |
| | | #define MT_WLAN_FUN_CTRL_WLAN_RESET BIT(3) /* MT76x0 */ |
| | | #define MT_WLAN_FUN_CTRL_CSR_F20M_CKEN BIT(3) /* MT76x2 */ |
| | | |
| | | #define MT_WLAN_FUN_CTRL_PCIE_CLK_REQ BIT(4) |
| | | #define MT_WLAN_FUN_CTRL_FRC_WL_ANT_SEL BIT(5) |
| | | #define MT_WLAN_FUN_CTRL_INV_ANT_SEL BIT(6) |
| | | #define MT_WLAN_FUN_CTRL_WAKE_HOST BIT(7) |
| | | |
| | | #define MT_WLAN_FUN_CTRL_THERM_RST BIT(8) /* MT76x2 */ |
| | | #define MT_WLAN_FUN_CTRL_THERM_CKEN BIT(9) /* MT76x2 */ |
| | | |
| | | #define MT_WLAN_FUN_CTRL_GPIO_IN GENMASK(15, 8) /* MT76x0 */ |
| | | #define MT_WLAN_FUN_CTRL_GPIO_OUT GENMASK(23, 16) /* MT76x0 */ |
| | | #define MT_WLAN_FUN_CTRL_GPIO_OUT_EN GENMASK(31, 24) /* MT76x0 */ |
| | | |
| | | #define MT_XO_CTRL0 0x0100 |
| | | #define MT_XO_CTRL1 0x0104 |
| | | #define MT_XO_CTRL2 0x0108 |
| | | #define MT_XO_CTRL3 0x010c |
| | | #define MT_XO_CTRL4 0x0110 |
| | | |
| | | #define MT_XO_CTRL5 0x0114 |
| | | #define MT_XO_CTRL5_C2_VAL GENMASK(14, 8) |
| | | |
| | | #define MT_XO_CTRL6 0x0118 |
| | | #define MT_XO_CTRL6_C2_CTRL GENMASK(14, 8) |
| | | |
| | | #define MT_XO_CTRL7 0x011c |
| | | |
| | | #define MT_WLAN_MTC_CTRL 0x10148 |
| | | #define MT_WLAN_MTC_CTRL_MTCMOS_PWR_UP BIT(0) |
| | | #define MT_WLAN_MTC_CTRL_PWR_ACK BIT(12) |
| | | #define MT_WLAN_MTC_CTRL_PWR_ACK_S BIT(13) |
| | | #define MT_WLAN_MTC_CTRL_BBP_MEM_PD GENMASK(19, 16) |
| | | #define MT_WLAN_MTC_CTRL_PBF_MEM_PD BIT(20) |
| | | #define MT_WLAN_MTC_CTRL_FCE_MEM_PD BIT(21) |
| | | #define MT_WLAN_MTC_CTRL_TSO_MEM_PD BIT(22) |
| | | #define MT_WLAN_MTC_CTRL_BBP_MEM_RB BIT(24) |
| | | #define MT_WLAN_MTC_CTRL_PBF_MEM_RB BIT(25) |
| | | #define MT_WLAN_MTC_CTRL_FCE_MEM_RB BIT(26) |
| | | #define MT_WLAN_MTC_CTRL_TSO_MEM_RB BIT(27) |
| | | #define MT_WLAN_MTC_CTRL_STATE_UP BIT(28) |
| | | |
| | | #define MT_INT_SOURCE_CSR 0x0200 |
| | | #define MT_INT_MASK_CSR 0x0204 |
| | | |
| | | #define MT_INT_RX_DONE(_n) BIT(_n) |
| | | #define MT_INT_RX_DONE_ALL GENMASK(1, 0) |
| | | #define MT_INT_TX_DONE_ALL GENMASK(13, 4) |
| | | #define MT_INT_TX_DONE(_n) BIT(_n + 4) |
| | | #define MT_INT_RX_COHERENT BIT(16) |
| | | #define MT_INT_TX_COHERENT BIT(17) |
| | | #define MT_INT_ANY_COHERENT BIT(18) |
| | | #define MT_INT_MCU_CMD BIT(19) |
| | | #define MT_INT_TBTT BIT(20) |
| | | #define MT_INT_PRE_TBTT BIT(21) |
| | | #define MT_INT_TX_STAT BIT(22) |
| | | #define MT_INT_AUTO_WAKEUP BIT(23) |
| | | #define MT_INT_GPTIMER BIT(24) |
| | | #define MT_INT_RXDELAYINT BIT(26) |
| | | #define MT_INT_TXDELAYINT BIT(27) |
| | | |
| | | #define MT_WPDMA_GLO_CFG 0x0208 |
| | | #define MT_WPDMA_GLO_CFG_TX_DMA_EN BIT(0) |
| | | #define MT_WPDMA_GLO_CFG_TX_DMA_BUSY BIT(1) |
| | | #define MT_WPDMA_GLO_CFG_RX_DMA_EN BIT(2) |
| | | #define MT_WPDMA_GLO_CFG_RX_DMA_BUSY BIT(3) |
| | | #define MT_WPDMA_GLO_CFG_DMA_BURST_SIZE GENMASK(5, 4) |
| | | #define MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE BIT(6) |
| | | #define MT_WPDMA_GLO_CFG_BIG_ENDIAN BIT(7) |
| | | #define MT_WPDMA_GLO_CFG_HDR_SEG_LEN GENMASK(15, 8) |
| | | #define MT_WPDMA_GLO_CFG_CLK_GATE_DIS BIT(30) |
| | | #define MT_WPDMA_GLO_CFG_RX_2B_OFFSET BIT(31) |
| | | |
| | | #define MT_WPDMA_RST_IDX 0x020c |
| | | |
| | | #define MT_WPDMA_DELAY_INT_CFG 0x0210 |
| | | |
| | | #define MT_WMM_AIFSN 0x0214 |
| | | #define MT_WMM_AIFSN_MASK GENMASK(3, 0) |
| | | #define MT_WMM_AIFSN_SHIFT(_n) ((_n) * 4) |
| | | |
| | | #define MT_WMM_CWMIN 0x0218 |
| | | #define MT_WMM_CWMIN_MASK GENMASK(3, 0) |
| | | #define MT_WMM_CWMIN_SHIFT(_n) ((_n) * 4) |
| | | |
| | | #define MT_WMM_CWMAX 0x021c |
| | | #define MT_WMM_CWMAX_MASK GENMASK(3, 0) |
| | | #define MT_WMM_CWMAX_SHIFT(_n) ((_n) * 4) |
| | | |
| | | #define MT_WMM_TXOP_BASE 0x0220 |
| | | #define MT_WMM_TXOP(_n) (MT_WMM_TXOP_BASE + (((_n) / 2) << 2)) |
| | | #define MT_WMM_TXOP_SHIFT(_n) ((_n & 1) * 16) |
| | | #define MT_WMM_TXOP_MASK GENMASK(15, 0) |
| | | |
| | | #define MT_FCE_DMA_ADDR 0x0230 |
| | | #define MT_FCE_DMA_LEN 0x0234 |
| | | |
| | | #define MT_USB_DMA_CFG 0x238 |
| | | #define MT_USB_DMA_CFG_RX_BULK_AGG_TOUT GENMASK(7, 0) |
| | | #define MT_USB_DMA_CFG_RX_BULK_AGG_LMT GENMASK(15, 8) |
| | | #define MT_USB_DMA_CFG_PHY_CLR BIT(16) |
| | | #define MT_USB_DMA_CFG_TX_CLR BIT(19) |
| | | #define MT_USB_DMA_CFG_TXOP_HALT BIT(20) |
| | | #define MT_USB_DMA_CFG_RX_BULK_AGG_EN BIT(21) |
| | | #define MT_USB_DMA_CFG_RX_BULK_EN BIT(22) |
| | | #define MT_USB_DMA_CFG_TX_BULK_EN BIT(23) |
| | | #define MT_USB_DMA_CFG_UDMA_RX_WL_DROP BIT(25) |
| | | #define MT_USB_DMA_CFG_EP_OUT_VALID GENMASK(29, 27) |
| | | #define MT_USB_DMA_CFG_RX_BUSY BIT(30) |
| | | #define MT_USB_DMA_CFG_TX_BUSY BIT(31) |
| | | |
| | | #define MT_TSO_CTRL 0x0250 |
| | | #define MT_HEADER_TRANS_CTRL_REG 0x0260 |
| | | |
| | | #define MT_US_CYC_CFG 0x02a4 |
| | | #define MT_US_CYC_CNT GENMASK(7, 0) |
| | | |
| | | #define MT_TX_RING_BASE 0x0300 |
| | | #define MT_RX_RING_BASE 0x03c0 |
| | | #define MT_RING_SIZE 0x10 |
| | | |
| | | #define MT_TX_HW_QUEUE_MCU 8 |
| | | #define MT_TX_HW_QUEUE_MGMT 9 |
| | | |
| | | #define MT_PBF_SYS_CTRL 0x0400 |
| | | #define MT_PBF_SYS_CTRL_MCU_RESET BIT(0) |
| | | #define MT_PBF_SYS_CTRL_DMA_RESET BIT(1) |
| | | #define MT_PBF_SYS_CTRL_MAC_RESET BIT(2) |
| | | #define MT_PBF_SYS_CTRL_PBF_RESET BIT(3) |
| | | #define MT_PBF_SYS_CTRL_ASY_RESET BIT(4) |
| | | |
| | | #define MT_PBF_CFG 0x0404 |
| | | #define MT_PBF_CFG_TX0Q_EN BIT(0) |
| | | #define MT_PBF_CFG_TX1Q_EN BIT(1) |
| | | #define MT_PBF_CFG_TX2Q_EN BIT(2) |
| | | #define MT_PBF_CFG_TX3Q_EN BIT(3) |
| | | #define MT_PBF_CFG_RX0Q_EN BIT(4) |
| | | #define MT_PBF_CFG_RX_DROP_EN BIT(8) |
| | | |
| | | #define MT_PBF_TX_MAX_PCNT 0x0408 |
| | | #define MT_PBF_RX_MAX_PCNT 0x040c |
| | | |
| | | #define MT_BCN_OFFSET_BASE 0x041c |
| | | #define MT_BCN_OFFSET(_n) (MT_BCN_OFFSET_BASE + ((_n) << 2)) |
| | | |
| | | #define MT_RXQ_STA 0x0430 |
| | | #define MT_TXQ_STA 0x0434 |
| | | |
| | | #define MT_RF_CSR_CFG 0x0500 |
| | | #define MT_RF_CSR_CFG_DATA GENMASK(7, 0) |
| | | #define MT_RF_CSR_CFG_REG_ID GENMASK(13, 8) |
| | | #define MT_RF_CSR_CFG_REG_BANK GENMASK(17, 14) |
| | | #define MT_RF_CSR_CFG_WR BIT(30) |
| | | #define MT_RF_CSR_CFG_KICK BIT(31) |
| | | |
| | | #define MT_RF_BYPASS_0 0x0504 |
| | | #define MT_RF_BYPASS_1 0x0508 |
| | | #define MT_RF_SETTING_0 0x050c |
| | | |
| | | #define MT_RF_DATA_WRITE 0x0524 |
| | | |
| | | #define MT_RF_CTRL 0x0528 |
| | | #define MT_RF_CTRL_ADDR GENMASK(11, 0) |
| | | #define MT_RF_CTRL_WRITE BIT(12) |
| | | #define MT_RF_CTRL_BUSY BIT(13) |
| | | #define MT_RF_CTRL_IDX BIT(16) |
| | | |
| | | #define MT_RF_DATA_READ 0x052c |
| | | |
| | | #define MT_FCE_PSE_CTRL 0x0800 |
| | | #define MT_FCE_PARAMETERS 0x0804 |
| | | #define MT_FCE_CSO 0x0808 |
| | | |
| | | #define MT_FCE_L2_STUFF 0x080c |
| | | #define MT_FCE_L2_STUFF_HT_L2_EN BIT(0) |
| | | #define MT_FCE_L2_STUFF_QOS_L2_EN BIT(1) |
| | | #define MT_FCE_L2_STUFF_RX_STUFF_EN BIT(2) |
| | | #define MT_FCE_L2_STUFF_TX_STUFF_EN BIT(3) |
| | | #define MT_FCE_L2_STUFF_WR_MPDU_LEN_EN BIT(4) |
| | | #define MT_FCE_L2_STUFF_MVINV_BSWAP BIT(5) |
| | | #define MT_FCE_L2_STUFF_TS_CMD_QSEL_EN GENMASK(15, 8) |
| | | #define MT_FCE_L2_STUFF_TS_LEN_EN GENMASK(23, 16) |
| | | #define MT_FCE_L2_STUFF_OTHER_PORT GENMASK(25, 24) |
| | | |
| | | #define MT_FCE_WLAN_FLOW_CONTROL1 0x0824 |
| | | |
| | | #define MT_TX_CPU_FROM_FCE_BASE_PTR 0x09a0 |
| | | #define MT_TX_CPU_FROM_FCE_MAX_COUNT 0x09a4 |
| | | #define MT_TX_CPU_FROM_FCE_CPU_DESC_IDX 0x09a8 |
| | | |
| | | #define MT_FCE_PDMA_GLOBAL_CONF 0x09c4 |
| | | |
| | | #define MT_PAUSE_ENABLE_CONTROL1 0x0a38 |
| | | |
| | | #define MT_FCE_SKIP_FS 0x0a6c |
| | | |
| | | #define MT_MAC_CSR0 0x1000 |
| | | |
| | | #define MT_MAC_SYS_CTRL 0x1004 |
| | | #define MT_MAC_SYS_CTRL_RESET_CSR BIT(0) |
| | | #define MT_MAC_SYS_CTRL_RESET_BBP BIT(1) |
| | | #define MT_MAC_SYS_CTRL_ENABLE_TX BIT(2) |
| | | #define MT_MAC_SYS_CTRL_ENABLE_RX BIT(3) |
| | | |
| | | #define MT_MAC_ADDR_DW0 0x1008 |
| | | #define MT_MAC_ADDR_DW1 0x100c |
| | | #define MT_MAC_ADDR_DW1_U2ME_MASK GENMASK(23, 16) |
| | | |
| | | #define MT_MAC_BSSID_DW0 0x1010 |
| | | #define MT_MAC_BSSID_DW1 0x1014 |
| | | #define MT_MAC_BSSID_DW1_ADDR GENMASK(15, 0) |
| | | #define MT_MAC_BSSID_DW1_MBSS_MODE GENMASK(17, 16) |
| | | #define MT_MAC_BSSID_DW1_MBEACON_N GENMASK(20, 18) |
| | | #define MT_MAC_BSSID_DW1_MBSS_LOCAL_BIT BIT(21) |
| | | #define MT_MAC_BSSID_DW1_MBSS_MODE_B2 BIT(22) |
| | | #define MT_MAC_BSSID_DW1_MBEACON_N_B3 BIT(23) |
| | | #define MT_MAC_BSSID_DW1_MBSS_IDX_BYTE GENMASK(26, 24) |
| | | |
| | | #define MT_MAX_LEN_CFG 0x1018 |
| | | #define MT_MAX_LEN_CFG_AMPDU GENMASK(13, 12) |
| | | |
| | | #define MT_BBP_CSR_CFG 0x101c |
| | | #define MT_BBP_CSR_CFG_VAL GENMASK(7, 0) |
| | | #define MT_BBP_CSR_CFG_REG_NUM GENMASK(15, 8) |
| | | #define MT_BBP_CSR_CFG_READ BIT(16) |
| | | #define MT_BBP_CSR_CFG_BUSY BIT(17) |
| | | #define MT_BBP_CSR_CFG_PAR_DUR BIT(18) |
| | | #define MT_BBP_CSR_CFG_RW_MODE BIT(19) |
| | | |
| | | #define MT_AMPDU_MAX_LEN_20M1S 0x1030 |
| | | #define MT_AMPDU_MAX_LEN_20M2S 0x1034 |
| | | #define MT_AMPDU_MAX_LEN_40M1S 0x1038 |
| | | #define MT_AMPDU_MAX_LEN_40M2S 0x103c |
| | | #define MT_AMPDU_MAX_LEN 0x1040 |
| | | |
| | | #define MT_WCID_DROP_BASE 0x106c |
| | | #define MT_WCID_DROP(_n) (MT_WCID_DROP_BASE + ((_n) >> 5) * 4) |
| | | #define MT_WCID_DROP_MASK(_n) BIT((_n) % 32) |
| | | |
| | | #define MT_BCN_BYPASS_MASK 0x108c |
| | | |
| | | #define MT_MAC_APC_BSSID_BASE 0x1090 |
| | | #define MT_MAC_APC_BSSID_L(_n) (MT_MAC_APC_BSSID_BASE + ((_n) * 8)) |
| | | #define MT_MAC_APC_BSSID_H(_n) (MT_MAC_APC_BSSID_BASE + ((_n) * 8 + 4)) |
| | | #define MT_MAC_APC_BSSID_H_ADDR GENMASK(15, 0) |
| | | #define MT_MAC_APC_BSSID0_H_EN BIT(16) |
| | | |
| | | #define MT_XIFS_TIME_CFG 0x1100 |
| | | #define MT_XIFS_TIME_CFG_CCK_SIFS GENMASK(7, 0) |
| | | #define MT_XIFS_TIME_CFG_OFDM_SIFS GENMASK(15, 8) |
| | | #define MT_XIFS_TIME_CFG_OFDM_XIFS GENMASK(19, 16) |
| | | #define MT_XIFS_TIME_CFG_EIFS GENMASK(28, 20) |
| | | #define MT_XIFS_TIME_CFG_BB_RXEND_EN BIT(29) |
| | | |
| | | #define MT_BKOFF_SLOT_CFG 0x1104 |
| | | #define MT_BKOFF_SLOT_CFG_SLOTTIME GENMASK(7, 0) |
| | | #define MT_BKOFF_SLOT_CFG_CC_DELAY GENMASK(11, 8) |
| | | |
| | | #define MT_BEACON_TIME_CFG 0x1114 |
| | | #define MT_BEACON_TIME_CFG_INTVAL GENMASK(15, 0) |
| | | #define MT_BEACON_TIME_CFG_TIMER_EN BIT(16) |
| | | #define MT_BEACON_TIME_CFG_SYNC_MODE GENMASK(18, 17) |
| | | #define MT_BEACON_TIME_CFG_TBTT_EN BIT(19) |
| | | #define MT_BEACON_TIME_CFG_BEACON_TX BIT(20) |
| | | #define MT_BEACON_TIME_CFG_TSF_COMP GENMASK(31, 24) |
| | | |
| | | #define MT_TBTT_SYNC_CFG 0x1118 |
| | | #define MT_TBTT_TIMER_CFG 0x1124 |
| | | |
| | | #define MT_INT_TIMER_CFG 0x1128 |
| | | #define MT_INT_TIMER_CFG_PRE_TBTT GENMASK(15, 0) |
| | | #define MT_INT_TIMER_CFG_GP_TIMER GENMASK(31, 16) |
| | | |
| | | #define MT_INT_TIMER_EN 0x112c |
| | | #define MT_INT_TIMER_EN_PRE_TBTT_EN BIT(0) |
| | | #define MT_INT_TIMER_EN_GP_TIMER_EN BIT(1) |
| | | |
| | | #define MT_MAC_STATUS 0x1200 |
| | | #define MT_MAC_STATUS_TX BIT(0) |
| | | #define MT_MAC_STATUS_RX BIT(1) |
| | | |
| | | #define MT_PWR_PIN_CFG 0x1204 |
| | | #define MT_AUX_CLK_CFG 0x120c |
| | | |
| | | #define MT_BB_PA_MODE_CFG0 0x1214 |
| | | #define MT_BB_PA_MODE_CFG1 0x1218 |
| | | #define MT_RF_PA_MODE_CFG0 0x121c |
| | | #define MT_RF_PA_MODE_CFG1 0x1220 |
| | | |
| | | #define MT_RF_PA_MODE_ADJ0 0x1228 |
| | | #define MT_RF_PA_MODE_ADJ1 0x122c |
| | | |
| | | #define MT_DACCLK_EN_DLY_CFG 0x1264 |
| | | |
| | | #define MT_EDCA_CFG_BASE 0x1300 |
| | | #define MT_EDCA_CFG_AC(_n) (MT_EDCA_CFG_BASE + ((_n) << 2)) |
| | | #define MT_EDCA_CFG_TXOP GENMASK(7, 0) |
| | | #define MT_EDCA_CFG_AIFSN GENMASK(11, 8) |
| | | #define MT_EDCA_CFG_CWMIN GENMASK(15, 12) |
| | | #define MT_EDCA_CFG_CWMAX GENMASK(19, 16) |
| | | |
| | | #define MT_TX_PWR_CFG_0 0x1314 |
| | | #define MT_TX_PWR_CFG_1 0x1318 |
| | | #define MT_TX_PWR_CFG_2 0x131c |
| | | #define MT_TX_PWR_CFG_3 0x1320 |
| | | #define MT_TX_PWR_CFG_4 0x1324 |
| | | |
| | | #define MT_TX_BAND_CFG 0x132c |
| | | #define MT_TX_BAND_CFG_UPPER_40M BIT(0) |
| | | #define MT_TX_BAND_CFG_5G BIT(1) |
| | | #define MT_TX_BAND_CFG_2G BIT(2) |
| | | |
| | | #define MT_HT_FBK_TO_LEGACY 0x1384 |
| | | #define MT_TX_MPDU_ADJ_INT 0x1388 |
| | | |
| | | #define MT_TX_PWR_CFG_7 0x13d4 |
| | | #define MT_TX_PWR_CFG_8 0x13d8 |
| | | #define MT_TX_PWR_CFG_9 0x13dc |
| | | |
| | | #define MT_TX_SW_CFG0 0x1330 |
| | | #define MT_TX_SW_CFG1 0x1334 |
| | | #define MT_TX_SW_CFG2 0x1338 |
| | | |
| | | #define MT_TXOP_CTRL_CFG 0x1340 |
| | | #define MT_TXOP_TRUN_EN GENMASK(5, 0) |
| | | #define MT_TXOP_EXT_CCA_DLY GENMASK(15, 8) |
| | | #define MT_TXOP_CTRL |
| | | |
| | | #define MT_TX_RTS_CFG 0x1344 |
| | | #define MT_TX_RTS_CFG_RETRY_LIMIT GENMASK(7, 0) |
| | | #define MT_TX_RTS_CFG_THRESH GENMASK(23, 8) |
| | | #define MT_TX_RTS_FALLBACK BIT(24) |
| | | |
| | | #define MT_TX_TIMEOUT_CFG 0x1348 |
| | | #define MT_TX_RETRY_CFG 0x134c |
| | | #define MT_TX_LINK_CFG 0x1350 |
| | | #define MT_HT_FBK_CFG0 0x1354 |
| | | #define MT_HT_FBK_CFG1 0x1358 |
| | | #define MT_LG_FBK_CFG0 0x135c |
| | | #define MT_LG_FBK_CFG1 0x1360 |
| | | |
| | | #define MT_CCK_PROT_CFG 0x1364 |
| | | #define MT_OFDM_PROT_CFG 0x1368 |
| | | #define MT_MM20_PROT_CFG 0x136c |
| | | #define MT_MM40_PROT_CFG 0x1370 |
| | | #define MT_GF20_PROT_CFG 0x1374 |
| | | #define MT_GF40_PROT_CFG 0x1378 |
| | | |
| | | #define MT_PROT_RATE GENMASK(15, 0) |
| | | #define MT_PROT_CTRL_RTS_CTS BIT(16) |
| | | #define MT_PROT_CTRL_CTS2SELF BIT(17) |
| | | #define MT_PROT_NAV_SHORT BIT(18) |
| | | #define MT_PROT_NAV_LONG BIT(19) |
| | | #define MT_PROT_TXOP_ALLOW_CCK BIT(20) |
| | | #define MT_PROT_TXOP_ALLOW_OFDM BIT(21) |
| | | #define MT_PROT_TXOP_ALLOW_MM20 BIT(22) |
| | | #define MT_PROT_TXOP_ALLOW_MM40 BIT(23) |
| | | #define MT_PROT_TXOP_ALLOW_GF20 BIT(24) |
| | | #define MT_PROT_TXOP_ALLOW_GF40 BIT(25) |
| | | #define MT_PROT_RTS_THR_EN BIT(26) |
| | | #define MT_PROT_RATE_CCK_11 0x0003 |
| | | #define MT_PROT_RATE_OFDM_6 0x4000 |
| | | #define MT_PROT_RATE_OFDM_24 0x4004 |
| | | #define MT_PROT_RATE_DUP_OFDM_24 0x4084 |
| | | #define MT_PROT_TXOP_ALLOW_ALL GENMASK(25, 20) |
| | | #define MT_PROT_TXOP_ALLOW_BW20 (MT_PROT_TXOP_ALLOW_ALL & \ |
| | | ~MT_PROT_TXOP_ALLOW_MM40 & \ |
| | | ~MT_PROT_TXOP_ALLOW_GF40) |
| | | |
| | | #define MT_EXP_ACK_TIME 0x1380 |
| | | |
| | | #define MT_TX_PWR_CFG_0_EXT 0x1390 |
| | | #define MT_TX_PWR_CFG_1_EXT 0x1394 |
| | | |
| | | #define MT_TX_FBK_LIMIT 0x1398 |
| | | #define MT_TX_FBK_LIMIT_MPDU_FBK GENMASK(7, 0) |
| | | #define MT_TX_FBK_LIMIT_AMPDU_FBK GENMASK(15, 8) |
| | | #define MT_TX_FBK_LIMIT_MPDU_UP_CLEAR BIT(16) |
| | | #define MT_TX_FBK_LIMIT_AMPDU_UP_CLEAR BIT(17) |
| | | #define MT_TX_FBK_LIMIT_RATE_LUT BIT(18) |
| | | |
| | | #define MT_TX0_RF_GAIN_CORR 0x13a0 |
| | | #define MT_TX1_RF_GAIN_CORR 0x13a4 |
| | | #define MT_TX0_RF_GAIN_ATTEN 0x13a8 |
| | | |
| | | #define MT_TX_ALC_CFG_0 0x13b0 |
| | | #define MT_TX_ALC_CFG_0_CH_INIT_0 GENMASK(5, 0) |
| | | #define MT_TX_ALC_CFG_0_CH_INIT_1 GENMASK(13, 8) |
| | | #define MT_TX_ALC_CFG_0_LIMIT_0 GENMASK(21, 16) |
| | | #define MT_TX_ALC_CFG_0_LIMIT_1 GENMASK(29, 24) |
| | | |
| | | #define MT_TX_ALC_CFG_1 0x13b4 |
| | | #define MT_TX_ALC_CFG_1_TEMP_COMP GENMASK(5, 0) |
| | | |
| | | #define MT_TX_ALC_CFG_2 0x13a8 |
| | | #define MT_TX_ALC_CFG_2_TEMP_COMP GENMASK(5, 0) |
| | | |
| | | #define MT_TX0_BB_GAIN_ATTEN 0x13c0 |
| | | |
| | | #define MT_TX_ALC_VGA3 0x13c8 |
| | | |
| | | #define MT_TX_PROT_CFG6 0x13e0 |
| | | #define MT_TX_PROT_CFG7 0x13e4 |
| | | #define MT_TX_PROT_CFG8 0x13e8 |
| | | |
| | | #define MT_PIFS_TX_CFG 0x13ec |
| | | |
| | | #define MT_RX_FILTR_CFG 0x1400 |
| | | |
| | | #define MT_RX_FILTR_CFG_CRC_ERR BIT(0) |
| | | #define MT_RX_FILTR_CFG_PHY_ERR BIT(1) |
| | | #define MT_RX_FILTR_CFG_PROMISC BIT(2) |
| | | #define MT_RX_FILTR_CFG_OTHER_BSS BIT(3) |
| | | #define MT_RX_FILTR_CFG_VER_ERR BIT(4) |
| | | #define MT_RX_FILTR_CFG_MCAST BIT(5) |
| | | #define MT_RX_FILTR_CFG_BCAST BIT(6) |
| | | #define MT_RX_FILTR_CFG_DUP BIT(7) |
| | | #define MT_RX_FILTR_CFG_CFACK BIT(8) |
| | | #define MT_RX_FILTR_CFG_CFEND BIT(9) |
| | | #define MT_RX_FILTR_CFG_ACK BIT(10) |
| | | #define MT_RX_FILTR_CFG_CTS BIT(11) |
| | | #define MT_RX_FILTR_CFG_RTS BIT(12) |
| | | #define MT_RX_FILTR_CFG_PSPOLL BIT(13) |
| | | #define MT_RX_FILTR_CFG_BA BIT(14) |
| | | #define MT_RX_FILTR_CFG_BAR BIT(15) |
| | | #define MT_RX_FILTR_CFG_CTRL_RSV BIT(16) |
| | | |
| | | #define MT_AUTO_RSP_CFG 0x1404 |
| | | |
| | | #define MT_AUTO_RSP_PREAMB_SHORT BIT(4) |
| | | |
| | | #define MT_LEGACY_BASIC_RATE 0x1408 |
| | | #define MT_HT_BASIC_RATE 0x140c |
| | | |
| | | #define MT_RX_PARSER_CFG 0x1418 |
| | | #define MT_RX_PARSER_RX_SET_NAV_ALL BIT(0) |
| | | |
| | | #define MT_EXT_CCA_CFG 0x141c |
| | | #define MT_EXT_CCA_CFG_CCA0 GENMASK(1, 0) |
| | | #define MT_EXT_CCA_CFG_CCA1 GENMASK(3, 2) |
| | | #define MT_EXT_CCA_CFG_CCA2 GENMASK(5, 4) |
| | | #define MT_EXT_CCA_CFG_CCA3 GENMASK(7, 6) |
| | | #define MT_EXT_CCA_CFG_CCA_MASK GENMASK(11, 8) |
| | | #define MT_EXT_CCA_CFG_ED_CCA_MASK GENMASK(15, 12) |
| | | |
| | | #define MT_TX_SW_CFG3 0x1478 |
| | | |
| | | #define MT_PN_PAD_MODE 0x150c |
| | | |
| | | #define MT_TXOP_HLDR_ET 0x1608 |
| | | |
| | | #define MT_PROT_AUTO_TX_CFG 0x1648 |
| | | |
| | | #define MT_RX_STA_CNT0 0x1700 |
| | | #define MT_RX_STA_CNT1 0x1704 |
| | | #define MT_RX_STA_CNT2 0x1708 |
| | | #define MT_TX_STA_CNT0 0x170c |
| | | #define MT_TX_STA_CNT1 0x1710 |
| | | #define MT_TX_STA_CNT2 0x1714 |
| | | |
| | | /* Vendor driver defines content of the second word of STAT_FIFO as follows: |
| | | * MT_TX_STAT_FIFO_RATE GENMASK(26, 16) |
| | | * MT_TX_STAT_FIFO_ETXBF BIT(27) |
| | | * MT_TX_STAT_FIFO_SND BIT(28) |
| | | * MT_TX_STAT_FIFO_ITXBF BIT(29) |
| | | * However, tests show that b16-31 have the same layout as TXWI rate_ctl |
| | | * with rate set to rate at which frame was acked. |
| | | */ |
| | | #define MT_TX_STAT_FIFO 0x1718 |
| | | #define MT_TX_STAT_FIFO_VALID BIT(0) |
| | | #define MT_TX_STAT_FIFO_PID_TYPE GENMASK(4, 1) |
| | | #define MT_TX_STAT_FIFO_SUCCESS BIT(5) |
| | | #define MT_TX_STAT_FIFO_AGGR BIT(6) |
| | | #define MT_TX_STAT_FIFO_ACKREQ BIT(7) |
| | | #define MT_TX_STAT_FIFO_WCID GENMASK(15, 8) |
| | | #define MT_TX_STAT_FIFO_RATE GENMASK(31, 16) |
| | | |
| | | #define MT_TX_AGG_STAT 0x171c |
| | | |
| | | #define MT_TX_AGG_CNT_BASE0 0x1720 |
| | | |
| | | #define MT_MPDU_DENSITY_CNT 0x1740 |
| | | |
| | | #define MT_TX_AGG_CNT_BASE1 0x174c |
| | | |
| | | #define MT_TX_AGG_CNT(_id) ((_id) < 8 ? \ |
| | | MT_TX_AGG_CNT_BASE0 + ((_id) << 2) : \ |
| | | MT_TX_AGG_CNT_BASE1 + ((_id - 8) << 2)) |
| | | |
| | | #define MT_TX_STAT_FIFO_EXT 0x1798 |
| | | #define MT_TX_STAT_FIFO_EXT_RETRY GENMASK(7, 0) |
| | | |
| | | #define MT_BBP_CORE_BASE 0x2000 |
| | | #define MT_BBP_IBI_BASE 0x2100 |
| | | #define MT_BBP_AGC_BASE 0x2300 |
| | | #define MT_BBP_TXC_BASE 0x2400 |
| | | #define MT_BBP_RXC_BASE 0x2500 |
| | | #define MT_BBP_TXO_BASE 0x2600 |
| | | #define MT_BBP_TXBE_BASE 0x2700 |
| | | #define MT_BBP_RXFE_BASE 0x2800 |
| | | #define MT_BBP_RXO_BASE 0x2900 |
| | | #define MT_BBP_DFS_BASE 0x2a00 |
| | | #define MT_BBP_TR_BASE 0x2b00 |
| | | #define MT_BBP_CAL_BASE 0x2c00 |
| | | #define MT_BBP_DSC_BASE 0x2e00 |
| | | #define MT_BBP_PFMU_BASE 0x2f00 |
| | | |
| | | #define MT_BBP(_type, _n) (MT_BBP_##_type##_BASE + ((_n) << 2)) |
| | | |
| | | #define MT_BBP_CORE_R1_BW GENMASK(4, 3) |
| | | |
| | | #define MT_BBP_AGC_R0_CTRL_CHAN GENMASK(9, 8) |
| | | #define MT_BBP_AGC_R0_BW GENMASK(14, 12) |
| | | |
| | | /* AGC, R4/R5 */ |
| | | #define MT_BBP_AGC_LNA_GAIN GENMASK(21, 16) |
| | | |
| | | /* AGC, R8/R9 */ |
| | | #define MT_BBP_AGC_GAIN GENMASK(14, 8) |
| | | |
| | | #define MT_BBP_AGC20_RSSI0 GENMASK(7, 0) |
| | | #define MT_BBP_AGC20_RSSI1 GENMASK(15, 8) |
| | | |
| | | #define MT_BBP_TXBE_R0_CTRL_CHAN GENMASK(1, 0) |
| | | |
| | | #define MT_WCID_ADDR_BASE 0x1800 |
| | | #define MT_WCID_ADDR(_n) (MT_WCID_ADDR_BASE + (_n) * 8) |
| | | |
| | | #define MT_SRAM_BASE 0x4000 |
| | | |
| | | #define MT_WCID_KEY_BASE 0x8000 |
| | | #define MT_WCID_KEY(_n) (MT_WCID_KEY_BASE + (_n) * 32) |
| | | |
| | | #define MT_WCID_IV_BASE 0xa000 |
| | | #define MT_WCID_IV(_n) (MT_WCID_IV_BASE + (_n) * 8) |
| | | |
| | | #define MT_WCID_ATTR_BASE 0xa800 |
| | | #define MT_WCID_ATTR(_n) (MT_WCID_ATTR_BASE + (_n) * 4) |
| | | |
| | | #define MT_WCID_ATTR_PAIRWISE BIT(0) |
| | | #define MT_WCID_ATTR_PKEY_MODE GENMASK(3, 1) |
| | | #define MT_WCID_ATTR_BSS_IDX GENMASK(6, 4) |
| | | #define MT_WCID_ATTR_RXWI_UDF GENMASK(9, 7) |
| | | #define MT_WCID_ATTR_PKEY_MODE_EXT BIT(10) |
| | | #define MT_WCID_ATTR_BSS_IDX_EXT BIT(11) |
| | | #define MT_WCID_ATTR_WAPI_MCBC BIT(15) |
| | | #define MT_WCID_ATTR_WAPI_KEYID GENMASK(31, 24) |
| | | |
| | | #define MT_SKEY_BASE_0 0xac00 |
| | | #define MT_SKEY_BASE_1 0xb400 |
| | | #define MT_SKEY_0(_bss, _idx) \ |
| | | (MT_SKEY_BASE_0 + (4 * (_bss) + _idx) * 32) |
| | | #define MT_SKEY_1(_bss, _idx) \ |
| | | (MT_SKEY_BASE_1 + (4 * ((_bss) & 7) + _idx) * 32) |
| | | #define MT_SKEY(_bss, _idx) \ |
| | | ((_bss & 8) ? MT_SKEY_1(_bss, _idx) : MT_SKEY_0(_bss, _idx)) |
| | | |
| | | #define MT_SKEY_MODE_BASE_0 0xb000 |
| | | #define MT_SKEY_MODE_BASE_1 0xb3f0 |
| | | #define MT_SKEY_MODE_0(_bss) \ |
| | | (MT_SKEY_MODE_BASE_0 + ((_bss / 2) << 2)) |
| | | #define MT_SKEY_MODE_1(_bss) \ |
| | | (MT_SKEY_MODE_BASE_1 + ((((_bss) & 7) / 2) << 2)) |
| | | #define MT_SKEY_MODE(_bss) \ |
| | | ((_bss & 8) ? MT_SKEY_MODE_1(_bss) : MT_SKEY_MODE_0(_bss)) |
| | | #define MT_SKEY_MODE_MASK GENMASK(3, 0) |
| | | #define MT_SKEY_MODE_SHIFT(_bss, _idx) (4 * ((_idx) + 4 * (_bss & 1))) |
| | | |
| | | #define MT_BEACON_BASE 0xc000 |
| | | |
| | | #define MT_TEMP_SENSOR 0x1d000 |
| | | #define MT_TEMP_SENSOR_VAL GENMASK(6, 0) |
| | | |
| | | enum mt76_cipher_type { |
| | | MT_CIPHER_NONE, |
| | | MT_CIPHER_WEP40, |
| | | MT_CIPHER_WEP104, |
| | | MT_CIPHER_TKIP, |
| | | MT_CIPHER_AES_CCMP, |
| | | MT_CIPHER_CKIP40, |
| | | MT_CIPHER_CKIP104, |
| | | MT_CIPHER_CKIP128, |
| | | MT_CIPHER_WAPI, |
| | | }; |
| | | |
| | | #endif |
New file |
| | |
| | | /* |
| | | * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> |
| | | * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> |
| | | * |
| | | * This program is free software; you can redistribute it and/or modify |
| | | * it under the terms of the GNU General Public License version 2 |
| | | * as published by the Free Software Foundation |
| | | * |
| | | * This program is distributed in the hope that it will be useful, |
| | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| | | * GNU General Public License for more details. |
| | | */ |
| | | |
| | | #include <linux/module.h> |
| | | |
| | | #ifndef __CHECKER__ |
| | | #define CREATE_TRACE_POINTS |
| | | #include "trace.h" |
| | | |
| | | #endif |
New file |
| | |
| | | /* |
| | | * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> |
| | | * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> |
| | | * |
| | | * This program is free software; you can redistribute it and/or modify |
| | | * it under the terms of the GNU General Public License version 2 |
| | | * as published by the Free Software Foundation |
| | | * |
| | | * This program is distributed in the hope that it will be useful, |
| | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| | | * GNU General Public License for more details. |
| | | */ |
| | | |
| | | #if !defined(__MT7601U_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) |
| | | #define __MT7601U_TRACE_H |
| | | |
| | | #include <linux/tracepoint.h> |
| | | #include "mt7601u.h" |
| | | #include "mac.h" |
| | | |
| | | #undef TRACE_SYSTEM |
| | | #define TRACE_SYSTEM mt7601u |
| | | |
| | | #define MAXNAME 32 |
| | | #define DEV_ENTRY __array(char, wiphy_name, 32) |
| | | #define DEV_ASSIGN strlcpy(__entry->wiphy_name, \ |
| | | wiphy_name(dev->hw->wiphy), MAXNAME) |
| | | #define DEV_PR_FMT "%s " |
| | | #define DEV_PR_ARG __entry->wiphy_name |
| | | |
| | | #define REG_ENTRY __field(u32, reg) __field(u32, val) |
| | | #define REG_ASSIGN __entry->reg = reg; __entry->val = val |
| | | #define REG_PR_FMT "%04x=%08x" |
| | | #define REG_PR_ARG __entry->reg, __entry->val |
| | | |
| | | DECLARE_EVENT_CLASS(dev_reg_evt, |
| | | TP_PROTO(struct mt7601u_dev *dev, u32 reg, u32 val), |
| | | TP_ARGS(dev, reg, val), |
| | | TP_STRUCT__entry( |
| | | DEV_ENTRY |
| | | REG_ENTRY |
| | | ), |
| | | TP_fast_assign( |
| | | DEV_ASSIGN; |
| | | REG_ASSIGN; |
| | | ), |
| | | TP_printk( |
| | | DEV_PR_FMT REG_PR_FMT, |
| | | DEV_PR_ARG, REG_PR_ARG |
| | | ) |
| | | ); |
| | | |
| | | DEFINE_EVENT(dev_reg_evt, reg_read, |
| | | TP_PROTO(struct mt7601u_dev *dev, u32 reg, u32 val), |
| | | TP_ARGS(dev, reg, val) |
| | | ); |
| | | |
| | | DEFINE_EVENT(dev_reg_evt, reg_write, |
| | | TP_PROTO(struct mt7601u_dev *dev, u32 reg, u32 val), |
| | | TP_ARGS(dev, reg, val) |
| | | ); |
| | | |
| | | TRACE_EVENT(mt_submit_urb, |
| | | TP_PROTO(struct mt7601u_dev *dev, struct urb *u), |
| | | TP_ARGS(dev, u), |
| | | TP_STRUCT__entry( |
| | | DEV_ENTRY __field(unsigned, pipe) __field(u32, len) |
| | | ), |
| | | TP_fast_assign( |
| | | DEV_ASSIGN; |
| | | __entry->pipe = u->pipe; |
| | | __entry->len = u->transfer_buffer_length; |
| | | ), |
| | | TP_printk(DEV_PR_FMT "p:%08x len:%u", |
| | | DEV_PR_ARG, __entry->pipe, __entry->len) |
| | | ); |
| | | |
| | | #define trace_mt_submit_urb_sync(__dev, __pipe, __len) ({ \ |
| | | struct urb u; \ |
| | | u.pipe = __pipe; \ |
| | | u.transfer_buffer_length = __len; \ |
| | | trace_mt_submit_urb(__dev, &u); \ |
| | | }) |
| | | |
| | | TRACE_EVENT(mt_mcu_msg_send, |
| | | TP_PROTO(struct mt7601u_dev *dev, |
| | | struct sk_buff *skb, u32 csum, bool resp), |
| | | TP_ARGS(dev, skb, csum, resp), |
| | | TP_STRUCT__entry( |
| | | DEV_ENTRY |
| | | __field(u32, info) |
| | | __field(u32, csum) |
| | | __field(bool, resp) |
| | | ), |
| | | TP_fast_assign( |
| | | DEV_ASSIGN; |
| | | __entry->info = *(u32 *)skb->data; |
| | | __entry->csum = csum; |
| | | __entry->resp = resp; |
| | | ), |
| | | TP_printk(DEV_PR_FMT "i:%08x c:%08x r:%d", |
| | | DEV_PR_ARG, __entry->info, __entry->csum, __entry->resp) |
| | | ); |
| | | |
| | | TRACE_EVENT(mt_vend_req, |
| | | TP_PROTO(struct mt7601u_dev *dev, unsigned pipe, u8 req, u8 req_type, |
| | | u16 val, u16 offset, void *buf, size_t buflen, int ret), |
| | | TP_ARGS(dev, pipe, req, req_type, val, offset, buf, buflen, ret), |
| | | TP_STRUCT__entry( |
| | | DEV_ENTRY |
| | | __field(unsigned, pipe) __field(u8, req) __field(u8, req_type) |
| | | __field(u16, val) __field(u16, offset) __field(void*, buf) |
| | | __field(int, buflen) __field(int, ret) |
| | | ), |
| | | TP_fast_assign( |
| | | DEV_ASSIGN; |
| | | __entry->pipe = pipe; |
| | | __entry->req = req; |
| | | __entry->req_type = req_type; |
| | | __entry->val = val; |
| | | __entry->offset = offset; |
| | | __entry->buf = buf; |
| | | __entry->buflen = buflen; |
| | | __entry->ret = ret; |
| | | ), |
| | | TP_printk(DEV_PR_FMT |
| | | "%d p:%08x req:%02hhx %02hhx val:%04hx %04hx buf:%d %d", |
| | | DEV_PR_ARG, __entry->ret, __entry->pipe, __entry->req, |
| | | __entry->req_type, __entry->val, __entry->offset, |
| | | !!__entry->buf, __entry->buflen) |
| | | ); |
| | | |
| | | TRACE_EVENT(ee_read, |
| | | TP_PROTO(struct mt7601u_dev *dev, int offset, u16 val), |
| | | TP_ARGS(dev, offset, val), |
| | | TP_STRUCT__entry( |
| | | DEV_ENTRY |
| | | __field(int, o) __field(u16, v) |
| | | ), |
| | | TP_fast_assign( |
| | | DEV_ASSIGN; |
| | | __entry->o = offset; |
| | | __entry->v = val; |
| | | ), |
| | | TP_printk(DEV_PR_FMT "%04x=%04x", DEV_PR_ARG, __entry->o, __entry->v) |
| | | ); |
| | | |
| | | DECLARE_EVENT_CLASS(dev_rf_reg_evt, |
| | | TP_PROTO(struct mt7601u_dev *dev, u8 bank, u8 reg, u8 val), |
| | | TP_ARGS(dev, bank, reg, val), |
| | | TP_STRUCT__entry( |
| | | DEV_ENTRY |
| | | __field(u8, bank) |
| | | __field(u8, reg) |
| | | __field(u8, val) |
| | | ), |
| | | TP_fast_assign( |
| | | DEV_ASSIGN; |
| | | REG_ASSIGN; |
| | | __entry->bank = bank; |
| | | ), |
| | | TP_printk( |
| | | DEV_PR_FMT "%02hhx:%02hhx=%02hhx", |
| | | DEV_PR_ARG, __entry->bank, __entry->reg, __entry->val |
| | | ) |
| | | ); |
| | | |
| | | DEFINE_EVENT(dev_rf_reg_evt, rf_read, |
| | | TP_PROTO(struct mt7601u_dev *dev, u8 bank, u8 reg, u8 val), |
| | | TP_ARGS(dev, bank, reg, val) |
| | | ); |
| | | |
| | | DEFINE_EVENT(dev_rf_reg_evt, rf_write, |
| | | TP_PROTO(struct mt7601u_dev *dev, u8 bank, u8 reg, u8 val), |
| | | TP_ARGS(dev, bank, reg, val) |
| | | ); |
| | | |
| | | DECLARE_EVENT_CLASS(dev_bbp_reg_evt, |
| | | TP_PROTO(struct mt7601u_dev *dev, u8 reg, u8 val), |
| | | TP_ARGS(dev, reg, val), |
| | | TP_STRUCT__entry( |
| | | DEV_ENTRY |
| | | __field(u8, reg) |
| | | __field(u8, val) |
| | | ), |
| | | TP_fast_assign( |
| | | DEV_ASSIGN; |
| | | REG_ASSIGN; |
| | | ), |
| | | TP_printk( |
| | | DEV_PR_FMT "%02hhx=%02hhx", |
| | | DEV_PR_ARG, __entry->reg, __entry->val |
| | | ) |
| | | ); |
| | | |
| | | DEFINE_EVENT(dev_bbp_reg_evt, bbp_read, |
| | | TP_PROTO(struct mt7601u_dev *dev, u8 reg, u8 val), |
| | | TP_ARGS(dev, reg, val) |
| | | ); |
| | | |
| | | DEFINE_EVENT(dev_bbp_reg_evt, bbp_write, |
| | | TP_PROTO(struct mt7601u_dev *dev, u8 reg, u8 val), |
| | | TP_ARGS(dev, reg, val) |
| | | ); |
| | | |
| | | DECLARE_EVENT_CLASS(dev_simple_evt, |
| | | TP_PROTO(struct mt7601u_dev *dev, u8 val), |
| | | TP_ARGS(dev, val), |
| | | TP_STRUCT__entry( |
| | | DEV_ENTRY |
| | | __field(u8, val) |
| | | ), |
| | | TP_fast_assign( |
| | | DEV_ASSIGN; |
| | | __entry->val = val; |
| | | ), |
| | | TP_printk( |
| | | DEV_PR_FMT "%02hhx", DEV_PR_ARG, __entry->val |
| | | ) |
| | | ); |
| | | |
| | | DEFINE_EVENT(dev_simple_evt, temp_mode, |
| | | TP_PROTO(struct mt7601u_dev *dev, u8 val), |
| | | TP_ARGS(dev, val) |
| | | ); |
| | | |
| | | DEFINE_EVENT(dev_simple_evt, read_temp, |
| | | TP_PROTO(struct mt7601u_dev *dev, u8 val), |
| | | TP_ARGS(dev, val) |
| | | ); |
| | | |
| | | DEFINE_EVENT(dev_simple_evt, freq_cal_adjust, |
| | | TP_PROTO(struct mt7601u_dev *dev, u8 val), |
| | | TP_ARGS(dev, val) |
| | | ); |
| | | |
| | | TRACE_EVENT(freq_cal_offset, |
| | | TP_PROTO(struct mt7601u_dev *dev, u8 phy_mode, s8 freq_off), |
| | | TP_ARGS(dev, phy_mode, freq_off), |
| | | TP_STRUCT__entry( |
| | | DEV_ENTRY |
| | | __field(u8, phy_mode) |
| | | __field(s8, freq_off) |
| | | ), |
| | | TP_fast_assign( |
| | | DEV_ASSIGN; |
| | | __entry->phy_mode = phy_mode; |
| | | __entry->freq_off = freq_off; |
| | | ), |
| | | TP_printk(DEV_PR_FMT "phy:%02hhx off:%02hhx", |
| | | DEV_PR_ARG, __entry->phy_mode, __entry->freq_off) |
| | | ); |
| | | |
| | | TRACE_EVENT(mt_rx, |
| | | TP_PROTO(struct mt7601u_dev *dev, struct mt7601u_rxwi *rxwi, u32 f), |
| | | TP_ARGS(dev, rxwi, f), |
| | | TP_STRUCT__entry( |
| | | DEV_ENTRY |
| | | __field_struct(struct mt7601u_rxwi, rxwi) |
| | | __field(u32, fce_info) |
| | | ), |
| | | TP_fast_assign( |
| | | DEV_ASSIGN; |
| | | __entry->rxwi = *rxwi; |
| | | __entry->fce_info = f; |
| | | ), |
| | | TP_printk(DEV_PR_FMT "rxi:%08x ctl:%08x frag_sn:%04hx rate:%04hx " |
| | | "uknw:%02hhx z:%02hhx%02hhx%02hhx snr:%02hhx " |
| | | "ant:%02hhx gain:%02hhx freq_o:%02hhx " |
| | | "r:%08x ea:%08x fce:%08x", DEV_PR_ARG, |
| | | le32_to_cpu(__entry->rxwi.rxinfo), |
| | | le32_to_cpu(__entry->rxwi.ctl), |
| | | le16_to_cpu(__entry->rxwi.frag_sn), |
| | | le16_to_cpu(__entry->rxwi.rate), |
| | | __entry->rxwi.unknown, |
| | | __entry->rxwi.zero[0], __entry->rxwi.zero[1], |
| | | __entry->rxwi.zero[2], |
| | | __entry->rxwi.snr, __entry->rxwi.ant, |
| | | __entry->rxwi.gain, __entry->rxwi.freq_off, |
| | | __entry->rxwi.resv2, __entry->rxwi.expert_ant, |
| | | __entry->fce_info) |
| | | ); |
| | | |
| | | TRACE_EVENT(mt_tx, |
| | | TP_PROTO(struct mt7601u_dev *dev, struct sk_buff *skb, |
| | | struct mt76_sta *sta, struct mt76_txwi *h), |
| | | TP_ARGS(dev, skb, sta, h), |
| | | TP_STRUCT__entry( |
| | | DEV_ENTRY |
| | | __field_struct(struct mt76_txwi, h) |
| | | __field(struct sk_buff *, skb) |
| | | __field(struct mt76_sta *, sta) |
| | | ), |
| | | TP_fast_assign( |
| | | DEV_ASSIGN; |
| | | __entry->h = *h; |
| | | __entry->skb = skb; |
| | | __entry->sta = sta; |
| | | ), |
| | | TP_printk(DEV_PR_FMT "skb:%p sta:%p flg:%04hx rate_ctl:%04hx " |
| | | "ack:%02hhx wcid:%02hhx len_ctl:%05hx", DEV_PR_ARG, |
| | | __entry->skb, __entry->sta, |
| | | le16_to_cpu(__entry->h.flags), |
| | | le16_to_cpu(__entry->h.rate_ctl), |
| | | __entry->h.ack_ctl, __entry->h.wcid, |
| | | le16_to_cpu(__entry->h.len_ctl)) |
| | | ); |
| | | |
| | | TRACE_EVENT(mt_tx_dma_done, |
| | | TP_PROTO(struct mt7601u_dev *dev, struct sk_buff *skb), |
| | | TP_ARGS(dev, skb), |
| | | TP_STRUCT__entry( |
| | | DEV_ENTRY |
| | | __field(struct sk_buff *, skb) |
| | | ), |
| | | TP_fast_assign( |
| | | DEV_ASSIGN; |
| | | __entry->skb = skb; |
| | | ), |
| | | TP_printk(DEV_PR_FMT "%p", DEV_PR_ARG, __entry->skb) |
| | | ); |
| | | |
| | | TRACE_EVENT(mt_tx_status_cleaned, |
| | | TP_PROTO(struct mt7601u_dev *dev, int cleaned), |
| | | TP_ARGS(dev, cleaned), |
| | | TP_STRUCT__entry( |
| | | DEV_ENTRY |
| | | __field(int, cleaned) |
| | | ), |
| | | TP_fast_assign( |
| | | DEV_ASSIGN; |
| | | __entry->cleaned = cleaned; |
| | | ), |
| | | TP_printk(DEV_PR_FMT "%d", DEV_PR_ARG, __entry->cleaned) |
| | | ); |
| | | |
| | | TRACE_EVENT(mt_tx_status, |
| | | TP_PROTO(struct mt7601u_dev *dev, u32 stat1, u32 stat2), |
| | | TP_ARGS(dev, stat1, stat2), |
| | | TP_STRUCT__entry( |
| | | DEV_ENTRY |
| | | __field(u32, stat1) __field(u32, stat2) |
| | | ), |
| | | TP_fast_assign( |
| | | DEV_ASSIGN; |
| | | __entry->stat1 = stat1; |
| | | __entry->stat2 = stat2; |
| | | ), |
| | | TP_printk(DEV_PR_FMT "%08x %08x", |
| | | DEV_PR_ARG, __entry->stat1, __entry->stat2) |
| | | ); |
| | | |
| | | TRACE_EVENT(mt_rx_dma_aggr, |
| | | TP_PROTO(struct mt7601u_dev *dev, int cnt, bool paged), |
| | | TP_ARGS(dev, cnt, paged), |
| | | TP_STRUCT__entry( |
| | | DEV_ENTRY |
| | | __field(u8, cnt) |
| | | __field(bool, paged) |
| | | ), |
| | | TP_fast_assign( |
| | | DEV_ASSIGN; |
| | | __entry->cnt = cnt; |
| | | __entry->paged = paged; |
| | | ), |
| | | TP_printk(DEV_PR_FMT "cnt:%d paged:%d", |
| | | DEV_PR_ARG, __entry->cnt, __entry->paged) |
| | | ); |
| | | |
| | | DEFINE_EVENT(dev_simple_evt, set_key, |
| | | TP_PROTO(struct mt7601u_dev *dev, u8 val), |
| | | TP_ARGS(dev, val) |
| | | ); |
| | | |
| | | TRACE_EVENT(set_shared_key, |
| | | TP_PROTO(struct mt7601u_dev *dev, u8 vid, u8 key), |
| | | TP_ARGS(dev, vid, key), |
| | | TP_STRUCT__entry( |
| | | DEV_ENTRY |
| | | __field(u8, vid) |
| | | __field(u8, key) |
| | | ), |
| | | TP_fast_assign( |
| | | DEV_ASSIGN; |
| | | __entry->vid = vid; |
| | | __entry->key = key; |
| | | ), |
| | | TP_printk(DEV_PR_FMT "phy:%02hhx off:%02hhx", |
| | | DEV_PR_ARG, __entry->vid, __entry->key) |
| | | ); |
| | | |
| | | #endif |
| | | |
| | | #undef TRACE_INCLUDE_PATH |
| | | #define TRACE_INCLUDE_PATH . |
| | | #undef TRACE_INCLUDE_FILE |
| | | #define TRACE_INCLUDE_FILE trace |
| | | |
| | | #include <trace/define_trace.h> |
New file |
| | |
| | | /* |
| | | * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> |
| | | * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> |
| | | * |
| | | * This program is free software; you can redistribute it and/or modify |
| | | * it under the terms of the GNU General Public License version 2 |
| | | * as published by the Free Software Foundation |
| | | * |
| | | * This program is distributed in the hope that it will be useful, |
| | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| | | * GNU General Public License for more details. |
| | | */ |
| | | |
| | | #include "mt7601u.h" |
| | | #include "trace.h" |
| | | |
| | | enum mt76_txq_id { |
| | | MT_TXQ_VO = IEEE80211_AC_VO, |
| | | MT_TXQ_VI = IEEE80211_AC_VI, |
| | | MT_TXQ_BE = IEEE80211_AC_BE, |
| | | MT_TXQ_BK = IEEE80211_AC_BK, |
| | | MT_TXQ_PSD, |
| | | MT_TXQ_MCU, |
| | | __MT_TXQ_MAX |
| | | }; |
| | | |
| | | /* Hardware uses mirrored order of queues with Q0 having the highest priority */ |
| | | static u8 q2hwq(u8 q) |
| | | { |
| | | return q ^ 0x3; |
| | | } |
| | | |
| | | /* Take mac80211 Q id from the skb and translate it to hardware Q id */ |
| | | static u8 skb2q(struct sk_buff *skb) |
| | | { |
| | | int qid = skb_get_queue_mapping(skb); |
| | | |
| | | if (WARN_ON(qid >= MT_TXQ_PSD)) { |
| | | qid = MT_TXQ_BE; |
| | | skb_set_queue_mapping(skb, qid); |
| | | } |
| | | |
| | | return q2hwq(qid); |
| | | } |
| | | |
| | | /* Note: TX retry reporting is a bit broken. |
| | | * Retries are reported only once per AMPDU and often come a frame early |
| | | * i.e. they are reported in the last status preceding the AMPDU. Apart |
| | | * from the fact that it's hard to know the length of the AMPDU (which is |
| | | * required to know to how many consecutive frames retries should be |
| | | * applied), if status comes early on full FIFO it gets lost and retries |
| | | * of the whole AMPDU become invisible. |
| | | * As a work-around encode the desired rate in PKT_ID of TX descriptor |
| | | * and based on that guess the retries (every rate is tried once). |
| | | * Only downside here is that for MCS0 we have to rely solely on |
| | | * transmission failures as no retries can ever be reported. |
| | | * Not having to read EXT_FIFO has a nice effect of doubling the number |
| | | * of reports which can be fetched. |
| | | * Also the vendor driver never uses the EXT_FIFO register so it may be |
| | | * undertested. |
| | | */ |
| | | static u8 mt7601u_tx_pktid_enc(struct mt7601u_dev *dev, u8 rate, bool is_probe) |
| | | { |
| | | u8 encoded = (rate + 1) + is_probe * 8; |
| | | |
| | | /* Because PKT_ID 0 disables status reporting only 15 values are |
| | | * available but 16 are needed (8 MCS * 2 for encoding is_probe) |
| | | * - we need to cram together two rates. MCS0 and MCS7 with is_probe |
| | | * share PKT_ID 9. |
| | | */ |
| | | if (is_probe && rate == 7) |
| | | return encoded - 7; |
| | | |
| | | return encoded; |
| | | } |
| | | |
| | | static void |
| | | mt7601u_tx_pktid_dec(struct mt7601u_dev *dev, struct mt76_tx_status *stat) |
| | | { |
| | | u8 req_rate = stat->pktid; |
| | | u8 eff_rate = stat->rate & 0x7; |
| | | |
| | | req_rate -= 1; |
| | | |
| | | if (req_rate > 7) { |
| | | stat->is_probe = true; |
| | | req_rate -= 8; |
| | | |
| | | /* Decide between MCS0 and MCS7 which share pktid 9 */ |
| | | if (!req_rate && eff_rate) |
| | | req_rate = 7; |
| | | } |
| | | |
| | | stat->retry = req_rate - eff_rate; |
| | | } |
| | | |
| | | static void mt7601u_tx_skb_remove_dma_overhead(struct sk_buff *skb, |
| | | struct ieee80211_tx_info *info) |
| | | { |
| | | int pkt_len = (unsigned long)info->status.status_driver_data[0]; |
| | | |
| | | skb_pull(skb, sizeof(struct mt76_txwi) + 4); |
| | | if (ieee80211_get_hdrlen_from_skb(skb) % 4) |
| | | mt76_remove_hdr_pad(skb); |
| | | |
| | | skb_trim(skb, pkt_len); |
| | | } |
| | | |
| | | void mt7601u_tx_status(struct mt7601u_dev *dev, struct sk_buff *skb) |
| | | { |
| | | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
| | | |
| | | mt7601u_tx_skb_remove_dma_overhead(skb, info); |
| | | |
| | | ieee80211_tx_info_clear_status(info); |
| | | info->status.rates[0].idx = -1; |
| | | info->flags |= IEEE80211_TX_STAT_ACK; |
| | | |
| | | spin_lock(&dev->mac_lock); |
| | | ieee80211_tx_status(dev->hw, skb); |
| | | spin_unlock(&dev->mac_lock); |
| | | } |
| | | |
| | | static int mt7601u_skb_rooms(struct mt7601u_dev *dev, struct sk_buff *skb) |
| | | { |
| | | int hdr_len = ieee80211_get_hdrlen_from_skb(skb); |
| | | u32 need_head; |
| | | |
| | | need_head = sizeof(struct mt76_txwi) + 4; |
| | | if (hdr_len % 4) |
| | | need_head += 2; |
| | | |
| | | return skb_cow(skb, need_head); |
| | | } |
| | | |
| | | static struct mt76_txwi * |
| | | mt7601u_push_txwi(struct mt7601u_dev *dev, struct sk_buff *skb, |
| | | struct ieee80211_sta *sta, struct mt76_wcid *wcid, |
| | | int pkt_len) |
| | | { |
| | | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
| | | struct ieee80211_tx_rate *rate = &info->control.rates[0]; |
| | | struct mt76_txwi *txwi; |
| | | unsigned long flags; |
| | | bool is_probe; |
| | | u32 pkt_id; |
| | | u16 rate_ctl; |
| | | u8 nss; |
| | | |
| | | txwi = (struct mt76_txwi *)skb_push(skb, sizeof(struct mt76_txwi)); |
| | | memset(txwi, 0, sizeof(*txwi)); |
| | | |
| | | if (!wcid->tx_rate_set) |
| | | ieee80211_get_tx_rates(info->control.vif, sta, skb, |
| | | info->control.rates, 1); |
| | | |
| | | spin_lock_irqsave(&dev->lock, flags); |
| | | if (rate->idx < 0 || !rate->count) |
| | | rate_ctl = wcid->tx_rate; |
| | | else |
| | | rate_ctl = mt76_mac_tx_rate_val(dev, rate, &nss); |
| | | spin_unlock_irqrestore(&dev->lock, flags); |
| | | txwi->rate_ctl = cpu_to_le16(rate_ctl); |
| | | |
| | | if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) |
| | | txwi->ack_ctl |= MT_TXWI_ACK_CTL_REQ; |
| | | if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) |
| | | txwi->ack_ctl |= MT_TXWI_ACK_CTL_NSEQ; |
| | | |
| | | if ((info->flags & IEEE80211_TX_CTL_AMPDU) && sta) { |
| | | u8 ba_size = IEEE80211_MIN_AMPDU_BUF; |
| | | |
| | | ba_size <<= sta->ht_cap.ampdu_factor; |
| | | ba_size = min_t(int, 63, ba_size); |
| | | if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) |
| | | ba_size = 0; |
| | | txwi->ack_ctl |= MT76_SET(MT_TXWI_ACK_CTL_BA_WINDOW, ba_size); |
| | | |
| | | txwi->flags = cpu_to_le16(MT_TXWI_FLAGS_AMPDU | |
| | | MT76_SET(MT_TXWI_FLAGS_MPDU_DENSITY, |
| | | sta->ht_cap.ampdu_density)); |
| | | if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) |
| | | txwi->flags = 0; |
| | | } |
| | | |
| | | txwi->wcid = wcid->idx; |
| | | |
| | | is_probe = !!(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE); |
| | | pkt_id = mt7601u_tx_pktid_enc(dev, rate_ctl & 0x7, is_probe); |
| | | pkt_len |= MT76_SET(MT_TXWI_LEN_PKTID, pkt_id); |
| | | txwi->len_ctl = cpu_to_le16(pkt_len); |
| | | |
| | | return txwi; |
| | | } |
| | | |
| | | void mt7601u_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, |
| | | struct sk_buff *skb) |
| | | { |
| | | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
| | | struct mt7601u_dev *dev = hw->priv; |
| | | struct ieee80211_vif *vif = info->control.vif; |
| | | struct ieee80211_sta *sta = control->sta; |
| | | struct mt76_sta *msta = NULL; |
| | | struct mt76_wcid *wcid = dev->mon_wcid; |
| | | struct mt76_txwi *txwi; |
| | | int pkt_len = skb->len; |
| | | int hw_q = skb2q(skb); |
| | | |
| | | BUILD_BUG_ON(ARRAY_SIZE(info->status.status_driver_data) < 1); |
| | | info->status.status_driver_data[0] = (void *)(unsigned long)pkt_len; |
| | | |
| | | if (mt7601u_skb_rooms(dev, skb) || mt76_insert_hdr_pad(skb)) { |
| | | ieee80211_free_txskb(dev->hw, skb); |
| | | return; |
| | | } |
| | | |
| | | if (sta) { |
| | | msta = (struct mt76_sta *) sta->drv_priv; |
| | | wcid = &msta->wcid; |
| | | } else if (vif) { |
| | | struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; |
| | | |
| | | wcid = &mvif->group_wcid; |
| | | } |
| | | |
| | | txwi = mt7601u_push_txwi(dev, skb, sta, wcid, pkt_len); |
| | | |
| | | if (mt7601u_dma_enqueue_tx(dev, skb, wcid, hw_q)) |
| | | return; |
| | | |
| | | trace_mt_tx(dev, skb, msta, txwi); |
| | | } |
| | | |
| | | void mt7601u_tx_stat(struct work_struct *work) |
| | | { |
| | | struct mt7601u_dev *dev = container_of(work, struct mt7601u_dev, |
| | | stat_work.work); |
| | | struct mt76_tx_status stat; |
| | | unsigned long flags; |
| | | int cleaned = 0; |
| | | |
| | | while (!test_bit(MT7601U_STATE_REMOVED, &dev->state)) { |
| | | stat = mt7601u_mac_fetch_tx_status(dev); |
| | | if (!stat.valid) |
| | | break; |
| | | |
| | | mt7601u_tx_pktid_dec(dev, &stat); |
| | | mt76_send_tx_status(dev, &stat); |
| | | |
| | | cleaned++; |
| | | } |
| | | trace_mt_tx_status_cleaned(dev, cleaned); |
| | | |
| | | spin_lock_irqsave(&dev->tx_lock, flags); |
| | | if (cleaned) |
| | | queue_delayed_work(dev->stat_wq, &dev->stat_work, |
| | | msecs_to_jiffies(10)); |
| | | else if (test_and_clear_bit(MT7601U_STATE_MORE_STATS, &dev->state)) |
| | | queue_delayed_work(dev->stat_wq, &dev->stat_work, |
| | | msecs_to_jiffies(20)); |
| | | else |
| | | clear_bit(MT7601U_STATE_READING_STATS, &dev->state); |
| | | spin_unlock_irqrestore(&dev->tx_lock, flags); |
| | | } |
| | | |
| | | int mt7601u_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
| | | u16 queue, const struct ieee80211_tx_queue_params *params) |
| | | { |
| | | struct mt7601u_dev *dev = hw->priv; |
| | | u8 cw_min = 5, cw_max = 10, hw_q = q2hwq(queue); |
| | | u32 val; |
| | | |
| | | /* TODO: should we do funny things with the parameters? |
| | | * See what mt7601u_set_default_edca() used to do in init.c. |
| | | */ |
| | | |
| | | if (params->cw_min) |
| | | cw_min = fls(params->cw_min); |
| | | if (params->cw_max) |
| | | cw_max = fls(params->cw_max); |
| | | |
| | | WARN_ON(params->txop > 0xff); |
| | | WARN_ON(params->aifs > 0xf); |
| | | WARN_ON(cw_min > 0xf); |
| | | WARN_ON(cw_max > 0xf); |
| | | |
| | | val = MT76_SET(MT_EDCA_CFG_AIFSN, params->aifs) | |
| | | MT76_SET(MT_EDCA_CFG_CWMIN, cw_min) | |
| | | MT76_SET(MT_EDCA_CFG_CWMAX, cw_max); |
| | | /* TODO: based on user-controlled EnableTxBurst var vendor drv sets |
| | | * a really long txop on AC0 (see connect.c:2009) but only on |
| | | * connect? When not connected should be 0. |
| | | */ |
| | | if (!hw_q) |
| | | val |= 0x60; |
| | | else |
| | | val |= MT76_SET(MT_EDCA_CFG_TXOP, params->txop); |
| | | mt76_wr(dev, MT_EDCA_CFG_AC(hw_q), val); |
| | | |
| | | val = mt76_rr(dev, MT_WMM_TXOP(hw_q)); |
| | | val &= ~(MT_WMM_TXOP_MASK << MT_WMM_TXOP_SHIFT(hw_q)); |
| | | val |= params->txop << MT_WMM_TXOP_SHIFT(hw_q); |
| | | mt76_wr(dev, MT_WMM_TXOP(hw_q), val); |
| | | |
| | | val = mt76_rr(dev, MT_WMM_AIFSN); |
| | | val &= ~(MT_WMM_AIFSN_MASK << MT_WMM_AIFSN_SHIFT(hw_q)); |
| | | val |= params->aifs << MT_WMM_AIFSN_SHIFT(hw_q); |
| | | mt76_wr(dev, MT_WMM_AIFSN, val); |
| | | |
| | | val = mt76_rr(dev, MT_WMM_CWMIN); |
| | | val &= ~(MT_WMM_CWMIN_MASK << MT_WMM_CWMIN_SHIFT(hw_q)); |
| | | val |= cw_min << MT_WMM_CWMIN_SHIFT(hw_q); |
| | | mt76_wr(dev, MT_WMM_CWMIN, val); |
| | | |
| | | val = mt76_rr(dev, MT_WMM_CWMAX); |
| | | val &= ~(MT_WMM_CWMAX_MASK << MT_WMM_CWMAX_SHIFT(hw_q)); |
| | | val |= cw_max << MT_WMM_CWMAX_SHIFT(hw_q); |
| | | mt76_wr(dev, MT_WMM_CWMAX, val); |
| | | |
| | | return 0; |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> |
| | | * |
| | | * This program is free software; you can redistribute it and/or modify |
| | | * it under the terms of the GNU General Public License version 2 |
| | | * as published by the Free Software Foundation |
| | | * |
| | | * This program is distributed in the hope that it will be useful, |
| | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| | | * GNU General Public License for more details. |
| | | */ |
| | | |
| | | #include <linux/kernel.h> |
| | | #include <linux/module.h> |
| | | #include <linux/usb.h> |
| | | |
| | | #include "mt7601u.h" |
| | | #include "usb.h" |
| | | #include "trace.h" |
| | | |
| | | static struct usb_device_id mt7601u_device_table[] = { |
| | | { USB_DEVICE(0x0b05, 0x17d3) }, |
| | | { USB_DEVICE(0x0e8d, 0x760a) }, |
| | | { USB_DEVICE(0x0e8d, 0x760b) }, |
| | | { USB_DEVICE(0x13d3, 0x3431) }, |
| | | { USB_DEVICE(0x13d3, 0x3434) }, |
| | | { USB_DEVICE(0x148f, 0x7601) }, |
| | | { USB_DEVICE(0x148f, 0x760a) }, |
| | | { USB_DEVICE(0x148f, 0x760b) }, |
| | | { USB_DEVICE(0x148f, 0x760c) }, |
| | | { USB_DEVICE(0x148f, 0x760d) }, |
| | | { USB_DEVICE(0x2001, 0x3d04) }, |
| | | { USB_DEVICE(0x2717, 0x4106) }, |
| | | { USB_DEVICE(0x2955, 0x0001) }, |
| | | { USB_DEVICE(0x2955, 0x1001) }, |
| | | { USB_DEVICE(0x2a5f, 0x1000) }, |
| | | { USB_DEVICE(0x7392, 0x7710) }, |
| | | { 0, } |
| | | }; |
| | | |
| | | bool mt7601u_usb_alloc_buf(struct mt7601u_dev *dev, size_t len, |
| | | struct mt7601u_dma_buf *buf) |
| | | { |
| | | struct usb_device *usb_dev = mt7601u_to_usb_dev(dev); |
| | | |
| | | buf->len = len; |
| | | buf->urb = usb_alloc_urb(0, GFP_KERNEL); |
| | | buf->buf = usb_alloc_coherent(usb_dev, buf->len, GFP_KERNEL, &buf->dma); |
| | | |
| | | return !buf->urb || !buf->buf; |
| | | } |
| | | |
| | | void mt7601u_usb_free_buf(struct mt7601u_dev *dev, struct mt7601u_dma_buf *buf) |
| | | { |
| | | struct usb_device *usb_dev = mt7601u_to_usb_dev(dev); |
| | | |
| | | usb_free_coherent(usb_dev, buf->len, buf->buf, buf->dma); |
| | | usb_free_urb(buf->urb); |
| | | } |
| | | |
| | | int mt7601u_usb_submit_buf(struct mt7601u_dev *dev, int dir, int ep_idx, |
| | | struct mt7601u_dma_buf *buf, gfp_t gfp, |
| | | usb_complete_t complete_fn, void *context) |
| | | { |
| | | struct usb_device *usb_dev = mt7601u_to_usb_dev(dev); |
| | | unsigned pipe; |
| | | int ret; |
| | | |
| | | if (dir == USB_DIR_IN) |
| | | pipe = usb_rcvbulkpipe(usb_dev, dev->in_eps[ep_idx]); |
| | | else |
| | | pipe = usb_sndbulkpipe(usb_dev, dev->out_eps[ep_idx]); |
| | | |
| | | usb_fill_bulk_urb(buf->urb, usb_dev, pipe, buf->buf, buf->len, |
| | | complete_fn, context); |
| | | buf->urb->transfer_dma = buf->dma; |
| | | buf->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; |
| | | |
| | | trace_mt_submit_urb(dev, buf->urb); |
| | | ret = usb_submit_urb(buf->urb, gfp); |
| | | if (ret) |
| | | dev_err(dev->dev, "Error: submit URB dir:%d ep:%d failed:%d\n", |
| | | dir, ep_idx, ret); |
| | | return ret; |
| | | } |
| | | |
| | | void mt7601u_complete_urb(struct urb *urb) |
| | | { |
| | | struct completion *cmpl = urb->context; |
| | | |
| | | complete(cmpl); |
| | | } |
| | | |
| | | int mt7601u_vendor_request(struct mt7601u_dev *dev, const u8 req, |
| | | const u8 direction, const u16 val, const u16 offset, |
| | | void *buf, const size_t buflen) |
| | | { |
| | | int i, ret; |
| | | struct usb_device *usb_dev = mt7601u_to_usb_dev(dev); |
| | | const u8 req_type = direction | USB_TYPE_VENDOR | USB_RECIP_DEVICE; |
| | | const unsigned int pipe = (direction == USB_DIR_IN) ? |
| | | usb_rcvctrlpipe(usb_dev, 0) : usb_sndctrlpipe(usb_dev, 0); |
| | | |
| | | for (i = 0; i < MT_VEND_REQ_MAX_RETRY; i++) { |
| | | ret = usb_control_msg(usb_dev, pipe, req, req_type, |
| | | val, offset, buf, buflen, |
| | | MT_VEND_REQ_TOUT_MS); |
| | | trace_mt_vend_req(dev, pipe, req, req_type, val, offset, |
| | | buf, buflen, ret); |
| | | |
| | | if (ret == -ENODEV) |
| | | set_bit(MT7601U_STATE_REMOVED, &dev->state); |
| | | if (ret >= 0 || ret == -ENODEV) |
| | | return ret; |
| | | |
| | | msleep(5); |
| | | } |
| | | |
| | | dev_err(dev->dev, "Vendor request req:%02x off:%04x failed:%d\n", |
| | | req, offset, ret); |
| | | |
| | | return ret; |
| | | } |
| | | |
| | | void mt7601u_vendor_reset(struct mt7601u_dev *dev) |
| | | { |
| | | mt7601u_vendor_request(dev, MT_VEND_DEV_MODE, USB_DIR_OUT, |
| | | MT_VEND_DEV_MODE_RESET, 0, NULL, 0); |
| | | } |
| | | |
| | | u32 mt7601u_rr(struct mt7601u_dev *dev, u32 offset) |
| | | { |
| | | int ret; |
| | | u32 val = ~0; |
| | | |
| | | WARN_ONCE(offset > USHRT_MAX, "read high off:%08x", offset); |
| | | |
| | | mutex_lock(&dev->vendor_req_mutex); |
| | | |
| | | ret = mt7601u_vendor_request(dev, MT_VEND_MULTI_READ, USB_DIR_IN, |
| | | 0, offset, dev->vend_buf, MT_VEND_BUF); |
| | | if (ret == MT_VEND_BUF) |
| | | val = get_unaligned_le32(dev->vend_buf); |
| | | else if (ret > 0) |
| | | dev_err(dev->dev, "Error: wrong size read:%d off:%08x\n", |
| | | ret, offset); |
| | | |
| | | mutex_unlock(&dev->vendor_req_mutex); |
| | | |
| | | trace_reg_read(dev, offset, val); |
| | | return val; |
| | | } |
| | | |
| | | int mt7601u_vendor_single_wr(struct mt7601u_dev *dev, const u8 req, |
| | | const u16 offset, const u32 val) |
| | | { |
| | | int ret; |
| | | |
| | | mutex_lock(&dev->vendor_req_mutex); |
| | | |
| | | ret = mt7601u_vendor_request(dev, req, USB_DIR_OUT, |
| | | val & 0xffff, offset, NULL, 0); |
| | | if (!ret) |
| | | ret = mt7601u_vendor_request(dev, req, USB_DIR_OUT, |
| | | val >> 16, offset + 2, NULL, 0); |
| | | |
| | | mutex_unlock(&dev->vendor_req_mutex); |
| | | |
| | | return ret; |
| | | } |
| | | |
| | | void mt7601u_wr(struct mt7601u_dev *dev, u32 offset, u32 val) |
| | | { |
| | | WARN_ONCE(offset > USHRT_MAX, "write high off:%08x", offset); |
| | | |
| | | mt7601u_vendor_single_wr(dev, MT_VEND_WRITE, offset, val); |
| | | trace_reg_write(dev, offset, val); |
| | | } |
| | | |
| | | u32 mt7601u_rmw(struct mt7601u_dev *dev, u32 offset, u32 mask, u32 val) |
| | | { |
| | | val |= mt7601u_rr(dev, offset) & ~mask; |
| | | mt7601u_wr(dev, offset, val); |
| | | return val; |
| | | } |
| | | |
| | | u32 mt7601u_rmc(struct mt7601u_dev *dev, u32 offset, u32 mask, u32 val) |
| | | { |
| | | u32 reg = mt7601u_rr(dev, offset); |
| | | |
| | | val |= reg & ~mask; |
| | | if (reg != val) |
| | | mt7601u_wr(dev, offset, val); |
| | | return val; |
| | | } |
| | | |
| | | void mt7601u_wr_copy(struct mt7601u_dev *dev, u32 offset, |
| | | const void *data, int len) |
| | | { |
| | | WARN_ONCE(offset & 3, "unaligned write copy off:%08x", offset); |
| | | WARN_ONCE(len & 3, "short write copy off:%08x", offset); |
| | | |
| | | mt7601u_burst_write_regs(dev, offset, data, len / 4); |
| | | } |
| | | |
| | | void mt7601u_addr_wr(struct mt7601u_dev *dev, const u32 offset, const u8 *addr) |
| | | { |
| | | mt7601u_wr(dev, offset, get_unaligned_le32(addr)); |
| | | mt7601u_wr(dev, offset + 4, addr[4] | addr[5] << 8); |
| | | } |
| | | |
| | | static int mt7601u_assign_pipes(struct usb_interface *usb_intf, |
| | | struct mt7601u_dev *dev) |
| | | { |
| | | struct usb_endpoint_descriptor *ep_desc; |
| | | struct usb_host_interface *intf_desc = usb_intf->cur_altsetting; |
| | | unsigned i, ep_i = 0, ep_o = 0; |
| | | |
| | | BUILD_BUG_ON(sizeof(dev->in_eps) < __MT_EP_IN_MAX); |
| | | BUILD_BUG_ON(sizeof(dev->out_eps) < __MT_EP_OUT_MAX); |
| | | |
| | | for (i = 0; i < intf_desc->desc.bNumEndpoints; i++) { |
| | | ep_desc = &intf_desc->endpoint[i].desc; |
| | | |
| | | if (usb_endpoint_is_bulk_in(ep_desc) && |
| | | ep_i++ < __MT_EP_IN_MAX) { |
| | | dev->in_eps[ep_i - 1] = usb_endpoint_num(ep_desc); |
| | | dev->in_max_packet = usb_endpoint_maxp(ep_desc); |
| | | /* Note: this is ignored by usb sub-system but vendor |
| | | * code does it. We can drop this at some point. |
| | | */ |
| | | dev->in_eps[ep_i - 1] |= USB_DIR_IN; |
| | | } else if (usb_endpoint_is_bulk_out(ep_desc) && |
| | | ep_o++ < __MT_EP_OUT_MAX) { |
| | | dev->out_eps[ep_o - 1] = usb_endpoint_num(ep_desc); |
| | | dev->out_max_packet = usb_endpoint_maxp(ep_desc); |
| | | } |
| | | } |
| | | |
| | | if (ep_i != __MT_EP_IN_MAX || ep_o != __MT_EP_OUT_MAX) { |
| | | dev_err(dev->dev, "Error: wrong pipe number in:%d out:%d\n", |
| | | ep_i, ep_o); |
| | | return -EINVAL; |
| | | } |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | static int mt7601u_probe(struct usb_interface *usb_intf, |
| | | const struct usb_device_id *id) |
| | | { |
| | | struct usb_device *usb_dev = interface_to_usbdev(usb_intf); |
| | | struct mt7601u_dev *dev; |
| | | u32 asic_rev, mac_rev; |
| | | int ret; |
| | | |
| | | dev = mt7601u_alloc_device(&usb_intf->dev); |
| | | if (!dev) |
| | | return -ENOMEM; |
| | | |
| | | usb_dev = usb_get_dev(usb_dev); |
| | | usb_reset_device(usb_dev); |
| | | |
| | | usb_set_intfdata(usb_intf, dev); |
| | | |
| | | dev->vend_buf = devm_kmalloc(dev->dev, MT_VEND_BUF, GFP_KERNEL); |
| | | if (!dev->vend_buf) { |
| | | ret = -ENOMEM; |
| | | goto err; |
| | | } |
| | | |
| | | ret = mt7601u_assign_pipes(usb_intf, dev); |
| | | if (ret) |
| | | goto err; |
| | | ret = mt7601u_wait_asic_ready(dev); |
| | | if (ret) |
| | | goto err; |
| | | |
| | | asic_rev = mt7601u_rr(dev, MT_ASIC_VERSION); |
| | | mac_rev = mt7601u_rr(dev, MT_MAC_CSR0); |
| | | dev_info(dev->dev, "ASIC revision: %08x MAC revision: %08x\n", |
| | | asic_rev, mac_rev); |
| | | |
| | | /* Note: vendor driver skips this check for MT7601U */ |
| | | if (!(mt7601u_rr(dev, MT_EFUSE_CTRL) & MT_EFUSE_CTRL_SEL)) |
| | | dev_warn(dev->dev, "Warning: eFUSE not present\n"); |
| | | |
| | | ret = mt7601u_init_hardware(dev); |
| | | if (ret) |
| | | goto err; |
| | | ret = mt7601u_register_device(dev); |
| | | if (ret) |
| | | goto err_hw; |
| | | |
| | | set_bit(MT7601U_STATE_INITIALIZED, &dev->state); |
| | | |
| | | return 0; |
| | | err_hw: |
| | | mt7601u_cleanup(dev); |
| | | err: |
| | | usb_set_intfdata(usb_intf, NULL); |
| | | usb_put_dev(interface_to_usbdev(usb_intf)); |
| | | |
| | | destroy_workqueue(dev->stat_wq); |
| | | ieee80211_free_hw(dev->hw); |
| | | return ret; |
| | | } |
| | | |
| | | static void mt7601u_disconnect(struct usb_interface *usb_intf) |
| | | { |
| | | struct mt7601u_dev *dev = usb_get_intfdata(usb_intf); |
| | | |
| | | ieee80211_unregister_hw(dev->hw); |
| | | mt7601u_cleanup(dev); |
| | | |
| | | usb_set_intfdata(usb_intf, NULL); |
| | | usb_put_dev(interface_to_usbdev(usb_intf)); |
| | | |
| | | destroy_workqueue(dev->stat_wq); |
| | | ieee80211_free_hw(dev->hw); |
| | | } |
| | | |
| | | static int mt7601u_suspend(struct usb_interface *usb_intf, pm_message_t state) |
| | | { |
| | | struct mt7601u_dev *dev = usb_get_intfdata(usb_intf); |
| | | |
| | | mt7601u_cleanup(dev); |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | static int mt7601u_resume(struct usb_interface *usb_intf) |
| | | { |
| | | struct mt7601u_dev *dev = usb_get_intfdata(usb_intf); |
| | | int ret; |
| | | |
| | | ret = mt7601u_init_hardware(dev); |
| | | if (ret) |
| | | return ret; |
| | | |
| | | set_bit(MT7601U_STATE_INITIALIZED, &dev->state); |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | MODULE_DEVICE_TABLE(usb, mt7601u_device_table); |
| | | MODULE_FIRMWARE(MT7601U_FIRMWARE); |
| | | MODULE_LICENSE("GPL"); |
| | | |
| | | static struct usb_driver mt7601u_driver = { |
| | | .name = KBUILD_MODNAME, |
| | | .id_table = mt7601u_device_table, |
| | | .probe = mt7601u_probe, |
| | | .disconnect = mt7601u_disconnect, |
| | | .suspend = mt7601u_suspend, |
| | | .resume = mt7601u_resume, |
| | | .reset_resume = mt7601u_resume, |
| | | .soft_unbind = 1, |
| | | .disable_hub_initiated_lpm = 1, |
| | | }; |
| | | module_usb_driver(mt7601u_driver); |
New file |
| | |
| | | /* |
| | | * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> |
| | | * |
| | | * This program is free software; you can redistribute it and/or modify |
| | | * it under the terms of the GNU General Public License version 2 |
| | | * as published by the Free Software Foundation |
| | | * |
| | | * This program is distributed in the hope that it will be useful, |
| | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| | | * GNU General Public License for more details. |
| | | */ |
| | | |
| | | #ifndef __MT7601U_USB_H |
| | | #define __MT7601U_USB_H |
| | | |
| | | #include "mt7601u.h" |
| | | |
| | | #define MT7601U_FIRMWARE "mt7601u.bin" |
| | | |
| | | #define MT_VEND_REQ_MAX_RETRY 10 |
| | | #define MT_VEND_REQ_TOUT_MS 300 |
| | | |
| | | #define MT_VEND_DEV_MODE_RESET 1 |
| | | |
| | | #define MT_VEND_BUF sizeof(__le32) |
| | | |
| | | enum mt_vendor_req { |
| | | MT_VEND_DEV_MODE = 1, |
| | | MT_VEND_WRITE = 2, |
| | | MT_VEND_MULTI_READ = 7, |
| | | MT_VEND_WRITE_FCE = 0x42, |
| | | }; |
| | | |
| | | enum mt_usb_ep_in { |
| | | MT_EP_IN_PKT_RX, |
| | | MT_EP_IN_CMD_RESP, |
| | | __MT_EP_IN_MAX, |
| | | }; |
| | | |
| | | enum mt_usb_ep_out { |
| | | MT_EP_OUT_INBAND_CMD, |
| | | MT_EP_OUT_AC_BK, |
| | | MT_EP_OUT_AC_BE, |
| | | MT_EP_OUT_AC_VI, |
| | | MT_EP_OUT_AC_VO, |
| | | MT_EP_OUT_HCCA, |
| | | __MT_EP_OUT_MAX, |
| | | }; |
| | | |
| | | static inline struct usb_device *mt7601u_to_usb_dev(struct mt7601u_dev *mt7601u) |
| | | { |
| | | return interface_to_usbdev(to_usb_interface(mt7601u->dev)); |
| | | } |
| | | |
| | | static inline bool mt7601u_urb_has_error(struct urb *urb) |
| | | { |
| | | return urb->status && |
| | | urb->status != -ENOENT && |
| | | urb->status != -ECONNRESET && |
| | | urb->status != -ESHUTDOWN; |
| | | } |
| | | |
| | | bool mt7601u_usb_alloc_buf(struct mt7601u_dev *dev, size_t len, |
| | | struct mt7601u_dma_buf *buf); |
| | | void mt7601u_usb_free_buf(struct mt7601u_dev *dev, struct mt7601u_dma_buf *buf); |
| | | int mt7601u_usb_submit_buf(struct mt7601u_dev *dev, int dir, int ep_idx, |
| | | struct mt7601u_dma_buf *buf, gfp_t gfp, |
| | | usb_complete_t complete_fn, void *context); |
| | | void mt7601u_complete_urb(struct urb *urb); |
| | | |
| | | int mt7601u_vendor_request(struct mt7601u_dev *dev, const u8 req, |
| | | const u8 direction, const u16 val, const u16 offset, |
| | | void *buf, const size_t buflen); |
| | | void mt7601u_vendor_reset(struct mt7601u_dev *dev); |
| | | int mt7601u_vendor_single_wr(struct mt7601u_dev *dev, const u8 req, |
| | | const u16 offset, const u32 val); |
| | | |
| | | #endif |
New file |
| | |
| | | /* |
| | | * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> |
| | | * |
| | | * This program is free software; you can redistribute it and/or modify |
| | | * it under the terms of the GNU General Public License version 2 |
| | | * as published by the Free Software Foundation |
| | | * |
| | | * This program is distributed in the hope that it will be useful, |
| | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| | | * GNU General Public License for more details. |
| | | */ |
| | | |
| | | #include "mt7601u.h" |
| | | |
| | | void mt76_remove_hdr_pad(struct sk_buff *skb) |
| | | { |
| | | int len = ieee80211_get_hdrlen_from_skb(skb); |
| | | |
| | | memmove(skb->data + 2, skb->data, len); |
| | | skb_pull(skb, 2); |
| | | } |
| | | |
| | | int mt76_insert_hdr_pad(struct sk_buff *skb) |
| | | { |
| | | int len = ieee80211_get_hdrlen_from_skb(skb); |
| | | int ret; |
| | | |
| | | if (len % 4 == 0) |
| | | return 0; |
| | | |
| | | ret = skb_cow(skb, 2); |
| | | if (ret) |
| | | return ret; |
| | | |
| | | skb_push(skb, 2); |
| | | memmove(skb->data, skb->data + 2, len); |
| | | |
| | | skb->data[len] = 0; |
| | | skb->data[len + 1] = 0; |
| | | return 0; |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> |
| | | * Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> |
| | | * |
| | | * This program is free software; you can redistribute it and/or modify |
| | | * it under the terms of the GNU General Public License version 2 |
| | | * as published by the Free Software Foundation |
| | | * |
| | | * This program is distributed in the hope that it will be useful, |
| | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| | | * GNU General Public License for more details. |
| | | */ |
| | | |
| | | #ifndef __MT76_UTIL_H |
| | | #define __MT76_UTIL_H |
| | | |
| | | /* |
| | | * Power of two check, this will check |
| | | * if the mask that has been given contains and contiguous set of bits. |
| | | * Note that we cannot use the is_power_of_2() function since this |
| | | * check must be done at compile-time. |
| | | */ |
| | | #define is_power_of_two(x) ( !((x) & ((x)-1)) ) |
| | | #define low_bit_mask(x) ( ((x)-1) & ~(x) ) |
| | | #define is_valid_mask(x) is_power_of_two(1LU + (x) + low_bit_mask(x)) |
| | | |
| | | /* |
| | | * Macros to find first set bit in a variable. |
| | | * These macros behave the same as the __ffs() functions but |
| | | * the most important difference that this is done during |
| | | * compile-time rather then run-time. |
| | | */ |
| | | #define compile_ffs2(__x) \ |
| | | __builtin_choose_expr(((__x) & 0x1), 0, 1) |
| | | |
| | | #define compile_ffs4(__x) \ |
| | | __builtin_choose_expr(((__x) & 0x3), \ |
| | | (compile_ffs2((__x))), \ |
| | | (compile_ffs2((__x) >> 2) + 2)) |
| | | |
| | | #define compile_ffs8(__x) \ |
| | | __builtin_choose_expr(((__x) & 0xf), \ |
| | | (compile_ffs4((__x))), \ |
| | | (compile_ffs4((__x) >> 4) + 4)) |
| | | |
| | | #define compile_ffs16(__x) \ |
| | | __builtin_choose_expr(((__x) & 0xff), \ |
| | | (compile_ffs8((__x))), \ |
| | | (compile_ffs8((__x) >> 8) + 8)) |
| | | |
| | | #define compile_ffs32(__x) \ |
| | | __builtin_choose_expr(((__x) & 0xffff), \ |
| | | (compile_ffs16((__x))), \ |
| | | (compile_ffs16((__x) >> 16) + 16)) |
| | | |
| | | /* |
| | | * This macro will check the requirements for the FIELD{8,16,32} macros |
| | | * The mask should be a constant non-zero contiguous set of bits which |
| | | * does not exceed the given typelimit. |
| | | */ |
| | | #define FIELD_CHECK(__mask) \ |
| | | BUILD_BUG_ON(!(__mask) || !is_valid_mask(__mask)) |
| | | |
| | | #define MT76_SET(_mask, _val) \ |
| | | ({ \ |
| | | FIELD_CHECK(_mask); \ |
| | | (((u32) (_val)) << compile_ffs32(_mask)) & _mask; \ |
| | | }) |
| | | |
| | | #define MT76_GET(_mask, _val) \ |
| | | ({ \ |
| | | FIELD_CHECK(_mask); \ |
| | | (u32) (((_val) & _mask) >> compile_ffs32(_mask)); \ |
| | | }) |
| | | |
| | | #endif |
New file |
| | |
| | | config RTL8188EU |
| | | tristate "Realtek 8188E USB WiFi" |
| | | depends on USB |
| | | ---help--- |
| | | Help message of RTL8188EU |
| | | |
New file |
| | |
| | | SOUI License
|
| | |
|
| | | The MIT License (MIT)
|
| | | Copyright (c) 2016 Æô³ÌÈüþ
|
| | |
|
| | | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
| | |
|
| | | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
| | |
|
| | | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
| | |
|
| | |
|
New file |
| | |
| | | EXTRA_CFLAGS += $(USER_EXTRA_CFLAGS) |
| | | EXTRA_CFLAGS += -O2 |
| | | #EXTRA_CFLAGS += -O3 |
| | | #EXTRA_CFLAGS += -Wall |
| | | #EXTRA_CFLAGS += -Wextra |
| | | #EXTRA_CFLAGS += -Werror |
| | | #EXTRA_CFLAGS += -pedantic |
| | | #EXTRA_CFLAGS += -Wshadow -Wpointer-arith -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes |
| | | |
| | | EXTRA_CFLAGS += -Wno-unused-variable |
| | | EXTRA_CFLAGS += -Wno-unused-value |
| | | EXTRA_CFLAGS += -Wno-unused-label |
| | | EXTRA_CFLAGS += -Wno-unused-parameter |
| | | EXTRA_CFLAGS += -Wno-unused-function |
| | | EXTRA_CFLAGS += -Wno-unused |
| | | #EXTRA_CFLAGS += -Wno-uninitialized |
| | | |
| | | GCC_VER_49 := $(shell echo `$(CC) -dumpversion | cut -f1-2 -d.` \>= 4.9 | bc ) |
| | | ifeq ($(GCC_VER_49),1) |
| | | EXTRA_CFLAGS += -Wno-date-time # Fix compile error && warning on gcc 4.9 and later |
| | | endif |
| | | |
| | | EXTRA_CFLAGS += -I$(src)/include |
| | | EXTRA_CFLAGS += -I$(src)/hal/phydm |
| | | |
| | | EXTRA_LDFLAGS += --strip-debug |
| | | |
| | | CONFIG_AUTOCFG_CP = n |
| | | |
| | | ########################## WIFI IC ############################ |
| | | CONFIG_MULTIDRV = n |
| | | CONFIG_RTL8188E = y |
| | | CONFIG_RTL8812A = n |
| | | CONFIG_RTL8821A = n |
| | | CONFIG_RTL8192E = n |
| | | CONFIG_RTL8723B = n |
| | | CONFIG_RTL8814A = n |
| | | CONFIG_RTL8723C = n |
| | | CONFIG_RTL8188F = n |
| | | CONFIG_RTL8822B = n |
| | | CONFIG_RTL8723D = n |
| | | CONFIG_RTL8821C = n |
| | | ######################### Interface ########################### |
| | | CONFIG_USB_HCI = y |
| | | CONFIG_PCI_HCI = n |
| | | CONFIG_SDIO_HCI = n |
| | | CONFIG_GSPI_HCI = n |
| | | ########################## Features ########################### |
| | | CONFIG_MP_INCLUDED = y |
| | | CONFIG_POWER_SAVING = y |
| | | CONFIG_USB_AUTOSUSPEND = n |
| | | CONFIG_HW_PWRP_DETECTION = n |
| | | CONFIG_WIFI_TEST = n |
| | | CONFIG_BT_COEXIST = n |
| | | CONFIG_INTEL_WIDI = n |
| | | CONFIG_WAPI_SUPPORT = n |
| | | CONFIG_EFUSE_CONFIG_FILE = y |
| | | CONFIG_EXT_CLK = n |
| | | CONFIG_TRAFFIC_PROTECT = y |
| | | CONFIG_LOAD_PHY_PARA_FROM_FILE = y |
| | | CONFIG_TXPWR_BY_RATE_EN = n |
| | | CONFIG_TXPWR_LIMIT_EN = n |
| | | CONFIG_RTW_ADAPTIVITY_EN = disable |
| | | CONFIG_RTW_ADAPTIVITY_MODE = normal |
| | | CONFIG_SIGNAL_SCALE_MAPPING = n |
| | | CONFIG_80211W = n |
| | | CONFIG_REDUCE_TX_CPU_LOADING = n |
| | | CONFIG_BR_EXT = y |
| | | CONFIG_TDLS = n |
| | | CONFIG_WIFI_MONITOR = y |
| | | CONFIG_MCC_MODE = n |
| | | CONFIG_APPEND_VENDOR_IE_ENABLE = n |
| | | CONFIG_RTW_NAPI = y |
| | | CONFIG_RTW_GRO = y |
| | | ########################## Debug ########################### |
| | | CONFIG_RTW_DEBUG = n |
| | | # default log level is _DRV_INFO_ = 4, |
| | | # please refer to "How_to_set_driver_debug_log_level.doc" to set the available level. |
| | | CONFIG_RTW_LOG_LEVEL = 4 |
| | | ######################## Wake On Lan ########################## |
| | | CONFIG_WOWLAN = n |
| | | CONFIG_GPIO_WAKEUP = n |
| | | CONFIG_DEFAULT_PATTERNS_EN = n |
| | | CONFIG_WAKEUP_GPIO_IDX = default |
| | | CONFIG_HIGH_ACTIVE = n |
| | | CONFIG_PNO_SUPPORT = n |
| | | CONFIG_PNO_SET_DEBUG = n |
| | | CONFIG_AP_WOWLAN = n |
| | | ######### Notify SDIO Host Keep Power During Syspend ########## |
| | | CONFIG_RTW_SDIO_PM_KEEP_POWER = y |
| | | ###################### MP HW TX MODE FOR VHT ####################### |
| | | CONFIG_MP_VHT_HW_TX_MODE = n |
| | | ###################### Platform Related ####################### |
| | | CONFIG_PLATFORM_I386_PC = n |
| | | CONFIG_PLATFORM_ARM_SAMA5D4 = y |
| | | CONFIG_PLATFORM_BCM2709 = n |
| | | CONFIG_PLATFORM_ANDROID_X86 = n |
| | | CONFIG_PLATFORM_ANDROID_X86_N70 = n |
| | | CONFIG_PLATFORM_ANDROID_INTEL_X86 = n |
| | | CONFIG_PLATFORM_JB_X86 = n |
| | | CONFIG_PLATFORM_ARM_S3C2K4 = n |
| | | CONFIG_PLATFORM_ARM_PXA2XX = n |
| | | CONFIG_PLATFORM_ARM_S3C6K4 = n |
| | | CONFIG_PLATFORM_MIPS_RMI = n |
| | | CONFIG_PLATFORM_RTD2880B = n |
| | | CONFIG_PLATFORM_MIPS_AR9132 = n |
| | | CONFIG_PLATFORM_RTK_DMP = n |
| | | CONFIG_PLATFORM_MIPS_PLM = n |
| | | CONFIG_PLATFORM_MSTAR389 = n |
| | | CONFIG_PLATFORM_MT53XX = n |
| | | CONFIG_PLATFORM_ARM_MX51_241H = n |
| | | CONFIG_PLATFORM_FS_MX61 = n |
| | | CONFIG_PLATFORM_ACTIONS_ATJ227X = n |
| | | CONFIG_PLATFORM_TEGRA3_CARDHU = n |
| | | CONFIG_PLATFORM_TEGRA4_DALMORE = n |
| | | CONFIG_PLATFORM_ARM_TCC8900 = n |
| | | CONFIG_PLATFORM_ARM_TCC8920 = n |
| | | CONFIG_PLATFORM_ARM_TCC8920_JB42 = n |
| | | CONFIG_PLATFORM_ARM_TCC8930_JB42 = n |
| | | CONFIG_PLATFORM_ARM_RK2818 = n |
| | | CONFIG_PLATFORM_ARM_RK3066 = n |
| | | CONFIG_PLATFORM_ARM_RK3188 = n |
| | | CONFIG_PLATFORM_ARM_URBETTER = n |
| | | CONFIG_PLATFORM_ARM_TI_PANDA = n |
| | | CONFIG_PLATFORM_MIPS_JZ4760 = n |
| | | CONFIG_PLATFORM_DMP_PHILIPS = n |
| | | CONFIG_PLATFORM_MSTAR_TITANIA12 = n |
| | | CONFIG_PLATFORM_MSTAR = n |
| | | CONFIG_PLATFORM_SZEBOOK = n |
| | | CONFIG_PLATFORM_ARM_SUNxI = n |
| | | CONFIG_PLATFORM_ARM_SUN6I = n |
| | | CONFIG_PLATFORM_ARM_SUN7I = n |
| | | CONFIG_PLATFORM_ARM_SUN8I_W3P1 = n |
| | | CONFIG_PLATFORM_ARM_SUN8I_W5P1 = n |
| | | CONFIG_PLATFORM_ACTIONS_ATM702X = n |
| | | CONFIG_PLATFORM_ACTIONS_ATV5201 = n |
| | | CONFIG_PLATFORM_ACTIONS_ATM705X = n |
| | | CONFIG_PLATFORM_ARM_SUN50IW1P1 = n |
| | | CONFIG_PLATFORM_ARM_RTD299X = n |
| | | CONFIG_PLATFORM_ARM_SPREADTRUM_6820 = n |
| | | CONFIG_PLATFORM_ARM_SPREADTRUM_8810 = n |
| | | CONFIG_PLATFORM_ARM_WMT = n |
| | | CONFIG_PLATFORM_TI_DM365 = n |
| | | CONFIG_PLATFORM_MOZART = n |
| | | CONFIG_PLATFORM_RTK119X = n |
| | | CONFIG_PLATFORM_RTK129X = n |
| | | CONFIG_PLATFORM_NOVATEK_NT72668 = n |
| | | CONFIG_PLATFORM_HISILICON = n |
| | | CONFIG_PLATFORM_NV_TK1 = n |
| | | ############################################################### |
| | | |
| | | CONFIG_DRVEXT_MODULE = n |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_ANDROID_X86_N70), y) |
| | | export TopDIR := $(shell pwd)/../../../../../../kernel/drivers/net/wireless/rtl8188ee/ |
| | | endif |
| | | |
| | | export TopDIR ?= $(shell pwd) |
| | | |
| | | ########### COMMON ################################# |
| | | ifeq ($(CONFIG_GSPI_HCI), y) |
| | | HCI_NAME = gspi |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_SDIO_HCI), y) |
| | | HCI_NAME = sdio |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_USB_HCI), y) |
| | | HCI_NAME = usb |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PCI_HCI), y) |
| | | HCI_NAME = pci |
| | | endif |
| | | |
| | | |
| | | _OS_INTFS_FILES := os_dep/osdep_service.o \ |
| | | os_dep/linux/os_intfs.o \ |
| | | os_dep/linux/$(HCI_NAME)_intf.o \ |
| | | os_dep/linux/$(HCI_NAME)_ops_linux.o \ |
| | | os_dep/linux/ioctl_linux.o \ |
| | | os_dep/linux/xmit_linux.o \ |
| | | os_dep/linux/mlme_linux.o \ |
| | | os_dep/linux/recv_linux.o \ |
| | | os_dep/linux/ioctl_cfg80211.o \ |
| | | os_dep/linux/rtw_cfgvendor.o \ |
| | | os_dep/linux/wifi_regd.o \ |
| | | os_dep/linux/rtw_android.o \ |
| | | os_dep/linux/rtw_proc.o |
| | | |
| | | ifeq ($(CONFIG_MP_INCLUDED), y) |
| | | _OS_INTFS_FILES += os_dep/linux/ioctl_mp.o |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_SDIO_HCI), y) |
| | | _OS_INTFS_FILES += os_dep/linux/custom_gpio_linux.o |
| | | _OS_INTFS_FILES += os_dep/linux/$(HCI_NAME)_ops_linux.o |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_GSPI_HCI), y) |
| | | _OS_INTFS_FILES += os_dep/linux/custom_gpio_linux.o |
| | | _OS_INTFS_FILES += os_dep/linux/$(HCI_NAME)_ops_linux.o |
| | | endif |
| | | |
| | | |
| | | _HAL_INTFS_FILES := hal/hal_intf.o \ |
| | | hal/hal_com.o \ |
| | | hal/hal_com_phycfg.o \ |
| | | hal/hal_phy.o \ |
| | | hal/hal_dm.o \ |
| | | hal/hal_btcoex_wifionly.o \ |
| | | hal/hal_btcoex.o \ |
| | | hal/hal_mp.o \ |
| | | hal/hal_mcc.o \ |
| | | hal/hal_hci/hal_$(HCI_NAME).o \ |
| | | hal/led/hal_$(HCI_NAME)_led.o |
| | | |
| | | |
| | | _OUTSRC_FILES := hal/phydm/phydm_debug.o \ |
| | | hal/phydm/phydm_antdiv.o\ |
| | | hal/phydm/phydm_antdect.o\ |
| | | hal/phydm/phydm_interface.o\ |
| | | hal/phydm/phydm_hwconfig.o\ |
| | | hal/phydm/phydm.o\ |
| | | hal/phydm/halphyrf_ce.o\ |
| | | hal/phydm/phydm_edcaturbocheck.o\ |
| | | hal/phydm/phydm_dig.o\ |
| | | hal/phydm/phydm_pathdiv.o\ |
| | | hal/phydm/phydm_rainfo.o\ |
| | | hal/phydm/phydm_dynamicbbpowersaving.o\ |
| | | hal/phydm/phydm_powertracking_ce.o\ |
| | | hal/phydm/phydm_dynamictxpower.o\ |
| | | hal/phydm/phydm_adaptivity.o\ |
| | | hal/phydm/phydm_cfotracking.o\ |
| | | hal/phydm/phydm_noisemonitor.o\ |
| | | hal/phydm/phydm_acs.o\ |
| | | hal/phydm/phydm_beamforming.o\ |
| | | hal/phydm/phydm_dfs.o\ |
| | | hal/phydm/txbf/halcomtxbf.o\ |
| | | hal/phydm/txbf/haltxbfinterface.o\ |
| | | hal/phydm/txbf/phydm_hal_txbf_api.o\ |
| | | hal/phydm/phydm_adc_sampling.o\ |
| | | hal/phydm/phydm_kfree.o\ |
| | | hal/phydm/phydm_ccx.o |
| | | |
| | | |
| | | EXTRA_CFLAGS += -I$(src)/platform |
| | | _PLATFORM_FILES := platform/platform_ops.o |
| | | |
| | | EXTRA_CFLAGS += -I$(src)/hal/btc |
| | | _OUTSRC_FILES += hal/btc/halbtc8723bwifionly.o \ |
| | | hal/btc/halbtc8822bwifionly.o \ |
| | | hal/btc/halbtc8821cwifionly.o |
| | | ifeq ($(CONFIG_BT_COEXIST), y) |
| | | _OUTSRC_FILES += hal/btc/halbtc8192e1ant.o \ |
| | | hal/btc/halbtc8192e2ant.o \ |
| | | hal/btc/halbtc8723b1ant.o \ |
| | | hal/btc/halbtc8723b2ant.o \ |
| | | hal/btc/halbtc8812a1ant.o \ |
| | | hal/btc/halbtc8812a2ant.o \ |
| | | hal/btc/halbtc8821a1ant.o \ |
| | | hal/btc/halbtc8821a2ant.o \ |
| | | hal/btc/halbtc8703b1ant.o \ |
| | | hal/btc/halbtc8723d1ant.o \ |
| | | hal/btc/halbtc8723d2ant.o \ |
| | | hal/btc/halbtc8822b1ant.o \ |
| | | hal/btc/halbtc8822b2ant.o \ |
| | | hal/btc/halbtc8821c1ant.o \ |
| | | hal/btc/halbtc8821c2ant.o |
| | | endif |
| | | |
| | | |
| | | ########### HAL_RTL8188E ################################# |
| | | ifeq ($(CONFIG_RTL8188E), y) |
| | | |
| | | RTL871X = rtl8188e |
| | | ifeq ($(CONFIG_SDIO_HCI), y) |
| | | MODULE_NAME = 8189es |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_GSPI_HCI), y) |
| | | MODULE_NAME = 8189es |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_USB_HCI), y) |
| | | MODULE_NAME = 8188eu |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PCI_HCI), y) |
| | | MODULE_NAME = 8188ee |
| | | endif |
| | | EXTRA_CFLAGS += -DCONFIG_RTL8188E |
| | | |
| | | _HAL_INTFS_FILES += hal/HalPwrSeqCmd.o \ |
| | | hal/$(RTL871X)/Hal8188EPwrSeq.o\ |
| | | hal/$(RTL871X)/$(RTL871X)_xmit.o\ |
| | | hal/$(RTL871X)/$(RTL871X)_sreset.o |
| | | |
| | | _HAL_INTFS_FILES += hal/$(RTL871X)/$(RTL871X)_hal_init.o \ |
| | | hal/$(RTL871X)/$(RTL871X)_phycfg.o \ |
| | | hal/$(RTL871X)/$(RTL871X)_rf6052.o \ |
| | | hal/$(RTL871X)/$(RTL871X)_dm.o \ |
| | | hal/$(RTL871X)/$(RTL871X)_rxdesc.o \ |
| | | hal/$(RTL871X)/$(RTL871X)_cmd.o \ |
| | | hal/$(RTL871X)/hal8188e_s_fw.o \ |
| | | hal/$(RTL871X)/hal8188e_t_fw.o \ |
| | | hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \ |
| | | hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_led.o \ |
| | | hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_xmit.o \ |
| | | hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_recv.o |
| | | |
| | | ifeq ($(CONFIG_SDIO_HCI), y) |
| | | _HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o |
| | | else |
| | | ifeq ($(CONFIG_GSPI_HCI), y) |
| | | _HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o |
| | | else |
| | | _HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops_linux.o |
| | | endif |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_USB_HCI), y) |
| | | _HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8188E_USB.o |
| | | endif |
| | | ifeq ($(CONFIG_PCI_HCI), y) |
| | | _HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8188E_PCIE.o |
| | | endif |
| | | ifeq ($(CONFIG_SDIO_HCI), y) |
| | | _HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8188E_SDIO.o |
| | | endif |
| | | |
| | | #hal/OUTSRC/$(RTL871X)/Hal8188EFWImg_CE.o |
| | | _OUTSRC_FILES += hal/phydm/$(RTL871X)/halhwimg8188e_mac.o\ |
| | | hal/phydm/$(RTL871X)/halhwimg8188e_bb.o\ |
| | | hal/phydm/$(RTL871X)/halhwimg8188e_rf.o\ |
| | | hal/phydm/$(RTL871X)/halphyrf_8188e_ce.o\ |
| | | hal/phydm/$(RTL871X)/phydm_regconfig8188e.o\ |
| | | hal/phydm/$(RTL871X)/hal8188erateadaptive.o\ |
| | | hal/phydm/$(RTL871X)/phydm_rtl8188e.o |
| | | |
| | | endif |
| | | |
| | | ########### HAL_RTL8192E ################################# |
| | | ifeq ($(CONFIG_RTL8192E), y) |
| | | |
| | | RTL871X = rtl8192e |
| | | ifeq ($(CONFIG_SDIO_HCI), y) |
| | | MODULE_NAME = 8192es |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_USB_HCI), y) |
| | | MODULE_NAME = 8192eu |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PCI_HCI), y) |
| | | MODULE_NAME = 8192ee |
| | | endif |
| | | EXTRA_CFLAGS += -DCONFIG_RTL8192E |
| | | _HAL_INTFS_FILES += hal/HalPwrSeqCmd.o \ |
| | | hal/$(RTL871X)/Hal8192EPwrSeq.o\ |
| | | hal/$(RTL871X)/$(RTL871X)_xmit.o\ |
| | | hal/$(RTL871X)/$(RTL871X)_sreset.o |
| | | |
| | | _HAL_INTFS_FILES += hal/$(RTL871X)/$(RTL871X)_hal_init.o \ |
| | | hal/$(RTL871X)/$(RTL871X)_phycfg.o \ |
| | | hal/$(RTL871X)/$(RTL871X)_rf6052.o \ |
| | | hal/$(RTL871X)/$(RTL871X)_dm.o \ |
| | | hal/$(RTL871X)/$(RTL871X)_rxdesc.o \ |
| | | hal/$(RTL871X)/$(RTL871X)_cmd.o \ |
| | | hal/$(RTL871X)/hal8192e_fw.o \ |
| | | hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \ |
| | | hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_led.o \ |
| | | hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_xmit.o \ |
| | | hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_recv.o |
| | | |
| | | ifeq ($(CONFIG_SDIO_HCI), y) |
| | | _HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o |
| | | else |
| | | ifeq ($(CONFIG_GSPI_HCI), y) |
| | | _HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o |
| | | else |
| | | _HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops_linux.o |
| | | endif |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_USB_HCI), y) |
| | | _HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8192E_USB.o |
| | | endif |
| | | ifeq ($(CONFIG_PCI_HCI), y) |
| | | _HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8192E_PCIE.o |
| | | endif |
| | | |
| | | #hal/OUTSRC/$(RTL871X)/HalHWImg8188E_FW.o |
| | | _OUTSRC_FILES += hal/phydm/$(RTL871X)/halhwimg8192e_mac.o\ |
| | | hal/phydm/$(RTL871X)/halhwimg8192e_bb.o\ |
| | | hal/phydm/$(RTL871X)/halhwimg8192e_rf.o\ |
| | | hal/phydm/$(RTL871X)/halphyrf_8192e_ce.o\ |
| | | hal/phydm/$(RTL871X)/phydm_regconfig8192e.o\ |
| | | hal/phydm/$(RTL871X)/phydm_rtl8192e.o |
| | | |
| | | endif |
| | | |
| | | ########### HAL_RTL8812A_RTL8821A ################################# |
| | | |
| | | ifneq ($(CONFIG_RTL8812A)_$(CONFIG_RTL8821A), n_n) |
| | | |
| | | RTL871X = rtl8812a |
| | | ifeq ($(CONFIG_USB_HCI), y) |
| | | MODULE_NAME = 8812au |
| | | endif |
| | | ifeq ($(CONFIG_PCI_HCI), y) |
| | | MODULE_NAME = 8812ae |
| | | endif |
| | | ifeq ($(CONFIG_SDIO_HCI), y) |
| | | MODULE_NAME = 8812as |
| | | endif |
| | | |
| | | _HAL_INTFS_FILES += hal/HalPwrSeqCmd.o \ |
| | | hal/$(RTL871X)/Hal8812PwrSeq.o \ |
| | | hal/$(RTL871X)/Hal8821APwrSeq.o\ |
| | | hal/$(RTL871X)/$(RTL871X)_xmit.o\ |
| | | hal/$(RTL871X)/$(RTL871X)_sreset.o |
| | | |
| | | _HAL_INTFS_FILES += hal/$(RTL871X)/$(RTL871X)_hal_init.o \ |
| | | hal/$(RTL871X)/$(RTL871X)_phycfg.o \ |
| | | hal/$(RTL871X)/$(RTL871X)_rf6052.o \ |
| | | hal/$(RTL871X)/$(RTL871X)_dm.o \ |
| | | hal/$(RTL871X)/$(RTL871X)_rxdesc.o \ |
| | | hal/$(RTL871X)/$(RTL871X)_cmd.o \ |
| | | hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \ |
| | | hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_led.o \ |
| | | hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_xmit.o \ |
| | | hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_recv.o |
| | | |
| | | ifeq ($(CONFIG_SDIO_HCI), y) |
| | | _HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o |
| | | else |
| | | ifeq ($(CONFIG_GSPI_HCI), y) |
| | | _HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o |
| | | else |
| | | _HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops_linux.o |
| | | endif |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_RTL8812A), y) |
| | | ifeq ($(CONFIG_USB_HCI), y) |
| | | _HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8812A_USB.o |
| | | endif |
| | | ifeq ($(CONFIG_PCI_HCI), y) |
| | | _HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8812A_PCIE.o |
| | | endif |
| | | endif |
| | | ifeq ($(CONFIG_RTL8821A), y) |
| | | ifeq ($(CONFIG_USB_HCI), y) |
| | | _HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8821A_USB.o |
| | | endif |
| | | ifeq ($(CONFIG_PCI_HCI), y) |
| | | _HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8821A_PCIE.o |
| | | endif |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_RTL8812A), y) |
| | | EXTRA_CFLAGS += -DCONFIG_RTL8812A |
| | | _HAL_INTFS_FILES += hal/rtl8812a/hal8812a_fw.o |
| | | |
| | | _OUTSRC_FILES += hal/phydm/$(RTL871X)/halhwimg8812a_mac.o\ |
| | | hal/phydm/$(RTL871X)/halhwimg8812a_bb.o\ |
| | | hal/phydm/$(RTL871X)/halhwimg8812a_rf.o\ |
| | | hal/phydm/$(RTL871X)/halphyrf_8812a_ce.o\ |
| | | hal/phydm/$(RTL871X)/phydm_regconfig8812a.o\ |
| | | hal/phydm/$(RTL871X)/phydm_rtl8812a.o\ |
| | | hal/phydm/txbf/haltxbfjaguar.o |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_RTL8821A), y) |
| | | |
| | | ifeq ($(CONFIG_RTL8812A), n) |
| | | |
| | | RTL871X = rtl8821a |
| | | ifeq ($(CONFIG_USB_HCI), y) |
| | | ifeq ($(CONFIG_BT_COEXIST), y) |
| | | MODULE_NAME := 8821au |
| | | else |
| | | MODULE_NAME := 8811au |
| | | endif |
| | | endif |
| | | ifeq ($(CONFIG_PCI_HCI), y) |
| | | MODULE_NAME := 8821ae |
| | | endif |
| | | ifeq ($(CONFIG_SDIO_HCI), y) |
| | | MODULE_NAME := 8821as |
| | | endif |
| | | |
| | | endif |
| | | |
| | | EXTRA_CFLAGS += -DCONFIG_RTL8821A |
| | | |
| | | _HAL_INTFS_FILES += hal/rtl8812a/hal8821a_fw.o |
| | | _OUTSRC_FILES += hal/phydm/rtl8821a/halhwimg8821a_mac.o\ |
| | | hal/phydm/rtl8821a/halhwimg8821a_bb.o\ |
| | | hal/phydm/rtl8821a/halhwimg8821a_rf.o\ |
| | | hal/phydm/rtl8812a/halphyrf_8812a_ce.o\ |
| | | hal/phydm/rtl8821a/halphyrf_8821a_ce.o\ |
| | | hal/phydm/rtl8821a/phydm_regconfig8821a.o\ |
| | | hal/phydm/rtl8821a/phydm_rtl8821a.o\ |
| | | hal/phydm/rtl8821a/phydm_iqk_8821a_ce.o\ |
| | | hal/phydm/txbf/haltxbfjaguar.o |
| | | |
| | | endif |
| | | |
| | | endif |
| | | |
| | | ########### HAL_RTL8723B ################################# |
| | | ifeq ($(CONFIG_RTL8723B), y) |
| | | |
| | | RTL871X = rtl8723b |
| | | ifeq ($(CONFIG_USB_HCI), y) |
| | | MODULE_NAME = 8723bu |
| | | endif |
| | | ifeq ($(CONFIG_PCI_HCI), y) |
| | | MODULE_NAME = 8723be |
| | | endif |
| | | ifeq ($(CONFIG_SDIO_HCI), y) |
| | | MODULE_NAME = 8723bs |
| | | endif |
| | | |
| | | EXTRA_CFLAGS += -DCONFIG_RTL8723B |
| | | |
| | | _HAL_INTFS_FILES += hal/HalPwrSeqCmd.o \ |
| | | hal/$(RTL871X)/Hal8723BPwrSeq.o\ |
| | | hal/$(RTL871X)/$(RTL871X)_sreset.o |
| | | |
| | | _HAL_INTFS_FILES += hal/$(RTL871X)/$(RTL871X)_hal_init.o \ |
| | | hal/$(RTL871X)/$(RTL871X)_phycfg.o \ |
| | | hal/$(RTL871X)/$(RTL871X)_rf6052.o \ |
| | | hal/$(RTL871X)/$(RTL871X)_dm.o \ |
| | | hal/$(RTL871X)/$(RTL871X)_rxdesc.o \ |
| | | hal/$(RTL871X)/$(RTL871X)_cmd.o \ |
| | | hal/$(RTL871X)/hal8723b_fw.o |
| | | |
| | | _HAL_INTFS_FILES += \ |
| | | hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \ |
| | | hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_led.o \ |
| | | hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_xmit.o \ |
| | | hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_recv.o |
| | | |
| | | ifeq ($(CONFIG_PCI_HCI), y) |
| | | _HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops_linux.o |
| | | else |
| | | _HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_USB_HCI), y) |
| | | _HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8723B_USB.o |
| | | endif |
| | | ifeq ($(CONFIG_PCI_HCI), y) |
| | | _HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8723B_PCIE.o |
| | | endif |
| | | |
| | | _OUTSRC_FILES += hal/phydm/$(RTL871X)/halhwimg8723b_bb.o\ |
| | | hal/phydm/$(RTL871X)/halhwimg8723b_mac.o\ |
| | | hal/phydm/$(RTL871X)/halhwimg8723b_rf.o\ |
| | | hal/phydm/$(RTL871X)/halhwimg8723b_mp.o\ |
| | | hal/phydm/$(RTL871X)/phydm_regconfig8723b.o\ |
| | | hal/phydm/$(RTL871X)/halphyrf_8723b_ce.o\ |
| | | hal/phydm/$(RTL871X)/phydm_rtl8723b.o |
| | | |
| | | endif |
| | | |
| | | ########### HAL_RTL8814A ################################# |
| | | ifeq ($(CONFIG_RTL8814A), y) |
| | | ## ADD NEW VHT MP HW TX MODE ## |
| | | #EXTRA_CFLAGS += -DCONFIG_MP_VHT_HW_TX_MODE |
| | | #CONFIG_MP_VHT_HW_TX_MODE = y |
| | | ########################################## |
| | | RTL871X = rtl8814a |
| | | ifeq ($(CONFIG_USB_HCI), y) |
| | | MODULE_NAME = 8814au |
| | | endif |
| | | ifeq ($(CONFIG_PCI_HCI), y) |
| | | MODULE_NAME = 8814ae |
| | | endif |
| | | ifeq ($(CONFIG_SDIO_HCI), y) |
| | | MODULE_NAME = 8814as |
| | | endif |
| | | |
| | | EXTRA_CFLAGS += -DCONFIG_RTL8814A |
| | | |
| | | _HAL_INTFS_FILES += hal/HalPwrSeqCmd.o \ |
| | | hal/$(RTL871X)/Hal8814PwrSeq.o \ |
| | | hal/$(RTL871X)/$(RTL871X)_xmit.o\ |
| | | hal/$(RTL871X)/$(RTL871X)_sreset.o |
| | | |
| | | _HAL_INTFS_FILES += hal/$(RTL871X)/$(RTL871X)_hal_init.o \ |
| | | hal/$(RTL871X)/$(RTL871X)_phycfg.o \ |
| | | hal/$(RTL871X)/$(RTL871X)_rf6052.o \ |
| | | hal/$(RTL871X)/$(RTL871X)_dm.o \ |
| | | hal/$(RTL871X)/$(RTL871X)_rxdesc.o \ |
| | | hal/$(RTL871X)/$(RTL871X)_cmd.o \ |
| | | hal/$(RTL871X)/hal8814a_fw.o |
| | | |
| | | |
| | | _HAL_INTFS_FILES += \ |
| | | hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \ |
| | | hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_led.o \ |
| | | hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_xmit.o \ |
| | | hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_recv.o |
| | | |
| | | ifeq ($(CONFIG_SDIO_HCI), y) |
| | | _HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o |
| | | else |
| | | ifeq ($(CONFIG_GSPI_HCI), y) |
| | | _HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o |
| | | else |
| | | _HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops_linux.o |
| | | endif |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_USB_HCI), y) |
| | | _HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8814A_USB.o |
| | | endif |
| | | ifeq ($(CONFIG_PCI_HCI), y) |
| | | _HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8814A_PCIE.o |
| | | endif |
| | | |
| | | _OUTSRC_FILES += hal/phydm/$(RTL871X)/halhwimg8814a_bb.o\ |
| | | hal/phydm/$(RTL871X)/halhwimg8814a_mac.o\ |
| | | hal/phydm/$(RTL871X)/halhwimg8814a_rf.o\ |
| | | hal/phydm/$(RTL871X)/phydm_iqk_8814a.o\ |
| | | hal/phydm/$(RTL871X)/phydm_regconfig8814a.o\ |
| | | hal/phydm/$(RTL871X)/halphyrf_8814a_ce.o\ |
| | | hal/phydm/$(RTL871X)/phydm_rtl8814a.o\ |
| | | hal/phydm/txbf/haltxbf8814a.o |
| | | |
| | | endif |
| | | |
| | | ########### HAL_RTL8723C ################################# |
| | | ifeq ($(CONFIG_RTL8723C), y) |
| | | |
| | | RTL871X = rtl8703b |
| | | ifeq ($(CONFIG_USB_HCI), y) |
| | | MODULE_NAME = 8723cu |
| | | MODULE_SUB_NAME = 8703bu |
| | | endif |
| | | ifeq ($(CONFIG_PCI_HCI), y) |
| | | MODULE_NAME = 8723ce |
| | | MODULE_SUB_NAME = 8703be |
| | | endif |
| | | ifeq ($(CONFIG_SDIO_HCI), y) |
| | | MODULE_NAME = 8723cs |
| | | MODULE_SUB_NAME = 8703bs |
| | | endif |
| | | |
| | | EXTRA_CFLAGS += -DCONFIG_RTL8703B |
| | | |
| | | _HAL_INTFS_FILES += hal/HalPwrSeqCmd.o \ |
| | | hal/$(RTL871X)/Hal8703BPwrSeq.o\ |
| | | hal/$(RTL871X)/$(RTL871X)_sreset.o |
| | | |
| | | _HAL_INTFS_FILES += hal/$(RTL871X)/$(RTL871X)_hal_init.o \ |
| | | hal/$(RTL871X)/$(RTL871X)_phycfg.o \ |
| | | hal/$(RTL871X)/$(RTL871X)_rf6052.o \ |
| | | hal/$(RTL871X)/$(RTL871X)_dm.o \ |
| | | hal/$(RTL871X)/$(RTL871X)_rxdesc.o \ |
| | | hal/$(RTL871X)/$(RTL871X)_cmd.o \ |
| | | hal/$(RTL871X)/hal8703b_fw.o |
| | | |
| | | _HAL_INTFS_FILES += \ |
| | | hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \ |
| | | hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_SUB_NAME)_led.o \ |
| | | hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_SUB_NAME)_xmit.o \ |
| | | hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_SUB_NAME)_recv.o |
| | | |
| | | ifeq ($(CONFIG_PCI_HCI), y) |
| | | _HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops_linux.o |
| | | else |
| | | _HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_USB_HCI), y) |
| | | _HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8703B_USB.o |
| | | endif |
| | | ifeq ($(CONFIG_PCI_HCI), y) |
| | | _HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8703B_PCIE.o |
| | | endif |
| | | |
| | | _OUTSRC_FILES += hal/phydm/$(RTL871X)/halhwimg8703b_bb.o\ |
| | | hal/phydm/$(RTL871X)/halhwimg8703b_mac.o\ |
| | | hal/phydm/$(RTL871X)/halhwimg8703b_rf.o\ |
| | | hal/phydm/$(RTL871X)/phydm_regconfig8703b.o\ |
| | | hal/phydm/$(RTL871X)/halphyrf_8703b.o |
| | | endif |
| | | |
| | | ########### HAL_RTL8723D ################################# |
| | | ifeq ($(CONFIG_RTL8723D), y) |
| | | |
| | | RTL871X = rtl8723d |
| | | ifeq ($(CONFIG_USB_HCI), y) |
| | | MODULE_NAME = 8723du |
| | | MODULE_SUB_NAME = 8723du |
| | | endif |
| | | ifeq ($(CONFIG_PCI_HCI), y) |
| | | MODULE_NAME = 8723de |
| | | MODULE_SUB_NAME = 8723de |
| | | endif |
| | | ifeq ($(CONFIG_SDIO_HCI), y) |
| | | MODULE_NAME = 8723ds |
| | | MODULE_SUB_NAME = 8723ds |
| | | endif |
| | | |
| | | EXTRA_CFLAGS += -DCONFIG_RTL8723D |
| | | |
| | | _HAL_INTFS_FILES += hal/HalPwrSeqCmd.o \ |
| | | hal/$(RTL871X)/Hal8723DPwrSeq.o\ |
| | | hal/$(RTL871X)/$(RTL871X)_sreset.o |
| | | |
| | | _HAL_INTFS_FILES += hal/$(RTL871X)/$(RTL871X)_hal_init.o \ |
| | | hal/$(RTL871X)/$(RTL871X)_phycfg.o \ |
| | | hal/$(RTL871X)/$(RTL871X)_rf6052.o \ |
| | | hal/$(RTL871X)/$(RTL871X)_dm.o \ |
| | | hal/$(RTL871X)/$(RTL871X)_rxdesc.o \ |
| | | hal/$(RTL871X)/$(RTL871X)_cmd.o \ |
| | | hal/$(RTL871X)/hal8723d_fw.o \ |
| | | hal/$(RTL871X)/$(RTL871X)_lps_poff.o |
| | | |
| | | |
| | | _HAL_INTFS_FILES += \ |
| | | hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \ |
| | | hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_SUB_NAME)_led.o \ |
| | | hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_SUB_NAME)_xmit.o \ |
| | | hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_SUB_NAME)_recv.o |
| | | |
| | | ifeq ($(CONFIG_PCI_HCI), y) |
| | | _HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops_linux.o |
| | | else |
| | | _HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_USB_HCI), y) |
| | | _HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8723D_USB.o |
| | | endif |
| | | ifeq ($(CONFIG_PCI_HCI), y) |
| | | _HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8723D_PCIE.o |
| | | endif |
| | | |
| | | _OUTSRC_FILES += hal/phydm/$(RTL871X)/halhwimg8723d_bb.o\ |
| | | hal/phydm/$(RTL871X)/halhwimg8723d_mac.o\ |
| | | hal/phydm/$(RTL871X)/halhwimg8723d_rf.o\ |
| | | hal/phydm/$(RTL871X)/phydm_regconfig8723d.o\ |
| | | hal/phydm/$(RTL871X)/phydm_rtl8723d.o\ |
| | | hal/phydm/$(RTL871X)/halphyrf_8723d.o |
| | | endif |
| | | |
| | | ########### HAL_RTL8188F ################################# |
| | | ifeq ($(CONFIG_RTL8188F), y) |
| | | |
| | | RTL871X = rtl8188f |
| | | ifeq ($(CONFIG_USB_HCI), y) |
| | | MODULE_NAME = 8188fu |
| | | endif |
| | | ifeq ($(CONFIG_PCI_HCI), y) |
| | | MODULE_NAME = 8188fe |
| | | endif |
| | | ifeq ($(CONFIG_SDIO_HCI), y) |
| | | MODULE_NAME = 8189fs |
| | | endif |
| | | |
| | | EXTRA_CFLAGS += -DCONFIG_RTL8188F |
| | | |
| | | _HAL_INTFS_FILES += hal/HalPwrSeqCmd.o \ |
| | | hal/$(RTL871X)/Hal8188FPwrSeq.o\ |
| | | hal/$(RTL871X)/$(RTL871X)_sreset.o |
| | | |
| | | _HAL_INTFS_FILES += hal/$(RTL871X)/$(RTL871X)_hal_init.o \ |
| | | hal/$(RTL871X)/$(RTL871X)_phycfg.o \ |
| | | hal/$(RTL871X)/$(RTL871X)_rf6052.o \ |
| | | hal/$(RTL871X)/$(RTL871X)_dm.o \ |
| | | hal/$(RTL871X)/$(RTL871X)_rxdesc.o \ |
| | | hal/$(RTL871X)/$(RTL871X)_cmd.o \ |
| | | hal/$(RTL871X)/hal8188f_fw.o |
| | | |
| | | _HAL_INTFS_FILES += \ |
| | | hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \ |
| | | hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_led.o \ |
| | | hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_xmit.o \ |
| | | hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_recv.o |
| | | |
| | | ifeq ($(CONFIG_PCI_HCI), y) |
| | | _HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops_linux.o |
| | | else |
| | | _HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_USB_HCI), y) |
| | | _HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8188F_USB.o |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_SDIO_HCI), y) |
| | | _HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8188F_SDIO.o |
| | | endif |
| | | |
| | | _OUTSRC_FILES += hal/phydm/$(RTL871X)/halhwimg8188f_bb.o\ |
| | | hal/phydm/$(RTL871X)/halhwimg8188f_mac.o\ |
| | | hal/phydm/$(RTL871X)/halhwimg8188f_rf.o\ |
| | | hal/phydm/$(RTL871X)/phydm_regconfig8188f.o\ |
| | | hal/phydm/$(RTL871X)/halphyrf_8188f.o \ |
| | | hal/phydm/$(RTL871X)/phydm_rtl8188f.o |
| | | |
| | | endif |
| | | |
| | | ########### HAL_RTL8822B ################################# |
| | | ifeq ($(CONFIG_RTL8822B), y) |
| | | include $(TopDIR)/rtl8822b.mk |
| | | endif |
| | | |
| | | ########### HAL_RTL8821C ################################# |
| | | ifeq ($(CONFIG_RTL8821C), y) |
| | | include $(TopDIR)/rtl8821c.mk |
| | | |
| | | _OUTSRC_FILES += hal/phydm/rtl8821c/halhwimg8821c_bb.o \ |
| | | hal/phydm/rtl8821c/halhwimg8821c_mac.o \ |
| | | hal/phydm/rtl8821c/halhwimg8821c_rf.o \ |
| | | hal/phydm/rtl8821c/phydm_hal_api8821c.o \ |
| | | hal/phydm/rtl8821c/phydm_regconfig8821c.o\ |
| | | hal/phydm/rtl8821c/halphyrf_8821c.o\ |
| | | hal/phydm/rtl8821c/phydm_iqk_8821c.o |
| | | endif |
| | | |
| | | ########### AUTO_CFG ################################# |
| | | |
| | | ifeq ($(CONFIG_AUTOCFG_CP), y) |
| | | |
| | | ifeq ($(CONFIG_MULTIDRV), y) |
| | | $(shell cp $(TopDIR)/autoconf_multidrv_$(HCI_NAME)_linux.h $(TopDIR)/include/autoconf.h) |
| | | else |
| | | ifeq ($(CONFIG_RTL8188E)$(CONFIG_SDIO_HCI),yy) |
| | | $(shell cp $(TopDIR)/autoconf_rtl8189e_$(HCI_NAME)_linux.h $(TopDIR)/include/autoconf.h) |
| | | else ifeq ($(CONFIG_RTL8188F)$(CONFIG_SDIO_HCI),yy) |
| | | $(shell cp $(TopDIR)/autoconf_rtl8189f_$(HCI_NAME)_linux.h $(TopDIR)/include/autoconf.h) |
| | | else ifeq ($(CONFIG_RTL8723C),y) |
| | | $(shell cp $(TopDIR)/autoconf_rtl8723c_$(HCI_NAME)_linux.h $(TopDIR)/include/autoconf.h) |
| | | else |
| | | $(shell cp $(TopDIR)/autoconf_$(RTL871X)_$(HCI_NAME)_linux.h $(TopDIR)/include/autoconf.h) |
| | | endif |
| | | endif |
| | | |
| | | endif |
| | | |
| | | ########### END OF PATH ################################# |
| | | |
| | | ifeq ($(CONFIG_USB_HCI), y) |
| | | ifeq ($(CONFIG_USB_AUTOSUSPEND), y) |
| | | EXTRA_CFLAGS += -DCONFIG_USB_AUTOSUSPEND |
| | | endif |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_MP_INCLUDED), y) |
| | | #MODULE_NAME := $(MODULE_NAME)_mp |
| | | EXTRA_CFLAGS += -DCONFIG_MP_INCLUDED |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_POWER_SAVING), y) |
| | | EXTRA_CFLAGS += -DCONFIG_POWER_SAVING |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_HW_PWRP_DETECTION), y) |
| | | EXTRA_CFLAGS += -DCONFIG_HW_PWRP_DETECTION |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_WIFI_TEST), y) |
| | | EXTRA_CFLAGS += -DCONFIG_WIFI_TEST |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_BT_COEXIST), y) |
| | | EXTRA_CFLAGS += -DCONFIG_BT_COEXIST |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_INTEL_WIDI), y) |
| | | EXTRA_CFLAGS += -DCONFIG_INTEL_WIDI |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_WAPI_SUPPORT), y) |
| | | EXTRA_CFLAGS += -DCONFIG_WAPI_SUPPORT |
| | | endif |
| | | |
| | | |
| | | ifeq ($(CONFIG_EFUSE_CONFIG_FILE), y) |
| | | EXTRA_CFLAGS += -DCONFIG_EFUSE_CONFIG_FILE |
| | | |
| | | #EFUSE_MAP_PATH |
| | | USER_EFUSE_MAP_PATH ?= |
| | | ifneq ($(USER_EFUSE_MAP_PATH),) |
| | | EXTRA_CFLAGS += -DEFUSE_MAP_PATH=\"$(USER_EFUSE_MAP_PATH)\" |
| | | else ifeq ($(MODULE_NAME), 8189es) |
| | | EXTRA_CFLAGS += -DEFUSE_MAP_PATH=\"/system/etc/wifi/wifi_efuse_8189e.map\" |
| | | else ifeq ($(MODULE_NAME), 8723bs) |
| | | EXTRA_CFLAGS += -DEFUSE_MAP_PATH=\"/system/etc/wifi/wifi_efuse_8723bs.map\" |
| | | else |
| | | EXTRA_CFLAGS += -DEFUSE_MAP_PATH=\"/system/etc/wifi/wifi_efuse_$(MODULE_NAME).map\" |
| | | endif |
| | | |
| | | #WIFIMAC_PATH |
| | | USER_WIFIMAC_PATH ?= |
| | | ifneq ($(USER_WIFIMAC_PATH),) |
| | | EXTRA_CFLAGS += -DWIFIMAC_PATH=\"$(USER_WIFIMAC_PATH)\" |
| | | else |
| | | EXTRA_CFLAGS += -DWIFIMAC_PATH=\"/data/wifimac.txt\" |
| | | endif |
| | | |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_EXT_CLK), y) |
| | | EXTRA_CFLAGS += -DCONFIG_EXT_CLK |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_TRAFFIC_PROTECT), y) |
| | | EXTRA_CFLAGS += -DCONFIG_TRAFFIC_PROTECT |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_LOAD_PHY_PARA_FROM_FILE), y) |
| | | EXTRA_CFLAGS += -DCONFIG_LOAD_PHY_PARA_FROM_FILE |
| | | #EXTRA_CFLAGS += -DREALTEK_CONFIG_PATH_WITH_IC_NAME_FOLDER |
| | | #EXTRA_CFLAGS += -DREALTEK_CONFIG_PATH=\"/lib/firmware/\" |
| | | EXTRA_CFLAGS += -DREALTEK_CONFIG_PATH=\"\" |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_TXPWR_BY_RATE_EN), n) |
| | | EXTRA_CFLAGS += -DCONFIG_TXPWR_BY_RATE_EN=0 |
| | | else ifeq ($(CONFIG_TXPWR_BY_RATE_EN), y) |
| | | EXTRA_CFLAGS += -DCONFIG_TXPWR_BY_RATE_EN=1 |
| | | else ifeq ($(CONFIG_TXPWR_BY_RATE_EN), auto) |
| | | EXTRA_CFLAGS += -DCONFIG_TXPWR_BY_RATE_EN=2 |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_TXPWR_LIMIT_EN), n) |
| | | EXTRA_CFLAGS += -DCONFIG_TXPWR_LIMIT_EN=0 |
| | | else ifeq ($(CONFIG_TXPWR_LIMIT_EN), y) |
| | | EXTRA_CFLAGS += -DCONFIG_TXPWR_LIMIT_EN=1 |
| | | else ifeq ($(CONFIG_TXPWR_LIMIT_EN), auto) |
| | | EXTRA_CFLAGS += -DCONFIG_TXPWR_LIMIT_EN=2 |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_CALIBRATE_TX_POWER_BY_REGULATORY), y) |
| | | EXTRA_CFLAGS += -DCONFIG_CALIBRATE_TX_POWER_BY_REGULATORY |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_CALIBRATE_TX_POWER_TO_MAX), y) |
| | | EXTRA_CFLAGS += -DCONFIG_CALIBRATE_TX_POWER_TO_MAX |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_RTW_ADAPTIVITY_EN), disable) |
| | | EXTRA_CFLAGS += -DCONFIG_RTW_ADAPTIVITY_EN=0 |
| | | else ifeq ($(CONFIG_RTW_ADAPTIVITY_EN), enable) |
| | | EXTRA_CFLAGS += -DCONFIG_RTW_ADAPTIVITY_EN=1 |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_RTW_ADAPTIVITY_MODE), normal) |
| | | EXTRA_CFLAGS += -DCONFIG_RTW_ADAPTIVITY_MODE=0 |
| | | else ifeq ($(CONFIG_RTW_ADAPTIVITY_MODE), carrier_sense) |
| | | EXTRA_CFLAGS += -DCONFIG_RTW_ADAPTIVITY_MODE=1 |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_SIGNAL_SCALE_MAPPING), y) |
| | | EXTRA_CFLAGS += -DCONFIG_SIGNAL_SCALE_MAPPING |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_80211W), y) |
| | | EXTRA_CFLAGS += -DCONFIG_IEEE80211W |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_WOWLAN), y) |
| | | EXTRA_CFLAGS += -DCONFIG_WOWLAN |
| | | ifeq ($(CONFIG_SDIO_HCI), y) |
| | | EXTRA_CFLAGS += -DCONFIG_RTW_SDIO_PM_KEEP_POWER |
| | | endif |
| | | ifeq ($(CONFIG_DEFAULT_PATTERNS_EN), y) |
| | | EXTRA_CFLAGS += -DCONFIG_DEFAULT_PATTERNS_EN |
| | | endif |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_AP_WOWLAN), y) |
| | | EXTRA_CFLAGS += -DCONFIG_AP_WOWLAN |
| | | ifeq ($(CONFIG_SDIO_HCI), y) |
| | | EXTRA_CFLAGS += -DCONFIG_RTW_SDIO_PM_KEEP_POWER |
| | | endif |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PNO_SUPPORT), y) |
| | | EXTRA_CFLAGS += -DCONFIG_PNO_SUPPORT |
| | | ifeq ($(CONFIG_PNO_SET_DEBUG), y) |
| | | EXTRA_CFLAGS += -DCONFIG_PNO_SET_DEBUG |
| | | endif |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_GPIO_WAKEUP), y) |
| | | EXTRA_CFLAGS += -DCONFIG_GPIO_WAKEUP |
| | | ifeq ($(CONFIG_HIGH_ACTIVE), y) |
| | | EXTRA_CFLAGS += -DHIGH_ACTIVE=1 |
| | | else |
| | | EXTRA_CFLAGS += -DHIGH_ACTIVE=0 |
| | | endif |
| | | endif |
| | | |
| | | ifneq ($(CONFIG_WAKEUP_GPIO_IDX), default) |
| | | EXTRA_CFLAGS += -DWAKEUP_GPIO_IDX=$(CONFIG_WAKEUP_GPIO_IDX) |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_RTW_SDIO_PM_KEEP_POWER), y) |
| | | ifeq ($(CONFIG_SDIO_HCI), y) |
| | | EXTRA_CFLAGS += -DCONFIG_RTW_SDIO_PM_KEEP_POWER |
| | | endif |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_REDUCE_TX_CPU_LOADING), y) |
| | | EXTRA_CFLAGS += -DCONFIG_REDUCE_TX_CPU_LOADING |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_BR_EXT), y) |
| | | BR_NAME = br0 |
| | | EXTRA_CFLAGS += -DCONFIG_BR_EXT |
| | | EXTRA_CFLAGS += '-DCONFIG_BR_EXT_BRNAME="'$(BR_NAME)'"' |
| | | endif |
| | | |
| | | |
| | | ifeq ($(CONFIG_TDLS), y) |
| | | EXTRA_CFLAGS += -DCONFIG_TDLS |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_WIFI_MONITOR), y) |
| | | EXTRA_CFLAGS += -DCONFIG_WIFI_MONITOR |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_MCC_MODE), y) |
| | | EXTRA_CFLAGS += -DCONFIG_MCC_MODE |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_RTW_NAPI), y) |
| | | EXTRA_CFLAGS += -DCONFIG_RTW_NAPI |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_RTW_GRO), y) |
| | | EXTRA_CFLAGS += -DCONFIG_RTW_GRO |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_MP_VHT_HW_TX_MODE), y) |
| | | EXTRA_CFLAGS += -DCONFIG_MP_VHT_HW_TX_MODE |
| | | ifeq ($(CONFIG_PLATFORM_I386_PC), y) |
| | | ## For I386 X86 ToolChain use Hardware FLOATING |
| | | EXTRA_CFLAGS += -mhard-float |
| | | else |
| | | ## For ARM ToolChain use Hardware FLOATING |
| | | EXTRA_CFLAGS += -mfloat-abi=hard |
| | | endif |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_APPEND_VENDOR_IE_ENABLE), y) |
| | | EXTRA_CFLAGS += -DCONFIG_APPEND_VENDOR_IE_ENABLE |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_RTW_DEBUG), y) |
| | | EXTRA_CFLAGS += -DCONFIG_RTW_DEBUG |
| | | EXTRA_CFLAGS += -DRTW_LOG_LEVEL=$(CONFIG_RTW_LOG_LEVEL) |
| | | endif |
| | | |
| | | EXTRA_CFLAGS += -DDM_ODM_SUPPORT_TYPE=0x04 |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_I386_PC), y) |
| | | EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN |
| | | EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT |
| | | SUBARCH := $(shell uname -m | sed -e s/i.86/i386/) |
| | | ARCH ?= $(SUBARCH) |
| | | CROSS_COMPILE ?= |
| | | KVER := $(shell uname -r) |
| | | KSRC := /lib/modules/$(KVER)/build |
| | | MODDESTDIR := /lib/modules/$(KVER)/kernel/drivers/net/wireless/ |
| | | INSTALL_PREFIX := |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_ARM_SAMA5D4), y) |
| | | EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN |
| | | EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT |
| | | ARCH := arm |
| | | CROSS_COMPILE := /opt/buildroot/cortex-a5/bin/arm-linux- |
| | | KVER := 4.9.151 |
| | | KSRC ?= ../../linux-at91/ |
| | | endif |
| | | |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_BCM2709), y) |
| | | EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN |
| | | EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT |
| | | ARCH ?= arm |
| | | CROSS_COMPILE ?= |
| | | KVER := $(shell uname -r) |
| | | KSRC := /lib/modules/$(KVER)/build |
| | | MODDESTDIR := /lib/modules/$(KVER)/kernel/drivers/net/wireless/ |
| | | INSTALL_PREFIX := |
| | | endif |
| | | ifeq ($(CONFIG_PLATFORM_NV_TK1), y) |
| | | EXTRA_CFLAGS += -DCONFIG_PLATFORM_NV_TK1 |
| | | EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN |
| | | EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT |
| | | EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE |
| | | ARCH ?= arm |
| | | CROSS_COMPILE ?= |
| | | KVER := $(shell uname -r) |
| | | KSRC := /lib/modules/$(KVER)/build |
| | | MODDESTDIR := /lib/modules/$(KVER)/kernel/drivers/net/wireless/ |
| | | INSTALL_PREFIX := |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_ACTIONS_ATM702X), y) |
| | | EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_ANDROID -DCONFIG_PLATFORM_ACTIONS_ATM702X |
| | | #ARCH := arm |
| | | ARCH := $(R_ARCH) |
| | | #CROSS_COMPILE := arm-none-linux-gnueabi- |
| | | CROSS_COMPILE := $(R_CROSS_COMPILE) |
| | | KVER:= 3.4.0 |
| | | #KSRC := ../../../../build/out/kernel |
| | | KSRC := $(KERNEL_BUILD_PATH) |
| | | MODULE_NAME :=wlan |
| | | endif |
| | | |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_ACTIONS_ATM705X), y) |
| | | EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN |
| | | #EXTRA_CFLAGS += -DRTW_ENABLE_WIFI_CONTROL_FUNC |
| | | # default setting for Android 4.1, 4.2, 4.3, 4.4 |
| | | EXTRA_CFLAGS += -DCONFIG_PLATFORM_ACTIONS_ATM705X |
| | | EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE |
| | | EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT |
| | | |
| | | # Enable this for Android 5.0 |
| | | EXTRA_CFLAGS += -DCONFIG_RADIO_WORK |
| | | |
| | | ifeq ($(CONFIG_SDIO_HCI), y) |
| | | EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS |
| | | _PLATFORM_FILES += platform/platform_arm_act_sdio.o |
| | | endif |
| | | |
| | | ARCH := arm |
| | | CROSS_COMPILE := /opt/arm-2011.09/bin/arm-none-linux-gnueabi- |
| | | KSRC := /home/android_sdk/Action-semi/705a_android_L/android/kernel |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_ARM_SUN50IW1P1), y) |
| | | EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN |
| | | EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUN50IW1P1 |
| | | EXTRA_CFLAGS += -DCONFIG_TRAFFIC_PROTECT |
| | | # default setting for Android 4.1, 4.2 |
| | | EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE |
| | | EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT |
| | | EXTRA_CFLAGS += -DCONFIG_RESUME_IN_WORKQUEUE |
| | | EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS |
| | | |
| | | # Enable this for Android 5.0 |
| | | EXTRA_CFLAGS += -DCONFIG_RADIO_WORK |
| | | |
| | | ifeq ($(CONFIG_USB_HCI), y) |
| | | EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX |
| | | _PLATFORM_FILES += platform/platform_ARM_SUNxI_usb.o |
| | | endif |
| | | ifeq ($(CONFIG_SDIO_HCI), y) |
| | | _PLATFORM_FILES += platform/platform_ARM_SUN50IW1P1_sdio.o |
| | | endif |
| | | |
| | | ARCH := arm64 |
| | | # ===Cross compile setting for Android 5.1(64) SDK === |
| | | CROSS_COMPILE := /home/android_sdk/Allwinner/a64/android-51/lichee/out/sun50iw1p1/android/common/buildroot/external-toolchain/bin/aarch64-linux-gnu- |
| | | KSRC :=/home/android_sdk/Allwinner/a64/android-51/lichee/linux-3.10/ |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_TI_AM3517), y) |
| | | EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_ANDROID -DCONFIG_PLATFORM_SHUTTLE |
| | | CROSS_COMPILE := arm-eabi- |
| | | KSRC := $(shell pwd)/../../../Android/kernel |
| | | ARCH := arm |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_MSTAR_TITANIA12), y) |
| | | EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_MSTAR -DCONFIG_PLATFORM_MSTAR_TITANIA12 |
| | | ARCH:=mips |
| | | CROSS_COMPILE:= /usr/src/Mstar_kernel/mips-4.3/bin/mips-linux-gnu- |
| | | KVER:= 2.6.28.9 |
| | | KSRC:= /usr/src/Mstar_kernel/2.6.28.9/ |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_MSTAR), y) |
| | | EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE |
| | | EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT |
| | | EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_MSTAR -DCONFIG_USE_USB_BUFFER_ALLOC_TX -DCONFIG_FIX_NR_BULKIN_BUFFER |
| | | EXTRA_CFLAGS += -DCONFIG_PLATFORM_MSTAR_HIGH |
| | | ARCH:=arm |
| | | CROSS_COMPILE:= /usr/src/bin/arm-none-linux-gnueabi- |
| | | KVER:= 3.1.10 |
| | | KSRC:= /usr/src/Mstar_kernel/3.1.10/ |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_ANDROID_X86), y) |
| | | EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN |
| | | SUBARCH := $(shell uname -m | sed -e s/i.86/i386/) |
| | | ARCH := $(SUBARCH) |
| | | CROSS_COMPILE := /media/DATA-2/android-x86/ics-x86_20120130/prebuilt/linux-x86/toolchain/i686-unknown-linux-gnu-4.2.1/bin/i686-unknown-linux-gnu- |
| | | KSRC := /media/DATA-2/android-x86/ics-x86_20120130/out/target/product/generic_x86/obj/kernel |
| | | MODULE_NAME :=wlan |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_ANDROID_X86_N70), y) |
| | | EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN |
| | | EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE |
| | | EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT |
| | | EXTRA_CFLAGS += -DCONFIG_RADIO_WORK |
| | | EXTRA_CFLAGS += -DCONFIG_PLATFORM_ANDROID |
| | | ARCH := x86 |
| | | #CROSS_COMPILE := /work/android-x86/android-x86/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7/bin/i686-linux-android- |
| | | CROSS_COMPILE := /home/work/android-N/prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/bin/x86_64-linux-android- |
| | | #CROSS_COMPILE := /work/78/android-x86/prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/bin/x86_64-linux-android- |
| | | KSRC := /home/work/android-N/out/target/product/x86/obj/kernel/ |
| | | #KSRC := /work/78/android-x86/out/target/product/x86/obj/kernel/ |
| | | MODULE_NAME :=wlan-8188ee |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_ANDROID_INTEL_X86), y) |
| | | EXTRA_CFLAGS += -DCONFIG_PLATFORM_ANDROID_INTEL_X86 |
| | | EXTRA_CFLAGS += -DCONFIG_PLATFORM_INTEL_BYT |
| | | EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_ANDROID |
| | | EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE |
| | | EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT |
| | | EXTRA_CFLAGS += -DCONFIG_SKIP_SIGNAL_SCALE_MAPPING |
| | | ifeq ($(CONFIG_SDIO_HCI), y) |
| | | EXTRA_CFLAGS += -DCONFIG_RESUME_IN_WORKQUEUE |
| | | endif |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_JB_X86), y) |
| | | EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN |
| | | EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE |
| | | EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT |
| | | SUBARCH := $(shell uname -m | sed -e s/i.86/i386/) |
| | | ARCH := $(SUBARCH) |
| | | CROSS_COMPILE := /home/android_sdk/android-x86_JB/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7/bin/i686-linux-android- |
| | | KSRC := /home/android_sdk/android-x86_JB/out/target/product/x86/obj/kernel/ |
| | | MODULE_NAME :=wlan |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_ARM_PXA2XX), y) |
| | | EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN |
| | | ARCH := arm |
| | | CROSS_COMPILE := arm-none-linux-gnueabi- |
| | | KVER := 2.6.34.1 |
| | | KSRC ?= /usr/src/linux-2.6.34.1 |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_ARM_S3C2K4), y) |
| | | EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN |
| | | ARCH := arm |
| | | CROSS_COMPILE := arm-linux- |
| | | KVER := 2.6.24.7_$(ARCH) |
| | | KSRC := /usr/src/kernels/linux-$(KVER) |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_ARM_S3C6K4), y) |
| | | EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN |
| | | ARCH := arm |
| | | CROSS_COMPILE := arm-none-linux-gnueabi- |
| | | KVER := 2.6.34.1 |
| | | KSRC ?= /usr/src/linux-2.6.34.1 |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_RTD2880B), y) |
| | | EXTRA_CFLAGS += -DCONFIG_BIG_ENDIAN -DCONFIG_PLATFORM_RTD2880B |
| | | ARCH:= |
| | | CROSS_COMPILE:= |
| | | KVER:= |
| | | KSRC:= |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_MIPS_RMI), y) |
| | | EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN |
| | | ARCH:=mips |
| | | CROSS_COMPILE:=mipsisa32r2-uclibc- |
| | | KVER:= |
| | | KSRC:= /root/work/kernel_realtek |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_MIPS_PLM), y) |
| | | EXTRA_CFLAGS += -DCONFIG_BIG_ENDIAN |
| | | ARCH:=mips |
| | | CROSS_COMPILE:=mipsisa32r2-uclibc- |
| | | KVER:= |
| | | KSRC:= /root/work/kernel_realtek |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_MSTAR389), y) |
| | | EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_MSTAR389 |
| | | ARCH:=mips |
| | | CROSS_COMPILE:= mips-linux-gnu- |
| | | KVER:= 2.6.28.10 |
| | | KSRC:= /home/mstar/mstar_linux/2.6.28.9/ |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_MIPS_AR9132), y) |
| | | EXTRA_CFLAGS += -DCONFIG_BIG_ENDIAN |
| | | ARCH := mips |
| | | CROSS_COMPILE := mips-openwrt-linux- |
| | | KSRC := /home/alex/test_openwrt/tmp/linux-2.6.30.9 |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_DMP_PHILIPS), y) |
| | | EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DRTK_DMP_PLATFORM |
| | | ARCH := mips |
| | | #CROSS_COMPILE:=/usr/local/msdk-4.3.6-mips-EL-2.6.12.6-0.9.30.3/bin/mipsel-linux- |
| | | CROSS_COMPILE:=/usr/local/toolchain_mipsel/bin/mipsel-linux- |
| | | KSRC ?=/usr/local/Jupiter/linux-2.6.12 |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_RTK_DMP), y) |
| | | EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DRTK_DMP_PLATFORM -DCONFIG_WIRELESS_EXT |
| | | EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS |
| | | ifeq ($(CONFIG_USB_HCI), y) |
| | | _PLATFORM_FILES += platform/platform_RTK_DMP_usb.o |
| | | endif |
| | | ARCH:=mips |
| | | CROSS_COMPILE:=mipsel-linux- |
| | | KVER:= |
| | | KSRC ?= /usr/src/DMP_Kernel/jupiter/linux-2.6.12 |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_MT53XX), y) |
| | | EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_MT53XX |
| | | ARCH:= arm |
| | | CROSS_COMPILE:= arm11_mtk_le- |
| | | KVER:= 2.6.27 |
| | | KSRC?= /proj/mtk00802/BD_Compare/BDP/Dev/BDP_V301/BDP_Linux/linux-2.6.27 |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_ARM_MX51_241H), y) |
| | | EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_WISTRON_PLATFORM |
| | | ARCH := arm |
| | | CROSS_COMPILE := /opt/freescale/usr/local/gcc-4.1.2-glibc-2.5-nptl-3/arm-none-linux-gnueabi/bin/arm-none-linux-gnueabi- |
| | | KVER := 2.6.31 |
| | | KSRC ?= /lib/modules/2.6.31-770-g0e46b52/source |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_FS_MX61), y) |
| | | EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN |
| | | ARCH := arm |
| | | CROSS_COMPILE := /home/share/CusEnv/FreeScale/arm-eabi-4.4.3/bin/arm-eabi- |
| | | KSRC ?= /home/share/CusEnv/FreeScale/FS_kernel_env |
| | | endif |
| | | |
| | | |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_ACTIONS_ATJ227X), y) |
| | | EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_ACTIONS_ATJ227X |
| | | ARCH := mips |
| | | CROSS_COMPILE := /home/cnsd4/project/actions/tools-2.6.27/bin/mipsel-linux-gnu- |
| | | KVER := 2.6.27 |
| | | KSRC := /home/cnsd4/project/actions/linux-2.6.27.28 |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_TI_DM365), y) |
| | | EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_TI_DM365 |
| | | EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_RX |
| | | EXTRA_CFLAGS += -DCONFIG_SINGLE_XMIT_BUF -DCONFIG_SINGLE_RECV_BUF |
| | | ARCH := arm |
| | | #CROSS_COMPILE := /home/cnsd4/Appro/mv_pro_5.0/montavista/pro/devkit/arm/v5t_le/bin/arm_v5t_le- |
| | | #KSRC := /home/cnsd4/Appro/mv_pro_5.0/montavista/pro/devkit/lsp/ti-davinci/linux-dm365 |
| | | CROSS_COMPILE := /opt/montavista/pro5.0/devkit/arm/v5t_le/bin/arm-linux- |
| | | KSRC:= /home/vivotek/lsp/DM365/kernel_platform/kernel/linux-2.6.18 |
| | | KERNELOUTPUT := ${PRODUCTDIR}/tmp |
| | | KVER := 2.6.18 |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_MOZART), y) |
| | | EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_MOZART |
| | | ARCH := arm |
| | | CROSS_COMPILE := /home/vivotek/lsp/mozart3v2/Mozart3e_Toolchain/build_arm_nofpu/usr/bin/arm-linux- |
| | | KVER := $(shell uname -r) |
| | | KSRC:= /opt/Vivotek/lsp/mozart3v2/kernel_platform/kernel/mozart_kernel-1.17 |
| | | KERNELOUTPUT := /home/pink/sample/ODM/IP8136W-VINT/tmp/kernel |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_TEGRA3_CARDHU), y) |
| | | EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN |
| | | # default setting for Android 4.1, 4.2 |
| | | EXTRA_CFLAGS += -DRTW_ENABLE_WIFI_CONTROL_FUNC |
| | | EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE |
| | | EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT |
| | | ARCH := arm |
| | | CROSS_COMPILE := /home/android_sdk/nvidia/tegra-16r3-partner-android-4.1_20120723/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi- |
| | | KSRC := /home/android_sdk/nvidia/tegra-16r3-partner-android-4.1_20120723/out/target/product/cardhu/obj/KERNEL |
| | | MODULE_NAME := wlan |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_TEGRA4_DALMORE), y) |
| | | EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN |
| | | # default setting for Android 4.1, 4.2 |
| | | EXTRA_CFLAGS += -DRTW_ENABLE_WIFI_CONTROL_FUNC |
| | | EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE |
| | | EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT |
| | | ARCH := arm |
| | | CROSS_COMPILE := /home/android_sdk/nvidia/tegra-17r9-partner-android-4.2-dalmore_20130131/prebuilts/gcc/linux-x86/arm/arm-eabi-4.6/bin/arm-eabi- |
| | | KSRC := /home/android_sdk/nvidia/tegra-17r9-partner-android-4.2-dalmore_20130131/out/target/product/dalmore/obj/KERNEL |
| | | MODULE_NAME := wlan |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_ARM_TCC8900), y) |
| | | EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN |
| | | ARCH := arm |
| | | CROSS_COMPILE := /home/android_sdk/Telechips/SDK_2304_20110613/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi- |
| | | KSRC := /home/android_sdk/Telechips/SDK_2304_20110613/kernel |
| | | MODULE_NAME := wlan |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_ARM_TCC8920), y) |
| | | EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN |
| | | ARCH := arm |
| | | CROSS_COMPILE := /home/android_sdk/Telechips/v12.06_r1-tcc-android-4.0.4/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi- |
| | | KSRC := /home/android_sdk/Telechips/v12.06_r1-tcc-android-4.0.4/kernel |
| | | MODULE_NAME := wlan |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_ARM_TCC8920_JB42), y) |
| | | EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN |
| | | # default setting for Android 4.1, 4.2 |
| | | EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE |
| | | EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT |
| | | ARCH := arm |
| | | CROSS_COMPILE := /home/android_sdk/Telechips/v13.03_r1-tcc-android-4.2.2_ds_patched/prebuilts/gcc/linux-x86/arm/arm-eabi-4.6/bin/arm-eabi- |
| | | KSRC := /home/android_sdk/Telechips/v13.03_r1-tcc-android-4.2.2_ds_patched/kernel |
| | | MODULE_NAME := wlan |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_ARM_RK2818), y) |
| | | EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_ANDROID -DCONFIG_PLATFORM_ROCKCHIPS |
| | | ARCH := arm |
| | | CROSS_COMPILE := /usr/src/release_fae_version/toolchain/arm-eabi-4.4.0/bin/arm-eabi- |
| | | KSRC := /usr/src/release_fae_version/kernel25_A7_281x |
| | | MODULE_NAME := wlan |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_ARM_RK3188), y) |
| | | EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_ANDROID -DCONFIG_PLATFORM_ROCKCHIPS |
| | | # default setting for Android 4.1, 4.2, 4.3, 4.4 |
| | | EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT |
| | | EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE |
| | | # default setting for Power control |
| | | EXTRA_CFLAGS += -DRTW_ENABLE_WIFI_CONTROL_FUNC |
| | | EXTRA_CFLAGS += -DRTW_SUPPORT_PLATFORM_SHUTDOWN |
| | | # default setting for Special function |
| | | ARCH := arm |
| | | CROSS_COMPILE := /home/android_sdk/Rockchip/Rk3188/prebuilts/gcc/linux-x86/arm/arm-eabi-4.6/bin/arm-eabi- |
| | | KSRC := /home/android_sdk/Rockchip/Rk3188/kernel |
| | | MODULE_NAME := wlan |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_ARM_RK3066), y) |
| | | EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_RK3066 |
| | | EXTRA_CFLAGS += -DRTW_ENABLE_WIFI_CONTROL_FUNC |
| | | EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN |
| | | EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE |
| | | EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 |
| | | ifeq ($(CONFIG_SDIO_HCI), y) |
| | | EXTRA_CFLAGS += -DRTW_SUPPORT_PLATFORM_SHUTDOWN |
| | | endif |
| | | EXTRA_CFLAGS += -fno-pic |
| | | ARCH := arm |
| | | CROSS_COMPILE := /home/android_sdk/Rockchip/rk3066_20130607/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.6/bin/arm-linux-androideabi- |
| | | #CROSS_COMPILE := /home/android_sdk/Rockchip/Rk3066sdk/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.6/bin/arm-linux-androideabi- |
| | | KSRC := /home/android_sdk/Rockchip/Rk3066sdk/kernel |
| | | MODULE_NAME :=wlan |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_ARM_URBETTER), y) |
| | | EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN #-DCONFIG_MINIMAL_MEMORY_USAGE |
| | | ARCH := arm |
| | | CROSS_COMPILE := /media/DATA-1/urbetter/arm-2009q3/bin/arm-none-linux-gnueabi- |
| | | KSRC := /media/DATA-1/urbetter/ics-urbetter/kernel |
| | | MODULE_NAME := wlan |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_ARM_TI_PANDA), y) |
| | | EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN #-DCONFIG_MINIMAL_MEMORY_USAGE |
| | | ARCH := arm |
| | | #CROSS_COMPILE := /media/DATA-1/aosp/ics-aosp_20111227/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi- |
| | | #KSRC := /media/DATA-1/aosp/android-omap-panda-3.0_20120104 |
| | | CROSS_COMPILE := /media/DATA-1/android-4.0/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi- |
| | | KSRC := /media/DATA-1/android-4.0/panda_kernel/omap |
| | | MODULE_NAME := wlan |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_MIPS_JZ4760), y) |
| | | EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_MINIMAL_MEMORY_USAGE |
| | | ARCH ?= mips |
| | | CROSS_COMPILE ?= /mnt/sdb5/Ingenic/Umido/mips-4.3/bin/mips-linux-gnu- |
| | | KSRC ?= /mnt/sdb5/Ingenic/Umido/kernel |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_SZEBOOK), y) |
| | | EXTRA_CFLAGS += -DCONFIG_BIG_ENDIAN |
| | | ARCH:=arm |
| | | CROSS_COMPILE:=/opt/crosstool2/bin/armeb-unknown-linux-gnueabi- |
| | | KVER:= 2.6.31.6 |
| | | KSRC:= ../code/linux-2.6.31.6-2020/ |
| | | endif |
| | | |
| | | #Add setting for MN10300 |
| | | ifeq ($(CONFIG_PLATFORM_MN10300), y) |
| | | EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_MN10300 |
| | | ARCH := mn10300 |
| | | CROSS_COMPILE := mn10300-linux- |
| | | KVER := 2.6.32.2 |
| | | KSRC := /home/winuser/work/Plat_sLD2T_V3010/usr/src/linux-2.6.32.2 |
| | | INSTALL_PREFIX := |
| | | endif |
| | | |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_ARM_SUNxI), y) |
| | | EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN |
| | | EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUNxI |
| | | # default setting for Android 4.1, 4.2 |
| | | EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE |
| | | EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT |
| | | |
| | | EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS |
| | | ifeq ($(CONFIG_USB_HCI), y) |
| | | EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX |
| | | _PLATFORM_FILES += platform/platform_ARM_SUNxI_usb.o |
| | | endif |
| | | ifeq ($(CONFIG_SDIO_HCI), y) |
| | | # default setting for A10-EVB mmc0 |
| | | #EXTRA_CFLAGS += -DCONFIG_WITS_EVB_V13 |
| | | _PLATFORM_FILES += platform/platform_ARM_SUNxI_sdio.o |
| | | endif |
| | | |
| | | ARCH := arm |
| | | #CROSS_COMPILE := arm-none-linux-gnueabi- |
| | | CROSS_COMPILE=/home/android_sdk/Allwinner/a10/android-jb42/lichee-jb42/buildroot/output/external-toolchain/bin/arm-none-linux-gnueabi- |
| | | KVER := 3.0.8 |
| | | #KSRC:= ../lichee/linux-3.0/ |
| | | KSRC=/home/android_sdk/Allwinner/a10/android-jb42/lichee-jb42/linux-3.0 |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_ARM_SUN6I), y) |
| | | EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN |
| | | EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUN6I |
| | | EXTRA_CFLAGS += -DCONFIG_TRAFFIC_PROTECT |
| | | # default setting for Android 4.1, 4.2, 4.3, 4.4 |
| | | EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE |
| | | EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT |
| | | EXTRA_CFLAGS += -DCONFIG_QOS_OPTIMIZATION |
| | | |
| | | EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS |
| | | ifeq ($(CONFIG_USB_HCI), y) |
| | | EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX |
| | | _PLATFORM_FILES += platform/platform_ARM_SUNxI_usb.o |
| | | endif |
| | | ifeq ($(CONFIG_SDIO_HCI), y) |
| | | # default setting for A31-EVB mmc0 |
| | | EXTRA_CFLAGS += -DCONFIG_A31_EVB |
| | | _PLATFORM_FILES += platform/platform_ARM_SUNnI_sdio.o |
| | | endif |
| | | |
| | | ARCH := arm |
| | | #Android-JB42 |
| | | #CROSS_COMPILE := /home/android_sdk/Allwinner/a31/android-jb42/lichee/buildroot/output/external-toolchain/bin/arm-linux-gnueabi- |
| | | #KSRC :=/home/android_sdk/Allwinner/a31/android-jb42/lichee/linux-3.3 |
| | | #ifeq ($(CONFIG_USB_HCI), y) |
| | | #MODULE_NAME := 8188eu_sw |
| | | #endif |
| | | # ==== Cross compile setting for kitkat-a3x_v4.5 ===== |
| | | CROSS_COMPILE := /home/android_sdk/Allwinner/a31/kitkat-a3x_v4.5/lichee/buildroot/output/external-toolchain/bin/arm-linux-gnueabi- |
| | | KSRC :=/home/android_sdk/Allwinner/a31/kitkat-a3x_v4.5/lichee/linux-3.3 |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_ARM_SUN7I), y) |
| | | EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN |
| | | EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUN7I |
| | | EXTRA_CFLAGS += -DCONFIG_TRAFFIC_PROTECT |
| | | # default setting for Android 4.1, 4.2, 4.3, 4.4 |
| | | EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE |
| | | EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT |
| | | EXTRA_CFLAGS += -DCONFIG_QOS_OPTIMIZATION |
| | | |
| | | EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS |
| | | ifeq ($(CONFIG_USB_HCI), y) |
| | | EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX |
| | | _PLATFORM_FILES += platform/platform_ARM_SUNxI_usb.o |
| | | endif |
| | | ifeq ($(CONFIG_SDIO_HCI), y) |
| | | _PLATFORM_FILES += platform/platform_ARM_SUNnI_sdio.o |
| | | endif |
| | | |
| | | ARCH := arm |
| | | # ===Cross compile setting for Android 4.2 SDK === |
| | | #CROSS_COMPILE := /home/android_sdk/Allwinner/a20_evb/lichee/out/android/common/buildroot/external-toolchain/bin/arm-linux-gnueabi- |
| | | #KSRC := /home/android_sdk/Allwinner/a20_evb/lichee/linux-3.3 |
| | | # ==== Cross compile setting for Android 4.3 SDK ===== |
| | | #CROSS_COMPILE := /home/android_sdk/Allwinner/a20/android-jb43/lichee/out/android/common/buildroot/external-toolchain/bin/arm-linux-gnueabi- |
| | | #KSRC := /home/android_sdk/Allwinner/a20/android-jb43/lichee/linux-3.4 |
| | | # ==== Cross compile setting for kitkat-a20_v4.4 ===== |
| | | CROSS_COMPILE := /home/android_sdk/Allwinner/a20/kitkat-a20_v4.4/lichee/out/android/common/buildroot/external-toolchain/bin/arm-linux-gnueabi- |
| | | KSRC := /home/android_sdk/Allwinner/a20/kitkat-a20_v4.4/lichee/linux-3.4 |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_ARM_SUN8I_W3P1), y) |
| | | EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN |
| | | EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUN8I |
| | | EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUN8I_W3P1 |
| | | EXTRA_CFLAGS += -DCONFIG_TRAFFIC_PROTECT |
| | | # default setting for Android 4.1, 4.2 |
| | | EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE |
| | | EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT |
| | | |
| | | EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS |
| | | ifeq ($(CONFIG_USB_HCI), y) |
| | | EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX |
| | | _PLATFORM_FILES += platform/platform_ARM_SUNxI_usb.o |
| | | endif |
| | | ifeq ($(CONFIG_SDIO_HCI), y) |
| | | _PLATFORM_FILES += platform/platform_ARM_SUNnI_sdio.o |
| | | endif |
| | | |
| | | ARCH := arm |
| | | # ===Cross compile setting for Android 4.2 SDK === |
| | | #CROSS_COMPILE := /home/android_sdk/Allwinner/a23/android-jb42/lichee/out/android/common/buildroot/external-toolchain/bin/arm-linux-gnueabi- |
| | | #KSRC :=/home/android_sdk/Allwinner/a23/android-jb42/lichee/linux-3.4 |
| | | # ===Cross compile setting for Android 4.4 SDK === |
| | | CROSS_COMPILE := /home/android_sdk/Allwinner/a23/android-kk44/lichee/out/android/common/buildroot/external-toolchain/bin/arm-linux-gnueabi- |
| | | KSRC :=/home/android_sdk/Allwinner/a23/android-kk44/lichee/linux-3.4 |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_ARM_SUN8I_W5P1), y) |
| | | EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN |
| | | EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUN8I |
| | | EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUN8I_W5P1 |
| | | EXTRA_CFLAGS += -DCONFIG_TRAFFIC_PROTECT |
| | | # default setting for Android 4.1, 4.2 |
| | | EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE |
| | | EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT |
| | | |
| | | # Enable this for Android 5.0 |
| | | EXTRA_CFLAGS += -DCONFIG_RADIO_WORK |
| | | |
| | | EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS |
| | | ifeq ($(CONFIG_USB_HCI), y) |
| | | EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX |
| | | _PLATFORM_FILES += platform/platform_ARM_SUNxI_usb.o |
| | | endif |
| | | ifeq ($(CONFIG_SDIO_HCI), y) |
| | | _PLATFORM_FILES += platform/platform_ARM_SUNnI_sdio.o |
| | | endif |
| | | |
| | | ARCH := arm |
| | | # ===Cross compile setting for Android L SDK === |
| | | CROSS_COMPILE := /home/android_sdk/Allwinner/a33/android-L/lichee/out/sun8iw5p1/android/common/buildroot/external-toolchain/bin/arm-linux-gnueabi- |
| | | KSRC :=/home/android_sdk/Allwinner/a33/android-L/lichee/linux-3.4 |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_ACTIONS_ATV5201), y) |
| | | EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_ACTIONS_ATV5201 |
| | | EXTRA_CFLAGS += -DCONFIG_SDIO_DISABLE_RXFIFO_POLLING_LOOP |
| | | ARCH := mips |
| | | CROSS_COMPILE := mipsel-linux-gnu- |
| | | KVER := $(KERNEL_VER) |
| | | KSRC:= $(CFGDIR)/../../kernel/linux-$(KERNEL_VER) |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_ARM_RTD299X), y) |
| | | EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN |
| | | EXTRA_CFLAGS += -DUSB_XMITBUF_ALIGN_SZ=1024 -DUSB_PACKET_OFFSET_SZ=0 |
| | | EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE |
| | | ifeq ($(CONFIG_ANDROID), y) |
| | | EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT |
| | | # Enable this for Android 5.0 |
| | | EXTRA_CFLAGS += -DCONFIG_RADIO_WORK |
| | | endif |
| | | #ARCH, CROSS_COMPILE, KSRC,and MODDESTDIR are provided by external makefile |
| | | INSTALL_PREFIX := |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_HISILICON), y) |
| | | EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_HISILICON |
| | | ifeq ($(SUPPORT_CONCURRENT),y) |
| | | EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE |
| | | endif |
| | | EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT |
| | | ARCH := arm |
| | | ifeq ($(CROSS_COMPILE),) |
| | | CROSS_COMPILE = arm-hisiv200-linux- |
| | | endif |
| | | MODULE_NAME := rtl8192eu |
| | | ifeq ($(KSRC),) |
| | | KSRC := ../../../../../../kernel/linux-3.4.y |
| | | endif |
| | | endif |
| | | |
| | | # Platform setting |
| | | ifeq ($(CONFIG_PLATFORM_ARM_SPREADTRUM_6820), y) |
| | | ifeq ($(CONFIG_ANDROID_2X), y) |
| | | EXTRA_CFLAGS += -DANDROID_2X |
| | | endif |
| | | EXTRA_CFLAGS += -DCONFIG_PLATFORM_SPRD |
| | | EXTRA_CFLAGS += -DPLATFORM_SPREADTRUM_6820 |
| | | EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN |
| | | ifeq ($(RTL871X), rtl8188e) |
| | | EXTRA_CFLAGS += -DSOFTAP_PS_DURATION=50 |
| | | endif |
| | | ifeq ($(CONFIG_SDIO_HCI), y) |
| | | EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS |
| | | _PLATFORM_FILES += platform/platform_sprd_sdio.o |
| | | endif |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_ARM_SPREADTRUM_8810), y) |
| | | ifeq ($(CONFIG_ANDROID_2X), y) |
| | | EXTRA_CFLAGS += -DANDROID_2X |
| | | endif |
| | | EXTRA_CFLAGS += -DCONFIG_PLATFORM_SPRD |
| | | EXTRA_CFLAGS += -DPLATFORM_SPREADTRUM_8810 |
| | | EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN |
| | | ifeq ($(RTL871X), rtl8188e) |
| | | EXTRA_CFLAGS += -DSOFTAP_PS_DURATION=50 |
| | | endif |
| | | ifeq ($(CONFIG_SDIO_HCI), y) |
| | | EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS |
| | | _PLATFORM_FILES += platform/platform_sprd_sdio.o |
| | | endif |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_ARM_WMT), y) |
| | | EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN |
| | | EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE |
| | | EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT |
| | | EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS |
| | | ifeq ($(CONFIG_SDIO_HCI), y) |
| | | _PLATFORM_FILES += platform/platform_ARM_WMT_sdio.o |
| | | endif |
| | | ARCH := arm |
| | | CROSS_COMPILE := /home/android_sdk/WonderMedia/wm8880-android4.4/toolchain/arm_201103_gcc4.5.2/mybin/arm_1103_le- |
| | | KSRC := /home/android_sdk/WonderMedia/wm8880-android4.4/kernel4.4/ |
| | | MODULE_NAME :=8189es_kk |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_RTK119X), y) |
| | | EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN |
| | | #EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUN7I |
| | | EXTRA_CFLAGS += -DCONFIG_TRAFFIC_PROTECT |
| | | # default setting for Android 4.1, 4.2 |
| | | EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE |
| | | EXTRA_CFLAGS += -DCONFIG_IFACE_NUMBER=3 |
| | | EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT |
| | | #EXTRA_CFLAGS += -DCONFIG_QOS_OPTIMIZATION |
| | | EXTRA_CFLAGS += -DCONFIG_QOS_OPTIMIZATION |
| | | |
| | | #EXTRA_CFLAGS += -DCONFIG_#PLATFORM_OPS |
| | | ifeq ($(CONFIG_USB_HCI), y) |
| | | EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX |
| | | #_PLATFORM_FILES += platform/platform_ARM_SUNxI_usb.o |
| | | endif |
| | | ifeq ($(CONFIG_SDIO_HCI), y) |
| | | _PLATFORM_FILES += platform/platform_ARM_SUNnI_sdio.o |
| | | endif |
| | | |
| | | ARCH := arm |
| | | |
| | | # ==== Cross compile setting for Android 4.4 SDK ===== |
| | | #CROSS_COMPILE := arm-linux-gnueabihf- |
| | | KVER := 3.10.24 |
| | | #KSRC :=/home/android_sdk/Allwinner/a20/android-kitkat44/lichee/linux-3.4 |
| | | CROSS_COMPILE := /home/realtek/software_phoenix/phoenix/toolchain/usr/local/arm-2013.11/bin/arm-linux-gnueabihf- |
| | | KSRC := /home/realtek/software_phoenix/linux-kernel |
| | | MODULE_NAME := 8192eu |
| | | |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_RTK129X), y) |
| | | EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN |
| | | EXTRA_CFLAGS += -DRTK_129X_PLATFORM |
| | | EXTRA_CFLAGS += -DCONFIG_TRAFFIC_PROTECT |
| | | # default setting for Android 4.1, 4.2 |
| | | #EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE |
| | | EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT |
| | | #EXTRA_CFLAGS += -DCONFIG_P2P_IPS -DCONFIG_QOS_OPTIMIZATION |
| | | EXTRA_CFLAGS += -DCONFIG_QOS_OPTIMIZATION |
| | | EXTRA_CFLAGS += -Wno-error=date-time |
| | | |
| | | # default setting for Android 7.0 |
| | | ifeq ($(RTK_ANDROID_VERSION), nougat) |
| | | EXTRA_CFLAGS += -DRTW_P2P_GROUP_INTERFACE=1 |
| | | endif |
| | | #EXTRA_CFLAGS += -DCONFIG_#PLATFORM_OPS |
| | | ifeq ($(CONFIG_USB_HCI), y) |
| | | EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX |
| | | #_PLATFORM_FILES += platform/platform_ARM_SUNxI_usb.o |
| | | endif |
| | | ifeq ($(CONFIG_SDIO_HCI), y) |
| | | _PLATFORM_FILES += platform/platform_ARM_SUNnI_sdio.o |
| | | endif |
| | | |
| | | ARCH := arm64 |
| | | |
| | | # ==== Cross compile setting for Android 4.4 SDK ===== |
| | | #CROSS_COMPILE := arm-linux-gnueabihf- |
| | | KVER := 4.1.10 |
| | | CROSS_COMPILE := $(CROSS) |
| | | KSRC := $(LINUX_KERNEL_PATH) |
| | | MODULE_NAME := 8822be |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_NOVATEK_NT72668), y) |
| | | EXTRA_CFLAGS += -DCONFIG_PLATFORM_NOVATEK_NT72668 |
| | | EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN |
| | | EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE |
| | | EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT |
| | | EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_RX |
| | | EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX |
| | | ARCH ?= arm |
| | | CROSS_COMPILE := arm-linux-gnueabihf- |
| | | KVER := 3.8.0 |
| | | KSRC := /Custom/Novatek/TCL/linux-3.8_header |
| | | #KSRC := $(KERNELDIR) |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PLATFORM_ARM_TCC8930_JB42), y) |
| | | EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN |
| | | # default setting for Android 4.1, 4.2 |
| | | EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE |
| | | EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT |
| | | ARCH := arm |
| | | CROSS_COMPILE := /home/android_sdk/Telechips/v13.05_r1-tcc-android-4.2.2_tcc893x-evm_build/prebuilts/gcc/linux-x86/arm/arm-eabi-4.6/bin/arm-eabi- |
| | | KSRC := /home/android_sdk/Telechips/v13.05_r1-tcc-android-4.2.2_tcc893x-evm_build/kernel |
| | | MODULE_NAME := wlan |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_MULTIDRV), y) |
| | | |
| | | ifeq ($(CONFIG_SDIO_HCI), y) |
| | | MODULE_NAME := rtw_sdio |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_USB_HCI), y) |
| | | MODULE_NAME := rtw_usb |
| | | endif |
| | | |
| | | ifeq ($(CONFIG_PCI_HCI), y) |
| | | MODULE_NAME := rtw_pci |
| | | endif |
| | | |
| | | |
| | | endif |
| | | |
| | | USER_MODULE_NAME ?= |
| | | ifneq ($(USER_MODULE_NAME),) |
| | | MODULE_NAME := $(USER_MODULE_NAME) |
| | | endif |
| | | |
| | | ifneq ($(KERNELRELEASE),) |
| | | |
| | | rtk_core := core/rtw_cmd.o \ |
| | | core/rtw_security.o \ |
| | | core/rtw_debug.o \ |
| | | core/rtw_io.o \ |
| | | core/rtw_ioctl_query.o \ |
| | | core/rtw_ioctl_set.o \ |
| | | core/rtw_ieee80211.o \ |
| | | core/rtw_mlme.o \ |
| | | core/rtw_mlme_ext.o \ |
| | | core/rtw_mi.o \ |
| | | core/rtw_wlan_util.o \ |
| | | core/rtw_vht.o \ |
| | | core/rtw_pwrctrl.o \ |
| | | core/rtw_rf.o \ |
| | | core/rtw_recv.o \ |
| | | core/rtw_sta_mgt.o \ |
| | | core/rtw_ap.o \ |
| | | core/rtw_xmit.o \ |
| | | core/rtw_p2p.o \ |
| | | core/rtw_tdls.o \ |
| | | core/rtw_br_ext.o \ |
| | | core/rtw_iol.o \ |
| | | core/rtw_sreset.o \ |
| | | core/rtw_btcoex_wifionly.o \ |
| | | core/rtw_btcoex.o \ |
| | | core/rtw_beamforming.o \ |
| | | core/rtw_odm.o \ |
| | | core/efuse/rtw_efuse.o |
| | | |
| | | ifeq ($(CONFIG_SDIO_HCI), y) |
| | | rtk_core += core/rtw_sdio.o |
| | | endif |
| | | |
| | | $(MODULE_NAME)-y += $(rtk_core) |
| | | |
| | | $(MODULE_NAME)-$(CONFIG_INTEL_WIDI) += core/rtw_intel_widi.o |
| | | |
| | | $(MODULE_NAME)-$(CONFIG_WAPI_SUPPORT) += core/rtw_wapi.o \ |
| | | core/rtw_wapi_sms4.o |
| | | |
| | | $(MODULE_NAME)-y += $(_OS_INTFS_FILES) |
| | | $(MODULE_NAME)-y += $(_HAL_INTFS_FILES) |
| | | $(MODULE_NAME)-y += $(_OUTSRC_FILES) |
| | | $(MODULE_NAME)-y += $(_PLATFORM_FILES) |
| | | |
| | | $(MODULE_NAME)-$(CONFIG_MP_INCLUDED) += core/rtw_mp.o |
| | | |
| | | ifeq ($(CONFIG_RTL8723B), y) |
| | | $(MODULE_NAME)-$(CONFIG_MP_INCLUDED)+= core/rtw_bt_mp.o |
| | | endif |
| | | |
| | | obj-$(CONFIG_RTL8188EU) := $(MODULE_NAME).o |
| | | |
| | | else |
| | | |
| | | export CONFIG_RTL8188EU = m |
| | | |
| | | all: modules |
| | | |
| | | modules: |
| | | $(MAKE) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) -C $(KSRC) M=$(shell pwd) modules |
| | | |
| | | strip: |
| | | $(CROSS_COMPILE)strip $(MODULE_NAME).ko --strip-unneeded |
| | | |
| | | install: |
| | | install -p -m 644 $(MODULE_NAME).ko $(MODDESTDIR) |
| | | /sbin/depmod -a ${KVER} |
| | | |
| | | uninstall: |
| | | rm -f $(MODDESTDIR)/$(MODULE_NAME).ko |
| | | /sbin/depmod -a ${KVER} |
| | | |
| | | config_r: |
| | | @echo "make config" |
| | | /bin/bash script/Configure script/config.in |
| | | |
| | | |
| | | .PHONY: modules clean |
| | | |
| | | clean: |
| | | #$(MAKE) -C $(KSRC) M=$(shell pwd) clean |
| | | cd hal ; rm -fr */*/*/*.mod.c */*/*/*.mod */*/*/*.o */*/*/.*.cmd */*/*/*.ko |
| | | cd hal ; rm -fr */*/*.mod.c */*/*.mod */*/*.o */*/.*.cmd */*/*.ko |
| | | cd hal ; rm -fr */*.mod.c */*.mod */*.o */.*.cmd */*.ko |
| | | cd hal ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko |
| | | cd core/efuse ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko |
| | | cd core ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko |
| | | cd os_dep/linux ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko |
| | | cd os_dep ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko |
| | | cd platform ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko |
| | | rm -fr Module.symvers ; rm -fr Module.markers ; rm -fr modules.order |
| | | rm -fr *.mod.c *.mod *.o .*.cmd *.ko *~ |
| | | rm -fr .tmp_versions .cache.mk |
| | | endif |
| | | |
New file |
| | |
| | | # Download |
| | | Downlink from https://github.com/quickreflex/rtl8188eus.git, 2019.08.19 |
| | | |
| | | # ChangeLog |
| | | 1, Remove unused files/scripts |
| | | 2, Update Makefile remove driver debug information "CONFIG_RTW_DEBUG = n" |
| | | 3, Update Makefile support SAMA5D4 compile |
| | | |
| | | |
| | | # rtl8188eus |
| | | Wifi driver support for rtl8188eu, rtl8188eus and rtl8188etv chips and working under the new linux kernel (5.1.x). |
| | | More information about your wifi device can be found here: https://wikidevi.com. |
| | | |
| | | Compiling & Building |
| | | --------- |
| | | ### Dependencies |
| | | To compile the driver, you need to have make and a compiler installed. In addition, |
| | | you must have the kernel headers installed. If you do not understand what this means, |
| | | consult your distro. if compile a new kernel, you will need to set two parameters |
| | | with make: KSRC=path_to_kernel_source and KVER=kernel_version. The same goes for installation. |
| | | |
| | | ### Download |
| | | ``` |
| | | git clone -b v5.2.2.4 https://github.com/quickreflex/rtl8188eus.git |
| | | cd rtl8188eu |
| | | ``` |
| | | |
| | | ### Compiling & Installing |
| | | ``` |
| | | make all |
| | | make install |
| | | ``` |
| | | |
| | | Or with DKMS |
| | | ``` |
| | | dkms add . |
| | | dkms build 8188eu/1.0 |
| | | dkms install 8188eu/1.0 |
| | | ``` |
| | | |
| | | Switch modes |
| | | --------- |
| | | ### Supported interface modes |
| | | ``` |
| | | * IBSS |
| | | * managed |
| | | * AP |
| | | * monitor |
| | | * P2P-client |
| | | * P2P-GO |
| | | ``` |
| | | ### For setting interface modes |
| | | ``` |
| | | ifconfig wlan0 down |
| | | iw dev wlan0 set type managed |
| | | ifconfig wlan0 up |
| | | ``` |
| | | ### For setting TX power |
| | | ``` |
| | | iw wlan0 set txpower fixed 1300 |
| | | ``` |
New file |
| | |
| | | /****************************************************************************** |
| | | * |
| | | * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. |
| | | * |
| | | * This program is free software; you can redistribute it and/or modify it |
| | | * under the terms of version 2 of the GNU General Public License as |
| | | * published by the Free Software Foundation. |
| | | * |
| | | * This program is distributed in the hope that it will be useful, but WITHOUT |
| | | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| | | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
| | | * more details. |
| | | * |
| | | * You should have received a copy of the GNU General Public License along with |
| | | * this program; if not, write to the Free Software Foundation, Inc., |
| | | * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA |
| | | * |
| | | * |
| | | ******************************************************************************/ |
| | | #define _RTW_EFUSE_C_ |
| | | |
| | | #include <drv_types.h> |
| | | #include <hal_data.h> |
| | | |
| | | #include "../hal/efuse/efuse_mask.h" |
| | | |
| | | /*------------------------Define local variable------------------------------*/ |
| | | u8 fakeEfuseBank = {0}; |
| | | u32 fakeEfuseUsedBytes = {0}; |
| | | u8 fakeEfuseContent[EFUSE_MAX_HW_SIZE] = {0}; |
| | | u8 fakeEfuseInitMap[EFUSE_MAX_MAP_LEN] = {0}; |
| | | u8 fakeEfuseModifiedMap[EFUSE_MAX_MAP_LEN] = {0}; |
| | | |
| | | u32 BTEfuseUsedBytes = {0}; |
| | | u8 BTEfuseContent[EFUSE_MAX_BT_BANK][EFUSE_MAX_HW_SIZE]; |
| | | u8 BTEfuseInitMap[EFUSE_BT_MAX_MAP_LEN] = {0}; |
| | | u8 BTEfuseModifiedMap[EFUSE_BT_MAX_MAP_LEN] = {0}; |
| | | |
| | | u32 fakeBTEfuseUsedBytes = {0}; |
| | | u8 fakeBTEfuseContent[EFUSE_MAX_BT_BANK][EFUSE_MAX_HW_SIZE]; |
| | | u8 fakeBTEfuseInitMap[EFUSE_BT_MAX_MAP_LEN] = {0}; |
| | | u8 fakeBTEfuseModifiedMap[EFUSE_BT_MAX_MAP_LEN] = {0}; |
| | | |
| | | u8 maskfileBuffer[64]; |
| | | /*------------------------Define local variable------------------------------*/ |
| | | BOOLEAN rtw_file_efuse_IsMasked(PADAPTER pAdapter, u16 Offset) |
| | | { |
| | | int r = Offset / 16; |
| | | int c = (Offset % 16) / 2; |
| | | int result = 0; |
| | | |
| | | if (pAdapter->registrypriv.boffefusemask) |
| | | return FALSE; |
| | | |
| | | if (c < 4) /* Upper double word */ |
| | | result = (maskfileBuffer[r] & (0x10 << c)); |
| | | else |
| | | result = (maskfileBuffer[r] & (0x01 << (c - 4))); |
| | | |
| | | return (result > 0) ? 0 : 1; |
| | | } |
| | | |
| | | BOOLEAN efuse_IsMasked(PADAPTER pAdapter, u16 Offset) |
| | | { |
| | | PHAL_DATA_TYPE pHalData = GET_HAL_DATA(pAdapter); |
| | | |
| | | if (pAdapter->registrypriv.boffefusemask) |
| | | return FALSE; |
| | | |
| | | #if DEV_BUS_TYPE == RT_USB_INTERFACE |
| | | #if defined(CONFIG_RTL8188E) |
| | | if (IS_HARDWARE_TYPE_8188E(pAdapter)) |
| | | return (IS_MASKED(8188E, _MUSB, Offset)) ? TRUE : FALSE; |
| | | #endif |
| | | #if defined(CONFIG_RTL8812A) |
| | | if (IS_HARDWARE_TYPE_8812(pAdapter)) |
| | | return (IS_MASKED(8812A, _MUSB, Offset)) ? TRUE : FALSE; |
| | | #endif |
| | | #if defined(CONFIG_RTL8821A) |
| | | #if 0 |
| | | if (IS_HARDWARE_TYPE_8811AU(pAdapter)) |
| | | return (IS_MASKED(8811A, _MUSB, Offset)) ? TRUE : FALSE; |
| | | #endif |
| | | if (IS_HARDWARE_TYPE_8821(pAdapter)) |
| | | return (IS_MASKED(8821A, _MUSB, Offset)) ? TRUE : FALSE; |
| | | #endif |
| | | #if defined(CONFIG_RTL8192E) |
| | | if (IS_HARDWARE_TYPE_8192E(pAdapter)) |
| | | return (IS_MASKED(8192E, _MUSB, Offset)) ? TRUE : FALSE; |
| | | #endif |
| | | #if defined(CONFIG_RTL8723B) |
| | | if (IS_HARDWARE_TYPE_8723B(pAdapter)) |
| | | return (IS_MASKED(8723B, _MUSB, Offset)) ? TRUE : FALSE; |
| | | #endif |
| | | #if defined(CONFIG_RTL8703B) |
| | | if (IS_HARDWARE_TYPE_8703B(pAdapter)) |
| | | return (IS_MASKED(8703B, _MUSB, Offset)) ? TRUE : FALSE; |
| | | #endif |
| | | #if defined(CONFIG_RTL8814A) |
| | | if (IS_HARDWARE_TYPE_8814A(pAdapter)) |
| | | return (IS_MASKED(8814A, _MUSB, Offset)) ? TRUE : FALSE; |
| | | #endif |
| | | #if defined(CONFIG_RTL8188F) |
| | | if (IS_HARDWARE_TYPE_8188F(pAdapter)) |
| | | return (IS_MASKED(8188F, _MUSB, Offset)) ? TRUE : FALSE; |
| | | #endif |
| | | #if defined(CONFIG_RTL8822B) |
| | | if (IS_HARDWARE_TYPE_8822B(pAdapter)) |
| | | return (IS_MASKED(8822B, _MUSB, Offset)) ? TRUE : FALSE; |
| | | #endif |
| | | #if defined(CONFIG_RTL8723D) |
| | | if (IS_HARDWARE_TYPE_8723D(pAdapter)) |
| | | return (IS_MASKED(8723D, _MUSB, Offset)) ? TRUE : FALSE; |
| | | #endif |
| | | |
| | | /*#if defined(CONFIG_RTL8821C) |
| | | if (IS_HARDWARE_TYPE_8821C(pAdapter)) |
| | | return (IS_MASKED(8821C,_MUSB,Offset)) ? TRUE : FALSE; |
| | | #endif*/ |
| | | |
| | | #elif DEV_BUS_TYPE == RT_PCI_INTERFACE |
| | | #if defined(CONFIG_RTL8188E) |
| | | if (IS_HARDWARE_TYPE_8188E(pAdapter)) |
| | | return (IS_MASKED(8188E, _MPCIE, Offset)) ? TRUE : FALSE; |
| | | #endif |
| | | #if defined(CONFIG_RTL8192E) |
| | | if (IS_HARDWARE_TYPE_8192E(pAdapter)) |
| | | return (IS_MASKED(8192E, _MPCIE, Offset)) ? TRUE : FALSE; |
| | | #endif |
| | | #if defined(CONFIG_RTL8812A) |
| | | if (IS_HARDWARE_TYPE_8812(pAdapter)) |
| | | return (IS_MASKED(8812A, _MPCIE, Offset)) ? TRUE : FALSE; |
| | | #endif |
| | | #if defined(CONFIG_RTL8821A) |
| | | if (IS_HARDWARE_TYPE_8821(pAdapter)) |
| | | return (IS_MASKED(8821A, _MPCIE, Offset)) ? TRUE : FALSE; |
| | | #endif |
| | | #if defined(CONFIG_RTL8723B) |
| | | if (IS_HARDWARE_TYPE_8723B(pAdapter)) |
| | | return (IS_MASKED(8723B, _MPCIE, Offset)) ? TRUE : FALSE; |
| | | #endif |
| | | #if defined(CONFIG_RTL8814A) |
| | | if (IS_HARDWARE_TYPE_8814A(pAdapter)) |
| | | return (IS_MASKED(8814A, _MPCIE, Offset)) ? TRUE : FALSE; |
| | | #endif |
| | | #if defined(CONFIG_RTL8822B) |
| | | if (IS_HARDWARE_TYPE_8822B(pAdapter)) |
| | | return (IS_MASKED(8822B, _MPCIE, Offset)) ? TRUE : FALSE; |
| | | #endif |
| | | |
| | | #elif DEV_BUS_TYPE == RT_SDIO_INTERFACE |
| | | #ifdef CONFIG_RTL8188E_SDIO |
| | | if (IS_HARDWARE_TYPE_8188E(pAdapter)) |
| | | return (IS_MASKED(8188E, _MSDIO, Offset)) ? TRUE : FALSE; |
| | | #endif |
| | | #ifdef CONFIG_RTL8188F_SDIO |
| | | if (IS_HARDWARE_TYPE_8188F(pAdapter)) |
| | | return (IS_MASKED(8188F, _MSDIO, Offset)) ? TRUE : FALSE; |
| | | #endif |
| | | #if defined(CONFIG_RTL8821C) |
| | | if (IS_HARDWARE_TYPE_8821C(pAdapter)) |
| | | return (IS_MASKED(8821C, _MSDIO, Offset)) ? TRUE : FALSE; |
| | | #endif |
| | | #if defined(CONFIG_RTL8822B) |
| | | if (IS_HARDWARE_TYPE_8822B(pAdapter)) |
| | | return (IS_MASKED(8822B, _MSDIO, Offset)) ? TRUE : FALSE; |
| | | #endif |
| | | #endif |
| | | |
| | | return FALSE; |
| | | } |
| | | |
| | | void rtw_efuse_mask_array(PADAPTER pAdapter, u8 *pArray) |
| | | { |
| | | PHAL_DATA_TYPE pHalData = GET_HAL_DATA(pAdapter); |
| | | |
| | | #if DEV_BUS_TYPE == RT_USB_INTERFACE |
| | | #if defined(CONFIG_RTL8188E) |
| | | if (IS_HARDWARE_TYPE_8188E(pAdapter)) |
| | | GET_MASK_ARRAY(8188E, _MUSB, pArray); |
| | | #endif |
| | | #if defined(CONFIG_RTL8812A) |
| | | if (IS_HARDWARE_TYPE_8812(pAdapter)) |
| | | GET_MASK_ARRAY(8812A, _MUSB, pArray); |
| | | #endif |
| | | #if defined(CONFIG_RTL8821A) |
| | | if (IS_HARDWARE_TYPE_8821(pAdapter)) |
| | | GET_MASK_ARRAY(8821A, _MUSB, pArray); |
| | | #endif |
| | | #if defined(CONFIG_RTL8192E) |
| | | if (IS_HARDWARE_TYPE_8192E(pAdapter)) |
| | | GET_MASK_ARRAY(8192E, _MUSB, pArray); |
| | | #endif |
| | | #if defined(CONFIG_RTL8723B) |
| | | if (IS_HARDWARE_TYPE_8723B(pAdapter)) |
| | | GET_MASK_ARRAY(8723B, _MUSB, pArray); |
| | | #endif |
| | | #if defined(CONFIG_RTL8703B) |
| | | if (IS_HARDWARE_TYPE_8703B(pAdapter)) |
| | | GET_MASK_ARRAY(8703B, _MUSB, pArray); |
| | | #endif |
| | | #if defined(CONFIG_RTL8188F) |
| | | if (IS_HARDWARE_TYPE_8188F(pAdapter)) |
| | | GET_MASK_ARRAY(8188F, _MUSB, pArray); |
| | | #endif |
| | | #if defined(CONFIG_RTL8814A) |
| | | if (IS_HARDWARE_TYPE_8814A(pAdapter)) |
| | | GET_MASK_ARRAY(8814A, _MUSB, pArray); |
| | | #endif |
| | | #if defined(CONFIG_RTL8822B) |
| | | if (IS_HARDWARE_TYPE_8822B(pAdapter)) |
| | | GET_MASK_ARRAY(8822B, _MUSB, pArray); |
| | | #endif |
| | | /*#if defined(CONFIG_RTL8821C) |
| | | if (IS_HARDWARE_TYPE_8821C(pAdapter)) |
| | | GET_MASK_ARRAY(8821C,_MUSB,pArray); |
| | | #endif*/ |
| | | #elif DEV_BUS_TYPE == RT_PCI_INTERFACE |
| | | #if defined(CONFIG_RTL8188E) |
| | | if (IS_HARDWARE_TYPE_8188E(pAdapter)) |
| | | GET_MASK_ARRAY(8188E, _MPCIE, pArray); |
| | | #endif |
| | | #if defined(CONFIG_RTL8192E) |
| | | if (IS_HARDWARE_TYPE_8192E(pAdapter)) |
| | | GET_MASK_ARRAY(8192E, _MPCIE, pArray); |
| | | #endif |
| | | #if defined(CONFIG_RTL8812A) |
| | | if (IS_HARDWARE_TYPE_8812(pAdapter)) |
| | | GET_MASK_ARRAY(8812A, _MPCIE, pArray); |
| | | #endif |
| | | #if defined(CONFIG_RTL8821A) |
| | | if (IS_HARDWARE_TYPE_8821(pAdapter)) |
| | | GET_MASK_ARRAY(8821A, _MPCIE, pArray); |
| | | #endif |
| | | #if defined(CONFIG_RTL8723B) |
| | | if (IS_HARDWARE_TYPE_8723B(pAdapter)) |
| | | GET_MASK_ARRAY(8723B, _MPCIE, pArray); |
| | | #endif |
| | | #if defined(CONFIG_RTL8814A) |
| | | if (IS_HARDWARE_TYPE_8814A(pAdapter)) |
| | | GET_MASK_ARRAY(8814A, _MPCIE, pArray); |
| | | #endif |
| | | #if defined(CONFIG_RTL8822B) |
| | | if (IS_HARDWARE_TYPE_8822B(pAdapter)) |
| | | GET_MASK_ARRAY(8822B, _MPCIE, pArray); |
| | | #endif |
| | | #elif DEV_BUS_TYPE == RT_SDIO_INTERFACE |
| | | #if defined(CONFIG_RTL8188E) |
| | | if (IS_HARDWARE_TYPE_8188E(pAdapter)) |
| | | GET_MASK_ARRAY(8188E, _MSDIO, pArray); |
| | | #endif |
| | | #if defined(CONFIG_RTL8188F) |
| | | if (IS_HARDWARE_TYPE_8188F(pAdapter)) |
| | | GET_MASK_ARRAY(8188F, _MSDIO, pArray); |
| | | #endif |
| | | #if defined(CONFIG_RTL8821C) |
| | | if (IS_HARDWARE_TYPE_8821C(pAdapter)) |
| | | GET_MASK_ARRAY(8821C , _MSDIO, pArray); |
| | | #endif |
| | | #if defined(CONFIG_RTL8822B) |
| | | if (IS_HARDWARE_TYPE_8822B(pAdapter)) |
| | | GET_MASK_ARRAY(8822B , _MSDIO, pArray); |
| | | #endif |
| | | #endif /*#elif DEV_BUS_TYPE == RT_SDIO_INTERFACE*/ |
| | | } |
| | | |
| | | u16 rtw_get_efuse_mask_arraylen(PADAPTER pAdapter) |
| | | { |
| | | HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); |
| | | |
| | | #if DEV_BUS_TYPE == RT_USB_INTERFACE |
| | | #if defined(CONFIG_RTL8188E) |
| | | if (IS_HARDWARE_TYPE_8188E(pAdapter)) |
| | | return GET_MASK_ARRAY_LEN(8188E, _MUSB); |
| | | #endif |
| | | #if defined(CONFIG_RTL8812A) |
| | | if (IS_HARDWARE_TYPE_8812(pAdapter)) |
| | | return GET_MASK_ARRAY_LEN(8812A, _MUSB); |
| | | #endif |
| | | #if defined(CONFIG_RTL8821A) |
| | | if (IS_HARDWARE_TYPE_8821(pAdapter)) |
| | | return GET_MASK_ARRAY_LEN(8821A, _MUSB); |
| | | #endif |
| | | #if defined(CONFIG_RTL8192E) |
| | | if (IS_HARDWARE_TYPE_8192E(pAdapter)) |
| | | return GET_MASK_ARRAY_LEN(8192E, _MUSB); |
| | | #endif |
| | | #if defined(CONFIG_RTL8723B) |
| | | if (IS_HARDWARE_TYPE_8723B(pAdapter)) |
| | | return GET_MASK_ARRAY_LEN(8723B, _MUSB); |
| | | #endif |
| | | #if defined(CONFIG_RTL8703B) |
| | | if (IS_HARDWARE_TYPE_8703B(pAdapter)) |
| | | return GET_MASK_ARRAY_LEN(8703B, _MUSB); |
| | | #endif |
| | | #if defined(CONFIG_RTL8188F) |
| | | if (IS_HARDWARE_TYPE_8188F(pAdapter)) |
| | | return GET_MASK_ARRAY_LEN(8188F, _MUSB); |
| | | #endif |
| | | #if defined(CONFIG_RTL8814A) |
| | | if (IS_HARDWARE_TYPE_8814A(pAdapter)) |
| | | return GET_MASK_ARRAY_LEN(8814A, _MUSB); |
| | | #endif |
| | | #if defined(CONFIG_RTL8822B) |
| | | if (IS_HARDWARE_TYPE_8822B(pAdapter)) |
| | | return GET_MASK_ARRAY_LEN(8822B, _MUSB); |
| | | #endif |
| | | /*#if defined(CONFIG_RTL8821C) |
| | | if (IS_HARDWARE_TYPE_8821C(pAdapter)) |
| | | return GET_MASK_ARRAY_LEN(8821C,_MUSB); |
| | | #endif*/ |
| | | #elif DEV_BUS_TYPE == RT_PCI_INTERFACE |
| | | #if defined(CONFIG_RTL8188E) |
| | | if (IS_HARDWARE_TYPE_8188E(pAdapter)) |
| | | return GET_MASK_ARRAY_LEN(8188E, _MPCIE); |
| | | #endif |
| | | #if defined(CONFIG_RTL8192E) |
| | | if (IS_HARDWARE_TYPE_8192E(pAdapter)) |
| | | return GET_MASK_ARRAY_LEN(8192E, _MPCIE); |
| | | #endif |
| | | #if defined(CONFIG_RTL8812A) |
| | | if (IS_HARDWARE_TYPE_8812(pAdapter)) |
| | | return GET_MASK_ARRAY_LEN(8812A, _MPCIE); |
| | | #endif |
| | | #if defined(CONFIG_RTL8821A) |
| | | if (IS_HARDWARE_TYPE_8821(pAdapter)) |
| | | return GET_MASK_ARRAY_LEN(8821A, _MPCIE); |
| | | #endif |
| | | #if defined(CONFIG_RTL8723B) |
| | | if (IS_HARDWARE_TYPE_8723B(pAdapter)) |
| | | return GET_MASK_ARRAY_LEN(8723B, _MPCIE); |
| | | #endif |
| | | #if defined(CONFIG_RTL8814A) |
| | | if (IS_HARDWARE_TYPE_8814A(pAdapter)) |
| | | return GET_MASK_ARRAY_LEN(8814A, _MPCIE); |
| | | #endif |
| | | #if defined(CONFIG_RTL8822B) |
| | | if (IS_HARDWARE_TYPE_8822B(pAdapter)) |
| | | return GET_MASK_ARRAY_LEN(8822B, _MPCIE); |
| | | #endif |
| | | #elif DEV_BUS_TYPE == RT_SDIO_INTERFACE |
| | | #if defined(CONFIG_RTL8188E) |
| | | if (IS_HARDWARE_TYPE_8188E(pAdapter)) |
| | | return GET_MASK_ARRAY_LEN(8188E, _MSDIO); |
| | | #endif |
| | | #if defined(CONFIG_RTL8188F) |
| | | if (IS_HARDWARE_TYPE_8188F(pAdapter)) |
| | | return GET_MASK_ARRAY_LEN(8188F, _MSDIO); |
| | | #endif |
| | | #if defined(CONFIG_RTL8821C) |
| | | if (IS_HARDWARE_TYPE_8821C(pAdapter)) |
| | | return GET_MASK_ARRAY_LEN(8821C, _MSDIO); |
| | | #endif |
| | | #if defined(CONFIG_RTL8822B) |
| | | if (IS_HARDWARE_TYPE_8822B(pAdapter)) |
| | | return GET_MASK_ARRAY_LEN(8822B, _MSDIO); |
| | | #endif |
| | | #endif |
| | | return 0; |
| | | } |
| | | |
| | | u8 rtw_efuse_mask_map_read(PADAPTER padapter, u16 addr, u16 cnts, u8 *data) |
| | | { |
| | | u8 ret = _SUCCESS; |
| | | u16 mapLen = 0, i = 0; |
| | | |
| | | EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (PVOID)&mapLen, _FALSE); |
| | | |
| | | ret = rtw_efuse_map_read(padapter, addr, cnts , data); |
| | | |
| | | if (padapter->registrypriv.boffefusemask == 0) { |
| | | |
| | | for (i = 0; i < cnts; i++) { |
| | | if (padapter->registrypriv.bFileMaskEfuse == _TRUE) { |
| | | if (rtw_file_efuse_IsMasked(padapter, addr + i)) /*use file efuse mask.*/ |
| | | data[i] = 0xff; |
| | | } else { |
| | | /*RTW_INFO(" %s , data[%d] = %x\n", __func__, i, data[i]);*/ |
| | | if (efuse_IsMasked(padapter, addr + i)) { |
| | | data[i] = 0xff; |
| | | /*RTW_INFO(" %s ,mask data[%d] = %x\n", __func__, i, data[i]);*/ |
| | | } |
| | | } |
| | | } |
| | | |
| | | } |
| | | return ret; |
| | | |
| | | } |
| | | |
| | | |
| | | #ifdef RTW_HALMAC |
| | | #include "../../hal/hal_halmac.h" |
| | | |
| | | void Efuse_PowerSwitch(PADAPTER adapter, u8 write, u8 pwrstate) |
| | | { |
| | | } |
| | | |
| | | void BTEfuse_PowerSwitch(PADAPTER adapter, u8 write, u8 pwrstate) |
| | | { |
| | | } |
| | | |
| | | u8 efuse_GetCurrentSize(PADAPTER adapter, u16 *size) |
| | | { |
| | | *size = 0; |
| | | |
| | | return _FAIL; |
| | | } |
| | | |
| | | u16 efuse_GetMaxSize(PADAPTER adapter) |
| | | { |
| | | struct dvobj_priv *d; |
| | | u32 size = 0; |
| | | int err; |
| | | |
| | | d = adapter_to_dvobj(adapter); |
| | | err = rtw_halmac_get_physical_efuse_size(d, &size); |
| | | if (err) |
| | | return 0; |
| | | |
| | | return size; |
| | | } |
| | | |
| | | u16 efuse_GetavailableSize(PADAPTER adapter) |
| | | { |
| | | struct dvobj_priv *d; |
| | | u32 size = 0; |
| | | int err; |
| | | |
| | | d = adapter_to_dvobj(adapter); |
| | | err = rtw_halmac_get_available_efuse_size(d, &size); |
| | | if (err) |
| | | return 0; |
| | | |
| | | return size; |
| | | } |
| | | |
| | | |
| | | u8 efuse_bt_GetCurrentSize(PADAPTER adapter, u16 *usesize) |
| | | { |
| | | u8 *efuse_map; |
| | | |
| | | *usesize = 0; |
| | | efuse_map = rtw_malloc(EFUSE_BT_MAP_LEN); |
| | | if (efuse_map == NULL) { |
| | | RTW_DBG("%s: malloc FAIL\n", __FUNCTION__); |
| | | return _FAIL; |
| | | } |
| | | |
| | | /* for get bt phy efuse last use byte */ |
| | | hal_ReadEFuse_BT_logic_map(adapter, 0x00, EFUSE_BT_MAP_LEN, efuse_map); |
| | | *usesize = fakeBTEfuseUsedBytes; |
| | | |
| | | if (efuse_map) |
| | | rtw_mfree(efuse_map, EFUSE_BT_MAP_LEN); |
| | | |
| | | return _SUCCESS; |
| | | } |
| | | |
| | | u16 efuse_bt_GetMaxSize(PADAPTER adapter) |
| | | { |
| | | return EFUSE_BT_REAL_CONTENT_LEN; |
| | | } |
| | | |
| | | void EFUSE_GetEfuseDefinition(PADAPTER adapter, u8 efusetype, u8 type, void *out, BOOLEAN test) |
| | | { |
| | | struct dvobj_priv *d; |
| | | u32 v32 = 0; |
| | | |
| | | |
| | | d = adapter_to_dvobj(adapter); |
| | | |
| | | if (adapter->hal_func.EFUSEGetEfuseDefinition) { |
| | | adapter->hal_func.EFUSEGetEfuseDefinition(adapter, efusetype, type, out, test); |
| | | return; |
| | | } |
| | | |
| | | if (EFUSE_WIFI == efusetype) { |
| | | switch (type) { |
| | | case TYPE_EFUSE_MAP_LEN: |
| | | rtw_halmac_get_logical_efuse_size(d, &v32); |
| | | *(u16 *)out = (u16)v32; |
| | | return; |
| | | |
| | | case TYPE_EFUSE_REAL_CONTENT_LEN: |
| | | rtw_halmac_get_physical_efuse_size(d, &v32); |
| | | *(u16 *)out = (u16)v32; |
| | | return; |
| | | } |
| | | } else if (EFUSE_BT == efusetype) { |
| | | switch (type) { |
| | | case TYPE_EFUSE_MAP_LEN: |
| | | *(u16 *)out = EFUSE_BT_MAP_LEN; |
| | | return; |
| | | |
| | | case TYPE_EFUSE_REAL_CONTENT_LEN: |
| | | *(u16 *)out = EFUSE_BT_REAL_CONTENT_LEN; |
| | | return; |
| | | } |
| | | } |
| | | } |
| | | |
| | | /* |
| | | * read/write raw efuse data |
| | | */ |
| | | u8 rtw_efuse_access(PADAPTER adapter, u8 write, u16 addr, u16 cnts, u8 *data) |
| | | { |
| | | struct dvobj_priv *d; |
| | | u8 *efuse = NULL; |
| | | u32 size, i; |
| | | int err; |
| | | |
| | | |
| | | d = adapter_to_dvobj(adapter); |
| | | err = rtw_halmac_get_physical_efuse_size(d, &size); |
| | | if (err) |
| | | size = EFUSE_MAX_SIZE; |
| | | |
| | | if ((addr + cnts) > size) |
| | | return _FAIL; |
| | | |
| | | if (_TRUE == write) { |
| | | err = rtw_halmac_write_physical_efuse(d, addr, cnts, data); |
| | | if (err) |
| | | return _FAIL; |
| | | } else { |
| | | if (cnts > 16) |
| | | efuse = rtw_zmalloc(size); |
| | | |
| | | if (efuse) { |
| | | err = rtw_halmac_read_physical_efuse_map(d, efuse, size); |
| | | if (err) { |
| | | rtw_mfree(efuse, size); |
| | | return _FAIL; |
| | | } |
| | | |
| | | _rtw_memcpy(data, efuse + addr, cnts); |
| | | rtw_mfree(efuse, size); |
| | | } else { |
| | | err = rtw_halmac_read_physical_efuse(d, addr, cnts, data); |
| | | if (err) |
| | | return _FAIL; |
| | | } |
| | | } |
| | | |
| | | return _SUCCESS; |
| | | } |
| | | |
| | | static inline void dump_buf(u8 *buf, u32 len) |
| | | { |
| | | u32 i; |
| | | |
| | | RTW_INFO("-----------------Len %d----------------\n", len); |
| | | for (i = 0; i < len; i++) |
| | | printk("%2.2x-", *(buf + i)); |
| | | printk("\n"); |
| | | } |
| | | |
| | | /* |
| | | * read/write raw efuse data |
| | | */ |
| | | u8 rtw_efuse_bt_access(PADAPTER adapter, u8 write, u16 addr, u16 cnts, u8 *data) |
| | | { |
| | | struct dvobj_priv *d; |
| | | u8 *efuse = NULL; |
| | | u32 size, i; |
| | | int err = _FAIL; |
| | | |
| | | |
| | | d = adapter_to_dvobj(adapter); |
| | | |
| | | size = EFUSE_BT_REAL_CONTENT_LEN; |
| | | |
| | | if ((addr + cnts) > size) |
| | | return _FAIL; |
| | | |
| | | if (_TRUE == write) { |
| | | err = rtw_halmac_write_bt_physical_efuse(d, addr, cnts, data); |
| | | if (err == -1) { |
| | | RTW_ERR("%s: rtw_halmac_write_bt_physical_efuse fail!\n", __FUNCTION__); |
| | | return _FAIL; |
| | | } |
| | | RTW_INFO("%s: rtw_halmac_write_bt_physical_efuse OK! data 0x%x\n", __FUNCTION__, *data); |
| | | } else { |
| | | efuse = rtw_zmalloc(size); |
| | | |
| | | if (efuse) { |
| | | err = rtw_halmac_read_bt_physical_efuse_map(d, efuse, size); |
| | | |
| | | if (err == -1) { |
| | | RTW_ERR("%s: rtw_halmac_read_bt_physical_efuse_map fail!\n", __FUNCTION__); |
| | | rtw_mfree(efuse, size); |
| | | return _FAIL; |
| | | } |
| | | dump_buf(efuse + addr, cnts); |
| | | |
| | | _rtw_memcpy(data, efuse + addr, cnts); |
| | | |
| | | RTW_INFO("%s: rtw_halmac_read_bt_physical_efuse_map ok! data 0x%x\n", __FUNCTION__, *data); |
| | | rtw_mfree(efuse, size); |
| | | } |
| | | } |
| | | |
| | | return _SUCCESS; |
| | | } |
| | | |
| | | u8 rtw_efuse_map_read(PADAPTER adapter, u16 addr, u16 cnts, u8 *data) |
| | | { |
| | | struct dvobj_priv *d; |
| | | u8 *efuse = NULL; |
| | | u32 size, i; |
| | | int err; |
| | | |
| | | |
| | | d = adapter_to_dvobj(adapter); |
| | | err = rtw_halmac_get_logical_efuse_size(d, &size); |
| | | if (err) |
| | | return _FAIL; |
| | | |
| | | /* size error handle */ |
| | | if ((addr + cnts) > size) { |
| | | if (addr < size) |
| | | cnts = size - addr; |
| | | else |
| | | return _FAIL; |
| | | } |
| | | |
| | | if (cnts > 16) |
| | | efuse = rtw_zmalloc(size); |
| | | |
| | | if (efuse) { |
| | | err = rtw_halmac_read_logical_efuse_map(d, efuse, size); |
| | | if (err) { |
| | | rtw_mfree(efuse, size); |
| | | return _FAIL; |
| | | } |
| | | |
| | | _rtw_memcpy(data, efuse + addr, cnts); |
| | | rtw_mfree(efuse, size); |
| | | } else { |
| | | err = rtw_halmac_read_logical_efuse(d, addr, cnts, data); |
| | | if (err) |
| | | return _FAIL; |
| | | } |
| | | |
| | | return _SUCCESS; |
| | | } |
| | | |
| | | u8 rtw_efuse_map_write(PADAPTER adapter, u16 addr, u16 cnts, u8 *data) |
| | | { |
| | | struct dvobj_priv *d; |
| | | u8 *efuse = NULL; |
| | | u32 size, i; |
| | | int err; |
| | | u8 mask_buf[64] = ""; |
| | | u16 mask_len = sizeof(u8) * rtw_get_efuse_mask_arraylen(adapter); |
| | | |
| | | d = adapter_to_dvobj(adapter); |
| | | err = rtw_halmac_get_logical_efuse_size(d, &size); |
| | | if (err) |
| | | return _FAIL; |
| | | |
| | | if ((addr + cnts) > size) |
| | | return _FAIL; |
| | | |
| | | efuse = rtw_zmalloc(size); |
| | | if (!efuse) |
| | | return _FAIL; |
| | | |
| | | err = rtw_halmac_read_logical_efuse_map(d, efuse, size); |
| | | if (err) { |
| | | rtw_mfree(efuse, size); |
| | | return _FAIL; |
| | | } |
| | | |
| | | _rtw_memcpy(efuse + addr, data, cnts); |
| | | |
| | | if (adapter->registrypriv.boffefusemask == 0) { |
| | | RTW_INFO("Use mask Array Len: %d\n", mask_len); |
| | | |
| | | if (mask_len != 0) { |
| | | if (adapter->registrypriv.bFileMaskEfuse == _TRUE) |
| | | _rtw_memcpy(mask_buf, maskfileBuffer, mask_len); |
| | | else |
| | | rtw_efuse_mask_array(adapter, mask_buf); |
| | | |
| | | err = rtw_halmac_write_logical_efuse_map(d, efuse, size, mask_buf, mask_len); |
| | | } else |
| | | err = rtw_halmac_write_logical_efuse_map(d, efuse, size, NULL, 0); |
| | | } else { |
| | | _rtw_memset(mask_buf, 0xFF, sizeof(mask_buf)); |
| | | RTW_INFO("Efuse mask off\n"); |
| | | err = rtw_halmac_write_logical_efuse_map(d, efuse, size, mask_buf, size/16); |
| | | } |
| | | |
| | | if (err) { |
| | | rtw_mfree(efuse, size); |
| | | return _FAIL; |
| | | } |
| | | |
| | | rtw_mfree(efuse, size); |
| | | |
| | | return _SUCCESS; |
| | | } |
| | | |
| | | int Efuse_PgPacketRead(PADAPTER adapter, u8 offset, u8 *data, BOOLEAN test) |
| | | { |
| | | return _FALSE; |
| | | } |
| | | |
| | | int Efuse_PgPacketWrite(PADAPTER adapter, u8 offset, u8 word_en, u8 *data, BOOLEAN test) |
| | | { |
| | | return _FALSE; |
| | | } |
| | | |
| | | u8 rtw_BT_efuse_map_read(PADAPTER adapter, u16 addr, u16 cnts, u8 *data) |
| | | { |
| | | hal_ReadEFuse_BT_logic_map(adapter,addr, cnts, data); |
| | | |
| | | return _SUCCESS; |
| | | } |
| | | |
| | | u8 rtw_BT_efuse_map_write(PADAPTER adapter, u16 addr, u16 cnts, u8 *data) |
| | | { |
| | | #define RT_ASSERT_RET(expr) \ |
| | | if (!(expr)) { \ |
| | | printk("Assertion failed! %s at ......\n", #expr); \ |
| | | printk(" ......%s,%s, line=%d\n",__FILE__, __FUNCTION__, __LINE__); \ |
| | | return _FAIL; \ |
| | | } |
| | | |
| | | u8 offset, word_en; |
| | | u8 *map; |
| | | u8 newdata[PGPKT_DATA_SIZE]; |
| | | s32 i = 0, j = 0, idx; |
| | | u8 ret = _SUCCESS; |
| | | u16 mapLen = 1024; |
| | | |
| | | if ((addr + cnts) > mapLen) |
| | | return _FAIL; |
| | | |
| | | RT_ASSERT_RET(PGPKT_DATA_SIZE == 8); /* have to be 8 byte alignment */ |
| | | RT_ASSERT_RET((mapLen & 0x7) == 0); /* have to be PGPKT_DATA_SIZE alignment for memcpy */ |
| | | |
| | | map = rtw_zmalloc(mapLen); |
| | | if (map == NULL) |
| | | return _FAIL; |
| | | |
| | | ret = rtw_BT_efuse_map_read(adapter, 0, mapLen, map); |
| | | if (ret == _FAIL) |
| | | goto exit; |
| | | RTW_INFO("OFFSET\tVALUE(hex)\n"); |
| | | for (i = 0; i < mapLen; i += 16) { /* set 512 because the iwpriv's extra size have limit 0x7FF */ |
| | | RTW_INFO("0x%03x\t", i); |
| | | for (j = 0; j < 8; j++) |
| | | RTW_INFO("%02X ", map[i + j]); |
| | | RTW_INFO("\t"); |
| | | for (; j < 16; j++) |
| | | RTW_INFO("%02X ", map[i + j]); |
| | | RTW_INFO("\n"); |
| | | } |
| | | RTW_INFO("\n"); |
| | | |
| | | idx = 0; |
| | | offset = (addr >> 3); |
| | | while (idx < cnts) { |
| | | word_en = 0xF; |
| | | j = (addr + idx) & 0x7; |
| | | _rtw_memcpy(newdata, &map[offset << 3], PGPKT_DATA_SIZE); |
| | | for (i = j; i < PGPKT_DATA_SIZE && idx < cnts; i++, idx++) { |
| | | if (data[idx] != map[addr + idx]) { |
| | | word_en &= ~BIT(i >> 1); |
| | | newdata[i] = data[idx]; |
| | | } |
| | | } |
| | | |
| | | if (word_en != 0xF) { |
| | | ret = EfusePgPacketWrite_BT(adapter, offset, word_en, newdata, _FALSE); |
| | | RTW_INFO("offset=%x\n", offset); |
| | | RTW_INFO("word_en=%x\n", word_en); |
| | | RTW_INFO("%s: data=", __FUNCTION__); |
| | | for (i = 0; i < PGPKT_DATA_SIZE; i++) |
| | | RTW_INFO("0x%02X ", newdata[i]); |
| | | RTW_INFO("\n"); |
| | | if (ret == _FAIL) |
| | | break; |
| | | } |
| | | offset++; |
| | | } |
| | | exit: |
| | | rtw_mfree(map, mapLen); |
| | | return _SUCCESS; |
| | | } |
| | | |
| | | VOID hal_ReadEFuse_BT_logic_map( |
| | | PADAPTER padapter, |
| | | u16 _offset, |
| | | u16 _size_byte, |
| | | u8 *pbuf |
| | | ) |
| | | { |
| | | |
| | | PHAL_DATA_TYPE pHalData = GET_HAL_DATA(padapter); |
| | | PEFUSE_HAL pEfuseHal = &pHalData->EfuseHal; |
| | | |
| | | u8 *efuseTbl, *phyefuse; |
| | | u8 bank; |
| | | u16 eFuse_Addr = 0; |
| | | u8 efuseHeader, efuseExtHdr, efuseData; |
| | | u8 offset, wden; |
| | | u16 i, total, used; |
| | | u8 efuse_usage; |
| | | |
| | | |
| | | /* */ |
| | | /* Do NOT excess total size of EFuse table. Added by Roger, 2008.11.10. */ |
| | | /* */ |
| | | if ((_offset + _size_byte) > EFUSE_BT_MAP_LEN) { |
| | | RTW_INFO("%s: Invalid offset(%#x) with read bytes(%#x)!!\n", __FUNCTION__, _offset, _size_byte); |
| | | return; |
| | | } |
| | | |
| | | efuseTbl = rtw_malloc(EFUSE_BT_MAP_LEN); |
| | | phyefuse = rtw_malloc(EFUSE_BT_REAL_CONTENT_LEN); |
| | | if (efuseTbl == NULL || phyefuse == NULL) { |
| | | RTW_INFO("%s: efuseTbl or phyefuse malloc fail!\n", __FUNCTION__); |
| | | goto exit; |
| | | } |
| | | |
| | | /* 0xff will be efuse default value instead of 0x00. */ |
| | | _rtw_memset(efuseTbl, 0xFF, EFUSE_BT_MAP_LEN); |
| | | _rtw_memset(phyefuse, 0xFF, EFUSE_BT_REAL_CONTENT_LEN); |
| | | |
| | | if (rtw_efuse_bt_access(padapter, _FALSE, 0, EFUSE_BT_REAL_CONTENT_LEN, phyefuse)) |
| | | dump_buf(phyefuse, EFUSE_BT_REAL_BANK_CONTENT_LEN); |
| | | |
| | | total = BANK_NUM; |
| | | for (bank = 1; bank <= total; bank++) { /* 8723d Max bake 0~2 */ |
| | | eFuse_Addr = 0; |
| | | |
| | | while (AVAILABLE_EFUSE_ADDR(eFuse_Addr)) { |
| | | /* ReadEFuseByte(padapter, eFuse_Addr++, &efuseHeader, bPseudoTest); */ |
| | | efuseHeader = phyefuse[eFuse_Addr++]; |
| | | |
| | | if (efuseHeader == 0xFF) |
| | | break; |
| | | RTW_INFO("%s: efuse[%#X]=0x%02x (header)\n", __FUNCTION__, (((bank - 1) * EFUSE_BT_REAL_CONTENT_LEN) + eFuse_Addr - 1), efuseHeader); |
| | | |
| | | /* Check PG header for section num. */ |
| | | if (EXT_HEADER(efuseHeader)) { /* extended header */ |
| | | offset = GET_HDR_OFFSET_2_0(efuseHeader); |
| | | RTW_INFO("%s: extended header offset_2_0=0x%X\n", __FUNCTION__, offset); |
| | | |
| | | /* ReadEFuseByte(padapter, eFuse_Addr++, &efuseExtHdr, bPseudoTest); */ |
| | | efuseExtHdr = phyefuse[eFuse_Addr++]; |
| | | |
| | | RTW_INFO("%s: efuse[%#X]=0x%02x (ext header)\n", __FUNCTION__, (((bank - 1) * EFUSE_BT_REAL_CONTENT_LEN) + eFuse_Addr - 1), efuseExtHdr); |
| | | if (ALL_WORDS_DISABLED(efuseExtHdr)) |
| | | continue; |
| | | |
| | | offset |= ((efuseExtHdr & 0xF0) >> 1); |
| | | wden = (efuseExtHdr & 0x0F); |
| | | } else { |
| | | offset = ((efuseHeader >> 4) & 0x0f); |
| | | wden = (efuseHeader & 0x0f); |
| | | } |
| | | |
| | | if (offset < EFUSE_BT_MAX_SECTION) { |
| | | u16 addr; |
| | | |
| | | /* Get word enable value from PG header */ |
| | | RTW_INFO("%s: Offset=%d Worden=%#X\n", __FUNCTION__, offset, wden); |
| | | |
| | | addr = offset * PGPKT_DATA_SIZE; |
| | | for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) { |
| | | /* Check word enable condition in the section */ |
| | | if (!(wden & (0x01 << i))) { |
| | | efuseData = 0; |
| | | /* ReadEFuseByte(padapter, eFuse_Addr++, &efuseData, bPseudoTest); */ |
| | | efuseData = phyefuse[eFuse_Addr++]; |
| | | |
| | | RTW_INFO("%s: efuse[%#X]=0x%02X\n", __FUNCTION__, eFuse_Addr - 1, efuseData); |
| | | efuseTbl[addr] = efuseData; |
| | | |
| | | efuseData = 0; |
| | | /* ReadEFuseByte(padapter, eFuse_Addr++, &efuseData, bPseudoTest); */ |
| | | efuseData = phyefuse[eFuse_Addr++]; |
| | | |
| | | RTW_INFO("%s: efuse[%#X]=0x%02X\n", __FUNCTION__, eFuse_Addr - 1, efuseData); |
| | | efuseTbl[addr + 1] = efuseData; |
| | | } |
| | | addr += 2; |
| | | } |
| | | } else { |
| | | RTW_INFO("%s: offset(%d) is illegal!!\n", __FUNCTION__, offset); |
| | | eFuse_Addr += Efuse_CalculateWordCnts(wden) * 2; |
| | | } |
| | | } |
| | | |
| | | if ((eFuse_Addr - 1) < total) { |
| | | RTW_INFO("%s: bank(%d) data end at %#x\n", __FUNCTION__, bank, eFuse_Addr - 1); |
| | | break; |
| | | } |
| | | } |
| | | |
| | | /* switch bank back to bank 0 for later BT and wifi use. */ |
| | | //hal_EfuseSwitchToBank(padapter, 0, bPseudoTest); |
| | | |
| | | /* Copy from Efuse map to output pointer memory!!! */ |
| | | for (i = 0; i < _size_byte; i++) |
| | | pbuf[i] = efuseTbl[_offset + i]; |
| | | /* Calculate Efuse utilization */ |
| | | total = EFUSE_BT_REAL_BANK_CONTENT_LEN; |
| | | |
| | | used = eFuse_Addr - 1; |
| | | |
| | | if (total) |
| | | efuse_usage = (u8)((used * 100) / total); |
| | | else |
| | | efuse_usage = 100; |
| | | |
| | | fakeBTEfuseUsedBytes = used; |
| | | RTW_INFO("%s: BTEfuseUsed last Bytes = %#x\n", __FUNCTION__, fakeBTEfuseUsedBytes); |
| | | |
| | | exit: |
| | | if (efuseTbl) |
| | | rtw_mfree(efuseTbl, EFUSE_BT_MAP_LEN); |
| | | if (phyefuse) |
| | | rtw_mfree(phyefuse, EFUSE_BT_REAL_BANK_CONTENT_LEN); |
| | | } |
| | | |
| | | |
| | | static u8 hal_EfusePartialWriteCheck( |
| | | PADAPTER padapter, |
| | | u8 efuseType, |
| | | u16 *pAddr, |
| | | PPGPKT_STRUCT pTargetPkt, |
| | | u8 bPseudoTest) |
| | | { |
| | | PHAL_DATA_TYPE pHalData = GET_HAL_DATA(padapter); |
| | | PEFUSE_HAL pEfuseHal = &pHalData->EfuseHal; |
| | | u8 bRet = _FALSE; |
| | | u16 startAddr = 0, efuse_max_available_len = EFUSE_BT_REAL_BANK_CONTENT_LEN, efuse_max = EFUSE_BT_REAL_BANK_CONTENT_LEN; |
| | | u8 efuse_data = 0; |
| | | |
| | | startAddr = (u16)fakeBTEfuseUsedBytes; |
| | | |
| | | startAddr %= efuse_max; |
| | | RTW_INFO("%s: startAddr=%#X\n", __FUNCTION__, startAddr); |
| | | |
| | | while (1) { |
| | | if (startAddr >= efuse_max_available_len) { |
| | | bRet = _FALSE; |
| | | RTW_INFO("%s: startAddr(%d) >= efuse_max_available_len(%d)\n", |
| | | __FUNCTION__, startAddr, efuse_max_available_len); |
| | | break; |
| | | } |
| | | if (rtw_efuse_bt_access(padapter, _FALSE, startAddr, 1, &efuse_data)&& (efuse_data != 0xFF)) { |
| | | bRet = _FALSE; |
| | | RTW_INFO("%s: Something Wrong! last bytes(%#X=0x%02X) is not 0xFF\n", |
| | | __FUNCTION__, startAddr, efuse_data); |
| | | break; |
| | | } else { |
| | | /* not used header, 0xff */ |
| | | *pAddr = startAddr; |
| | | /* RTW_INFO("%s: Started from unused header offset=%d\n", __FUNCTION__, startAddr)); */ |
| | | bRet = _TRUE; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | return bRet; |
| | | } |
| | | |
| | | |
| | | static u8 hal_EfusePgPacketWrite2ByteHeader( |
| | | PADAPTER padapter, |
| | | u8 efuseType, |
| | | u16 *pAddr, |
| | | PPGPKT_STRUCT pTargetPkt, |
| | | u8 bPseudoTest) |
| | | { |
| | | u16 efuse_addr, efuse_max_available_len = EFUSE_BT_REAL_BANK_CONTENT_LEN; |
| | | u8 pg_header = 0, tmp_header = 0; |
| | | u8 repeatcnt = 0; |
| | | |
| | | /* RTW_INFO("%s\n", __FUNCTION__); */ |
| | | |
| | | efuse_addr = *pAddr; |
| | | if (efuse_addr >= efuse_max_available_len) { |
| | | RTW_INFO("%s: addr(%d) over avaliable(%d)!!\n", __FUNCTION__, efuse_addr, efuse_max_available_len); |
| | | return _FALSE; |
| | | } |
| | | |
| | | pg_header = ((pTargetPkt->offset & 0x07) << 5) | 0x0F; |
| | | /* RTW_INFO("%s: pg_header=0x%x\n", __FUNCTION__, pg_header); */ |
| | | |
| | | do { |
| | | |
| | | rtw_efuse_bt_access(padapter, _TRUE, efuse_addr, 1, &pg_header); |
| | | rtw_efuse_bt_access(padapter, _FALSE, efuse_addr, 1, &tmp_header); |
| | | |
| | | if (tmp_header != 0xFF) |
| | | break; |
| | | if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) { |
| | | RTW_INFO("%s: Repeat over limit for pg_header!!\n", __FUNCTION__); |
| | | return _FALSE; |
| | | } |
| | | } while (1); |
| | | |
| | | if (tmp_header != pg_header) { |
| | | RTW_ERR("%s: PG Header Fail!!(pg=0x%02X read=0x%02X)\n", __FUNCTION__, pg_header, tmp_header); |
| | | return _FALSE; |
| | | } |
| | | |
| | | /* to write ext_header */ |
| | | efuse_addr++; |
| | | pg_header = ((pTargetPkt->offset & 0x78) << 1) | pTargetPkt->word_en; |
| | | |
| | | do { |
| | | rtw_efuse_bt_access(padapter, _TRUE, efuse_addr, 1, &pg_header); |
| | | rtw_efuse_bt_access(padapter, _FALSE, efuse_addr, 1, &tmp_header); |
| | | |
| | | if (tmp_header != 0xFF) |
| | | break; |
| | | if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) { |
| | | RTW_INFO("%s: Repeat over limit for ext_header!!\n", __FUNCTION__); |
| | | return _FALSE; |
| | | } |
| | | } while (1); |
| | | |
| | | if (tmp_header != pg_header) { /* offset PG fail */ |
| | | RTW_ERR("%s: PG EXT Header Fail!!(pg=0x%02X read=0x%02X)\n", __FUNCTION__, pg_header, tmp_header); |
| | | return _FALSE; |
| | | } |
| | | |
| | | *pAddr = efuse_addr; |
| | | |
| | | return _TRUE; |
| | | } |
| | | |
| | | |
| | | static u8 hal_EfusePgPacketWrite1ByteHeader( |
| | | PADAPTER pAdapter, |
| | | u8 efuseType, |
| | | u16 *pAddr, |
| | | PPGPKT_STRUCT pTargetPkt, |
| | | u8 bPseudoTest) |
| | | { |
| | | u8 bRet = _FALSE; |
| | | u8 pg_header = 0, tmp_header = 0; |
| | | u16 efuse_addr = *pAddr; |
| | | u8 repeatcnt = 0; |
| | | |
| | | |
| | | /* RTW_INFO("%s\n", __FUNCTION__); */ |
| | | pg_header = ((pTargetPkt->offset << 4) & 0xf0) | pTargetPkt->word_en; |
| | | |
| | | do { |
| | | rtw_efuse_bt_access(pAdapter, _TRUE, efuse_addr, 1, &pg_header); |
| | | rtw_efuse_bt_access(pAdapter, _FALSE, efuse_addr, 1, &tmp_header); |
| | | |
| | | if (tmp_header != 0xFF) |
| | | break; |
| | | if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) { |
| | | RTW_INFO("%s: Repeat over limit for pg_header!!\n", __FUNCTION__); |
| | | return _FALSE; |
| | | } |
| | | } while (1); |
| | | |
| | | if (tmp_header != pg_header) { |
| | | RTW_ERR("%s: PG Header Fail!!(pg=0x%02X read=0x%02X)\n", __FUNCTION__, pg_header, tmp_header); |
| | | return _FALSE; |
| | | } |
| | | |
| | | *pAddr = efuse_addr; |
| | | |
| | | return _TRUE; |
| | | } |
| | | |
| | | static u8 hal_EfusePgPacketWriteHeader( |
| | | PADAPTER padapter, |
| | | u8 efuseType, |
| | | u16 *pAddr, |
| | | PPGPKT_STRUCT pTargetPkt, |
| | | u8 bPseudoTest) |
| | | { |
| | | u8 bRet = _FALSE; |
| | | |
| | | if (pTargetPkt->offset >= EFUSE_MAX_SECTION_BASE) |
| | | bRet = hal_EfusePgPacketWrite2ByteHeader(padapter, efuseType, pAddr, pTargetPkt, bPseudoTest); |
| | | else |
| | | bRet = hal_EfusePgPacketWrite1ByteHeader(padapter, efuseType, pAddr, pTargetPkt, bPseudoTest); |
| | | |
| | | return bRet; |
| | | } |
| | | |
| | | |
| | | static u8 |
| | | Hal_EfuseWordEnableDataWrite( |
| | | PADAPTER padapter, |
| | | u16 efuse_addr, |
| | | u8 word_en, |
| | | u8 *data, |
| | | u8 bPseudoTest) |
| | | { |
| | | u16 tmpaddr = 0; |
| | | u16 start_addr = efuse_addr; |
| | | u8 badworden = 0x0F; |
| | | u8 tmpdata[PGPKT_DATA_SIZE]; |
| | | |
| | | |
| | | /* RTW_INFO("%s: efuse_addr=%#x word_en=%#x\n", __FUNCTION__, efuse_addr, word_en); */ |
| | | _rtw_memset(tmpdata, 0xFF, PGPKT_DATA_SIZE); |
| | | |
| | | if (!(word_en & BIT(0))) { |
| | | tmpaddr = start_addr; |
| | | rtw_efuse_bt_access(padapter, _TRUE, start_addr++, 1, &data[0]); |
| | | rtw_efuse_bt_access(padapter, _TRUE, start_addr++, 1, &data[1]); |
| | | rtw_efuse_bt_access(padapter, _FALSE, tmpaddr, 1, &tmpdata[0]); |
| | | rtw_efuse_bt_access(padapter, _FALSE, tmpaddr + 1, 1, &tmpdata[1]); |
| | | if ((data[0] != tmpdata[0]) || (data[1] != tmpdata[1])) |
| | | badworden &= (~BIT(0)); |
| | | } |
| | | if (!(word_en & BIT(1))) { |
| | | tmpaddr = start_addr; |
| | | rtw_efuse_bt_access(padapter, _TRUE, start_addr++, 1, &data[2]); |
| | | rtw_efuse_bt_access(padapter, _TRUE, start_addr++, 1, &data[3]); |
| | | rtw_efuse_bt_access(padapter, _FALSE, tmpaddr, 1, &tmpdata[2]); |
| | | rtw_efuse_bt_access(padapter, _FALSE, tmpaddr + 1, 1, &tmpdata[3]); |
| | | if ((data[2] != tmpdata[2]) || (data[3] != tmpdata[3])) |
| | | badworden &= (~BIT(1)); |
| | | } |
| | | if (!(word_en & BIT(2))) { |
| | | tmpaddr = start_addr; |
| | | rtw_efuse_bt_access(padapter, _TRUE, start_addr++, 1, &data[4]); |
| | | rtw_efuse_bt_access(padapter, _TRUE, start_addr++, 1, &data[5]); |
| | | rtw_efuse_bt_access(padapter, _FALSE, tmpaddr, 1, &tmpdata[4]); |
| | | rtw_efuse_bt_access(padapter, _FALSE, tmpaddr + 1, 1, &tmpdata[5]); |
| | | if ((data[4] != tmpdata[4]) || (data[5] != tmpdata[5])) |
| | | badworden &= (~BIT(2)); |
| | | } |
| | | if (!(word_en & BIT(3))) { |
| | | tmpaddr = start_addr; |
| | | rtw_efuse_bt_access(padapter, _TRUE, start_addr++, 1, &data[6]); |
| | | rtw_efuse_bt_access(padapter, _TRUE, start_addr++, 1, &data[7]); |
| | | rtw_efuse_bt_access(padapter, _FALSE, tmpaddr, 1, &tmpdata[6]); |
| | | rtw_efuse_bt_access(padapter, _FALSE, tmpaddr + 1, 1, &tmpdata[7]); |
| | | |
| | | if ((data[6] != tmpdata[6]) || (data[7] != tmpdata[7])) |
| | | badworden &= (~BIT(3)); |
| | | } |
| | | |
| | | return badworden; |
| | | } |
| | | |
| | | static void |
| | | hal_EfuseConstructPGPkt( |
| | | u8 offset, |
| | | u8 word_en, |
| | | u8 *pData, |
| | | PPGPKT_STRUCT pTargetPkt) |
| | | { |
| | | _rtw_memset(pTargetPkt->data, 0xFF, PGPKT_DATA_SIZE); |
| | | pTargetPkt->offset = offset; |
| | | pTargetPkt->word_en = word_en; |
| | | efuse_WordEnableDataRead(word_en, pData, pTargetPkt->data); |
| | | pTargetPkt->word_cnts = Efuse_CalculateWordCnts(pTargetPkt->word_en); |
| | | } |
| | | |
| | | static u8 |
| | | hal_EfusePgPacketWriteData( |
| | | PADAPTER pAdapter, |
| | | u8 efuseType, |
| | | u16 *pAddr, |
| | | PPGPKT_STRUCT pTargetPkt, |
| | | u8 bPseudoTest) |
| | | { |
| | | u16 efuse_addr; |
| | | u8 badworden; |
| | | |
| | | efuse_addr = *pAddr; |
| | | badworden = Hal_EfuseWordEnableDataWrite(pAdapter, efuse_addr + 1, pTargetPkt->word_en, pTargetPkt->data, bPseudoTest); |
| | | if (badworden != 0x0F) { |
| | | RTW_INFO("%s: Fail!!\n", __FUNCTION__); |
| | | return _FALSE; |
| | | } else |
| | | RTW_INFO("%s: OK!!\n", __FUNCTION__); |
| | | |
| | | return _TRUE; |
| | | } |
| | | |
| | | /* *********************************************************** |
| | | * Efuse related code |
| | | * *********************************************************** */ |
| | | static u8 |
| | | hal_EfuseSwitchToBank( |
| | | PADAPTER padapter, |
| | | u8 bank, |
| | | u8 bPseudoTest) |
| | | { |
| | | u8 bRet = _FALSE; |
| | | u32 value32 = 0; |
| | | #ifdef HAL_EFUSE_MEMORY |
| | | PHAL_DATA_TYPE pHalData = GET_HAL_DATA(padapter); |
| | | PEFUSE_HAL pEfuseHal = &pHalData->EfuseHal; |
| | | #endif |
| | | |
| | | |
| | | RTW_INFO("%s: Efuse switch bank to %d\n", __FUNCTION__, bank); |
| | | if (bPseudoTest) { |
| | | #ifdef HAL_EFUSE_MEMORY |
| | | pEfuseHal->fakeEfuseBank = bank; |
| | | #else |
| | | fakeEfuseBank = bank; |
| | | #endif |
| | | bRet = _TRUE; |
| | | } else { |
| | | value32 = rtw_read32(padapter, 0x34); |
| | | bRet = _TRUE; |
| | | switch (bank) { |
| | | case 0: |
| | | value32 = (value32 & ~EFUSE_SEL_MASK) | EFUSE_SEL(EFUSE_WIFI_SEL_0); |
| | | break; |
| | | case 1: |
| | | value32 = (value32 & ~EFUSE_SEL_MASK) | EFUSE_SEL(EFUSE_BT_SEL_0); |
| | | break; |
| | | case 2: |
| | | value32 = (value32 & ~EFUSE_SEL_MASK) | EFUSE_SEL(EFUSE_BT_SEL_1); |
| | | break; |
| | | case 3: |
| | | value32 = (value32 & ~EFUSE_SEL_MASK) | EFUSE_SEL(EFUSE_BT_SEL_2); |
| | | break; |
| | | default: |
| | | value32 = (value32 & ~EFUSE_SEL_MASK) | EFUSE_SEL(EFUSE_WIFI_SEL_0); |
| | | bRet = _FALSE; |
| | | break; |
| | | } |
| | | rtw_write32(padapter, 0x34, value32); |
| | | } |
| | | |
| | | return bRet; |
| | | } |
| | | |
| | | |
| | | #define EFUSE_CTRL 0x30 /* E-Fuse Control. */ |
| | | |
| | | /* 11/16/2008 MH Read one byte from real Efuse. */ |
| | | u8 |
| | | efuse_OneByteRead( |
| | | IN PADAPTER pAdapter, |
| | | IN u16 addr, |
| | | IN u8 *data, |
| | | IN BOOLEAN bPseudoTest) |
| | | { |
| | | u32 tmpidx = 0; |
| | | u8 bResult; |
| | | u8 readbyte; |
| | | HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); |
| | | |
| | | if (IS_HARDWARE_TYPE_8723B(pAdapter) || |
| | | (IS_HARDWARE_TYPE_8192E(pAdapter) && (!IS_A_CUT(pHalData->version_id))) || |
| | | (IS_VENDOR_8188E_I_CUT_SERIES(pAdapter)) || (IS_CHIP_VENDOR_SMIC(pHalData->version_id)) |
| | | ) { |
| | | /* <20130121, Kordan> For SMIC EFUSE specificatoin. */ |
| | | /* 0x34[11]: SW force PGMEN input of efuse to high. (for the bank selected by 0x34[9:8]) */ |
| | | /* phy_set_mac_reg(pAdapter, 0x34, BIT11, 0); */ |
| | | rtw_write16(pAdapter, 0x34, rtw_read16(pAdapter, 0x34) & (~BIT11)); |
| | | } |
| | | |
| | | /* -----------------e-fuse reg ctrl --------------------------------- */ |
| | | /* address */ |
| | | rtw_write8(pAdapter, EFUSE_CTRL + 1, (u8)(addr & 0xff)); |
| | | rtw_write8(pAdapter, EFUSE_CTRL + 2, ((u8)((addr >> 8) & 0x03)) | |
| | | (rtw_read8(pAdapter, EFUSE_CTRL + 2) & 0xFC)); |
| | | |
| | | /* rtw_write8(pAdapter, EFUSE_CTRL+3, 0x72); */ /* read cmd */ |
| | | /* Write bit 32 0 */ |
| | | readbyte = rtw_read8(pAdapter, EFUSE_CTRL + 3); |
| | | rtw_write8(pAdapter, EFUSE_CTRL + 3, (readbyte & 0x7f)); |
| | | |
| | | while (!(0x80 & rtw_read8(pAdapter, EFUSE_CTRL + 3)) && (tmpidx < 1000)) { |
| | | rtw_mdelay_os(1); |
| | | tmpidx++; |
| | | } |
| | | if (tmpidx < 100) { |
| | | *data = rtw_read8(pAdapter, EFUSE_CTRL); |
| | | bResult = _TRUE; |
| | | } else { |
| | | *data = 0xff; |
| | | bResult = _FALSE; |
| | | RTW_INFO("%s: [ERROR] addr=0x%x bResult=%d time out 1s !!!\n", __FUNCTION__, addr, bResult); |
| | | RTW_INFO("%s: [ERROR] EFUSE_CTRL =0x%08x !!!\n", __FUNCTION__, rtw_read32(pAdapter, EFUSE_CTRL)); |
| | | } |
| | | |
| | | return bResult; |
| | | } |
| | | |
| | | |
| | | static u16 |
| | | hal_EfuseGetCurrentSize_BT( |
| | | PADAPTER padapter, |
| | | u8 bPseudoTest) |
| | | { |
| | | #ifdef HAL_EFUSE_MEMORY |
| | | PHAL_DATA_TYPE pHalData = GET_HAL_DATA(padapter); |
| | | PEFUSE_HAL pEfuseHal = &pHalData->EfuseHal; |
| | | #endif |
| | | u16 btusedbytes; |
| | | u16 efuse_addr; |
| | | u8 bank, startBank; |
| | | u8 hoffset = 0, hworden = 0; |
| | | u8 efuse_data, word_cnts = 0; |
| | | u16 retU2 = 0; |
| | | u8 bContinual = _TRUE; |
| | | |
| | | |
| | | btusedbytes = fakeBTEfuseUsedBytes; |
| | | |
| | | efuse_addr = (u16)((btusedbytes % EFUSE_BT_REAL_BANK_CONTENT_LEN)); |
| | | startBank = (u8)(1 + (btusedbytes / EFUSE_BT_REAL_BANK_CONTENT_LEN)); |
| | | |
| | | RTW_INFO("%s: start from bank=%d addr=0x%X\n", __FUNCTION__, startBank, efuse_addr); |
| | | retU2 = EFUSE_BT_REAL_CONTENT_LEN - EFUSE_PROTECT_BYTES_BANK; |
| | | |
| | | for (bank = startBank; bank < 3; bank++) { |
| | | if (hal_EfuseSwitchToBank(padapter, bank, bPseudoTest) == _FALSE) { |
| | | RTW_ERR("%s: switch bank(%d) Fail!!\n", __FUNCTION__, bank); |
| | | /* bank = EFUSE_MAX_BANK; */ |
| | | break; |
| | | } |
| | | |
| | | /* only when bank is switched we have to reset the efuse_addr. */ |
| | | if (bank != startBank) |
| | | efuse_addr = 0; |
| | | |
| | | |
| | | while (AVAILABLE_EFUSE_ADDR(efuse_addr)) { |
| | | if (rtw_efuse_bt_access(padapter, _FALSE, efuse_addr, 1, &efuse_data) == _FALSE) { |
| | | RTW_ERR("%s: efuse_OneByteRead Fail! addr=0x%X !!\n", __FUNCTION__, efuse_addr); |
| | | /* bank = EFUSE_MAX_BANK; */ |
| | | break; |
| | | } |
| | | RTW_INFO("%s: efuse_OneByteRead ! addr=0x%X !efuse_data=0x%X! bank =%d\n", __FUNCTION__, efuse_addr, efuse_data, bank); |
| | | |
| | | if (efuse_data == 0xFF) |
| | | break; |
| | | |
| | | if (EXT_HEADER(efuse_data)) { |
| | | hoffset = GET_HDR_OFFSET_2_0(efuse_data); |
| | | efuse_addr++; |
| | | rtw_efuse_bt_access(padapter, _FALSE, efuse_addr, 1, &efuse_data); |
| | | RTW_INFO("%s: efuse_OneByteRead EXT_HEADER ! addr=0x%X !efuse_data=0x%X! bank =%d\n", __FUNCTION__, efuse_addr, efuse_data, bank); |
| | | |
| | | if (ALL_WORDS_DISABLED(efuse_data)) { |
| | | efuse_addr++; |
| | | continue; |
| | | } |
| | | |
| | | /* hoffset = ((hoffset & 0xE0) >> 5) | ((efuse_data & 0xF0) >> 1); */ |
| | | hoffset |= ((efuse_data & 0xF0) >> 1); |
| | | hworden = efuse_data & 0x0F; |
| | | } else { |
| | | hoffset = (efuse_data >> 4) & 0x0F; |
| | | hworden = efuse_data & 0x0F; |
| | | } |
| | | |
| | | RTW_INFO(FUNC_ADPT_FMT": Offset=%d Worden=%#X\n", |
| | | FUNC_ADPT_ARG(padapter), hoffset, hworden); |
| | | |
| | | word_cnts = Efuse_CalculateWordCnts(hworden); |
| | | /* read next header */ |
| | | efuse_addr += (word_cnts * 2) + 1; |
| | | } |
| | | /* Check if we need to check next bank efuse */ |
| | | if (efuse_addr < retU2) |
| | | break;/* don't need to check next bank. */ |
| | | } |
| | | retU2 = ((bank - 1) * EFUSE_BT_REAL_BANK_CONTENT_LEN) + efuse_addr; |
| | | |
| | | fakeBTEfuseUsedBytes = retU2; |
| | | RTW_INFO("%s: CurrentSize=%d\n", __FUNCTION__, retU2); |
| | | return retU2; |
| | | } |
| | | |
| | | |
| | | static u8 |
| | | hal_BT_EfusePgCheckAvailableAddr( |
| | | PADAPTER pAdapter, |
| | | u8 bPseudoTest) |
| | | { |
| | | u16 max_available = EFUSE_BT_REAL_CONTENT_LEN - EFUSE_PROTECT_BYTES_BANK; |
| | | u16 current_size = 0; |
| | | |
| | | RTW_INFO("%s: max_available=%d\n", __FUNCTION__, max_available); |
| | | current_size = hal_EfuseGetCurrentSize_BT(pAdapter, bPseudoTest); |
| | | if (current_size >= max_available) { |
| | | RTW_INFO("%s: Error!! current_size(%d)>max_available(%d)\n", __FUNCTION__, current_size, max_available); |
| | | return _FALSE; |
| | | } |
| | | return _TRUE; |
| | | } |
| | | |
| | | u8 EfusePgPacketWrite_BT( |
| | | PADAPTER pAdapter, |
| | | u8 offset, |
| | | u8 word_en, |
| | | u8 *pData, |
| | | u8 bPseudoTest) |
| | | { |
| | | PGPKT_STRUCT targetPkt; |
| | | u16 startAddr = 0; |
| | | u8 efuseType = EFUSE_BT; |
| | | |
| | | if (!hal_BT_EfusePgCheckAvailableAddr(pAdapter, bPseudoTest)) |
| | | return _FALSE; |
| | | |
| | | hal_EfuseConstructPGPkt(offset, word_en, pData, &targetPkt); |
| | | |
| | | if (!hal_EfusePartialWriteCheck(pAdapter, efuseType, &startAddr, &targetPkt, bPseudoTest)) |
| | | return _FALSE; |
| | | |
| | | if (!hal_EfusePgPacketWriteHeader(pAdapter, efuseType, &startAddr, &targetPkt, bPseudoTest)) |
| | | return _FALSE; |
| | | |
| | | if (!hal_EfusePgPacketWriteData(pAdapter, efuseType, &startAddr, &targetPkt, bPseudoTest)) |
| | | return _FALSE; |
| | | |
| | | return _TRUE; |
| | | } |
| | | |
| | | |
| | | #else /* !RTW_HALMAC */ |
| | | /* ------------------------------------------------------------------------------ */ |
| | | #define REG_EFUSE_CTRL 0x0030 |
| | | #define EFUSE_CTRL REG_EFUSE_CTRL /* E-Fuse Control. */ |
| | | /* ------------------------------------------------------------------------------ */ |
| | | |
| | | VOID efuse_PreUpdateAction( |
| | | PADAPTER pAdapter, |
| | | pu4Byte BackupRegs) |
| | | { |
| | | #if defined(CONFIG_RTL8812A) |
| | | if (IS_HARDWARE_TYPE_8812AU(pAdapter)) { |
| | | /* <20131115, Kordan> Turn off Rx to prevent from being busy when writing the EFUSE. (Asked by Chunchu.)*/ |
| | | BackupRegs[0] = phy_query_mac_reg(pAdapter, REG_RCR, bMaskDWord); |
| | | BackupRegs[1] = phy_query_mac_reg(pAdapter, REG_RXFLTMAP0, bMaskDWord); |
| | | BackupRegs[2] = phy_query_mac_reg(pAdapter, REG_RXFLTMAP0+4, bMaskDWord); |
| | | BackupRegs[3] = phy_query_mac_reg(pAdapter, REG_AFE_MISC, bMaskDWord); |
| | | |
| | | PlatformEFIOWrite4Byte(pAdapter, REG_RCR, 0x1); |
| | | PlatformEFIOWrite1Byte(pAdapter, REG_RXFLTMAP0, 0); |
| | | PlatformEFIOWrite1Byte(pAdapter, REG_RXFLTMAP0+1, 0); |
| | | PlatformEFIOWrite1Byte(pAdapter, REG_RXFLTMAP0+2, 0); |
| | | PlatformEFIOWrite1Byte(pAdapter, REG_RXFLTMAP0+3, 0); |
| | | PlatformEFIOWrite1Byte(pAdapter, REG_RXFLTMAP0+4, 0); |
| | | PlatformEFIOWrite1Byte(pAdapter, REG_RXFLTMAP0+5, 0); |
| | | |
| | | /* <20140410, Kordan> 0x11 = 0x4E, lower down LX_SPS0 voltage. (Asked by Chunchu)*/ |
| | | phy_set_mac_reg(pAdapter, REG_AFE_MISC, bMaskByte1, 0x4E); |
| | | } |
| | | #endif |
| | | } |
| | | |
| | | VOID efuse_PostUpdateAction( |
| | | PADAPTER pAdapter, |
| | | pu4Byte BackupRegs) |
| | | { |
| | | #if defined(CONFIG_RTL8812A) |
| | | if (IS_HARDWARE_TYPE_8812AU(pAdapter)) { |
| | | /* <20131115, Kordan> Turn on Rx and restore the registers. (Asked by Chunchu.)*/ |
| | | phy_set_mac_reg(pAdapter, REG_RCR, bMaskDWord, BackupRegs[0]); |
| | | phy_set_mac_reg(pAdapter, REG_RXFLTMAP0, bMaskDWord, BackupRegs[1]); |
| | | phy_set_mac_reg(pAdapter, REG_RXFLTMAP0+4, bMaskDWord, BackupRegs[2]); |
| | | phy_set_mac_reg(pAdapter, REG_AFE_MISC, bMaskDWord, BackupRegs[3]); |
| | | } |
| | | #endif |
| | | } |
| | | |
| | | |
| | | BOOLEAN |
| | | Efuse_Read1ByteFromFakeContent( |
| | | IN PADAPTER pAdapter, |
| | | IN u16 Offset, |
| | | IN OUT u8 *Value); |
| | | BOOLEAN |
| | | Efuse_Read1ByteFromFakeContent( |
| | | IN PADAPTER pAdapter, |
| | | IN u16 Offset, |
| | | IN OUT u8 *Value) |
| | | { |
| | | if (Offset >= EFUSE_MAX_HW_SIZE) |
| | | return _FALSE; |
| | | /* DbgPrint("Read fake content, offset = %d\n", Offset); */ |
| | | if (fakeEfuseBank == 0) |
| | | *Value = fakeEfuseContent[Offset]; |
| | | else |
| | | *Value = fakeBTEfuseContent[fakeEfuseBank - 1][Offset]; |
| | | return _TRUE; |
| | | } |
| | | |
| | | BOOLEAN |
| | | Efuse_Write1ByteToFakeContent( |
| | | IN PADAPTER pAdapter, |
| | | IN u16 Offset, |
| | | IN u8 Value); |
| | | BOOLEAN |
| | | Efuse_Write1ByteToFakeContent( |
| | | IN PADAPTER pAdapter, |
| | | IN u16 Offset, |
| | | IN u8 Value) |
| | | { |
| | | if (Offset >= EFUSE_MAX_HW_SIZE) |
| | | return _FALSE; |
| | | if (fakeEfuseBank == 0) |
| | | fakeEfuseContent[Offset] = Value; |
| | | else |
| | | fakeBTEfuseContent[fakeEfuseBank - 1][Offset] = Value; |
| | | return _TRUE; |
| | | } |
| | | |
| | | /*----------------------------------------------------------------------------- |
| | | * Function: Efuse_PowerSwitch |
| | | * |
| | | * Overview: When we want to enable write operation, we should change to |
| | | * pwr on state. When we stop write, we should switch to 500k mode |
| | | * and disable LDO 2.5V. |
| | | * |
| | | * Input: NONE |
| | | * |
| | | * Output: NONE |
| | | * |
| | | * Return: NONE |
| | | * |
| | | * Revised History: |
| | | * When Who Remark |
| | | * 11/17/2008 MHC Create Version 0. |
| | | * |
| | | *---------------------------------------------------------------------------*/ |
| | | VOID |
| | | Efuse_PowerSwitch( |
| | | IN PADAPTER pAdapter, |
| | | IN u8 bWrite, |
| | | IN u8 PwrState) |
| | | { |
| | | pAdapter->hal_func.EfusePowerSwitch(pAdapter, bWrite, PwrState); |
| | | } |
| | | |
| | | VOID |
| | | BTEfuse_PowerSwitch( |
| | | IN PADAPTER pAdapter, |
| | | IN u8 bWrite, |
| | | IN u8 PwrState) |
| | | { |
| | | if (pAdapter->hal_func.BTEfusePowerSwitch) |
| | | pAdapter->hal_func.BTEfusePowerSwitch(pAdapter, bWrite, PwrState); |
| | | } |
| | | |
| | | /*----------------------------------------------------------------------------- |
| | | * Function: efuse_GetCurrentSize |
| | | * |
| | | * Overview: Get current efuse size!!! |
| | | * |
| | | * Input: NONE |
| | | * |
| | | * Output: NONE |
| | | * |
| | | * Return: NONE |
| | | * |
| | | * Revised History: |
| | | * When Who Remark |
| | | * 11/16/2008 MHC Create Version 0. |
| | | * |
| | | *---------------------------------------------------------------------------*/ |
| | | u16 |
| | | Efuse_GetCurrentSize( |
| | | IN PADAPTER pAdapter, |
| | | IN u8 efuseType, |
| | | IN BOOLEAN bPseudoTest) |
| | | { |
| | | u16 ret = 0; |
| | | |
| | | ret = pAdapter->hal_func.EfuseGetCurrentSize(pAdapter, efuseType, bPseudoTest); |
| | | |
| | | return ret; |
| | | } |
| | | |
| | | /* |
| | | * Description: |
| | | * Execute E-Fuse read byte operation. |
| | | * Refered from SD1 Richard. |
| | | * |
| | | * Assumption: |
| | | * 1. Boot from E-Fuse and successfully auto-load. |
| | | * 2. PASSIVE_LEVEL (USB interface) |
| | | * |
| | | * Created by Roger, 2008.10.21. |
| | | * */ |
| | | VOID |
| | | ReadEFuseByte( |
| | | PADAPTER Adapter, |
| | | u16 _offset, |
| | | u8 *pbuf, |
| | | IN BOOLEAN bPseudoTest) |
| | | { |
| | | u32 value32; |
| | | u8 readbyte; |
| | | u16 retry; |
| | | /* u32 start=rtw_get_current_time(); */ |
| | | |
| | | if (bPseudoTest) { |
| | | Efuse_Read1ByteFromFakeContent(Adapter, _offset, pbuf); |
| | | return; |
| | | } |
| | | if (IS_HARDWARE_TYPE_8723B(Adapter)) { |
| | | /* <20130121, Kordan> For SMIC S55 EFUSE specificatoin. */ |
| | | /* 0x34[11]: SW force PGMEN input of efuse to high. (for the bank selected by 0x34[9:8]) */ |
| | | phy_set_mac_reg(Adapter, EFUSE_TEST, BIT11, 0); |
| | | } |
| | | /* Write Address */ |
| | | rtw_write8(Adapter, EFUSE_CTRL + 1, (_offset & 0xff)); |
| | | readbyte = rtw_read8(Adapter, EFUSE_CTRL + 2); |
| | | rtw_write8(Adapter, EFUSE_CTRL + 2, ((_offset >> 8) & 0x03) | (readbyte & 0xfc)); |
| | | |
| | | /* Write bit 32 0 */ |
| | | readbyte = rtw_read8(Adapter, EFUSE_CTRL + 3); |
| | | rtw_write8(Adapter, EFUSE_CTRL + 3, (readbyte & 0x7f)); |
| | | |
| | | /* Check bit 32 read-ready */ |
| | | retry = 0; |
| | | value32 = rtw_read32(Adapter, EFUSE_CTRL); |
| | | /* while(!(((value32 >> 24) & 0xff) & 0x80) && (retry<10)) */ |
| | | while (!(((value32 >> 24) & 0xff) & 0x80) && (retry < 10000)) { |
| | | value32 = rtw_read32(Adapter, EFUSE_CTRL); |
| | | retry++; |
| | | } |
| | | |
| | | /* 20100205 Joseph: Add delay suggested by SD1 Victor. */ |
| | | /* This fix the problem that Efuse read error in high temperature condition. */ |
| | | /* Designer says that there shall be some delay after ready bit is set, or the */ |
| | | /* result will always stay on last data we read. */ |
| | | rtw_udelay_os(50); |
| | | value32 = rtw_read32(Adapter, EFUSE_CTRL); |
| | | |
| | | *pbuf = (u8)(value32 & 0xff); |
| | | /* RTW_INFO("ReadEFuseByte _offset:%08u, in %d ms\n",_offset ,rtw_get_passing_time_ms(start)); */ |
| | | |
| | | } |
| | | |
| | | /* |
| | | * Description: |
| | | * 1. Execute E-Fuse read byte operation according as map offset and |
| | | * save to E-Fuse table. |
| | | * 2. Refered from SD1 Richard. |
| | | * |
| | | * Assumption: |
| | | * 1. Boot from E-Fuse and successfully auto-load. |
| | | * 2. PASSIVE_LEVEL (USB interface) |
| | | * |
| | | * Created by Roger, 2008.10.21. |
| | | * |
| | | * 2008/12/12 MH 1. Reorganize code flow and reserve bytes. and add description. |
| | | * 2. Add efuse utilization collect. |
| | | * 2008/12/22 MH Read Efuse must check if we write section 1 data again!!! Sec1 |
| | | * write addr must be after sec5. |
| | | * */ |
| | | |
| | | VOID |
| | | efuse_ReadEFuse( |
| | | PADAPTER Adapter, |
| | | u8 efuseType, |
| | | u16 _offset, |
| | | u16 _size_byte, |
| | | u8 *pbuf, |
| | | IN BOOLEAN bPseudoTest |
| | | ); |
| | | VOID |
| | | efuse_ReadEFuse( |
| | | PADAPTER Adapter, |
| | | u8 efuseType, |
| | | u16 _offset, |
| | | u16 _size_byte, |
| | | u8 *pbuf, |
| | | IN BOOLEAN bPseudoTest |
| | | ) |
| | | { |
| | | Adapter->hal_func.ReadEFuse(Adapter, efuseType, _offset, _size_byte, pbuf, bPseudoTest); |
| | | } |
| | | |
| | | VOID |
| | | EFUSE_GetEfuseDefinition( |
| | | IN PADAPTER pAdapter, |
| | | IN u8 efuseType, |
| | | IN u8 type, |
| | | OUT void *pOut, |
| | | IN BOOLEAN bPseudoTest |
| | | ) |
| | | { |
| | | pAdapter->hal_func.EFUSEGetEfuseDefinition(pAdapter, efuseType, type, pOut, bPseudoTest); |
| | | } |
| | | |
| | | |
| | | /* 11/16/2008 MH Read one byte from real Efuse. */ |
| | | u8 |
| | | efuse_OneByteRead( |
| | | IN PADAPTER pAdapter, |
| | | IN u16 addr, |
| | | IN u8 *data, |
| | | IN BOOLEAN bPseudoTest) |
| | | { |
| | | u32 tmpidx = 0; |
| | | u8 bResult; |
| | | u8 readbyte; |
| | | HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); |
| | | |
| | | /* RTW_INFO("===> EFUSE_OneByteRead(), addr = %x\n", addr); */ |
| | | /* RTW_INFO("===> EFUSE_OneByteRead() start, 0x34 = 0x%X\n", rtw_read32(pAdapter, EFUSE_TEST)); */ |
| | | |
| | | if (bPseudoTest) { |
| | | bResult = Efuse_Read1ByteFromFakeContent(pAdapter, addr, data); |
| | | return bResult; |
| | | } |
| | | |
| | | if (IS_HARDWARE_TYPE_8723B(pAdapter) || |
| | | (IS_HARDWARE_TYPE_8192E(pAdapter) && (!IS_A_CUT(pHalData->version_id))) || |
| | | (IS_VENDOR_8188E_I_CUT_SERIES(pAdapter)) || (IS_CHIP_VENDOR_SMIC(pHalData->version_id)) |
| | | ) { |
| | | /* <20130121, Kordan> For SMIC EFUSE specificatoin. */ |
| | | /* 0x34[11]: SW force PGMEN input of efuse to high. (for the bank selected by 0x34[9:8]) */ |
| | | /* phy_set_mac_reg(pAdapter, 0x34, BIT11, 0); */ |
| | | rtw_write16(pAdapter, 0x34, rtw_read16(pAdapter, 0x34) & (~BIT11)); |
| | | } |
| | | |
| | | /* -----------------e-fuse reg ctrl --------------------------------- */ |
| | | /* address */ |
| | | rtw_write8(pAdapter, EFUSE_CTRL + 1, (u8)(addr & 0xff)); |
| | | rtw_write8(pAdapter, EFUSE_CTRL + 2, ((u8)((addr >> 8) & 0x03)) | |
| | | (rtw_read8(pAdapter, EFUSE_CTRL + 2) & 0xFC)); |
| | | |
| | | /* rtw_write8(pAdapter, EFUSE_CTRL+3, 0x72); */ /* read cmd */ |
| | | /* Write bit 32 0 */ |
| | | readbyte = rtw_read8(pAdapter, EFUSE_CTRL + 3); |
| | | rtw_write8(pAdapter, EFUSE_CTRL + 3, (readbyte & 0x7f)); |
| | | |
| | | while (!(0x80 & rtw_read8(pAdapter, EFUSE_CTRL + 3)) && (tmpidx < 1000)) { |
| | | rtw_mdelay_os(1); |
| | | tmpidx++; |
| | | } |
| | | if (tmpidx < 100) { |
| | | *data = rtw_read8(pAdapter, EFUSE_CTRL); |
| | | bResult = _TRUE; |
| | | } else { |
| | | *data = 0xff; |
| | | bResult = _FALSE; |
| | | RTW_INFO("%s: [ERROR] addr=0x%x bResult=%d time out 1s !!!\n", __FUNCTION__, addr, bResult); |
| | | RTW_INFO("%s: [ERROR] EFUSE_CTRL =0x%08x !!!\n", __FUNCTION__, rtw_read32(pAdapter, EFUSE_CTRL)); |
| | | } |
| | | |
| | | return bResult; |
| | | } |
| | | |
| | | /* 11/16/2008 MH Write one byte to reald Efuse. */ |
| | | u8 |
| | | efuse_OneByteWrite( |
| | | IN PADAPTER pAdapter, |
| | | IN u16 addr, |
| | | IN u8 data, |
| | | IN BOOLEAN bPseudoTest) |
| | | { |
| | | u8 tmpidx = 0; |
| | | u8 bResult = _FALSE; |
| | | u32 efuseValue = 0; |
| | | HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); |
| | | |
| | | /* RTW_INFO("===> EFUSE_OneByteWrite(), addr = %x data=%x\n", addr, data); */ |
| | | /* RTW_INFO("===> EFUSE_OneByteWrite() start, 0x34 = 0x%X\n", rtw_read32(pAdapter, EFUSE_TEST)); */ |
| | | |
| | | if (bPseudoTest) { |
| | | bResult = Efuse_Write1ByteToFakeContent(pAdapter, addr, data); |
| | | return bResult; |
| | | } |
| | | |
| | | Efuse_PowerSwitch(pAdapter, _TRUE, _TRUE); |
| | | |
| | | /* -----------------e-fuse reg ctrl --------------------------------- */ |
| | | /* address */ |
| | | |
| | | |
| | | efuseValue = rtw_read32(pAdapter, EFUSE_CTRL); |
| | | efuseValue |= (BIT21 | BIT31); |
| | | efuseValue &= ~(0x3FFFF); |
| | | efuseValue |= ((addr << 8 | data) & 0x3FFFF); |
| | | |
| | | /* <20130227, Kordan> 8192E MP chip A-cut had better not set 0x34[11] until B-Cut. */ |
| | | if (IS_HARDWARE_TYPE_8723B(pAdapter) || |
| | | (IS_HARDWARE_TYPE_8192E(pAdapter) && (!IS_A_CUT(pHalData->version_id))) || |
| | | (IS_VENDOR_8188E_I_CUT_SERIES(pAdapter)) || (IS_CHIP_VENDOR_SMIC(pHalData->version_id)) |
| | | ) { |
| | | /* <20130121, Kordan> For SMIC EFUSE specificatoin. */ |
| | | /* 0x34[11]: SW force PGMEN input of efuse to high. (for the bank selected by 0x34[9:8]) */ |
| | | /* phy_set_mac_reg(pAdapter, 0x34, BIT11, 1); */ |
| | | rtw_write16(pAdapter, 0x34, rtw_read16(pAdapter, 0x34) | (BIT11)); |
| | | rtw_write32(pAdapter, EFUSE_CTRL, 0x90600000 | ((addr << 8 | data))); |
| | | } else |
| | | rtw_write32(pAdapter, EFUSE_CTRL, efuseValue); |
| | | |
| | | rtw_mdelay_os(1); |
| | | |
| | | while ((0x80 & rtw_read8(pAdapter, EFUSE_CTRL + 3)) && (tmpidx < 100)) { |
| | | rtw_mdelay_os(1); |
| | | tmpidx++; |
| | | } |
| | | |
| | | if (tmpidx < 100) |
| | | bResult = _TRUE; |
| | | else { |
| | | bResult = _FALSE; |
| | | RTW_INFO("%s: [ERROR] addr=0x%x ,efuseValue=0x%x ,bResult=%d time out 1s !!!\n", |
| | | __FUNCTION__, addr, efuseValue, bResult); |
| | | RTW_INFO("%s: [ERROR] EFUSE_CTRL =0x%08x !!!\n", __FUNCTION__, rtw_read32(pAdapter, EFUSE_CTRL)); |
| | | } |
| | | |
| | | /* disable Efuse program enable */ |
| | | if (IS_HARDWARE_TYPE_8723B(pAdapter) || |
| | | (IS_HARDWARE_TYPE_8192E(pAdapter) && (!IS_A_CUT(pHalData->version_id))) || |
| | | (IS_VENDOR_8188E_I_CUT_SERIES(pAdapter)) || (IS_CHIP_VENDOR_SMIC(pHalData->version_id)) |
| | | ) |
| | | phy_set_mac_reg(pAdapter, EFUSE_TEST, BIT(11), 0); |
| | | |
| | | Efuse_PowerSwitch(pAdapter, _TRUE, _FALSE); |
| | | |
| | | return bResult; |
| | | } |
| | | |
| | | int |
| | | Efuse_PgPacketRead(IN PADAPTER pAdapter, |
| | | IN u8 offset, |
| | | IN u8 *data, |
| | | IN BOOLEAN bPseudoTest) |
| | | { |
| | | int ret = 0; |
| | | |
| | | ret = pAdapter->hal_func.Efuse_PgPacketRead(pAdapter, offset, data, bPseudoTest); |
| | | |
| | | return ret; |
| | | } |
| | | |
| | | int |
| | | Efuse_PgPacketWrite(IN PADAPTER pAdapter, |
| | | IN u8 offset, |
| | | IN u8 word_en, |
| | | IN u8 *data, |
| | | IN BOOLEAN bPseudoTest) |
| | | { |
| | | int ret; |
| | | |
| | | ret = pAdapter->hal_func.Efuse_PgPacketWrite(pAdapter, offset, word_en, data, bPseudoTest); |
| | | |
| | | return ret; |
| | | } |
| | | |
| | | |
| | | int |
| | | Efuse_PgPacketWrite_BT(IN PADAPTER pAdapter, |
| | | IN u8 offset, |
| | | IN u8 word_en, |
| | | IN u8 *data, |
| | | IN BOOLEAN bPseudoTest) |
| | | { |
| | | int ret; |
| | | |
| | | ret = pAdapter->hal_func.Efuse_PgPacketWrite_BT(pAdapter, offset, word_en, data, bPseudoTest); |
| | | |
| | | return ret; |
| | | } |
| | | |
| | | |
| | | u8 |
| | | Efuse_WordEnableDataWrite(IN PADAPTER pAdapter, |
| | | IN u16 efuse_addr, |
| | | IN u8 word_en, |
| | | IN u8 *data, |
| | | IN BOOLEAN bPseudoTest) |
| | | { |
| | | u8 ret = 0; |
| | | |
| | | ret = pAdapter->hal_func.Efuse_WordEnableDataWrite(pAdapter, efuse_addr, word_en, data, bPseudoTest); |
| | | |
| | | return ret; |
| | | } |
| | | |
| | | static u8 efuse_read8(PADAPTER padapter, u16 address, u8 *value) |
| | | { |
| | | return efuse_OneByteRead(padapter, address, value, _FALSE); |
| | | } |
| | | |
| | | static u8 efuse_write8(PADAPTER padapter, u16 address, u8 *value) |
| | | { |
| | | return efuse_OneByteWrite(padapter, address, *value, _FALSE); |
| | | } |
| | | |
| | | /* |
| | | * read/wirte raw efuse data |
| | | */ |
| | | u8 rtw_efuse_access(PADAPTER padapter, u8 bWrite, u16 start_addr, u16 cnts, u8 *data) |
| | | { |
| | | int i = 0; |
| | | u16 real_content_len = 0, max_available_size = 0; |
| | | u8 res = _FAIL ; |
| | | u8(*rw8)(PADAPTER, u16, u8 *); |
| | | u32 backupRegs[4] = {0}; |
| | | |
| | | |
| | | EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_REAL_CONTENT_LEN, (PVOID)&real_content_len, _FALSE); |
| | | EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (PVOID)&max_available_size, _FALSE); |
| | | |
| | | if (start_addr > real_content_len) |
| | | return _FAIL; |
| | | |
| | | if (_TRUE == bWrite) { |
| | | if ((start_addr + cnts) > max_available_size) |
| | | return _FAIL; |
| | | rw8 = &efuse_write8; |
| | | } else |
| | | rw8 = &efuse_read8; |
| | | |
| | | efuse_PreUpdateAction(padapter, backupRegs); |
| | | |
| | | Efuse_PowerSwitch(padapter, bWrite, _TRUE); |
| | | |
| | | /* e-fuse one byte read / write */ |
| | | for (i = 0; i < cnts; i++) { |
| | | if (start_addr >= real_content_len) { |
| | | res = _FAIL; |
| | | break; |
| | | } |
| | | |
| | | res = rw8(padapter, start_addr++, data++); |
| | | if (_FAIL == res) |
| | | break; |
| | | } |
| | | |
| | | Efuse_PowerSwitch(padapter, bWrite, _FALSE); |
| | | |
| | | efuse_PostUpdateAction(padapter, backupRegs); |
| | | |
| | | return res; |
| | | } |
| | | /* ------------------------------------------------------------------------------ */ |
| | | u16 efuse_GetMaxSize(PADAPTER padapter) |
| | | { |
| | | u16 max_size; |
| | | |
| | | max_size = 0; |
| | | EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI , TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (PVOID)&max_size, _FALSE); |
| | | return max_size; |
| | | } |
| | | /* ------------------------------------------------------------------------------ */ |
| | | u8 efuse_GetCurrentSize(PADAPTER padapter, u16 *size) |
| | | { |
| | | Efuse_PowerSwitch(padapter, _FALSE, _TRUE); |
| | | *size = Efuse_GetCurrentSize(padapter, EFUSE_WIFI, _FALSE); |
| | | Efuse_PowerSwitch(padapter, _FALSE, _FALSE); |
| | | |
| | | return _SUCCESS; |
| | | } |
| | | /* ------------------------------------------------------------------------------ */ |
| | | u16 efuse_bt_GetMaxSize(PADAPTER padapter) |
| | | { |
| | | u16 max_size; |
| | | |
| | | max_size = 0; |
| | | EFUSE_GetEfuseDefinition(padapter, EFUSE_BT , TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (PVOID)&max_size, _FALSE); |
| | | return max_size; |
| | | } |
| | | |
| | | u8 efuse_bt_GetCurrentSize(PADAPTER padapter, u16 *size) |
| | | { |
| | | Efuse_PowerSwitch(padapter, _FALSE, _TRUE); |
| | | *size = Efuse_GetCurrentSize(padapter, EFUSE_BT, _FALSE); |
| | | Efuse_PowerSwitch(padapter, _FALSE, _FALSE); |
| | | |
| | | return _SUCCESS; |
| | | } |
| | | |
| | | u8 rtw_efuse_map_read(PADAPTER padapter, u16 addr, u16 cnts, u8 *data) |
| | | { |
| | | u16 mapLen = 0; |
| | | |
| | | EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (PVOID)&mapLen, _FALSE); |
| | | |
| | | if ((addr + cnts) > mapLen) |
| | | return _FAIL; |
| | | |
| | | Efuse_PowerSwitch(padapter, _FALSE, _TRUE); |
| | | |
| | | efuse_ReadEFuse(padapter, EFUSE_WIFI, addr, cnts, data, _FALSE); |
| | | |
| | | Efuse_PowerSwitch(padapter, _FALSE, _FALSE); |
| | | |
| | | return _SUCCESS; |
| | | } |
| | | |
| | | u8 rtw_BT_efuse_map_read(PADAPTER padapter, u16 addr, u16 cnts, u8 *data) |
| | | { |
| | | u16 mapLen = 0; |
| | | |
| | | EFUSE_GetEfuseDefinition(padapter, EFUSE_BT, TYPE_EFUSE_MAP_LEN, (PVOID)&mapLen, _FALSE); |
| | | |
| | | if ((addr + cnts) > mapLen) |
| | | return _FAIL; |
| | | |
| | | Efuse_PowerSwitch(padapter, _FALSE, _TRUE); |
| | | |
| | | efuse_ReadEFuse(padapter, EFUSE_BT, addr, cnts, data, _FALSE); |
| | | |
| | | Efuse_PowerSwitch(padapter, _FALSE, _FALSE); |
| | | |
| | | return _SUCCESS; |
| | | } |
| | | |
| | | /* ------------------------------------------------------------------------------ */ |
| | | u8 rtw_efuse_map_write(PADAPTER padapter, u16 addr, u16 cnts, u8 *data) |
| | | { |
| | | #define RT_ASSERT_RET(expr) \ |
| | | if (!(expr)) { \ |
| | | printk("Assertion failed! %s at ......\n", #expr); \ |
| | | printk(" ......%s,%s, line=%d\n",__FILE__, __FUNCTION__, __LINE__); \ |
| | | return _FAIL; \ |
| | | } |
| | | |
| | | u8 offset, word_en; |
| | | u8 *map; |
| | | u8 newdata[PGPKT_DATA_SIZE]; |
| | | s32 i, j, idx, chk_total_byte; |
| | | u8 ret = _SUCCESS; |
| | | u16 mapLen = 0, startAddr = 0, efuse_max_available_len = 0; |
| | | u32 backupRegs[4] = {0}; |
| | | HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); |
| | | PEFUSE_HAL pEfuseHal = &pHalData->EfuseHal; |
| | | |
| | | |
| | | EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (PVOID)&mapLen, _FALSE); |
| | | EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, &efuse_max_available_len, _FALSE); |
| | | |
| | | if ((addr + cnts) > mapLen) |
| | | return _FAIL; |
| | | |
| | | RT_ASSERT_RET(PGPKT_DATA_SIZE == 8); /* have to be 8 byte alignment */ |
| | | RT_ASSERT_RET((mapLen & 0x7) == 0); /* have to be PGPKT_DATA_SIZE alignment for memcpy */ |
| | | |
| | | map = rtw_zmalloc(mapLen); |
| | | if (map == NULL) |
| | | return _FAIL; |
| | | |
| | | _rtw_memset(map, 0xFF, mapLen); |
| | | |
| | | ret = rtw_efuse_map_read(padapter, 0, mapLen, map); |
| | | if (ret == _FAIL) |
| | | goto exit; |
| | | |
| | | if (padapter->registrypriv.boffefusemask == 0) { |
| | | for (i = 0; i < cnts; i++) { |
| | | if (padapter->registrypriv.bFileMaskEfuse == _TRUE) { |
| | | if (rtw_file_efuse_IsMasked(padapter, addr + i)) /*use file efuse mask. */ |
| | | data[i] = map[addr + i]; |
| | | } else { |
| | | if (efuse_IsMasked(padapter, addr + i)) |
| | | data[i] = map[addr + i]; |
| | | } |
| | | RTW_INFO("%s , data[%d] = %x, map[addr+i]= %x\n", __func__, i, data[i], map[addr + i]); |
| | | } |
| | | } |
| | | /*Efuse_PowerSwitch(padapter, _TRUE, _TRUE);*/ |
| | | |
| | | chk_total_byte = 0; |
| | | idx = 0; |
| | | offset = (addr >> 3); |
| | | |
| | | while (idx < cnts) { |
| | | word_en = 0xF; |
| | | j = (addr + idx) & 0x7; |
| | | for (i = j; i < PGPKT_DATA_SIZE && idx < cnts; i++, idx++) { |
| | | if (data[idx] != map[addr + idx]) |
| | | word_en &= ~BIT(i >> 1); |
| | | } |
| | | |
| | | if (word_en != 0xF) { |
| | | chk_total_byte += Efuse_CalculateWordCnts(word_en) * 2; |
| | | |
| | | if (offset >= EFUSE_MAX_SECTION_BASE) /* Over EFUSE_MAX_SECTION 16 for 2 ByteHeader */ |
| | | chk_total_byte += 2; |
| | | else |
| | | chk_total_byte += 1; |
| | | } |
| | | |
| | | offset++; |
| | | } |
| | | |
| | | RTW_INFO("Total PG bytes Count = %d\n", chk_total_byte); |
| | | rtw_hal_get_hwreg(padapter, HW_VAR_EFUSE_BYTES, (u8 *)&startAddr); |
| | | |
| | | if (startAddr == 0) { |
| | | startAddr = Efuse_GetCurrentSize(padapter, EFUSE_WIFI, _FALSE); |
| | | RTW_INFO("%s: Efuse_GetCurrentSize startAddr=%#X\n", __func__, startAddr); |
| | | } |
| | | RTW_DBG("%s: startAddr=%#X\n", __func__, startAddr); |
| | | |
| | | if ((startAddr + chk_total_byte) >= efuse_max_available_len) { |
| | | RTW_INFO("%s: startAddr(0x%X) + PG data len %d >= efuse_max_available_len(0x%X)\n", |
| | | __func__, startAddr, chk_total_byte, efuse_max_available_len); |
| | | ret = _FAIL; |
| | | goto exit; |
| | | } |
| | | |
| | | efuse_PreUpdateAction(padapter, backupRegs); |
| | | |
| | | idx = 0; |
| | | offset = (addr >> 3); |
| | | while (idx < cnts) { |
| | | word_en = 0xF; |
| | | j = (addr + idx) & 0x7; |
| | | _rtw_memcpy(newdata, &map[offset << 3], PGPKT_DATA_SIZE); |
| | | for (i = j; i < PGPKT_DATA_SIZE && idx < cnts; i++, idx++) { |
| | | if (data[idx] != map[addr + idx]) { |
| | | word_en &= ~BIT(i >> 1); |
| | | newdata[i] = data[idx]; |
| | | #ifdef CONFIG_RTL8723B |
| | | if (addr + idx == 0x8) { |
| | | if (IS_C_CUT(pHalData->version_id) || IS_B_CUT(pHalData->version_id)) { |
| | | if (pHalData->adjuseVoltageVal == 6) { |
| | | newdata[i] = map[addr + idx]; |
| | | RTW_INFO(" %s ,\n adjuseVoltageVal = %d ,newdata[%d] = %x\n", __func__, pHalData->adjuseVoltageVal, i, newdata[i]); |
| | | } |
| | | } |
| | | } |
| | | #endif |
| | | } |
| | | } |
| | | |
| | | if (word_en != 0xF) { |
| | | ret = Efuse_PgPacketWrite(padapter, offset, word_en, newdata, _FALSE); |
| | | RTW_INFO("offset=%x\n", offset); |
| | | RTW_INFO("word_en=%x\n", word_en); |
| | | |
| | | for (i = 0; i < PGPKT_DATA_SIZE; i++) |
| | | RTW_INFO("data=%x \t", newdata[i]); |
| | | if (ret == _FAIL) |
| | | break; |
| | | } |
| | | |
| | | offset++; |
| | | } |
| | | |
| | | /*Efuse_PowerSwitch(padapter, _TRUE, _FALSE);*/ |
| | | |
| | | efuse_PostUpdateAction(padapter, backupRegs); |
| | | |
| | | exit: |
| | | |
| | | rtw_mfree(map, mapLen); |
| | | |
| | | return ret; |
| | | } |
| | | |
| | | |
| | | u8 rtw_BT_efuse_map_write(PADAPTER padapter, u16 addr, u16 cnts, u8 *data) |
| | | { |
| | | #define RT_ASSERT_RET(expr) \ |
| | | if (!(expr)) { \ |
| | | printk("Assertion failed! %s at ......\n", #expr); \ |
| | | printk(" ......%s,%s, line=%d\n",__FILE__, __FUNCTION__, __LINE__); \ |
| | | return _FAIL; \ |
| | | } |
| | | |
| | | u8 offset, word_en; |
| | | u8 *map; |
| | | u8 newdata[PGPKT_DATA_SIZE]; |
| | | s32 i = 0, j = 0, idx; |
| | | u8 ret = _SUCCESS; |
| | | u16 mapLen = 0; |
| | | |
| | | EFUSE_GetEfuseDefinition(padapter, EFUSE_BT, TYPE_EFUSE_MAP_LEN, (PVOID)&mapLen, _FALSE); |
| | | |
| | | if ((addr + cnts) > mapLen) |
| | | return _FAIL; |
| | | |
| | | RT_ASSERT_RET(PGPKT_DATA_SIZE == 8); /* have to be 8 byte alignment */ |
| | | RT_ASSERT_RET((mapLen & 0x7) == 0); /* have to be PGPKT_DATA_SIZE alignment for memcpy */ |
| | | |
| | | map = rtw_zmalloc(mapLen); |
| | | if (map == NULL) |
| | | return _FAIL; |
| | | |
| | | ret = rtw_BT_efuse_map_read(padapter, 0, mapLen, map); |
| | | if (ret == _FAIL) |
| | | goto exit; |
| | | RTW_INFO("OFFSET\tVALUE(hex)\n"); |
| | | for (i = 0; i < 1024; i += 16) { /* set 512 because the iwpriv's extra size have limit 0x7FF */ |
| | | RTW_INFO("0x%03x\t", i); |
| | | for (j = 0; j < 8; j++) |
| | | RTW_INFO("%02X ", map[i + j]); |
| | | RTW_INFO("\t"); |
| | | for (; j < 16; j++) |
| | | RTW_INFO("%02X ", map[i + j]); |
| | | RTW_INFO("\n"); |
| | | } |
| | | RTW_INFO("\n"); |
| | | Efuse_PowerSwitch(padapter, _TRUE, _TRUE); |
| | | |
| | | idx = 0; |
| | | offset = (addr >> 3); |
| | | while (idx < cnts) { |
| | | word_en = 0xF; |
| | | j = (addr + idx) & 0x7; |
| | | _rtw_memcpy(newdata, &map[offset << 3], PGPKT_DATA_SIZE); |
| | | for (i = j; i < PGPKT_DATA_SIZE && idx < cnts; i++, idx++) { |
| | | if (data[idx] != map[addr + idx]) { |
| | | word_en &= ~BIT(i >> 1); |
| | | newdata[i] = data[idx]; |
| | | } |
| | | } |
| | | |
| | | if (word_en != 0xF) { |
| | | RTW_INFO("offset=%x\n", offset); |
| | | RTW_INFO("word_en=%x\n", word_en); |
| | | RTW_INFO("%s: data=", __FUNCTION__); |
| | | for (i = 0; i < PGPKT_DATA_SIZE; i++) |
| | | RTW_INFO("0x%02X ", newdata[i]); |
| | | RTW_INFO("\n"); |
| | | ret = Efuse_PgPacketWrite_BT(padapter, offset, word_en, newdata, _FALSE); |
| | | if (ret == _FAIL) |
| | | break; |
| | | } |
| | | |
| | | offset++; |
| | | } |
| | | |
| | | Efuse_PowerSwitch(padapter, _TRUE, _FALSE); |
| | | |
| | | exit: |
| | | |
| | | rtw_mfree(map, mapLen); |
| | | |
| | | return ret; |
| | | } |
| | | |
| | | /*----------------------------------------------------------------------------- |
| | | * Function: Efuse_ReadAllMap |
| | | * |
| | | * Overview: Read All Efuse content |
| | | * |
| | | * Input: NONE |
| | | * |
| | | * Output: NONE |
| | | * |
| | | * Return: NONE |
| | | * |
| | | * Revised History: |
| | | * When Who Remark |
| | | * 11/11/2008 MHC Create Version 0. |
| | | * |
| | | *---------------------------------------------------------------------------*/ |
| | | VOID |
| | | Efuse_ReadAllMap( |
| | | IN PADAPTER pAdapter, |
| | | IN u8 efuseType, |
| | | IN OUT u8 *Efuse, |
| | | IN BOOLEAN bPseudoTest); |
| | | VOID |
| | | Efuse_ReadAllMap( |
| | | IN PADAPTER pAdapter, |
| | | IN u8 efuseType, |
| | | IN OUT u8 *Efuse, |
| | | IN BOOLEAN bPseudoTest) |
| | | { |
| | | u16 mapLen = 0; |
| | | |
| | | Efuse_PowerSwitch(pAdapter, _FALSE, _TRUE); |
| | | |
| | | EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_EFUSE_MAP_LEN, (PVOID)&mapLen, bPseudoTest); |
| | | |
| | | efuse_ReadEFuse(pAdapter, efuseType, 0, mapLen, Efuse, bPseudoTest); |
| | | |
| | | Efuse_PowerSwitch(pAdapter, _FALSE, _FALSE); |
| | | } |
| | | |
| | | /*----------------------------------------------------------------------------- |
| | | * Function: efuse_ShadowRead1Byte |
| | | * efuse_ShadowRead2Byte |
| | | * efuse_ShadowRead4Byte |
| | | * |
| | | * Overview: Read from efuse init map by one/two/four bytes !!!!! |
| | | * |
| | | * Input: NONE |
| | | * |
| | | * Output: NONE |
| | | * |
| | | * Return: NONE |
| | | * |
| | | * Revised History: |
| | | * When Who Remark |
| | | * 11/12/2008 MHC Create Version 0. |
| | | * |
| | | *---------------------------------------------------------------------------*/ |
| | | static VOID |
| | | efuse_ShadowRead1Byte( |
| | | IN PADAPTER pAdapter, |
| | | IN u16 Offset, |
| | | IN OUT u8 *Value) |
| | | { |
| | | PHAL_DATA_TYPE pHalData = GET_HAL_DATA(pAdapter); |
| | | |
| | | *Value = pHalData->efuse_eeprom_data[Offset]; |
| | | |
| | | } /* EFUSE_ShadowRead1Byte */ |
| | | |
| | | /* ---------------Read Two Bytes */ |
| | | static VOID |
| | | efuse_ShadowRead2Byte( |
| | | IN PADAPTER pAdapter, |
| | | IN u16 Offset, |
| | | IN OUT u16 *Value) |
| | | { |
| | | PHAL_DATA_TYPE pHalData = GET_HAL_DATA(pAdapter); |
| | | |
| | | *Value = pHalData->efuse_eeprom_data[Offset]; |
| | | *Value |= pHalData->efuse_eeprom_data[Offset + 1] << 8; |
| | | |
| | | } /* EFUSE_ShadowRead2Byte */ |
| | | |
| | | /* ---------------Read Four Bytes */ |
| | | static VOID |
| | | efuse_ShadowRead4Byte( |
| | | IN PADAPTER pAdapter, |
| | | IN u16 Offset, |
| | | IN OUT u32 *Value) |
| | | { |
| | | PHAL_DATA_TYPE pHalData = GET_HAL_DATA(pAdapter); |
| | | |
| | | *Value = pHalData->efuse_eeprom_data[Offset]; |
| | | *Value |= pHalData->efuse_eeprom_data[Offset + 1] << 8; |
| | | *Value |= pHalData->efuse_eeprom_data[Offset + 2] << 16; |
| | | *Value |= pHalData->efuse_eeprom_data[Offset + 3] << 24; |
| | | |
| | | } /* efuse_ShadowRead4Byte */ |
| | | |
| | | |
| | | /*----------------------------------------------------------------------------- |
| | | * Function: efuse_ShadowWrite1Byte |
| | | * efuse_ShadowWrite2Byte |
| | | * efuse_ShadowWrite4Byte |
| | | * |
| | | * Overview: Write efuse modify map by one/two/four byte. |
| | | * |
| | | * Input: NONE |
| | | * |
| | | * Output: NONE |
| | | * |
| | | * Return: NONE |
| | | * |
| | | * Revised History: |
| | | * When Who Remark |
| | | * 11/12/2008 MHC Create Version 0. |
| | | * |
| | | *---------------------------------------------------------------------------*/ |
| | | #ifdef PLATFORM |
| | | static VOID |
| | | efuse_ShadowWrite1Byte( |
| | | IN PADAPTER pAdapter, |
| | | IN u16 Offset, |
| | | IN u8 Value); |
| | | #endif /* PLATFORM */ |
| | | static VOID |
| | | efuse_ShadowWrite1Byte( |
| | | IN PADAPTER pAdapter, |
| | | IN u16 Offset, |
| | | IN u8 Value) |
| | | { |
| | | PHAL_DATA_TYPE pHalData = GET_HAL_DATA(pAdapter); |
| | | |
| | | pHalData->efuse_eeprom_data[Offset] = Value; |
| | | |
| | | } /* efuse_ShadowWrite1Byte */ |
| | | |
| | | /* ---------------Write Two Bytes */ |
| | | static VOID |
| | | efuse_ShadowWrite2Byte( |
| | | IN PADAPTER pAdapter, |
| | | IN u16 Offset, |
| | | IN u16 Value) |
| | | { |
| | | |
| | | PHAL_DATA_TYPE pHalData = GET_HAL_DATA(pAdapter); |
| | | |
| | | |
| | | pHalData->efuse_eeprom_data[Offset] = Value & 0x00FF; |
| | | pHalData->efuse_eeprom_data[Offset + 1] = Value >> 8; |
| | | |
| | | } /* efuse_ShadowWrite1Byte */ |
| | | |
| | | /* ---------------Write Four Bytes */ |
| | | static VOID |
| | | efuse_ShadowWrite4Byte( |
| | | IN PADAPTER pAdapter, |
| | | IN u16 Offset, |
| | | IN u32 Value) |
| | | { |
| | | PHAL_DATA_TYPE pHalData = GET_HAL_DATA(pAdapter); |
| | | |
| | | pHalData->efuse_eeprom_data[Offset] = (u8)(Value & 0x000000FF); |
| | | pHalData->efuse_eeprom_data[Offset + 1] = (u8)((Value >> 8) & 0x0000FF); |
| | | pHalData->efuse_eeprom_data[Offset + 2] = (u8)((Value >> 16) & 0x00FF); |
| | | pHalData->efuse_eeprom_data[Offset + 3] = (u8)((Value >> 24) & 0xFF); |
| | | |
| | | } /* efuse_ShadowWrite1Byte */ |
| | | |
| | | |
| | | /*----------------------------------------------------------------------------- |
| | | * Function: EFUSE_ShadowRead |
| | | * |
| | | * Overview: Read from efuse init map !!!!! |
| | | * |
| | | * Input: NONE |
| | | * |
| | | * Output: NONE |
| | | * |
| | | * Return: NONE |
| | | * |
| | | * Revised History: |
| | | * When Who Remark |
| | | * 11/12/2008 MHC Create Version 0. |
| | | * |
| | | *---------------------------------------------------------------------------*/ |
| | | void |
| | | EFUSE_ShadowRead( |
| | | IN PADAPTER pAdapter, |
| | | IN u8 Type, |
| | | IN u16 Offset, |
| | | IN OUT u32 *Value) |
| | | { |
| | | if (Type == 1) |
| | | efuse_ShadowRead1Byte(pAdapter, Offset, (u8 *)Value); |
| | | else if (Type == 2) |
| | | efuse_ShadowRead2Byte(pAdapter, Offset, (u16 *)Value); |
| | | else if (Type == 4) |
| | | efuse_ShadowRead4Byte(pAdapter, Offset, (u32 *)Value); |
| | | |
| | | } /* EFUSE_ShadowRead */ |
| | | |
| | | /*----------------------------------------------------------------------------- |
| | | * Function: EFUSE_ShadowWrite |
| | | * |
| | | * Overview: Write efuse modify map for later update operation to use!!!!! |
| | | * |
| | | * Input: NONE |
| | | * |
| | | * Output: NONE |
| | | * |
| | | * Return: NONE |
| | | * |
| | | * Revised History: |
| | | * When Who Remark |
| | | * 11/12/2008 MHC Create Version 0. |
| | | * |
| | | *---------------------------------------------------------------------------*/ |
| | | VOID |
| | | EFUSE_ShadowWrite( |
| | | IN PADAPTER pAdapter, |
| | | IN u8 Type, |
| | | IN u16 Offset, |
| | | IN OUT u32 Value); |
| | | VOID |
| | | EFUSE_ShadowWrite( |
| | | IN PADAPTER pAdapter, |
| | | IN u8 Type, |
| | | IN u16 Offset, |
| | | IN OUT u32 Value) |
| | | { |
| | | #if (MP_DRIVER == 0) |
| | | return; |
| | | #endif |
| | | if (pAdapter->registrypriv.mp_mode == 0) |
| | | return; |
| | | |
| | | |
| | | if (Type == 1) |
| | | efuse_ShadowWrite1Byte(pAdapter, Offset, (u8)Value); |
| | | else if (Type == 2) |
| | | efuse_ShadowWrite2Byte(pAdapter, Offset, (u16)Value); |
| | | else if (Type == 4) |
| | | efuse_ShadowWrite4Byte(pAdapter, Offset, (u32)Value); |
| | | |
| | | } /* EFUSE_ShadowWrite */ |
| | | |
| | | VOID |
| | | Efuse_InitSomeVar( |
| | | IN PADAPTER pAdapter |
| | | ); |
| | | VOID |
| | | Efuse_InitSomeVar( |
| | | IN PADAPTER pAdapter |
| | | ) |
| | | { |
| | | u8 i; |
| | | |
| | | _rtw_memset((PVOID)&fakeEfuseContent[0], 0xff, EFUSE_MAX_HW_SIZE); |
| | | _rtw_memset((PVOID)&fakeEfuseInitMap[0], 0xff, EFUSE_MAX_MAP_LEN); |
| | | _rtw_memset((PVOID)&fakeEfuseModifiedMap[0], 0xff, EFUSE_MAX_MAP_LEN); |
| | | |
| | | for (i = 0; i < EFUSE_MAX_BT_BANK; i++) |
| | | _rtw_memset((PVOID)&BTEfuseContent[i][0], EFUSE_MAX_HW_SIZE, 0xff); |
| | | _rtw_memset((PVOID)&BTEfuseInitMap[0], 0xff, EFUSE_BT_MAX_MAP_LEN); |
| | | _rtw_memset((PVOID)&BTEfuseModifiedMap[0], 0xff, EFUSE_BT_MAX_MAP_LEN); |
| | | |
| | | for (i = 0; i < EFUSE_MAX_BT_BANK; i++) |
| | | _rtw_memset((PVOID)&fakeBTEfuseContent[i][0], 0xff, EFUSE_MAX_HW_SIZE); |
| | | _rtw_memset((PVOID)&fakeBTEfuseInitMap[0], 0xff, EFUSE_BT_MAX_MAP_LEN); |
| | | _rtw_memset((PVOID)&fakeBTEfuseModifiedMap[0], 0xff, EFUSE_BT_MAX_MAP_LEN); |
| | | } |
| | | #endif /* !RTW_HALMAC */ |
| | | /* 11/16/2008 MH Add description. Get current efuse area enabled word!!. */ |
| | | u8 |
| | | Efuse_CalculateWordCnts(IN u8 word_en) |
| | | { |
| | | u8 word_cnts = 0; |
| | | if (!(word_en & BIT(0))) |
| | | word_cnts++; /* 0 : write enable */ |
| | | if (!(word_en & BIT(1))) |
| | | word_cnts++; |
| | | if (!(word_en & BIT(2))) |
| | | word_cnts++; |
| | | if (!(word_en & BIT(3))) |
| | | word_cnts++; |
| | | return word_cnts; |
| | | } |
| | | |
| | | /*----------------------------------------------------------------------------- |
| | | * Function: efuse_WordEnableDataRead |
| | | * |
| | | * Overview: Read allowed word in current efuse section data. |
| | | * |
| | | * Input: NONE |
| | | * |
| | | * Output: NONE |
| | | * |
| | | * Return: NONE |
| | | * |
| | | * Revised History: |
| | | * When Who Remark |
| | | * 11/16/2008 MHC Create Version 0. |
| | | * 11/21/2008 MHC Fix Write bug when we only enable late word. |
| | | * |
| | | *---------------------------------------------------------------------------*/ |
| | | void |
| | | efuse_WordEnableDataRead(IN u8 word_en, |
| | | IN u8 *sourdata, |
| | | IN u8 *targetdata) |
| | | { |
| | | if (!(word_en & BIT(0))) { |
| | | targetdata[0] = sourdata[0]; |
| | | targetdata[1] = sourdata[1]; |
| | | } |
| | | if (!(word_en & BIT(1))) { |
| | | targetdata[2] = sourdata[2]; |
| | | targetdata[3] = sourdata[3]; |
| | | } |
| | | if (!(word_en & BIT(2))) { |
| | | targetdata[4] = sourdata[4]; |
| | | targetdata[5] = sourdata[5]; |
| | | } |
| | | if (!(word_en & BIT(3))) { |
| | | targetdata[6] = sourdata[6]; |
| | | targetdata[7] = sourdata[7]; |
| | | } |
| | | } |
| | | |
| | | /*----------------------------------------------------------------------------- |
| | | * Function: EFUSE_ShadowMapUpdate |
| | | * |
| | | * Overview: Transfer current EFUSE content to shadow init and modify map. |
| | | * |
| | | * Input: NONE |
| | | * |
| | | * Output: NONE |
| | | * |
| | | * Return: NONE |
| | | * |
| | | * Revised History: |
| | | * When Who Remark |
| | | * 11/13/2008 MHC Create Version 0. |
| | | * |
| | | *---------------------------------------------------------------------------*/ |
| | | void EFUSE_ShadowMapUpdate( |
| | | IN PADAPTER pAdapter, |
| | | IN u8 efuseType, |
| | | IN BOOLEAN bPseudoTest) |
| | | { |
| | | PHAL_DATA_TYPE pHalData = GET_HAL_DATA(pAdapter); |
| | | u16 mapLen = 0; |
| | | #ifdef RTW_HALMAC |
| | | u8 *efuse_map = NULL; |
| | | int err; |
| | | |
| | | |
| | | mapLen = EEPROM_MAX_SIZE; |
| | | efuse_map = pHalData->efuse_eeprom_data; |
| | | /* efuse default content is 0xFF */ |
| | | _rtw_memset(efuse_map, 0xFF, EEPROM_MAX_SIZE); |
| | | |
| | | EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_EFUSE_MAP_LEN, (PVOID)&mapLen, bPseudoTest); |
| | | if (!mapLen) { |
| | | RTW_WARN("%s: <ERROR> fail to get efuse size!\n", __FUNCTION__); |
| | | mapLen = EEPROM_MAX_SIZE; |
| | | } |
| | | if (mapLen > EEPROM_MAX_SIZE) { |
| | | RTW_WARN("%s: <ERROR> size of efuse data(%d) is large than expected(%d)!\n", |
| | | __FUNCTION__, mapLen, EEPROM_MAX_SIZE); |
| | | mapLen = EEPROM_MAX_SIZE; |
| | | } |
| | | |
| | | if (pHalData->bautoload_fail_flag == _FALSE) { |
| | | err = rtw_halmac_read_logical_efuse_map(adapter_to_dvobj(pAdapter), efuse_map, mapLen); |
| | | if (err) |
| | | RTW_ERR("%s: <ERROR> fail to get efuse map!\n", __FUNCTION__); |
| | | } |
| | | #else /* !RTW_HALMAC */ |
| | | EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_EFUSE_MAP_LEN, (PVOID)&mapLen, bPseudoTest); |
| | | |
| | | if (pHalData->bautoload_fail_flag == _TRUE) |
| | | _rtw_memset(pHalData->efuse_eeprom_data, 0xFF, mapLen); |
| | | else { |
| | | #ifdef CONFIG_ADAPTOR_INFO_CACHING_FILE |
| | | if (_SUCCESS != retriveAdaptorInfoFile(pAdapter->registrypriv.adaptor_info_caching_file_path, pHalData->efuse_eeprom_data)) { |
| | | #endif |
| | | |
| | | Efuse_ReadAllMap(pAdapter, efuseType, pHalData->efuse_eeprom_data, bPseudoTest); |
| | | |
| | | #ifdef CONFIG_ADAPTOR_INFO_CACHING_FILE |
| | | storeAdaptorInfoFile(pAdapter->registrypriv.adaptor_info_caching_file_path, pHalData->efuse_eeprom_data); |
| | | } |
| | | #endif |
| | | } |
| | | |
| | | /* PlatformMoveMemory((PVOID)&pHalData->EfuseMap[EFUSE_MODIFY_MAP][0], */ |
| | | /* (PVOID)&pHalData->EfuseMap[EFUSE_INIT_MAP][0], mapLen); */ |
| | | #endif /* !RTW_HALMAC */ |
| | | |
| | | rtw_dump_cur_efuse(pAdapter); |
| | | } /* EFUSE_ShadowMapUpdate */ |
| | | |
| | | const u8 _mac_hidden_max_bw_to_hal_bw_cap[MAC_HIDDEN_MAX_BW_NUM] = { |
| | | 0, |
| | | 0, |
| | | (BW_CAP_160M | BW_CAP_80M | BW_CAP_40M | BW_CAP_20M | BW_CAP_10M | BW_CAP_5M), |
| | | (BW_CAP_5M), |
| | | (BW_CAP_10M | BW_CAP_5M), |
| | | (BW_CAP_20M | BW_CAP_10M | BW_CAP_5M), |
| | | (BW_CAP_40M | BW_CAP_20M | BW_CAP_10M | BW_CAP_5M), |
| | | (BW_CAP_80M | BW_CAP_40M | BW_CAP_20M | BW_CAP_10M | BW_CAP_5M), |
| | | }; |
| | | |
| | | const u8 _mac_hidden_proto_to_hal_proto_cap[MAC_HIDDEN_PROTOCOL_NUM] = { |
| | | 0, |
| | | 0, |
| | | (PROTO_CAP_11N | PROTO_CAP_11G | PROTO_CAP_11B), |
| | | (PROTO_CAP_11AC | PROTO_CAP_11N | PROTO_CAP_11G | PROTO_CAP_11B), |
| | | }; |
| | | |
| | | u8 mac_hidden_wl_func_to_hal_wl_func(u8 func) |
| | | { |
| | | u8 wl_func = 0; |
| | | |
| | | if (func & BIT0) |
| | | wl_func |= WL_FUNC_MIRACAST; |
| | | if (func & BIT1) |
| | | wl_func |= WL_FUNC_P2P; |
| | | if (func & BIT2) |
| | | wl_func |= WL_FUNC_TDLS; |
| | | if (func & BIT3) |
| | | wl_func |= WL_FUNC_FTM; |
| | | |
| | | return wl_func; |
| | | } |
| | | |
| | | #ifdef PLATFORM_LINUX |
| | | #ifdef CONFIG_ADAPTOR_INFO_CACHING_FILE |
| | | /* #include <rtw_eeprom.h> */ |
| | | |
| | | int isAdaptorInfoFileValid(void) |
| | | { |
| | | return _TRUE; |
| | | } |
| | | |
| | | int storeAdaptorInfoFile(char *path, u8 *efuse_data) |
| | | { |
| | | int ret = _SUCCESS; |
| | | |
| | | if (path && efuse_data) { |
| | | ret = rtw_store_to_file(path, efuse_data, EEPROM_MAX_SIZE_512); |
| | | if (ret == EEPROM_MAX_SIZE) |
| | | ret = _SUCCESS; |
| | | else |
| | | ret = _FAIL; |
| | | } else { |
| | | RTW_INFO("%s NULL pointer\n", __FUNCTION__); |
| | | ret = _FAIL; |
| | | } |
| | | return ret; |
| | | } |
| | | |
| | | int retriveAdaptorInfoFile(char *path, u8 *efuse_data) |
| | | { |
| | | int ret = _SUCCESS; |
| | | mm_segment_t oldfs; |
| | | struct file *fp; |
| | | |
| | | if (path && efuse_data) { |
| | | |
| | | ret = rtw_retrieve_from_file(path, efuse_data, EEPROM_MAX_SIZE); |
| | | |
| | | if (ret == EEPROM_MAX_SIZE) |
| | | ret = _SUCCESS; |
| | | else |
| | | ret = _FAIL; |
| | | |
| | | #if 0 |
| | | if (isAdaptorInfoFileValid()) |
| | | return 0; |
| | | else |
| | | return _FAIL; |
| | | #endif |
| | | |
| | | } else { |
| | | RTW_INFO("%s NULL pointer\n", __FUNCTION__); |
| | | ret = _FAIL; |
| | | } |
| | | return ret; |
| | | } |
| | | #endif /* CONFIG_ADAPTOR_INFO_CACHING_FILE */ |
| | | |
| | | u8 rtw_efuse_file_read(PADAPTER padapter, u8 *filepatch, u8 *buf, u32 len) |
| | | { |
| | | char *ptmpbuf = NULL, *ptr; |
| | | u8 val8; |
| | | u32 count, i, j; |
| | | int err; |
| | | u32 bufsize = 4096; |
| | | |
| | | ptmpbuf = rtw_zmalloc(bufsize); |
| | | if (ptmpbuf == NULL) |
| | | return _FALSE; |
| | | |
| | | count = rtw_retrieve_from_file(filepatch, ptmpbuf, bufsize); |
| | | if (count <= 100) { |
| | | rtw_mfree(ptmpbuf, bufsize); |
| | | RTW_ERR("%s, filepatch %s, size=%d, FAIL!!\n", __FUNCTION__, filepatch, count); |
| | | return _FALSE; |
| | | } |
| | | |
| | | i = 0; |
| | | j = 0; |
| | | ptr = ptmpbuf; |
| | | while ((j < len) && (i < count)) { |
| | | if (ptmpbuf[i] == '\0') |
| | | break; |
| | | |
| | | ptr = strpbrk(&ptmpbuf[i], " \t\n\r"); |
| | | if (ptr) { |
| | | if (ptr == &ptmpbuf[i]) { |
| | | i++; |
| | | continue; |
| | | } |
| | | |
| | | /* Add string terminating null */ |
| | | *ptr = 0; |
| | | } else { |
| | | ptr = &ptmpbuf[count-1]; |
| | | } |
| | | |
| | | err = sscanf(&ptmpbuf[i], "%hhx", &val8); |
| | | if (err != 1) { |
| | | RTW_WARN("Something wrong to parse efuse file, string=%s\n", &ptmpbuf[i]); |
| | | } else { |
| | | buf[j] = val8; |
| | | RTW_DBG("i=%d, j=%d, 0x%02x\n", i, j, buf[j]); |
| | | j++; |
| | | } |
| | | |
| | | i = ptr - ptmpbuf + 1; |
| | | } |
| | | |
| | | rtw_mfree(ptmpbuf, bufsize); |
| | | RTW_INFO("%s, filepatch %s, size=%d, done\n", __FUNCTION__, filepatch, count); |
| | | return _TRUE; |
| | | } |
| | | |
| | | #ifdef CONFIG_EFUSE_CONFIG_FILE |
| | | u32 rtw_read_efuse_from_file(const char *path, u8 *buf, int map_size) |
| | | { |
| | | u32 i; |
| | | u8 c; |
| | | u8 temp[3]; |
| | | u8 temp_i; |
| | | u8 end = _FALSE; |
| | | u32 ret = _FAIL; |
| | | |
| | | u8 *file_data = NULL; |
| | | u32 file_size, read_size, pos = 0; |
| | | u8 *map = NULL; |
| | | |
| | | if (rtw_is_file_readable_with_size(path, &file_size) != _TRUE) { |
| | | RTW_PRINT("%s %s is not readable\n", __func__, path); |
| | | goto exit; |
| | | } |
| | | |
| | | file_data = rtw_vmalloc(file_size); |
| | | if (!file_data) { |
| | | RTW_ERR("%s rtw_vmalloc(%d) fail\n", __func__, file_size); |
| | | goto exit; |
| | | } |
| | | |
| | | read_size = rtw_retrieve_from_file(path, file_data, file_size); |
| | | if (read_size == 0) { |
| | | RTW_ERR("%s read from %s fail\n", __func__, path); |
| | | goto exit; |
| | | } |
| | | |
| | | map = rtw_vmalloc(map_size); |
| | | if (!map) { |
| | | RTW_ERR("%s rtw_vmalloc(%d) fail\n", __func__, map_size); |
| | | goto exit; |
| | | } |
| | | _rtw_memset(map, 0xff, map_size); |
| | | |
| | | temp[2] = 0; /* end of string '\0' */ |
| | | |
| | | for (i = 0 ; i < map_size ; i++) { |
| | | temp_i = 0; |
| | | |
| | | while (1) { |
| | | if (pos >= read_size) { |
| | | end = _TRUE; |
| | | break; |
| | | } |
| | | c = file_data[pos++]; |
| | | |
| | | /* bypass spece or eol or null before first hex digit */ |
| | | if (temp_i == 0 && (is_eol(c) == _TRUE || is_space(c) == _TRUE || is_null(c) == _TRUE)) |
| | | continue; |
| | | |
| | | if (IsHexDigit(c) == _FALSE) { |
| | | RTW_ERR("%s invalid 8-bit hex format for offset:0x%03x\n", __func__, i); |
| | | goto exit; |
| | | } |
| | | |
| | | temp[temp_i++] = c; |
| | | |
| | | if (temp_i == 2) { |
| | | /* parse value */ |
| | | if (sscanf(temp, "%hhx", &map[i]) != 1) { |
| | | RTW_ERR("%s sscanf fail for offset:0x%03x\n", __func__, i); |
| | | goto exit; |
| | | } |
| | | break; |
| | | } |
| | | } |
| | | |
| | | if (end == _TRUE) { |
| | | if (temp_i != 0) { |
| | | RTW_ERR("%s incomplete 8-bit hex format for offset:0x%03x\n", __func__, i); |
| | | goto exit; |
| | | } |
| | | break; |
| | | } |
| | | } |
| | | |
| | | RTW_PRINT("efuse file:%s, 0x%03x byte content read\n", path, i); |
| | | |
| | | _rtw_memcpy(buf, map, map_size); |
| | | |
| | | ret = _SUCCESS; |
| | | |
| | | exit: |
| | | if (file_data) |
| | | rtw_vmfree(file_data, file_size); |
| | | if (map) |
| | | rtw_vmfree(map, map_size); |
| | | |
| | | return ret; |
| | | } |
| | | |
| | | u32 rtw_read_macaddr_from_file(const char *path, u8 *buf) |
| | | { |
| | | u32 i; |
| | | u8 temp[3]; |
| | | u32 ret = _FAIL; |
| | | |
| | | u8 file_data[17]; |
| | | u32 read_size, pos = 0; |
| | | u8 addr[ETH_ALEN]; |
| | | |
| | | if (rtw_is_file_readable(path) != _TRUE) { |
| | | RTW_PRINT("%s %s is not readable\n", __func__, path); |
| | | goto exit; |
| | | } |
| | | |
| | | read_size = rtw_retrieve_from_file(path, file_data, 17); |
| | | if (read_size != 17) { |
| | | RTW_ERR("%s read from %s fail\n", __func__, path); |
| | | goto exit; |
| | | } |
| | | |
| | | temp[2] = 0; /* end of string '\0' */ |
| | | |
| | | for (i = 0 ; i < ETH_ALEN ; i++) { |
| | | if (IsHexDigit(file_data[i * 3]) == _FALSE || IsHexDigit(file_data[i * 3 + 1]) == _FALSE) { |
| | | RTW_ERR("%s invalid 8-bit hex format for address offset:%u\n", __func__, i); |
| | | goto exit; |
| | | } |
| | | |
| | | if (i < ETH_ALEN - 1 && file_data[i * 3 + 2] != ':') { |
| | | RTW_ERR("%s invalid separator after address offset:%u\n", __func__, i); |
| | | goto exit; |
| | | } |
| | | |
| | | temp[0] = file_data[i * 3]; |
| | | temp[1] = file_data[i * 3 + 1]; |
| | | if (sscanf(temp, "%hhx", &addr[i]) != 1) { |
| | | RTW_ERR("%s sscanf fail for address offset:0x%03x\n", __func__, i); |
| | | goto exit; |
| | | } |
| | | } |
| | | |
| | | _rtw_memcpy(buf, addr, ETH_ALEN); |
| | | |
| | | RTW_PRINT("wifi_mac file: %s\n", path); |
| | | #ifdef CONFIG_RTW_DEBUG |
| | | RTW_INFO(MAC_FMT"\n", MAC_ARG(buf)); |
| | | #endif |
| | | |
| | | ret = _SUCCESS; |
| | | |
| | | exit: |
| | | return ret; |
| | | } |
| | | #endif /* CONFIG_EFUSE_CONFIG_FILE */ |
| | | |
| | | #endif /* PLATFORM_LINUX */ |
New file |
| | |
| | | /****************************************************************************** |
| | | * |
| | | * Copyright(c) 2007 - 2016 Realtek Corporation. All rights reserved. |
| | | * |
| | | * This program is free software; you can redistribute it and/or modify it |
| | | * under the terms of version 2 of the GNU General Public License as |
| | | * published by the Free Software Foundation. |
| | | * |
| | | * This program is distributed in the hope that it will be useful, but WITHOUT |
| | | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| | | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
| | | * more details. |
| | | * |
| | | * You should have received a copy of the GNU General Public License along with |
| | | * this program; if not, write to the Free Software Foundation, Inc., |
| | | * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA |
| | | * |
| | | * |
| | | ******************************************************************************/ |
| | | #define _RTW_BEAMFORMING_C_ |
| | | |
| | | #include <drv_types.h> |
| | | #include <hal_data.h> |
| | | |
| | | #ifdef CONFIG_BEAMFORMING |
| | | |
| | | #ifdef RTW_BEAMFORMING_VERSION_2 |
| | | |
| | | struct ndpa_sta_info { |
| | | u16 aid:12; |
| | | u16 feedback_type:1; |
| | | u16 nc_index:3; |
| | | }; |
| | | |
| | | static void _get_txvector_parameter(PADAPTER adapter, struct sta_info *sta, u8 *g_id, u16 *p_aid) |
| | | { |
| | | struct mlme_priv *mlme; |
| | | u16 aid; |
| | | u8 *bssid; |
| | | u16 val16; |
| | | u8 i; |
| | | |
| | | |
| | | mlme = &adapter->mlmepriv; |
| | | |
| | | if (check_fwstate(mlme, WIFI_AP_STATE)) { |
| | | /* |
| | | * Sent by an AP and addressed to a STA associated with that AP |
| | | * or sent by a DLS or TDLS STA in a direct path to |
| | | * a DLS or TDLS peer STA |
| | | */ |
| | | |
| | | aid = sta->aid; |
| | | bssid = adapter_mac_addr(adapter); |
| | | RTW_INFO("%s: AID=0x%x BSSID=" MAC_FMT "\n", |
| | | __FUNCTION__, sta->aid, MAC_ARG(bssid)); |
| | | |
| | | /* AID[0:8] */ |
| | | aid &= 0x1FF; |
| | | /* BSSID[44:47] xor BSSID[40:43] */ |
| | | val16 = ((bssid[5] & 0xF0) >> 4) ^ (bssid[5] & 0xF); |
| | | /* (dec(AID[0:8]) + dec(BSSID)*2^5) mod 2^9 */ |
| | | *p_aid = (aid + (val16 << 5)) & 0x1FF; |
| | | *g_id = 63; |
| | | } else if ((check_fwstate(mlme, WIFI_ADHOC_STATE) == _TRUE) |
| | | || (check_fwstate(mlme, WIFI_ADHOC_MASTER_STATE) == _TRUE)) { |
| | | /* |
| | | * Otherwise, includes |
| | | * 1. Sent to an IBSS STA |
| | | * 2. Sent by an AP to a non associated STA |
| | | * 3. Sent to a STA for which it is not known |
| | | * which condition is applicable |
| | | */ |
| | | *p_aid = 0; |
| | | *g_id = 63; |
| | | } else { |
| | | /* Addressed to AP */ |
| | | bssid = sta->hwaddr; |
| | | RTW_INFO("%s: BSSID=" MAC_FMT "\n", __FUNCTION__, MAC_ARG(bssid)); |
| | | |
| | | /* BSSID[39:47] */ |
| | | *p_aid = (bssid[5] << 1) | (bssid[4] >> 7); |
| | | *g_id = 0; |
| | | } |
| | | |
| | | RTW_INFO("%s: GROUP_ID=0x%02x PARTIAL_AID=0x%04x\n", |
| | | __FUNCTION__, *g_id, *p_aid); |
| | | } |
| | | |
| | | /* |
| | | * Parameters |
| | | * adapter struct _adapter* |
| | | * sta struct sta_info* |
| | | * sta_bf_cap beamforming capabe of sta |
| | | * sounding_dim Number of Sounding Dimensions |
| | | * comp_steering Compressed Steering Number of Beamformer Antennas Supported |
| | | */ |
| | | static void _get_sta_beamform_cap(PADAPTER adapter, struct sta_info *sta, |
| | | u8 *sta_bf_cap, u8 *sounding_dim, u8 *comp_steering) |
| | | { |
| | | struct beamforming_info *info; |
| | | struct ht_priv *ht; |
| | | #ifdef CONFIG_80211AC_VHT |
| | | struct vht_priv *vht; |
| | | #endif /* CONFIG_80211AC_VHT */ |
| | | u16 bf_cap; |
| | | |
| | | |
| | | *sta_bf_cap = 0; |
| | | *sounding_dim = 0; |
| | | *comp_steering = 0; |
| | | |
| | | info = GET_BEAMFORM_INFO(adapter); |
| | | ht = &adapter->mlmepriv.htpriv; |
| | | #ifdef CONFIG_80211AC_VHT |
| | | vht = &adapter->mlmepriv.vhtpriv; |
| | | #endif /* CONFIG_80211AC_VHT */ |
| | | |
| | | if (is_supported_ht(sta->wireless_mode) == _TRUE) { |
| | | /* HT */ |
| | | bf_cap = ht->beamform_cap; |
| | | |
| | | if (TEST_FLAG(bf_cap, BEAMFORMING_HT_BEAMFORMEE_ENABLE)) { |
| | | info->beamforming_cap |= BEAMFORMEE_CAP_HT_EXPLICIT; |
| | | *sta_bf_cap |= BEAMFORMER_CAP_HT_EXPLICIT; |
| | | *sounding_dim = (bf_cap & BEAMFORMING_HT_BEAMFORMEE_CHNL_EST_CAP) >> 6; |
| | | } |
| | | if (TEST_FLAG(bf_cap, BEAMFORMING_HT_BEAMFORMER_ENABLE)) { |
| | | info->beamforming_cap |= BEAMFORMER_CAP_HT_EXPLICIT; |
| | | *sta_bf_cap |= BEAMFORMEE_CAP_HT_EXPLICIT; |
| | | *comp_steering = (bf_cap & BEAMFORMING_HT_BEAMFORMER_STEER_NUM) >> 4; |
| | | } |
| | | } |
| | | |
| | | #ifdef CONFIG_80211AC_VHT |
| | | if (is_supported_vht(sta->wireless_mode) == _TRUE) { |
| | | /* VHT */ |
| | | bf_cap = vht->beamform_cap; |
| | | |
| | | /* We are SU Beamformee because the STA is SU Beamformer */ |
| | | if (TEST_FLAG(bf_cap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE)) { |
| | | info->beamforming_cap |= BEAMFORMEE_CAP_VHT_SU; |
| | | *sta_bf_cap |= BEAMFORMER_CAP_VHT_SU; |
| | | |
| | | /* We are MU Beamformee because the STA is MU Beamformer */ |
| | | if (TEST_FLAG(bf_cap, BEAMFORMING_VHT_MU_MIMO_STA_ENABLE)) { |
| | | info->beamforming_cap |= BEAMFORMEE_CAP_VHT_MU; |
| | | *sta_bf_cap |= BEAMFORMER_CAP_VHT_MU; |
| | | } |
| | | |
| | | *sounding_dim = (bf_cap & BEAMFORMING_VHT_BEAMFORMEE_SOUND_DIM) >> 12; |
| | | } |
| | | /* We are SU Beamformer because the STA is SU Beamformee */ |
| | | if (TEST_FLAG(bf_cap, BEAMFORMING_VHT_BEAMFORMER_ENABLE)) { |
| | | info->beamforming_cap |= BEAMFORMER_CAP_VHT_SU; |
| | | *sta_bf_cap |= BEAMFORMEE_CAP_VHT_SU; |
| | | |
| | | /* We are MU Beamformer because the STA is MU Beamformee */ |
| | | if (TEST_FLAG(bf_cap, BEAMFORMING_VHT_MU_MIMO_AP_ENABLE)) { |
| | | info->beamforming_cap |= BEAMFORMER_CAP_VHT_MU; |
| | | *sta_bf_cap |= BEAMFORMEE_CAP_VHT_MU; |
| | | } |
| | | |
| | | *comp_steering = (bf_cap & BEAMFORMING_VHT_BEAMFORMER_STS_CAP) >> 8; |
| | | } |
| | | } |
| | | #endif /* CONFIG_80211AC_VHT */ |
| | | } |
| | | |
| | | static u8 _send_ht_ndpa_packet(PADAPTER adapter, u8 *ra, CHANNEL_WIDTH bw) |
| | | { |
| | | /* General */ |
| | | struct xmit_priv *pxmitpriv; |
| | | struct mlme_ext_priv *pmlmeext; |
| | | struct mlme_ext_info *pmlmeinfo; |
| | | struct xmit_frame *pmgntframe; |
| | | /* Beamforming */ |
| | | struct beamforming_info *info; |
| | | struct beamformee_entry *bfee; |
| | | struct ndpa_sta_info sta_info; |
| | | u8 ActionHdr[4] = {ACT_CAT_VENDOR, 0x00, 0xE0, 0x4C}; |
| | | /* MISC */ |
| | | struct pkt_attrib *attrib; |
| | | struct rtw_ieee80211_hdr *pwlanhdr; |
| | | enum MGN_RATE txrate; |
| | | u8 *pframe; |
| | | u16 duration = 0; |
| | | u8 aSifsTime = 0; |
| | | |
| | | |
| | | RTW_INFO("+%s: Send to " MAC_FMT "\n", __FUNCTION__, MAC_ARG(ra)); |
| | | |
| | | pxmitpriv = &adapter->xmitpriv; |
| | | pmlmeext = &adapter->mlmeextpriv; |
| | | pmlmeinfo = &pmlmeext->mlmext_info; |
| | | bfee = rtw_bf_bfee_get_entry_by_addr(adapter, ra); |
| | | if (!bfee) { |
| | | RTW_ERR("%s: Cann't find beamformee entry!\n", __FUNCTION__); |
| | | return _FALSE; |
| | | } |
| | | |
| | | pmgntframe = alloc_mgtxmitframe(pxmitpriv); |
| | | if (!pmgntframe) { |
| | | RTW_ERR("%s: alloc mgnt frame fail!\n", __FUNCTION__); |
| | | return _FALSE; |
| | | } |
| | | |
| | | txrate = beamforming_get_htndp_tx_rate(GET_PDM_ODM(adapter), bfee->comp_steering_num_of_bfer); |
| | | |
| | | /* update attribute */ |
| | | attrib = &pmgntframe->attrib; |
| | | update_mgntframe_attrib(adapter, attrib); |
| | | /*attrib->type = WIFI_MGT_TYPE;*/ /* set in update_mgntframe_attrib() */ |
| | | attrib->subtype = WIFI_ACTION_NOACK; |
| | | attrib->bwmode = bw; |
| | | /*attrib->qsel = QSLT_MGNT;*/ /* set in update_mgntframe_attrib() */ |
| | | attrib->order = 1; |
| | | attrib->rate = (u8)txrate; |
| | | attrib->bf_pkt_type = 0; |
| | | |
| | | _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); |
| | | pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; |
| | | pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; |
| | | |
| | | /* Frame control */ |
| | | pwlanhdr->frame_ctl = 0; |
| | | set_frame_sub_type(pframe, attrib->subtype); |
| | | set_order_bit(pframe); |
| | | |
| | | /* Duration */ |
| | | if (pmlmeext->cur_wireless_mode == WIRELESS_11B) |
| | | aSifsTime = 10; |
| | | else |
| | | aSifsTime = 16; |
| | | duration = 2 * aSifsTime + 40; |
| | | if (bw == CHANNEL_WIDTH_40) |
| | | duration += 87; |
| | | else |
| | | duration += 180; |
| | | set_duration(pframe, duration); |
| | | |
| | | /* DA */ |
| | | _rtw_memcpy(pwlanhdr->addr1, ra, ETH_ALEN); |
| | | /* SA */ |
| | | _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(adapter), ETH_ALEN); |
| | | /* BSSID */ |
| | | _rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&pmlmeinfo->network), ETH_ALEN); |
| | | |
| | | /* HT control field */ |
| | | SET_HT_CTRL_CSI_STEERING(pframe + 24, 3); |
| | | SET_HT_CTRL_NDP_ANNOUNCEMENT(pframe + 24, 1); |
| | | |
| | | /* |
| | | * Frame Body |
| | | * Category field: vender-specific value, 0x7F |
| | | * OUI: 0x00E04C |
| | | */ |
| | | _rtw_memcpy(pframe + 28, ActionHdr, 4); |
| | | |
| | | attrib->pktlen = 32; |
| | | attrib->last_txcmdsz = attrib->pktlen; |
| | | |
| | | dump_mgntframe(adapter, pmgntframe); |
| | | |
| | | return _TRUE; |
| | | } |
| | | |
| | | static u8 _send_vht_ndpa_packet(PADAPTER adapter, u8 *ra, u16 aid, CHANNEL_WIDTH bw) |
| | | { |
| | | /* General */ |
| | | struct xmit_priv *pxmitpriv; |
| | | struct mlme_ext_priv *pmlmeext; |
| | | struct xmit_frame *pmgntframe; |
| | | /* Beamforming */ |
| | | struct beamforming_info *info; |
| | | struct beamformee_entry *bfee; |
| | | struct ndpa_sta_info sta_info; |
| | | /* MISC */ |
| | | struct pkt_attrib *attrib; |
| | | struct rtw_ieee80211_hdr *pwlanhdr; |
| | | u8 *pframe; |
| | | enum MGN_RATE txrate; |
| | | u16 duration = 0; |
| | | u8 sequence = 0, aSifsTime = 0; |
| | | |
| | | |
| | | RTW_INFO("+%s: Send to " MAC_FMT "\n", __FUNCTION__, MAC_ARG(ra)); |
| | | |
| | | pxmitpriv = &adapter->xmitpriv; |
| | | pmlmeext = &adapter->mlmeextpriv; |
| | | info = GET_BEAMFORM_INFO(adapter); |
| | | bfee = rtw_bf_bfee_get_entry_by_addr(adapter, ra); |
| | | if (!bfee) { |
| | | RTW_ERR("%s: Cann't find beamformee entry!\n", __FUNCTION__); |
| | | return _FALSE; |
| | | } |
| | | |
| | | pmgntframe = alloc_mgtxmitframe(pxmitpriv); |
| | | if (!pmgntframe) { |
| | | RTW_ERR("%s: alloc mgnt frame fail!\n", __FUNCTION__); |
| | | return _FALSE; |
| | | } |
| | | |
| | | txrate = beamforming_get_vht_ndp_tx_rate(GET_PDM_ODM(adapter), bfee->comp_steering_num_of_bfer); |
| | | |
| | | /* update attribute */ |
| | | attrib = &pmgntframe->attrib; |
| | | update_mgntframe_attrib(adapter, attrib); |
| | | /*pattrib->type = WIFI_MGT_TYPE;*/ /* set in update_mgntframe_attrib() */ |
| | | attrib->subtype = WIFI_NDPA; |
| | | attrib->bwmode = bw; |
| | | /*attrib->qsel = QSLT_MGNT;*/ /* set in update_mgntframe_attrib() */ |
| | | attrib->rate = (u8)txrate; |
| | | attrib->bf_pkt_type = 0; |
| | | |
| | | _rtw_memset(pmgntframe->buf_addr, 0, TXDESC_OFFSET + WLANHDR_OFFSET); |
| | | pframe = pmgntframe->buf_addr + TXDESC_OFFSET; |
| | | pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; |
| | | |
| | | /* Frame control */ |
| | | pwlanhdr->frame_ctl = 0; |
| | | set_frame_sub_type(pframe, attrib->subtype); |
| | | |
| | | /* Duration */ |
| | | if (is_supported_5g(pmlmeext->cur_wireless_mode) || is_supported_ht(pmlmeext->cur_wireless_mode)) |
| | | aSifsTime = 16; |
| | | else |
| | | aSifsTime = 10; |
| | | duration = 2 * aSifsTime + 44; |
| | | if (bw == CHANNEL_WIDTH_80) |
| | | duration += 40; |
| | | else if (bw == CHANNEL_WIDTH_40) |
| | | duration += 87; |
| | | else |
| | | duration += 180; |
| | | set_duration(pframe, duration); |
| | | |
| | | /* RA */ |
| | | _rtw_memcpy(pwlanhdr->addr1, ra, ETH_ALEN); |
| | | |
| | | /* TA */ |
| | | _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(adapter), ETH_ALEN); |
| | | |
| | | /* Sounding Sequence, bit0~1 is reserved */ |
| | | sequence = info->sounding_sequence << 2; |
| | | if (info->sounding_sequence >= 0x3f) |
| | | info->sounding_sequence = 0; |
| | | else |
| | | info->sounding_sequence++; |
| | | _rtw_memcpy(pframe + 16, &sequence, 1); |
| | | |
| | | /* STA Info */ |
| | | /* |
| | | * "AID12" Equal to 0 if the STA is an AP, mesh STA or |
| | | * STA that is a member of an IBSS |
| | | */ |
| | | if (check_fwstate(&adapter->mlmepriv, WIFI_AP_STATE) == _FALSE) |
| | | aid = 0; |
| | | sta_info.aid = aid; |
| | | /* "Feedback Type" set to 0 for SU */ |
| | | sta_info.feedback_type = 0; |
| | | /* "Nc Index" reserved if the Feedback Type field indicates SU */ |
| | | sta_info.nc_index = 0; |
| | | _rtw_memcpy(pframe + 17, (u8 *)&sta_info, 2); |
| | | |
| | | attrib->pktlen = 19; |
| | | attrib->last_txcmdsz = attrib->pktlen; |
| | | |
| | | dump_mgntframe(adapter, pmgntframe); |
| | | |
| | | return _TRUE; |
| | | } |
| | | |
| | | static u8 _send_vht_mu_ndpa_packet(PADAPTER adapter, CHANNEL_WIDTH bw) |
| | | { |
| | | /* General */ |
| | | struct xmit_priv *pxmitpriv; |
| | | struct mlme_ext_priv *pmlmeext; |
| | | struct xmit_frame *pmgntframe; |
| | | /* Beamforming */ |
| | | struct beamforming_info *info; |
| | | struct sounding_info *sounding; |
| | | struct beamformee_entry *bfee; |
| | | struct ndpa_sta_info sta_info; |
| | | /* MISC */ |
| | | struct pkt_attrib *attrib; |
| | | struct rtw_ieee80211_hdr *pwlanhdr; |
| | | enum MGN_RATE txrate; |
| | | u8 *pframe; |
| | | u8 *ra = NULL; |
| | | u16 duration = 0; |
| | | u8 sequence = 0, aSifsTime = 0; |
| | | u8 i; |
| | | |
| | | |
| | | RTW_INFO("+%s\n", __FUNCTION__); |
| | | |
| | | pxmitpriv = &adapter->xmitpriv; |
| | | pmlmeext = &adapter->mlmeextpriv; |
| | | info = GET_BEAMFORM_INFO(adapter); |
| | | sounding = &info->sounding_info; |
| | | |
| | | txrate = MGN_VHT2SS_MCS0; |
| | | |
| | | /* |
| | | * Fill the first MU BFee entry (STA1) MAC addr to destination address then |
| | | * HW will change A1 to broadcast addr. |
| | | * 2015.05.28. Suggested by SD1 Chunchu. |
| | | */ |
| | | bfee = &info->bfee_entry[sounding->mu_sounding_list[0]]; |
| | | ra = bfee->mac_addr; |
| | | |
| | | pmgntframe = alloc_mgtxmitframe(pxmitpriv); |
| | | if (!pmgntframe) { |
| | | RTW_ERR("%s: alloc mgnt frame fail!\n", __FUNCTION__); |
| | | return _FALSE; |
| | | } |
| | | |
| | | /* update attribute */ |
| | | attrib = &pmgntframe->attrib; |
| | | update_mgntframe_attrib(adapter, attrib); |
| | | /*attrib->type = WIFI_MGT_TYPE;*/ /* set in update_mgntframe_attrib() */ |
| | | attrib->subtype = WIFI_NDPA; |
| | | attrib->bwmode = bw; |
| | | /*attrib->qsel = QSLT_MGNT;*/ /* set in update_mgntframe_attrib() */ |
| | | attrib->rate = (u8)txrate; |
| | | /* Set TxBFPktType of Tx desc to unicast type if there is only one MU STA for HW design */ |
| | | if (info->sounding_info.candidate_mu_bfee_cnt > 1) |
| | | attrib->bf_pkt_type = 1; |
| | | else |
| | | attrib->bf_pkt_type = 0; |
| | | |
| | | _rtw_memset(pmgntframe->buf_addr, 0, TXDESC_OFFSET + WLANHDR_OFFSET); |
| | | pframe = pmgntframe->buf_addr + TXDESC_OFFSET; |
| | | pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; |
| | | |
| | | /* Frame control */ |
| | | pwlanhdr->frame_ctl = 0; |
| | | set_frame_sub_type(pframe, attrib->subtype); |
| | | |
| | | /* Duration */ |
| | | if (is_supported_5g(pmlmeext->cur_wireless_mode) || is_supported_ht(pmlmeext->cur_wireless_mode)) |
| | | aSifsTime = 16; |
| | | else |
| | | aSifsTime = 10; |
| | | duration = 2 * aSifsTime + 44; |
| | | if (bw == CHANNEL_WIDTH_80) |
| | | duration += 40; |
| | | else if (bw == CHANNEL_WIDTH_40) |
| | | duration += 87; |
| | | else |
| | | duration += 180; |
| | | set_duration(pframe, duration); |
| | | |
| | | /* RA */ |
| | | _rtw_memcpy(pwlanhdr->addr1, ra, ETH_ALEN); |
| | | |
| | | /* TA */ |
| | | _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(adapter), ETH_ALEN); |
| | | |
| | | /* Sounding Sequence, bit0~1 is reserved */ |
| | | sequence = info->sounding_sequence << 2; |
| | | if (info->sounding_sequence >= 0x3f) |
| | | info->sounding_sequence = 0; |
| | | else |
| | | info->sounding_sequence++; |
| | | _rtw_memcpy(pframe + 16, &sequence, 1); |
| | | |
| | | attrib->pktlen = 17; |
| | | |
| | | /* |
| | | * Construct STA info. for multiple STAs |
| | | * STA Info1, ..., STA Info n |
| | | */ |
| | | for (i = 0; i < sounding->candidate_mu_bfee_cnt; i++) { |
| | | bfee = &info->bfee_entry[sounding->mu_sounding_list[i]]; |
| | | sta_info.aid = bfee->aid; |
| | | sta_info.feedback_type = 1; /* 1'b1: MU */ |
| | | sta_info.nc_index = 0; |
| | | _rtw_memcpy(pframe + attrib->pktlen, (u8 *)&sta_info, 2); |
| | | attrib->pktlen += 2; |
| | | } |
| | | |
| | | attrib->last_txcmdsz = attrib->pktlen; |
| | | |
| | | dump_mgntframe(adapter, pmgntframe); |
| | | |
| | | return _TRUE; |
| | | } |
| | | |
| | | static u8 _send_bf_report_poll(PADAPTER adapter, u8 *ra, u8 bFinalPoll) |
| | | { |
| | | /* General */ |
| | | struct xmit_priv *pxmitpriv; |
| | | struct xmit_frame *pmgntframe; |
| | | /* MISC */ |
| | | struct pkt_attrib *attrib; |
| | | struct rtw_ieee80211_hdr *pwlanhdr; |
| | | u8 *pframe; |
| | | |
| | | |
| | | RTW_INFO("+%s: Send to " MAC_FMT "\n", __FUNCTION__, MAC_ARG(ra)); |
| | | |
| | | pxmitpriv = &adapter->xmitpriv; |
| | | |
| | | pmgntframe = alloc_mgtxmitframe(pxmitpriv); |
| | | if (!pmgntframe) { |
| | | RTW_ERR("%s: alloc mgnt frame fail!\n", __FUNCTION__); |
| | | return _FALSE; |
| | | } |
| | | |
| | | /* update attribute */ |
| | | attrib = &pmgntframe->attrib; |
| | | update_mgntframe_attrib(adapter, attrib); |
| | | /*attrib->type = WIFI_MGT_TYPE;*/ /* set in update_mgntframe_attrib() */ |
| | | attrib->subtype = WIFI_BF_REPORT_POLL; |
| | | attrib->bwmode = CHANNEL_WIDTH_20; |
| | | /*attrib->qsel = QSLT_MGNT;*/ /* set in update_mgntframe_attrib() */ |
| | | attrib->rate = MGN_6M; |
| | | if (bFinalPoll) |
| | | attrib->bf_pkt_type = 3; |
| | | else |
| | | attrib->bf_pkt_type = 2; |
| | | |
| | | _rtw_memset(pmgntframe->buf_addr, 0, TXDESC_OFFSET + WLANHDR_OFFSET); |
| | | pframe = pmgntframe->buf_addr + TXDESC_OFFSET; |
| | | pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; |
| | | |
| | | /* Frame control */ |
| | | pwlanhdr->frame_ctl = 0; |
| | | set_frame_sub_type(pframe, attrib->subtype); |
| | | |
| | | /* Duration */ |
| | | set_duration(pframe, 100); |
| | | |
| | | /* RA */ |
| | | _rtw_memcpy(pwlanhdr->addr1, ra, ETH_ALEN); |
| | | |
| | | /* TA */ |
| | | _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(adapter), ETH_ALEN); |
| | | |
| | | /* Feedback Segment Retransmission Bitmap */ |
| | | pframe[16] = 0xFF; |
| | | |
| | | attrib->pktlen = 17; |
| | | attrib->last_txcmdsz = attrib->pktlen; |
| | | |
| | | dump_mgntframe(adapter, pmgntframe); |
| | | |
| | | return _TRUE; |
| | | } |
| | | |
| | | static void _sounding_update_min_period(PADAPTER adapter, u16 period, u8 leave) |
| | | { |
| | | struct beamforming_info *info; |
| | | struct beamformee_entry *bfee; |
| | | u8 i = 0; |
| | | u16 min_val = 0xFFFF; |
| | | |
| | | |
| | | info = GET_BEAMFORM_INFO(adapter); |
| | | |
| | | if (_TRUE == leave) { |
| | | /* |
| | | * When a BFee left, |
| | | * we need to find the latest min sounding period |
| | | * from the remaining BFees |
| | | */ |
| | | for (i = 0; i < MAX_BEAMFORMEE_ENTRY_NUM; i++) { |
| | | bfee = &info->bfee_entry[i]; |
| | | if ((bfee->used == _TRUE) |
| | | && (bfee->sound_period < min_val)) |
| | | min_val = bfee->sound_period; |
| | | } |
| | | |
| | | if (min_val == 0xFFFF) |
| | | info->sounding_info.min_sounding_period = 0; |
| | | else |
| | | info->sounding_info.min_sounding_period = min_val; |
| | | } else { |
| | | if ((info->sounding_info.min_sounding_period == 0) |
| | | || (period < info->sounding_info.min_sounding_period)) |
| | | info->sounding_info.min_sounding_period = period; |
| | | } |
| | | } |
| | | |
| | | static void _sounding_init(struct sounding_info *sounding) |
| | | { |
| | | _rtw_memset(sounding->su_sounding_list, 0xFF, MAX_NUM_BEAMFORMEE_SU); |
| | | _rtw_memset(sounding->mu_sounding_list, 0xFF, MAX_NUM_BEAMFORMEE_MU); |
| | | sounding->state = SOUNDING_STATE_NONE; |
| | | sounding->su_bfee_curidx = 0xFF; |
| | | sounding->candidate_mu_bfee_cnt = 0; |
| | | sounding->min_sounding_period = 0; |
| | | sounding->sound_remain_cnt_per_period = 0; |
| | | } |
| | | |
| | | static void _sounding_reset_vars(PADAPTER adapter) |
| | | { |
| | | struct beamforming_info *info; |
| | | struct sounding_info *sounding; |
| | | u8 idx; |
| | | |
| | | |
| | | info = GET_BEAMFORM_INFO(adapter); |
| | | sounding = &info->sounding_info; |
| | | |
| | | _rtw_memset(sounding->su_sounding_list, 0xFF, MAX_NUM_BEAMFORMEE_SU); |
| | | _rtw_memset(sounding->mu_sounding_list, 0xFF, MAX_NUM_BEAMFORMEE_MU); |
| | | sounding->su_bfee_curidx = 0xFF; |
| | | sounding->candidate_mu_bfee_cnt = 0; |
| | | |
| | | /* Clear bSound flag for the new period */ |
| | | for (idx = 0; idx < MAX_BEAMFORMEE_ENTRY_NUM; idx++) { |
| | | if ((info->bfee_entry[idx].used == _TRUE) |
| | | && (info->bfee_entry[idx].sounding == _TRUE)) { |
| | | info->bfee_entry[idx].sounding = _FALSE; |
| | | info->bfee_entry[idx].bCandidateSoundingPeer = _FALSE; |
| | | } |
| | | } |
| | | } |
| | | |
| | | /* |
| | | * Return |
| | | * 0 Prepare sounding list OK |
| | | * -1 Fail to prepare sounding list, because no beamformee need to souding |
| | | * -2 Fail to prepare sounding list, because beamformee state not ready |
| | | * |
| | | */ |
| | | static int _sounding_get_list(PADAPTER adapter) |
| | | { |
| | | struct beamforming_info *info; |
| | | struct sounding_info *sounding; |
| | | struct beamformee_entry *bfee; |
| | | u8 i, mu_idx = 0, su_idx = 0, not_ready = 0; |
| | | int ret = 0; |
| | | |
| | | |
| | | info = GET_BEAMFORM_INFO(adapter); |
| | | sounding = &info->sounding_info; |
| | | |
| | | /* Add MU BFee list first because MU priority is higher than SU */ |
| | | for (i = 0; i < MAX_BEAMFORMEE_ENTRY_NUM; i++) { |
| | | bfee = &info->bfee_entry[i]; |
| | | if (bfee->used == _FALSE) |
| | | continue; |
| | | |
| | | if (bfee->state != BEAMFORM_ENTRY_HW_STATE_ADDED) { |
| | | RTW_ERR("%s: Invalid BFee idx(%d) Hw state=%d\n", __FUNCTION__, i, bfee->state); |
| | | not_ready++; |
| | | continue; |
| | | } |
| | | |
| | | /* |
| | | * Decrease BFee's SoundCnt per period |
| | | * If the remain count is 0, |
| | | * then it can be sounded at this time |
| | | */ |
| | | if (bfee->SoundCnt) { |
| | | bfee->SoundCnt--; |
| | | if (bfee->SoundCnt) |
| | | continue; |
| | | } |
| | | |
| | | /* |
| | | * <tynli_Note> |
| | | * If the STA supports MU BFee capability then we add it to MUSoundingList directly |
| | | * because we can only sound one STA by unicast NDPA with MU cap enabled to get correct channel info. |
| | | * Suggested by BB team Luke Lee. 2015.11.25. |
| | | */ |
| | | if (bfee->cap & BEAMFORMEE_CAP_VHT_MU) { |
| | | /* MU BFee */ |
| | | if (mu_idx >= MAX_NUM_BEAMFORMEE_MU) { |
| | | RTW_ERR("%s: Too much MU bfee entry(Limit:%d)\n", __FUNCTION__, MAX_NUM_BEAMFORMEE_MU); |
| | | continue; |
| | | } |
| | | |
| | | if (bfee->bApplySounding == _TRUE) { |
| | | bfee->bCandidateSoundingPeer = _TRUE; |
| | | bfee->SoundCnt = GetInitSoundCnt(bfee->sound_period, sounding->min_sounding_period); |
| | | sounding->mu_sounding_list[mu_idx] = i; |
| | | mu_idx++; |
| | | } |
| | | } else if (bfee->cap & (BEAMFORMEE_CAP_VHT_SU|BEAMFORMEE_CAP_HT_EXPLICIT)) { |
| | | /* SU BFee (HT/VHT) */ |
| | | if (su_idx >= MAX_NUM_BEAMFORMEE_SU) { |
| | | RTW_ERR("%s: Too much SU bfee entry(Limit:%d)\n", __FUNCTION__, MAX_NUM_BEAMFORMEE_SU); |
| | | continue; |
| | | } |
| | | |
| | | if (bfee->bDeleteSounding == _TRUE) { |
| | | sounding->su_sounding_list[su_idx] = i; |
| | | su_idx++; |
| | | } else if ((bfee->bApplySounding == _TRUE) |
| | | && (bfee->bSuspendSUCap == _FALSE)) { |
| | | bfee->bCandidateSoundingPeer = _TRUE; |
| | | bfee->SoundCnt = GetInitSoundCnt(bfee->sound_period, sounding->min_sounding_period); |
| | | sounding->su_sounding_list[su_idx] = i; |
| | | su_idx++; |
| | | } |
| | | } |
| | | } |
| | | |
| | | sounding->candidate_mu_bfee_cnt = mu_idx; |
| | | |
| | | if (su_idx + mu_idx == 0) { |
| | | ret = -1; |
| | | if (not_ready) |
| | | ret = -2; |
| | | } |
| | | |
| | | RTW_INFO("-%s: There are %d SU and %d MU BFees in this sounding period\n", __FUNCTION__, su_idx, mu_idx); |
| | | |
| | | return ret; |
| | | } |
| | | |
| | | static void _sounding_handler(PADAPTER adapter) |
| | | { |
| | | struct beamforming_info *info; |
| | | struct sounding_info *sounding; |
| | | struct beamformee_entry *bfee; |
| | | u8 su_idx, i; |
| | | u32 timeout_period = 0; |
| | | u8 set_timer = _FALSE; |
| | | int ret = 0; |
| | | static u16 wait_cnt = 0; |
| | | |
| | | |
| | | info = GET_BEAMFORM_INFO(adapter); |
| | | sounding = &info->sounding_info; |
| | | |
| | | RTW_DBG("+%s: state=%d\n", __FUNCTION__, sounding->state); |
| | | if ((sounding->state != SOUNDING_STATE_INIT) |
| | | && (sounding->state != SOUNDING_STATE_SU_SOUNDDOWN) |
| | | && (sounding->state != SOUNDING_STATE_MU_SOUNDDOWN) |
| | | && (sounding->state != SOUNDING_STATE_SOUNDING_TIMEOUT)) { |
| | | RTW_WARN("%s: Invalid State(%d) and return!\n", __FUNCTION__, sounding->state); |
| | | return; |
| | | } |
| | | |
| | | if (sounding->state == SOUNDING_STATE_INIT) { |
| | | RTW_INFO("%s: Sounding start\n", __FUNCTION__); |
| | | |
| | | /* Init Var */ |
| | | _sounding_reset_vars(adapter); |
| | | |
| | | /* Get the sounding list of this sounding period */ |
| | | ret = _sounding_get_list(adapter); |
| | | if (ret == -1) { |
| | | wait_cnt = 0; |
| | | sounding->state = SOUNDING_STATE_NONE; |
| | | RTW_ERR("%s: No BFees found, set to SOUNDING_STATE_NONE\n", __FUNCTION__); |
| | | info->sounding_running--; |
| | | return; |
| | | } |
| | | if (ret == -2) { |
| | | RTW_WARN("%s: Temporarily cann't find BFee to sounding\n", __FUNCTION__); |
| | | if (wait_cnt < 5) { |
| | | wait_cnt++; |
| | | } else { |
| | | wait_cnt = 0; |
| | | sounding->state = SOUNDING_STATE_NONE; |
| | | RTW_ERR("%s: Wait changing state timeout!! Set to SOUNDING_STATE_NONE\n", __FUNCTION__); |
| | | } |
| | | info->sounding_running--; |
| | | return; |
| | | } |
| | | if (ret != 0) { |
| | | wait_cnt = 0; |
| | | RTW_ERR("%s: Unkown state(%d)!\n", __FUNCTION__, ret); |
| | | info->sounding_running--; |
| | | return; |
| | | |
| | | } |
| | | |
| | | wait_cnt = 0; |
| | | |
| | | if (check_fwstate(&adapter->mlmepriv, WIFI_SITE_MONITOR) == _TRUE) { |
| | | RTW_INFO("%s: Sounding abort! scanning APs...\n", __FUNCTION__); |
| | | info->sounding_running--; |
| | | return; |
| | | } |
| | | |
| | | rtw_ps_deny(adapter, PS_DENY_BEAMFORMING); |
| | | LeaveAllPowerSaveModeDirect(adapter); |
| | | } |
| | | |
| | | /* Get non-sound SU BFee index */ |
| | | for (i = 0; i < MAX_NUM_BEAMFORMEE_SU; i++) { |
| | | su_idx = sounding->su_sounding_list[i]; |
| | | if (su_idx >= MAX_BEAMFORMEE_ENTRY_NUM) |
| | | continue; |
| | | bfee = &info->bfee_entry[su_idx]; |
| | | if (_FALSE == bfee->sounding) |
| | | break; |
| | | } |
| | | if (i < MAX_NUM_BEAMFORMEE_SU) { |
| | | sounding->su_bfee_curidx = su_idx; |
| | | /* Set to sounding start state */ |
| | | sounding->state = SOUNDING_STATE_SU_START; |
| | | RTW_DBG("%s: Set to SOUNDING_STATE_SU_START\n", __FUNCTION__); |
| | | |
| | | bfee->sounding = _TRUE; |
| | | /* Reset sounding timeout flag for the new sounding */ |
| | | bfee->bSoundingTimeout = _FALSE; |
| | | |
| | | if (_TRUE == bfee->bDeleteSounding) { |
| | | u8 res = _FALSE; |
| | | rtw_bf_cmd(adapter, BEAMFORMING_CTRL_END_PERIOD, &res, 1, 0); |
| | | return; |
| | | } |
| | | |
| | | /* Start SU sounding */ |
| | | if (bfee->cap & BEAMFORMEE_CAP_VHT_SU) |
| | | _send_vht_ndpa_packet(adapter, bfee->mac_addr, bfee->aid, bfee->sound_bw); |
| | | else if (bfee->cap & BEAMFORMEE_CAP_HT_EXPLICIT) |
| | | _send_ht_ndpa_packet(adapter, bfee->mac_addr, bfee->sound_bw); |
| | | |
| | | /* Set sounding timeout timer */ |
| | | _set_timer(&info->sounding_timeout_timer, SU_SOUNDING_TIMEOUT); |
| | | return; |
| | | } |
| | | |
| | | if (sounding->candidate_mu_bfee_cnt > 0) { |
| | | /* |
| | | * If there is no SU BFee then find MU BFee and perform MU sounding |
| | | * |
| | | * <tynli_note> Need to check the MU starting condition. 2015.12.15. |
| | | */ |
| | | sounding->state = SOUNDING_STATE_MU_START; |
| | | RTW_DBG("%s: Set to SOUNDING_STATE_MU_START\n", __FUNCTION__); |
| | | |
| | | /* Update MU BFee info */ |
| | | for (i = 0; i < sounding->candidate_mu_bfee_cnt; i++) { |
| | | bfee = &info->bfee_entry[sounding->mu_sounding_list[i]]; |
| | | bfee->sounding = _TRUE; |
| | | } |
| | | |
| | | /* Send MU NDPA */ |
| | | bfee = &info->bfee_entry[sounding->mu_sounding_list[0]]; |
| | | _send_vht_mu_ndpa_packet(adapter, bfee->sound_bw); |
| | | |
| | | /* Send BF report poll if more than 1 MU STA */ |
| | | for (i = 1; i < sounding->candidate_mu_bfee_cnt; i++) { |
| | | bfee = &info->bfee_entry[sounding->mu_sounding_list[i]]; |
| | | |
| | | if (i == (sounding->candidate_mu_bfee_cnt - 1))/* The last STA*/ |
| | | _send_bf_report_poll(adapter, bfee->mac_addr, _TRUE); |
| | | else |
| | | _send_bf_report_poll(adapter, bfee->mac_addr, _FALSE); |
| | | } |
| | | |
| | | sounding->candidate_mu_bfee_cnt = 0; |
| | | |
| | | /* Set sounding timeout timer */ |
| | | _set_timer(&info->sounding_timeout_timer, MU_SOUNDING_TIMEOUT); |
| | | return; |
| | | } |
| | | |
| | | info->sounding_running--; |
| | | sounding->state = SOUNDING_STATE_INIT; |
| | | RTW_INFO("%s: Sounding finished!\n", __FUNCTION__); |
| | | rtw_ps_deny_cancel(adapter, PS_DENY_BEAMFORMING); |
| | | } |
| | | |
| | | static void _sounding_force_stop(PADAPTER adapter) |
| | | { |
| | | struct beamforming_info *info; |
| | | struct sounding_info *sounding; |
| | | u8 cancelled; |
| | | |
| | | |
| | | info = GET_BEAMFORM_INFO(adapter); |
| | | sounding = &info->sounding_info; |
| | | |
| | | if ((sounding->state == SOUNDING_STATE_SU_START) |
| | | || (sounding->state == SOUNDING_STATE_MU_START)) { |
| | | u8 res = _FALSE; |
| | | _cancel_timer(&info->sounding_timeout_timer, &cancelled); |
| | | rtw_bf_cmd(adapter, BEAMFORMING_CTRL_END_PERIOD, &res, 1, 1); |
| | | return; |
| | | } |
| | | |
| | | info->sounding_running--; |
| | | sounding->state = SOUNDING_STATE_INIT; |
| | | RTW_INFO("%s: Sounding finished!\n", __FUNCTION__); |
| | | rtw_ps_deny_cancel(adapter, PS_DENY_BEAMFORMING); |
| | | } |
| | | |
| | | static void _sounding_timer_handler(void *FunctionContext) |
| | | { |
| | | PADAPTER adapter; |
| | | struct beamforming_info *info; |
| | | struct sounding_info *sounding; |
| | | static u8 delay = 0; |
| | | |
| | | |
| | | RTW_DBG("+%s\n", __FUNCTION__); |
| | | |
| | | adapter = (PADAPTER)FunctionContext; |
| | | info = GET_BEAMFORM_INFO(adapter); |
| | | sounding = &info->sounding_info; |
| | | |
| | | if (SOUNDING_STATE_NONE == sounding->state) { |
| | | RTW_INFO("%s: Stop!\n", __FUNCTION__); |
| | | if (info->sounding_running) |
| | | RTW_WARN("%s: souding_running=%d when thread stop!\n", |
| | | __FUNCTION__, info->sounding_running); |
| | | return; |
| | | } |
| | | |
| | | _set_timer(&info->sounding_timer, sounding->min_sounding_period); |
| | | |
| | | if (!info->sounding_running) { |
| | | if (SOUNDING_STATE_INIT != sounding->state) { |
| | | RTW_WARN("%s: state(%d) != SOUNDING_STATE_INIT!!\n", __FUNCTION__, sounding->state); |
| | | sounding->state = SOUNDING_STATE_INIT; |
| | | } |
| | | delay = 0; |
| | | info->sounding_running++; |
| | | rtw_bf_cmd(adapter, BEAMFORMING_CTRL_START_PERIOD, NULL, 0, 1); |
| | | } else { |
| | | if (delay != 0xFF) |
| | | delay++; |
| | | RTW_WARN("%s: souding is still processing...(state:%d, running:%d, delay:%d)\n", |
| | | __FUNCTION__, sounding->state, info->sounding_running, delay); |
| | | if (delay > 3) { |
| | | RTW_WARN("%s: Stop sounding!!\n", __FUNCTION__); |
| | | _sounding_force_stop(adapter); |
| | | } |
| | | } |
| | | } |
| | | |
| | | static void _sounding_timeout_timer_handler(void *FunctionContext) |
| | | { |
| | | PADAPTER adapter; |
| | | struct beamforming_info *info; |
| | | struct sounding_info *sounding; |
| | | struct beamformee_entry *bfee; |
| | | |
| | | |
| | | RTW_WARN("+%s\n", __FUNCTION__); |
| | | |
| | | adapter = (PADAPTER)FunctionContext; |
| | | info = GET_BEAMFORM_INFO(adapter); |
| | | sounding = &info->sounding_info; |
| | | |
| | | if (SOUNDING_STATE_SU_START == sounding->state) { |
| | | sounding->state = SOUNDING_STATE_SOUNDING_TIMEOUT; |
| | | RTW_ERR("%s: Set to SU SOUNDING_STATE_SOUNDING_TIMEOUT\n", __FUNCTION__); |
| | | /* SU BFee */ |
| | | bfee = &info->bfee_entry[sounding->su_bfee_curidx]; |
| | | bfee->bSoundingTimeout = _TRUE; |
| | | RTW_WARN("%s: The BFee entry[%d] is Sounding Timeout!\n", __FUNCTION__, sounding->su_bfee_curidx); |
| | | } else if (SOUNDING_STATE_MU_START == sounding->state) { |
| | | sounding->state = SOUNDING_STATE_SOUNDING_TIMEOUT; |
| | | RTW_ERR("%s: Set to MU SOUNDING_STATE_SOUNDING_TIMEOUT\n", __FUNCTION__); |
| | | } else { |
| | | RTW_WARN("%s: unexpected sounding state:0x%02x\n", __FUNCTION__, sounding->state); |
| | | return; |
| | | } |
| | | |
| | | rtw_bf_cmd(adapter, BEAMFORMING_CTRL_START_PERIOD, NULL, 0, 1); |
| | | } |
| | | |
| | | static struct beamformer_entry *_bfer_get_free_entry(PADAPTER adapter) |
| | | { |
| | | u8 i = 0; |
| | | struct beamforming_info *info; |
| | | struct beamformer_entry *bfer; |
| | | |
| | | |
| | | info = GET_BEAMFORM_INFO(adapter); |
| | | |
| | | for (i = 0; i < MAX_BEAMFORMER_ENTRY_NUM; i++) { |
| | | bfer = &info->bfer_entry[i]; |
| | | if (bfer->used == _FALSE) |
| | | return bfer; |
| | | } |
| | | |
| | | return NULL; |
| | | } |
| | | |
| | | static struct beamformer_entry *_bfer_get_entry_by_addr(PADAPTER adapter, u8 *ra) |
| | | { |
| | | u8 i = 0; |
| | | struct beamforming_info *info; |
| | | struct beamformer_entry *bfer; |
| | | |
| | | |
| | | info = GET_BEAMFORM_INFO(adapter); |
| | | |
| | | for (i = 0; i < MAX_BEAMFORMER_ENTRY_NUM; i++) { |
| | | bfer = &info->bfer_entry[i]; |
| | | if (bfer->used == _FALSE) |
| | | continue; |
| | | if (_rtw_memcmp(ra, bfer->mac_addr, ETH_ALEN) == _TRUE) |
| | | return bfer; |
| | | } |
| | | |
| | | return NULL; |
| | | } |
| | | |
| | | static struct beamformer_entry *_bfer_add_entry(PADAPTER adapter, |
| | | struct sta_info *sta, u8 bf_cap, u8 sounding_dim, u8 comp_steering) |
| | | { |
| | | struct mlme_priv *mlme; |
| | | struct beamforming_info *info; |
| | | struct beamformer_entry *bfer; |
| | | u8 *bssid; |
| | | u16 val16; |
| | | u8 i; |
| | | |
| | | |
| | | mlme = &adapter->mlmepriv; |
| | | info = GET_BEAMFORM_INFO(adapter); |
| | | |
| | | bfer = _bfer_get_entry_by_addr(adapter, sta->hwaddr); |
| | | if (!bfer) { |
| | | bfer = _bfer_get_free_entry(adapter); |
| | | if (!bfer) |
| | | return NULL; |
| | | } |
| | | |
| | | bfer->used = _TRUE; |
| | | _get_txvector_parameter(adapter, sta, &bfer->g_id, &bfer->p_aid); |
| | | _rtw_memcpy(bfer->mac_addr, sta->hwaddr, ETH_ALEN); |
| | | bfer->cap = bf_cap; |
| | | bfer->state = BEAMFORM_ENTRY_HW_STATE_ADD_INIT; |
| | | bfer->NumofSoundingDim = sounding_dim; |
| | | |
| | | if (TEST_FLAG(bf_cap, BEAMFORMER_CAP_VHT_MU)) { |
| | | info->beamformer_mu_cnt += 1; |
| | | bfer->aid = sta->aid; |
| | | } else if (TEST_FLAG(bf_cap, BEAMFORMER_CAP_VHT_SU|BEAMFORMER_CAP_HT_EXPLICIT)) { |
| | | info->beamformer_su_cnt += 1; |
| | | |
| | | /* Record HW idx info */ |
| | | for (i = 0; i < MAX_NUM_BEAMFORMER_SU; i++) { |
| | | if ((info->beamformer_su_reg_maping & BIT(i)) == 0) { |
| | | info->beamformer_su_reg_maping |= BIT(i); |
| | | bfer->su_reg_index = i; |
| | | break; |
| | | } |
| | | } |
| | | RTW_INFO("%s: Add BFer entry beamformer_su_reg_maping=%#x, su_reg_index=%d\n", |
| | | __FUNCTION__, info->beamformer_su_reg_maping, bfer->su_reg_index); |
| | | } |
| | | |
| | | return bfer; |
| | | } |
| | | |
| | | static void _bfer_remove_entry(PADAPTER adapter, struct beamformer_entry *entry) |
| | | { |
| | | struct beamforming_info *info; |
| | | |
| | | |
| | | info = GET_BEAMFORM_INFO(adapter); |
| | | |
| | | entry->state = BEAMFORM_ENTRY_HW_STATE_DELETE_INIT; |
| | | |
| | | if (TEST_FLAG(entry->cap, BEAMFORMER_CAP_VHT_MU)) { |
| | | info->beamformer_mu_cnt -= 1; |
| | | _rtw_memset(entry->gid_valid, 0, 8); |
| | | _rtw_memset(entry->user_position, 0, 16); |
| | | } else if (TEST_FLAG(entry->cap, BEAMFORMER_CAP_VHT_SU|BEAMFORMER_CAP_HT_EXPLICIT)) { |
| | | info->beamformer_su_cnt -= 1; |
| | | } |
| | | |
| | | if (info->beamformer_mu_cnt == 0) |
| | | info->beamforming_cap &= ~BEAMFORMEE_CAP_VHT_MU; |
| | | if (info->beamformer_su_cnt == 0) |
| | | info->beamforming_cap &= ~(BEAMFORMEE_CAP_VHT_SU|BEAMFORMEE_CAP_HT_EXPLICIT); |
| | | } |
| | | |
| | | static u8 _bfer_set_entry_gid(PADAPTER adapter, u8 *addr, u8 *gid, u8 *position) |
| | | { |
| | | struct beamformer_entry *bfer = NULL; |
| | | |
| | | |
| | | bfer = _bfer_get_entry_by_addr(adapter, addr); |
| | | if (!bfer) { |
| | | RTW_INFO("%s: Cannot find BFer entry!!\n", __FUNCTION__); |
| | | return _FAIL; |
| | | } |
| | | |
| | | /* Parsing Membership Status Array */ |
| | | _rtw_memcpy(bfer->gid_valid, gid, 8); |
| | | /* Parsing User Position Array */ |
| | | _rtw_memcpy(bfer->user_position, position, 16); |
| | | |
| | | /* Config HW GID table */ |
| | | rtw_bf_cmd(adapter, BEAMFORMING_CTRL_SET_GID_TABLE, (u8*)&bfer, sizeof(struct beamformer_entry *), 1); |
| | | |
| | | return _SUCCESS; |
| | | } |
| | | |
| | | static struct beamformee_entry *_bfee_get_free_entry(PADAPTER adapter) |
| | | { |
| | | u8 i = 0; |
| | | struct beamforming_info *info; |
| | | struct beamformee_entry *bfee; |
| | | |
| | | |
| | | info = GET_BEAMFORM_INFO(adapter); |
| | | |
| | | for (i = 0; i < MAX_BEAMFORMEE_ENTRY_NUM; i++) { |
| | | bfee = &info->bfee_entry[i]; |
| | | if (bfee->used == _FALSE) |
| | | return bfee; |
| | | } |
| | | |
| | | return NULL; |
| | | } |
| | | |
| | | static struct beamformee_entry *_bfee_get_entry_by_addr(PADAPTER adapter, u8 *ra) |
| | | { |
| | | u8 i = 0; |
| | | struct beamforming_info *info; |
| | | struct beamformee_entry *bfee; |
| | | |
| | | |
| | | info = GET_BEAMFORM_INFO(adapter); |
| | | |
| | | for (i = 0; i < MAX_BEAMFORMEE_ENTRY_NUM; i++) { |
| | | bfee = &info->bfee_entry[i]; |
| | | if (bfee->used == _FALSE) |
| | | continue; |
| | | if (_rtw_memcmp(ra, bfee->mac_addr, ETH_ALEN) == _TRUE) |
| | | return bfee; |
| | | } |
| | | |
| | | return NULL; |
| | | } |
| | | |
| | | static u8 _bfee_get_first_su_entry_idx(PADAPTER adapter, struct beamformee_entry *ignore) |
| | | { |
| | | struct beamforming_info *info; |
| | | struct beamformee_entry *bfee; |
| | | u8 i; |
| | | |
| | | |
| | | info = GET_BEAMFORM_INFO(adapter); |
| | | |
| | | for (i = 0; i < MAX_BEAMFORMEE_ENTRY_NUM; i++) { |
| | | bfee = &info->bfee_entry[i]; |
| | | if (ignore && (bfee == ignore)) |
| | | continue; |
| | | if (bfee->used == _FALSE) |
| | | continue; |
| | | if ((!TEST_FLAG(bfee->cap, BEAMFORMEE_CAP_VHT_MU)) |
| | | && TEST_FLAG(bfee->cap, BEAMFORMEE_CAP_VHT_SU|BEAMFORMEE_CAP_HT_EXPLICIT)) |
| | | return i; |
| | | } |
| | | |
| | | return 0xFF; |
| | | } |
| | | |
| | | /* |
| | | * Description: |
| | | * Get the first entry index of MU Beamformee. |
| | | * |
| | | * Return Value: |
| | | * Index of the first MU sta, or 0xFF for invalid index. |
| | | * |
| | | * 2015.05.25. Created by tynli. |
| | | * |
| | | */ |
| | | static u8 _bfee_get_first_mu_entry_idx(PADAPTER adapter, struct beamformee_entry *ignore) |
| | | { |
| | | struct beamforming_info *info; |
| | | struct beamformee_entry *bfee; |
| | | u8 i; |
| | | |
| | | |
| | | info = GET_BEAMFORM_INFO(adapter); |
| | | |
| | | for (i = 0; i < MAX_BEAMFORMEE_ENTRY_NUM; i++) { |
| | | bfee = &info->bfee_entry[i]; |
| | | if (ignore && (bfee == ignore)) |
| | | continue; |
| | | if (bfee->used == _FALSE) |
| | | continue; |
| | | if (TEST_FLAG(bfee->cap, BEAMFORMEE_CAP_VHT_MU)) |
| | | return i; |
| | | } |
| | | |
| | | return 0xFF; |
| | | } |
| | | |
| | | static struct beamformee_entry *_bfee_add_entry(PADAPTER adapter, |
| | | struct sta_info *sta, u8 bf_cap, u8 sounding_dim, u8 comp_steering) |
| | | { |
| | | struct mlme_priv *mlme; |
| | | struct beamforming_info *info; |
| | | struct beamformee_entry *bfee; |
| | | u8 *bssid; |
| | | u16 val16; |
| | | u8 i; |
| | | |
| | | |
| | | mlme = &adapter->mlmepriv; |
| | | info = GET_BEAMFORM_INFO(adapter); |
| | | |
| | | bfee = _bfee_get_entry_by_addr(adapter, sta->hwaddr); |
| | | if (!bfee) { |
| | | bfee = _bfee_get_free_entry(adapter); |
| | | if (!bfee) |
| | | return NULL; |
| | | } |
| | | |
| | | bfee->used = _TRUE; |
| | | bfee->aid = sta->aid; |
| | | bfee->mac_id = sta->mac_id; |
| | | bfee->sound_bw = sta->bw_mode; |
| | | |
| | | _get_txvector_parameter(adapter, sta, &bfee->g_id, &bfee->p_aid); |
| | | sta->txbf_gid = bfee->g_id; |
| | | sta->txbf_paid = bfee->p_aid; |
| | | |
| | | _rtw_memcpy(bfee->mac_addr, sta->hwaddr, ETH_ALEN); |
| | | bfee->txbf = _FALSE; |
| | | bfee->sounding = _FALSE; |
| | | bfee->sound_period = 40; |
| | | _sounding_update_min_period(adapter, bfee->sound_period, _FALSE); |
| | | bfee->SoundCnt = GetInitSoundCnt(bfee->sound_period, info->sounding_info.min_sounding_period); |
| | | bfee->cap = bf_cap; |
| | | bfee->state = BEAMFORM_ENTRY_HW_STATE_ADD_INIT; |
| | | |
| | | bfee->bCandidateSoundingPeer = _FALSE; |
| | | bfee->bSoundingTimeout = _FALSE; |
| | | bfee->bDeleteSounding = _FALSE; |
| | | bfee->bApplySounding = _TRUE; |
| | | |
| | | bfee->tx_timestamp = 0; |
| | | bfee->tx_bytes = 0; |
| | | |
| | | bfee->LogStatusFailCnt = 0; |
| | | bfee->NumofSoundingDim = sounding_dim; |
| | | bfee->comp_steering_num_of_bfer = comp_steering; |
| | | bfee->bSuspendSUCap = _FALSE; |
| | | |
| | | if (TEST_FLAG(bf_cap, BEAMFORMEE_CAP_VHT_MU)) { |
| | | info->beamformee_mu_cnt += 1; |
| | | info->first_mu_bfee_index = _bfee_get_first_mu_entry_idx(adapter, NULL); |
| | | |
| | | if (_TRUE == info->bEnableSUTxBFWorkAround) { |
| | | /* When the first MU BFee added, discard SU BFee bfee's capability */ |
| | | if ((info->beamformee_mu_cnt == 1) && (info->beamformee_su_cnt > 0)) { |
| | | if (info->TargetSUBFee) { |
| | | info->TargetSUBFee->bSuspendSUCap = _TRUE; |
| | | info->TargetSUBFee->bDeleteSounding = _TRUE; |
| | | } else { |
| | | RTW_ERR("%s: UNEXPECTED!! info->TargetSUBFee is NULL!", __FUNCTION__); |
| | | } |
| | | info->TargetSUBFee = NULL; |
| | | _rtw_memset(&info->TargetCSIInfo, 0, sizeof(struct _RT_CSI_INFO)); |
| | | rtw_bf_cmd(adapter, BEAMFORMING_CTRL_SET_CSI_REPORT, (u8*)&info->TargetCSIInfo, sizeof(struct _RT_CSI_INFO), 0); |
| | | } |
| | | } |
| | | |
| | | /* Record HW idx info */ |
| | | for (i = 0; i < MAX_NUM_BEAMFORMEE_MU; i++) { |
| | | if ((info->beamformee_mu_reg_maping & BIT(i)) == 0) { |
| | | info->beamformee_mu_reg_maping |= BIT(i); |
| | | bfee->mu_reg_index = i; |
| | | break; |
| | | } |
| | | } |
| | | RTW_INFO("%s: Add BFee entry beamformee_mu_reg_maping=%#x, mu_reg_index=%d\n", |
| | | __FUNCTION__, info->beamformee_mu_reg_maping, bfee->mu_reg_index); |
| | | |
| | | } else if (TEST_FLAG(bf_cap, BEAMFORMEE_CAP_VHT_SU|BEAMFORMEE_CAP_HT_EXPLICIT)) { |
| | | info->beamformee_su_cnt += 1; |
| | | |
| | | if (_TRUE == info->bEnableSUTxBFWorkAround) { |
| | | /* Record the first SU BFee index. We only allow the first SU BFee to be sound */ |
| | | if ((info->beamformee_su_cnt == 1) && (info->beamformee_mu_cnt == 0)) { |
| | | info->TargetSUBFee = bfee; |
| | | _rtw_memset(&info->TargetCSIInfo, 0, sizeof(struct _RT_CSI_INFO)); |
| | | bfee->bSuspendSUCap = _FALSE; |
| | | } else { |
| | | bfee->bSuspendSUCap = _TRUE; |
| | | } |
| | | } |
| | | |
| | | /* Record HW idx info */ |
| | | for (i = 0; i < MAX_NUM_BEAMFORMEE_SU; i++) { |
| | | if ((info->beamformee_su_reg_maping & BIT(i)) == 0) { |
| | | info->beamformee_su_reg_maping |= BIT(i); |
| | | bfee->su_reg_index = i; |
| | | break; |
| | | } |
| | | } |
| | | RTW_INFO("%s: Add BFee entry beamformee_su_reg_maping=%#x, su_reg_index=%d\n", |
| | | __FUNCTION__, info->beamformee_su_reg_maping, bfee->su_reg_index); |
| | | } |
| | | |
| | | return bfee; |
| | | } |
| | | |
| | | static void _bfee_remove_entry(PADAPTER adapter, struct beamformee_entry *entry) |
| | | { |
| | | struct beamforming_info *info; |
| | | u8 idx; |
| | | |
| | | |
| | | info = GET_BEAMFORM_INFO(adapter); |
| | | |
| | | entry->state = BEAMFORM_ENTRY_HW_STATE_DELETE_INIT; |
| | | |
| | | if (TEST_FLAG(entry->cap, BEAMFORMEE_CAP_VHT_MU)) { |
| | | info->beamformee_mu_cnt -= 1; |
| | | info->first_mu_bfee_index = _bfee_get_first_mu_entry_idx(adapter, entry); |
| | | |
| | | if (_TRUE == info->bEnableSUTxBFWorkAround) { |
| | | if ((info->beamformee_mu_cnt == 0) && (info->beamformee_su_cnt > 0)) { |
| | | idx = _bfee_get_first_su_entry_idx(adapter, NULL); |
| | | info->TargetSUBFee = &info->bfee_entry[idx]; |
| | | _rtw_memset(&info->TargetCSIInfo, 0, sizeof(struct _RT_CSI_INFO)); |
| | | info->TargetSUBFee->bSuspendSUCap = _FALSE; |
| | | } |
| | | } |
| | | } else if (TEST_FLAG(entry->cap, BEAMFORMEE_CAP_VHT_SU|BEAMFORMEE_CAP_HT_EXPLICIT)) { |
| | | info->beamformee_su_cnt -= 1; |
| | | |
| | | /* When the target SU BFee leaves, disable workaround */ |
| | | if ((_TRUE == info->bEnableSUTxBFWorkAround) |
| | | && (entry == info->TargetSUBFee)) { |
| | | entry->bSuspendSUCap = _TRUE; |
| | | info->TargetSUBFee = NULL; |
| | | _rtw_memset(&info->TargetCSIInfo, 0, sizeof(struct _RT_CSI_INFO)); |
| | | rtw_bf_cmd(adapter, BEAMFORMING_CTRL_SET_CSI_REPORT, (u8*)&info->TargetCSIInfo, sizeof(struct _RT_CSI_INFO), 0); |
| | | } |
| | | } |
| | | |
| | | if (info->beamformee_mu_cnt == 0) |
| | | info->beamforming_cap &= ~BEAMFORMER_CAP_VHT_MU; |
| | | if (info->beamformee_su_cnt == 0) |
| | | info->beamforming_cap &= ~(BEAMFORMER_CAP_VHT_SU|BEAMFORMER_CAP_HT_EXPLICIT); |
| | | |
| | | _sounding_update_min_period(adapter, 0, _TRUE); |
| | | } |
| | | |
| | | static enum beamforming_cap _bfee_get_entry_cap_by_macid(PADAPTER adapter, u8 macid) |
| | | { |
| | | struct beamforming_info *info; |
| | | struct beamformee_entry *bfee; |
| | | u8 i; |
| | | |
| | | |
| | | info = GET_BEAMFORM_INFO(adapter); |
| | | |
| | | for (i = 0; i < MAX_BEAMFORMER_ENTRY_NUM; i++) { |
| | | bfee = &info->bfee_entry[i]; |
| | | if (bfee->used == _FALSE) |
| | | continue; |
| | | if (bfee->mac_id == macid) |
| | | return bfee->cap; |
| | | } |
| | | |
| | | return BEAMFORMING_CAP_NONE; |
| | | } |
| | | |
| | | static void _beamforming_enter(PADAPTER adapter, void *p) |
| | | { |
| | | struct mlme_priv *mlme; |
| | | struct ht_priv *htpriv; |
| | | #ifdef CONFIG_80211AC_VHT |
| | | struct vht_priv *vhtpriv; |
| | | #endif |
| | | struct mlme_ext_priv *mlme_ext; |
| | | struct sta_info *sta, *sta_copy; |
| | | struct beamforming_info *info; |
| | | struct beamformer_entry *bfer = NULL; |
| | | struct beamformee_entry *bfee = NULL; |
| | | u8 wireless_mode; |
| | | u8 sta_bf_cap; |
| | | u8 sounding_dim = 0; /* number of sounding dimensions */ |
| | | u8 comp_steering_num = 0; /* compressed steering number */ |
| | | |
| | | |
| | | mlme = &adapter->mlmepriv; |
| | | htpriv = &mlme->htpriv; |
| | | #ifdef CONFIG_80211AC_VHT |
| | | vhtpriv = &mlme->vhtpriv; |
| | | #endif |
| | | mlme_ext = &adapter->mlmeextpriv; |
| | | info = GET_BEAMFORM_INFO(adapter); |
| | | |
| | | sta_copy = (struct sta_info *)p; |
| | | sta = rtw_get_stainfo(&adapter->stapriv, sta_copy->hwaddr); |
| | | if (!sta) { |
| | | RTW_ERR("%s: Cann't find STA info for " MAC_FMT "\n", |
| | | __FUNCTION__, MAC_ARG(sta_copy->hwaddr)); |
| | | return; |
| | | } |
| | | if (sta != sta_copy) { |
| | | RTW_WARN("%s: Origin sta(fake)=%p realsta=%p for " MAC_FMT "\n", |
| | | __FUNCTION__, sta_copy, sta, MAC_ARG(sta_copy->hwaddr)); |
| | | } |
| | | |
| | | /* The current setting does not support Beaforming */ |
| | | wireless_mode = sta->wireless_mode; |
| | | if ((is_supported_ht(wireless_mode) == _FALSE) |
| | | && (is_supported_vht(wireless_mode) == _FALSE)) { |
| | | RTW_WARN("%s: Not support HT or VHT mode\n", __FUNCTION__); |
| | | return; |
| | | } |
| | | |
| | | if ((0 == htpriv->beamform_cap) |
| | | #ifdef CONFIG_80211AC_VHT |
| | | && (0 == vhtpriv->beamform_cap) |
| | | #endif |
| | | ) { |
| | | RTW_INFO("The configuration disabled Beamforming! Skip...\n"); |
| | | return; |
| | | } |
| | | |
| | | _get_sta_beamform_cap(adapter, sta, |
| | | &sta_bf_cap, &sounding_dim, &comp_steering_num); |
| | | RTW_INFO("STA Beamforming Capability=0x%02X\n", sta_bf_cap); |
| | | if (sta_bf_cap == BEAMFORMING_CAP_NONE) |
| | | return; |
| | | if ((sta_bf_cap & BEAMFORMEE_CAP_HT_EXPLICIT) |
| | | || (sta_bf_cap & BEAMFORMEE_CAP_VHT_SU) |
| | | || (sta_bf_cap & BEAMFORMEE_CAP_VHT_MU)) |
| | | sta_bf_cap |= BEAMFORMEE_CAP; |
| | | if ((sta_bf_cap & BEAMFORMER_CAP_HT_EXPLICIT) |
| | | || (sta_bf_cap & BEAMFORMER_CAP_VHT_SU) |
| | | || (sta_bf_cap & BEAMFORMER_CAP_VHT_MU)) |
| | | sta_bf_cap |= BEAMFORMER_CAP; |
| | | |
| | | if (sta_bf_cap & BEAMFORMER_CAP) { |
| | | /* The other side is beamformer */ |
| | | bfer = _bfer_add_entry(adapter, sta, sta_bf_cap, sounding_dim, comp_steering_num); |
| | | if (!bfer) |
| | | RTW_ERR("%s: Fail to allocate bfer entry!\n", __FUNCTION__); |
| | | } |
| | | if (sta_bf_cap & BEAMFORMEE_CAP) { |
| | | /* The other side is beamformee */ |
| | | bfee = _bfee_add_entry(adapter, sta, sta_bf_cap, sounding_dim, comp_steering_num); |
| | | if (!bfee) |
| | | RTW_ERR("%s: Fail to allocate bfee entry!\n", __FUNCTION__); |
| | | } |
| | | if (!bfer && !bfee) |
| | | return; |
| | | |
| | | rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_ENTER, (u8*)sta); |
| | | |
| | | /* Perform sounding if there is BFee */ |
| | | if ((info->beamformee_su_cnt != 0) |
| | | || (info->beamformee_mu_cnt != 0)) { |
| | | if (SOUNDING_STATE_NONE == info->sounding_info.state) { |
| | | info->sounding_info.state = SOUNDING_STATE_INIT; |
| | | /* Start sounding after 2 sec */ |
| | | _set_timer(&info->sounding_timer, 2000); |
| | | } |
| | | } |
| | | } |
| | | |
| | | static void _beamforming_reset(PADAPTER adapter) |
| | | { |
| | | RTW_ERR("%s: Not ready!!\n", __FUNCTION__); |
| | | } |
| | | |
| | | static void _beamforming_leave(PADAPTER adapter, u8 *ra) |
| | | { |
| | | struct beamforming_info *info; |
| | | struct beamformer_entry *bfer = NULL; |
| | | struct beamformee_entry *bfee = NULL; |
| | | u8 bHwStateAddInit = _FALSE; |
| | | |
| | | |
| | | RTW_INFO("+%s\n", __FUNCTION__); |
| | | |
| | | info = GET_BEAMFORM_INFO(adapter); |
| | | bfer = _bfer_get_entry_by_addr(adapter, ra); |
| | | bfee = _bfee_get_entry_by_addr(adapter, ra); |
| | | |
| | | if (!bfer && !bfee) { |
| | | RTW_WARN("%s: " MAC_FMT " is neither beamforming ee or er!!\n", |
| | | __FUNCTION__, MAC_ARG(ra)); |
| | | return; |
| | | } |
| | | |
| | | if (bfer) |
| | | _bfer_remove_entry(adapter, bfer); |
| | | |
| | | if (bfee) |
| | | _bfee_remove_entry(adapter, bfee); |
| | | |
| | | rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_LEAVE, ra); |
| | | |
| | | /* Stop sounding if there is no any BFee */ |
| | | if ((info->beamformee_su_cnt == 0) |
| | | && (info->beamformee_mu_cnt == 0)) { |
| | | u8 cancelled; |
| | | _cancel_timer(&info->sounding_timer, &cancelled); |
| | | _sounding_init(&info->sounding_info); |
| | | } |
| | | |
| | | RTW_INFO("-%s\n", __FUNCTION__); |
| | | } |
| | | |
| | | static void _beamforming_sounding_down(PADAPTER adapter, u8 status) |
| | | { |
| | | struct beamforming_info *info; |
| | | struct sounding_info *sounding; |
| | | struct beamformee_entry *bfee; |
| | | |
| | | |
| | | info = GET_BEAMFORM_INFO(adapter); |
| | | sounding = &info->sounding_info; |
| | | |
| | | RTW_INFO("+%s: sounding=%d, status=0x%02x\n", __FUNCTION__, sounding->state, status); |
| | | |
| | | if (sounding->state == SOUNDING_STATE_MU_START) { |
| | | RTW_INFO("%s: MU sounding done\n", __FUNCTION__); |
| | | sounding->state = SOUNDING_STATE_MU_SOUNDDOWN; |
| | | RTW_INFO("%s: Set to SOUNDING_STATE_MU_SOUNDDOWN\n", __FUNCTION__); |
| | | info->SetHalSoundownOnDemandCnt++; |
| | | rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_STATUS, &status); |
| | | } else if (sounding->state == SOUNDING_STATE_SU_START) { |
| | | RTW_INFO("%s: SU entry[%d] sounding down\n", __FUNCTION__, sounding->su_bfee_curidx); |
| | | bfee = &info->bfee_entry[sounding->su_bfee_curidx]; |
| | | sounding->state = SOUNDING_STATE_SU_SOUNDDOWN; |
| | | RTW_INFO("%s: Set to SOUNDING_STATE_SU_SOUNDDOWN\n", __FUNCTION__); |
| | | |
| | | /* |
| | | * <tynli_note> |
| | | * bfee->bSoundingTimeout this flag still cannot avoid |
| | | * old sound down event happens in the new sounding period. |
| | | * 2015.12.10 |
| | | */ |
| | | if (_TRUE == bfee->bSoundingTimeout) { |
| | | RTW_WARN("%s: The entry[%d] is bSoundingTimeout!\n", __FUNCTION__, sounding->su_bfee_curidx); |
| | | bfee->bSoundingTimeout = _FALSE; |
| | | return; |
| | | } |
| | | |
| | | if (_TRUE == status) { |
| | | /* success */ |
| | | bfee->LogStatusFailCnt = 0; |
| | | info->SetHalSoundownOnDemandCnt++; |
| | | rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_STATUS, &status); |
| | | } else if (_TRUE == bfee->bDeleteSounding) { |
| | | RTW_WARN("%s: Delete entry[%d] sounding info!\n", __FUNCTION__, sounding->su_bfee_curidx); |
| | | rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_STATUS, &status); |
| | | bfee->bDeleteSounding = _FALSE; |
| | | } else { |
| | | bfee->LogStatusFailCnt++; |
| | | RTW_WARN("%s: LogStatusFailCnt=%d\n", __FUNCTION__, bfee->LogStatusFailCnt); |
| | | if (bfee->LogStatusFailCnt > 30) { |
| | | RTW_ERR("%s: LogStatusFailCnt > 30, Stop SOUNDING!!\n", __FUNCTION__); |
| | | rtw_bf_cmd(adapter, BEAMFORMING_CTRL_LEAVE, bfee->mac_addr, ETH_ALEN, 1); |
| | | } |
| | | } |
| | | } else { |
| | | RTW_WARN("%s: unexpected sounding state:0x%02x\n", __FUNCTION__, sounding->state); |
| | | return; |
| | | } |
| | | |
| | | rtw_bf_cmd(adapter, BEAMFORMING_CTRL_START_PERIOD, NULL, 0, 0); |
| | | } |
| | | |
| | | static void _c2h_snd_txbf(PADAPTER adapter, u8 *buf, u8 buf_len) |
| | | { |
| | | struct beamforming_info *info; |
| | | u8 cancelled; |
| | | u8 res; |
| | | |
| | | |
| | | info = GET_BEAMFORM_INFO(adapter); |
| | | |
| | | _cancel_timer(&info->sounding_timeout_timer, &cancelled); |
| | | |
| | | res = C2H_SND_TXBF_GET_SND_RESULT(buf) ? _TRUE : _FALSE; |
| | | RTW_INFO("+%s: %s\n", __FUNCTION__, res==_TRUE?"Success":"Fail!"); |
| | | |
| | | rtw_bf_cmd(adapter, BEAMFORMING_CTRL_END_PERIOD, &res, 1, 1); |
| | | } |
| | | |
| | | /* |
| | | * Description: |
| | | * This function is for phydm only |
| | | */ |
| | | enum beamforming_cap rtw_bf_bfee_get_entry_cap_by_macid(void *mlme, u8 macid) |
| | | { |
| | | PADAPTER adapter; |
| | | enum beamforming_cap cap = BEAMFORMING_CAP_NONE; |
| | | |
| | | |
| | | adapter = mlme_to_adapter((struct mlme_priv *)mlme); |
| | | cap = _bfee_get_entry_cap_by_macid(adapter, macid); |
| | | |
| | | return cap; |
| | | } |
| | | |
| | | struct beamformer_entry *rtw_bf_bfer_get_entry_by_addr(PADAPTER adapter, u8 *ra) |
| | | { |
| | | return _bfer_get_entry_by_addr(adapter, ra); |
| | | } |
| | | |
| | | struct beamformee_entry *rtw_bf_bfee_get_entry_by_addr(PADAPTER adapter, u8 *ra) |
| | | { |
| | | return _bfee_get_entry_by_addr(adapter, ra); |
| | | } |
| | | |
| | | void rtw_bf_get_ndpa_packet(PADAPTER adapter, union recv_frame *precv_frame) |
| | | { |
| | | RTW_DBG("+%s\n", __FUNCTION__); |
| | | } |
| | | |
| | | u32 rtw_bf_get_report_packet(PADAPTER adapter, union recv_frame *precv_frame) |
| | | { |
| | | u32 ret = _SUCCESS; |
| | | struct beamforming_info *info; |
| | | struct beamformee_entry *bfee = NULL; |
| | | u8 *pframe; |
| | | u32 frame_len; |
| | | u8 *ta; |
| | | u8 *frame_body; |
| | | u8 category, action; |
| | | u8 *pMIMOCtrlField, *pCSIMatrix; |
| | | u8 Nc = 0, Nr = 0, CH_W = 0, Ng = 0, CodeBook = 0; |
| | | u16 CSIMatrixLen = 0; |
| | | |
| | | |
| | | RTW_INFO("+%s\n", __FUNCTION__); |
| | | |
| | | info = GET_BEAMFORM_INFO(adapter); |
| | | pframe = precv_frame->u.hdr.rx_data; |
| | | frame_len = precv_frame->u.hdr.len; |
| | | |
| | | /* Memory comparison to see if CSI report is the same with previous one */ |
| | | ta = get_addr2_ptr(pframe); |
| | | bfee = _bfee_get_entry_by_addr(adapter, ta); |
| | | if (!bfee) |
| | | return _FAIL; |
| | | |
| | | frame_body = pframe + sizeof(struct rtw_ieee80211_hdr_3addr); |
| | | category = frame_body[0]; |
| | | action = frame_body[1]; |
| | | |
| | | if ((category == RTW_WLAN_CATEGORY_VHT) |
| | | && (action == RTW_WLAN_ACTION_VHT_COMPRESSED_BEAMFORMING)) { |
| | | pMIMOCtrlField = pframe + 26; |
| | | Nc = (*pMIMOCtrlField) & 0x7; |
| | | Nr = ((*pMIMOCtrlField) & 0x38) >> 3; |
| | | CH_W = (((*pMIMOCtrlField) & 0xC0) >> 6); |
| | | Ng = (*(pMIMOCtrlField+1)) & 0x3; |
| | | CodeBook = ((*(pMIMOCtrlField+1)) & 0x4) >> 2; |
| | | /* |
| | | * 24+(1+1+3)+2 |
| | | * ==> MAC header+(Category+ActionCode+MIMOControlField)+SNR(Nc=2) |
| | | */ |
| | | pCSIMatrix = pMIMOCtrlField + 3 + Nc; |
| | | CSIMatrixLen = frame_len - 26 - 3 - Nc; |
| | | info->TargetCSIInfo.bVHT = _TRUE; |
| | | } else if ((category == RTW_WLAN_CATEGORY_HT) |
| | | && (action == RTW_WLAN_ACTION_HT_COMPRESS_BEAMFORMING)) { |
| | | pMIMOCtrlField = pframe + 26; |
| | | Nc = (*pMIMOCtrlField) & 0x3; |
| | | Nr = ((*pMIMOCtrlField) & 0xC) >> 2; |
| | | CH_W = ((*pMIMOCtrlField) & 0x10) >> 4; |
| | | Ng = ((*pMIMOCtrlField) & 0x60) >> 5; |
| | | CodeBook = ((*(pMIMOCtrlField+1)) & 0x6) >> 1; |
| | | /* |
| | | * 24+(1+1+6)+2 |
| | | * ==> MAC header+(Category+ActionCode+MIMOControlField)+SNR(Nc=2) |
| | | */ |
| | | pCSIMatrix = pMIMOCtrlField + 6 + Nr; |
| | | CSIMatrixLen = frame_len - 26 - 6 - Nr; |
| | | info->TargetCSIInfo.bVHT = _FALSE; |
| | | } |
| | | |
| | | /* Update current CSI report info */ |
| | | if ((_TRUE == info->bEnableSUTxBFWorkAround) |
| | | && (info->TargetSUBFee == bfee)) { |
| | | if ((info->TargetCSIInfo.Nc != Nc) || (info->TargetCSIInfo.Nr != Nr) || |
| | | (info->TargetCSIInfo.ChnlWidth != CH_W) || (info->TargetCSIInfo.Ng != Ng) || |
| | | (info->TargetCSIInfo.CodeBook != CodeBook)) { |
| | | info->TargetCSIInfo.Nc = Nc; |
| | | info->TargetCSIInfo.Nr = Nr; |
| | | info->TargetCSIInfo.ChnlWidth = CH_W; |
| | | info->TargetCSIInfo.Ng = Ng; |
| | | info->TargetCSIInfo.CodeBook = CodeBook; |
| | | |
| | | rtw_bf_cmd(adapter, BEAMFORMING_CTRL_SET_CSI_REPORT, (u8*)&info->TargetCSIInfo, sizeof(struct _RT_CSI_INFO), 1); |
| | | } |
| | | } |
| | | |
| | | RTW_INFO("%s: pkt type=%d-%d, Nc=%d, Nr=%d, CH_W=%d, Ng=%d, CodeBook=%d\n", |
| | | __FUNCTION__, category, action, Nc, Nr, CH_W, Ng, CodeBook); |
| | | |
| | | return ret; |
| | | } |
| | | |
| | | u8 rtw_bf_send_vht_gid_mgnt_packet(PADAPTER adapter, u8 *ra, u8 *gid, u8 *position) |
| | | { |
| | | /* General */ |
| | | struct xmit_priv *xmitpriv; |
| | | struct mlme_priv *mlmepriv; |
| | | struct xmit_frame *pmgntframe; |
| | | /* MISC */ |
| | | struct pkt_attrib *attrib; |
| | | struct rtw_ieee80211_hdr *wlanhdr; |
| | | u8 *pframe, *ptr; |
| | | |
| | | |
| | | xmitpriv = &adapter->xmitpriv; |
| | | mlmepriv = &adapter->mlmepriv; |
| | | |
| | | pmgntframe = alloc_mgtxmitframe(xmitpriv); |
| | | if (!pmgntframe) |
| | | return _FALSE; |
| | | |
| | | /* update attribute */ |
| | | attrib = &pmgntframe->attrib; |
| | | update_mgntframe_attrib(adapter, attrib); |
| | | attrib->rate = MGN_6M; |
| | | attrib->bwmode = CHANNEL_WIDTH_20; |
| | | attrib->subtype = WIFI_ACTION; |
| | | |
| | | _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); |
| | | |
| | | pframe = (u8 *)pmgntframe->buf_addr + TXDESC_OFFSET; |
| | | wlanhdr = (struct rtw_ieee80211_hdr *)pframe; |
| | | |
| | | wlanhdr->frame_ctl = 0; |
| | | set_frame_sub_type(pframe, attrib->subtype); |
| | | set_duration(pframe, 0); |
| | | SetFragNum(pframe, 0); |
| | | SetSeqNum(pframe, 0); |
| | | |
| | | _rtw_memcpy(wlanhdr->addr1, ra, ETH_ALEN); |
| | | _rtw_memcpy(wlanhdr->addr2, adapter_mac_addr(adapter), ETH_ALEN); |
| | | _rtw_memcpy(wlanhdr->addr3, get_bssid(mlmepriv), ETH_ALEN); |
| | | |
| | | pframe[24] = RTW_WLAN_CATEGORY_VHT; |
| | | pframe[25] = RTW_WLAN_ACTION_VHT_GROUPID_MANAGEMENT; |
| | | /* Set Membership Status Array */ |
| | | ptr = pframe + 26; |
| | | _rtw_memcpy(ptr, gid, 8); |
| | | /* Set User Position Array */ |
| | | ptr = pframe + 34; |
| | | _rtw_memcpy(ptr, position, 16); |
| | | |
| | | attrib->pktlen = 54; |
| | | attrib->last_txcmdsz = attrib->pktlen; |
| | | |
| | | dump_mgntframe(adapter, pmgntframe); |
| | | |
| | | return _TRUE; |
| | | } |
| | | |
| | | /* |
| | | * Description: |
| | | * On VHT GID management frame by an MU beamformee. |
| | | */ |
| | | void rtw_bf_get_vht_gid_mgnt_packet(PADAPTER adapter, union recv_frame *precv_frame) |
| | | { |
| | | u8 *pframe; |
| | | u8 *ta, *gid, *position; |
| | | |
| | | |
| | | RTW_DBG("+%s\n", __FUNCTION__); |
| | | |
| | | pframe = precv_frame->u.hdr.rx_data; |
| | | |
| | | /* Get address by Addr2 */ |
| | | ta = get_addr2_ptr(pframe); |
| | | /* Remove signaling TA */ |
| | | ta[0] &= 0xFE; |
| | | |
| | | /* Membership Status Array */ |
| | | gid = pframe + 26; |
| | | /* User Position Array */ |
| | | position= pframe + 34; |
| | | |
| | | _bfer_set_entry_gid(adapter, ta, gid, position); |
| | | } |
| | | |
| | | void rtw_bf_init(PADAPTER adapter) |
| | | { |
| | | struct beamforming_info *info; |
| | | |
| | | |
| | | info = GET_BEAMFORM_INFO(adapter); |
| | | info->beamforming_cap = BEAMFORMING_CAP_NONE; |
| | | info->beamforming_state = BEAMFORMING_STATE_IDLE; |
| | | /* |
| | | info->bfee_entry[MAX_BEAMFORMEE_ENTRY_NUM]; |
| | | info->bfer_entry[MAX_BEAMFORMER_ENTRY_NUM]; |
| | | */ |
| | | info->sounding_sequence = 0; |
| | | info->beamformee_su_cnt = 0; |
| | | info->beamformer_su_cnt = 0; |
| | | info->beamformee_su_reg_maping = 0; |
| | | info->beamformer_su_reg_maping = 0; |
| | | info->beamformee_mu_cnt = 0; |
| | | info->beamformer_mu_cnt = 0; |
| | | info->beamformee_mu_reg_maping = 0; |
| | | info->first_mu_bfee_index = 0xFF; |
| | | info->mu_bfer_curidx = 0xFF; |
| | | |
| | | _sounding_init(&info->sounding_info); |
| | | _init_timer(&info->sounding_timer, adapter->pnetdev, _sounding_timer_handler, adapter); |
| | | _init_timer(&info->sounding_timeout_timer, adapter->pnetdev, _sounding_timeout_timer_handler, adapter); |
| | | |
| | | info->SetHalBFEnterOnDemandCnt = 0; |
| | | info->SetHalBFLeaveOnDemandCnt = 0; |
| | | info->SetHalSoundownOnDemandCnt = 0; |
| | | |
| | | info->bEnableSUTxBFWorkAround = _TRUE; |
| | | info->TargetSUBFee = NULL; |
| | | |
| | | info->sounding_running = 0; |
| | | } |
| | | |
| | | void rtw_bf_cmd_hdl(PADAPTER adapter, u8 type, u8 *pbuf) |
| | | { |
| | | switch (type) { |
| | | case BEAMFORMING_CTRL_ENTER: |
| | | _beamforming_enter(adapter, pbuf); |
| | | break; |
| | | |
| | | case BEAMFORMING_CTRL_LEAVE: |
| | | if (pbuf == NULL) |
| | | _beamforming_reset(adapter); |
| | | else |
| | | _beamforming_leave(adapter, pbuf); |
| | | break; |
| | | |
| | | case BEAMFORMING_CTRL_START_PERIOD: |
| | | _sounding_handler(adapter); |
| | | break; |
| | | |
| | | case BEAMFORMING_CTRL_END_PERIOD: |
| | | _beamforming_sounding_down(adapter, *pbuf); |
| | | break; |
| | | |
| | | case BEAMFORMING_CTRL_SET_GID_TABLE: |
| | | rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_SET_GID_TABLE, *(void**)pbuf); |
| | | break; |
| | | |
| | | case BEAMFORMING_CTRL_SET_CSI_REPORT: |
| | | rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_CSI_REPORT, pbuf); |
| | | break; |
| | | |
| | | default: |
| | | break; |
| | | } |
| | | } |
| | | |
| | | u8 rtw_bf_cmd(PADAPTER adapter, s32 type, u8 *pbuf, s32 size, u8 enqueue) |
| | | { |
| | | struct cmd_obj *ph2c; |
| | | struct drvextra_cmd_parm *pdrvextra_cmd_parm; |
| | | struct cmd_priv *pcmdpriv = &adapter->cmdpriv; |
| | | u8 *wk_buf; |
| | | u8 res = _SUCCESS; |
| | | |
| | | |
| | | if (!enqueue) { |
| | | rtw_bf_cmd_hdl(adapter, type, pbuf); |
| | | goto exit; |
| | | } |
| | | |
| | | ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); |
| | | if (ph2c == NULL) { |
| | | res = _FAIL; |
| | | goto exit; |
| | | } |
| | | |
| | | pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); |
| | | if (pdrvextra_cmd_parm == NULL) { |
| | | rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj)); |
| | | res = _FAIL; |
| | | goto exit; |
| | | } |
| | | |
| | | if (pbuf != NULL) { |
| | | wk_buf = rtw_zmalloc(size); |
| | | if (wk_buf == NULL) { |
| | | rtw_mfree((u8 *)ph2c, sizeof(struct cmd_obj)); |
| | | rtw_mfree((u8 *)pdrvextra_cmd_parm, sizeof(struct drvextra_cmd_parm)); |
| | | res = _FAIL; |
| | | goto exit; |
| | | } |
| | | |
| | | _rtw_memcpy(wk_buf, pbuf, size); |
| | | } else { |
| | | wk_buf = NULL; |
| | | size = 0; |
| | | } |
| | | |
| | | pdrvextra_cmd_parm->ec_id = BEAMFORMING_WK_CID; |
| | | pdrvextra_cmd_parm->type = type; |
| | | pdrvextra_cmd_parm->size = size; |
| | | pdrvextra_cmd_parm->pbuf = wk_buf; |
| | | |
| | | init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); |
| | | |
| | | res = rtw_enqueue_cmd(pcmdpriv, ph2c); |
| | | |
| | | exit: |
| | | return res; |
| | | } |
| | | |
| | | void rtw_bf_update_attrib(PADAPTER adapter, struct pkt_attrib *attrib, struct sta_info *sta) |
| | | { |
| | | if (sta) { |
| | | attrib->txbf_g_id = sta->txbf_gid; |
| | | attrib->txbf_p_aid = sta->txbf_paid; |
| | | } |
| | | } |
| | | |
| | | void rtw_bf_c2h_handler(PADAPTER adapter, u8 id, u8 *buf, u8 buf_len) |
| | | { |
| | | switch (id) { |
| | | case CMD_ID_C2H_SND_TXBF: |
| | | _c2h_snd_txbf(adapter, buf, buf_len); |
| | | break; |
| | | } |
| | | } |
| | | |
| | | #define toMbps(bytes, secs) (rtw_division64(bytes >> 17, secs)) |
| | | void rtw_bf_update_traffic(PADAPTER adapter) |
| | | { |
| | | struct beamforming_info *info; |
| | | struct sounding_info *sounding; |
| | | struct beamformee_entry *bfee; |
| | | struct sta_info *sta; |
| | | u8 bfee_cnt, sounding_idx, i; |
| | | u16 tp[MAX_BEAMFORMEE_ENTRY_NUM] = {0}; |
| | | u8 tx_rate[MAX_BEAMFORMEE_ENTRY_NUM] = {0}; |
| | | u64 tx_bytes, last_bytes; |
| | | u32 time, last_timestamp; |
| | | u8 set_timer = _FALSE; |
| | | |
| | | |
| | | info = GET_BEAMFORM_INFO(adapter); |
| | | sounding = &info->sounding_info; |
| | | |
| | | /* Check any bfee exist? */ |
| | | bfee_cnt = info->beamformee_su_cnt + info->beamformee_mu_cnt; |
| | | if (bfee_cnt == 0) |
| | | return; |
| | | |
| | | for (i = 0; i < MAX_BEAMFORMEE_ENTRY_NUM; i++) { |
| | | bfee = &info->bfee_entry[i]; |
| | | if (_FALSE == bfee->used) |
| | | continue; |
| | | |
| | | sta = rtw_get_stainfo(&adapter->stapriv, bfee->mac_addr); |
| | | if (!sta) { |
| | | RTW_ERR("%s: Cann't find sta_info for " MAC_FMT "!\n", __FUNCTION__, MAC_ARG(bfee->mac_addr)); |
| | | continue; |
| | | } |
| | | |
| | | last_timestamp = bfee->tx_timestamp; |
| | | last_bytes = bfee->tx_bytes; |
| | | bfee->tx_timestamp = rtw_get_current_time(); |
| | | bfee->tx_bytes = sta->sta_stats.tx_bytes; |
| | | if (last_timestamp) { |
| | | if (bfee->tx_bytes >= last_bytes) |
| | | tx_bytes = bfee->tx_bytes - last_bytes; |
| | | else |
| | | tx_bytes = bfee->tx_bytes + (~last_bytes); |
| | | time = rtw_get_time_interval_ms(last_timestamp, bfee->tx_timestamp); |
| | | time = (time > 1000) ? time/1000 : 1; |
| | | tp[i] = toMbps(tx_bytes, time); |
| | | tx_rate[i] = rtw_get_current_tx_rate(adapter, bfee->mac_id); |
| | | RTW_INFO("%s: BFee idx(%d), MadId(%d), TxTP=%lld bytes (%d Mbps), txrate=%d\n", |
| | | __FUNCTION__, i, bfee->mac_id, tx_bytes, tp[i], tx_rate[i]); |
| | | } |
| | | } |
| | | |
| | | sounding_idx = phydm_get_beamforming_sounding_info(GET_PDM_ODM(adapter), tp, MAX_BEAMFORMEE_ENTRY_NUM, tx_rate); |
| | | |
| | | for (i = 0; i < MAX_BEAMFORMEE_ENTRY_NUM; i++) { |
| | | bfee = &info->bfee_entry[i]; |
| | | if (_FALSE == bfee->used) { |
| | | if (sounding_idx & BIT(i)) |
| | | RTW_WARN("%s: bfee(%d) not in used but need sounding?!\n", __FUNCTION__, i); |
| | | continue; |
| | | } |
| | | |
| | | if (sounding_idx & BIT(i)) { |
| | | if (_FALSE == bfee->bApplySounding) { |
| | | bfee->bApplySounding = _TRUE; |
| | | bfee->SoundCnt = 0; |
| | | set_timer = _TRUE; |
| | | } |
| | | } else { |
| | | if (_TRUE == bfee->bApplySounding) { |
| | | bfee->bApplySounding = _FALSE; |
| | | bfee->bDeleteSounding = _TRUE; |
| | | bfee->SoundCnt = 0; |
| | | set_timer = _TRUE; |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (_TRUE == set_timer) { |
| | | if (SOUNDING_STATE_NONE == info->sounding_info.state) { |
| | | info->sounding_info.state = SOUNDING_STATE_INIT; |
| | | _set_timer(&info->sounding_timer, 0); |
| | | } |
| | | } |
| | | } |
| | | |
| | | #else /* !RTW_BEAMFORMING_VERSION_2 */ |
| | | |
| | | #if (BEAMFORMING_SUPPORT == 0) /*for diver defined beamforming*/ |
| | | struct beamforming_entry *beamforming_get_entry_by_addr(struct mlme_priv *pmlmepriv, u8 *ra, u8 *idx) |
| | | { |
| | | u8 i = 0; |
| | | struct beamforming_info *pBeamInfo = GET_BEAMFORM_INFO(pmlmepriv); |
| | | |
| | | for (i = 0; i < BEAMFORMING_ENTRY_NUM; i++) { |
| | | if (pBeamInfo->beamforming_entry[i].bUsed && |
| | | (_rtw_memcmp(ra, pBeamInfo->beamforming_entry[i].mac_addr, ETH_ALEN))) { |
| | | *idx = i; |
| | | return &(pBeamInfo->beamforming_entry[i]); |
| | | } |
| | | } |
| | | |
| | | return NULL; |
| | | } |
| | | |
| | | BEAMFORMING_CAP beamforming_get_entry_beam_cap_by_mac_id(PVOID pmlmepriv , u8 mac_id) |
| | | { |
| | | u8 i = 0; |
| | | struct beamforming_info *pBeamInfo = GET_BEAMFORM_INFO((struct mlme_priv *)pmlmepriv); |
| | | BEAMFORMING_CAP BeamformEntryCap = BEAMFORMING_CAP_NONE; |
| | | |
| | | for (i = 0; i < BEAMFORMING_ENTRY_NUM; i++) { |
| | | if (pBeamInfo->beamforming_entry[i].bUsed && |
| | | (mac_id == pBeamInfo->beamforming_entry[i].mac_id)) { |
| | | BeamformEntryCap = pBeamInfo->beamforming_entry[i].beamforming_entry_cap; |
| | | i = BEAMFORMING_ENTRY_NUM; |
| | | } |
| | | } |
| | | |
| | | return BeamformEntryCap; |
| | | } |
| | | |
| | | struct beamforming_entry *beamforming_get_free_entry(struct mlme_priv *pmlmepriv, u8 *idx) |
| | | { |
| | | u8 i = 0; |
| | | struct beamforming_info *pBeamInfo = GET_BEAMFORM_INFO(pmlmepriv); |
| | | |
| | | for (i = 0; i < BEAMFORMING_ENTRY_NUM; i++) { |
| | | if (pBeamInfo->beamforming_entry[i].bUsed == _FALSE) { |
| | | *idx = i; |
| | | return &(pBeamInfo->beamforming_entry[i]); |
| | | } |
| | | } |
| | | return NULL; |
| | | } |
| | | |
| | | |
| | | struct beamforming_entry *beamforming_add_entry(PADAPTER adapter, u8 *ra, u16 aid, |
| | | u16 mac_id, CHANNEL_WIDTH bw, BEAMFORMING_CAP beamfrom_cap, u8 *idx) |
| | | { |
| | | struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); |
| | | struct beamforming_entry *pEntry = beamforming_get_free_entry(pmlmepriv, idx); |
| | | |
| | | if (pEntry != NULL) { |
| | | pEntry->bUsed = _TRUE; |
| | | pEntry->aid = aid; |
| | | pEntry->mac_id = mac_id; |
| | | pEntry->sound_bw = bw; |
| | | if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { |
| | | u16 BSSID = ((*(adapter_mac_addr(adapter) + 5) & 0xf0) >> 4) ^ |
| | | (*(adapter_mac_addr(adapter) + 5) & 0xf); /* BSSID[44:47] xor BSSID[40:43] */ |
| | | pEntry->p_aid = (aid + BSSID * 32) & 0x1ff; /* (dec(A) + dec(B)*32) mod 512 */ |
| | | pEntry->g_id = 63; |
| | | } else if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) || check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) { |
| | | pEntry->p_aid = 0; |
| | | pEntry->g_id = 63; |
| | | } else { |
| | | pEntry->p_aid = ra[5]; /* BSSID[39:47] */ |
| | | pEntry->p_aid = (pEntry->p_aid << 1) | (ra[4] >> 7); |
| | | pEntry->g_id = 0; |
| | | } |
| | | _rtw_memcpy(pEntry->mac_addr, ra, ETH_ALEN); |
| | | pEntry->bSound = _FALSE; |
| | | |
| | | /* 3 TODO SW/FW sound period */ |
| | | pEntry->sound_period = 200; |
| | | pEntry->beamforming_entry_cap = beamfrom_cap; |
| | | pEntry->beamforming_entry_state = BEAMFORMING_ENTRY_STATE_UNINITIALIZE; |
| | | |
| | | |
| | | pEntry->PreLogSeq = 0; /*Modified by Jeffery @2015-04-13*/ |
| | | pEntry->LogSeq = 0; /*Modified by Jeffery @2014-10-29*/ |
| | | pEntry->LogRetryCnt = 0; /*Modified by Jeffery @2014-10-29*/ |
| | | pEntry->LogSuccess = 0; /*LogSuccess is NOT needed to be accumulated, so LogSuccessCnt->LogSuccess, 2015-04-13, Jeffery*/ |
| | | pEntry->ClockResetTimes = 0; /*Modified by Jeffery @2015-04-13*/ |
| | | pEntry->LogStatusFailCnt = 0; |
| | | |
| | | return pEntry; |
| | | } else |
| | | return NULL; |
| | | } |
| | | |
| | | BOOLEAN beamforming_remove_entry(struct mlme_priv *pmlmepriv, u8 *ra, u8 *idx) |
| | | { |
| | | struct beamforming_entry *pEntry = beamforming_get_entry_by_addr(pmlmepriv, ra, idx); |
| | | |
| | | if (pEntry != NULL) { |
| | | pEntry->bUsed = _FALSE; |
| | | pEntry->beamforming_entry_cap = BEAMFORMING_CAP_NONE; |
| | | pEntry->beamforming_entry_state = BEAMFORMING_ENTRY_STATE_UNINITIALIZE; |
| | | return _TRUE; |
| | | } else |
| | | return _FALSE; |
| | | } |
| | | |
| | | /* Used for BeamformingStart_V1 */ |
| | | void beamforming_dym_ndpa_rate(PADAPTER adapter) |
| | | { |
| | | u16 NDPARate = MGN_6M; |
| | | PHAL_DATA_TYPE pHalData = GET_HAL_DATA(adapter); |
| | | |
| | | if (pHalData->min_undecorated_pwdb_for_dm > 30) /* link RSSI > 30% */ |
| | | NDPARate = MGN_24M; |
| | | else |
| | | NDPARate = MGN_6M; |
| | | |
| | | /* BW = CHANNEL_WIDTH_20; */ |
| | | NDPARate = NDPARate << 8; |
| | | rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_RATE, (u8 *)&NDPARate); |
| | | } |
| | | |
| | | void beamforming_dym_period(PADAPTER Adapter) |
| | | { |
| | | u8 Idx; |
| | | BOOLEAN bChangePeriod = _FALSE; |
| | | u16 SoundPeriod_SW, SoundPeriod_FW; |
| | | PHAL_DATA_TYPE pHalData = GET_HAL_DATA(Adapter); |
| | | struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(Adapter); |
| | | struct beamforming_entry *pBeamformEntry; |
| | | struct beamforming_info *pBeamInfo = GET_BEAMFORM_INFO((&Adapter->mlmepriv)); |
| | | struct sounding_info *pSoundInfo = &(pBeamInfo->sounding_info); |
| | | |
| | | /* 3 TODO per-client throughput caculation. */ |
| | | |
| | | if (pdvobjpriv->traffic_stat.cur_tx_tp + pdvobjpriv->traffic_stat.cur_rx_tp > 2) { |
| | | SoundPeriod_SW = 32 * 20; |
| | | SoundPeriod_FW = 2; |
| | | } else { |
| | | SoundPeriod_SW = 32 * 2000; |
| | | SoundPeriod_FW = 200; |
| | | } |
| | | |
| | | for (Idx = 0; Idx < BEAMFORMING_ENTRY_NUM; Idx++) { |
| | | pBeamformEntry = pBeamInfo->beamforming_entry + Idx; |
| | | if (pBeamformEntry->bDefaultCSI) { |
| | | SoundPeriod_SW = 32 * 2000; |
| | | SoundPeriod_FW = 200; |
| | | } |
| | | |
| | | if (pBeamformEntry->beamforming_entry_cap & (BEAMFORMER_CAP_HT_EXPLICIT | BEAMFORMER_CAP_VHT_SU)) { |
| | | if (pSoundInfo->sound_mode == SOUNDING_FW_VHT_TIMER || pSoundInfo->sound_mode == SOUNDING_FW_HT_TIMER) { |
| | | if (pBeamformEntry->sound_period != SoundPeriod_FW) { |
| | | pBeamformEntry->sound_period = SoundPeriod_FW; |
| | | bChangePeriod = _TRUE; /* Only FW sounding need to send H2C packet to change sound period. */ |
| | | } |
| | | } else if (pBeamformEntry->sound_period != SoundPeriod_SW) |
| | | pBeamformEntry->sound_period = SoundPeriod_SW; |
| | | } |
| | | } |
| | | |
| | | if (bChangePeriod) |
| | | rtw_hal_set_hwreg(Adapter, HW_VAR_SOUNDING_FW_NDPA, (u8 *)&Idx); |
| | | } |
| | | |
| | | BOOLEAN issue_ht_sw_ndpa_packet(PADAPTER Adapter, u8 *ra, CHANNEL_WIDTH bw, u8 qidx) |
| | | { |
| | | struct xmit_frame *pmgntframe; |
| | | struct pkt_attrib *pattrib; |
| | | struct rtw_ieee80211_hdr *pwlanhdr; |
| | | struct xmit_priv *pxmitpriv = &(Adapter->xmitpriv); |
| | | struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; |
| | | struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); |
| | | u8 ActionHdr[4] = {ACT_CAT_VENDOR, 0x00, 0xe0, 0x4c}; |
| | | u8 *pframe; |
| | | u16 *fctrl; |
| | | u16 duration = 0; |
| | | u8 aSifsTime = 0; |
| | | u8 NDPTxRate = 0; |
| | | |
| | | RTW_INFO("%s: issue_ht_sw_ndpa_packet!\n", __func__); |
| | | |
| | | NDPTxRate = MGN_MCS8; |
| | | RTW_INFO("%s: NDPTxRate =%d\n", __func__, NDPTxRate); |
| | | pmgntframe = alloc_mgtxmitframe(pxmitpriv); |
| | | |
| | | if (pmgntframe == NULL) |
| | | return _FALSE; |
| | | |
| | | /*update attribute*/ |
| | | pattrib = &pmgntframe->attrib; |
| | | update_mgntframe_attrib(Adapter, pattrib); |
| | | pattrib->qsel = QSLT_MGNT; |
| | | pattrib->rate = NDPTxRate; |
| | | pattrib->bwmode = bw; |
| | | pattrib->order = 1; |
| | | pattrib->subtype = WIFI_ACTION_NOACK; |
| | | |
| | | _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); |
| | | |
| | | pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; |
| | | |
| | | pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; |
| | | |
| | | fctrl = &pwlanhdr->frame_ctl; |
| | | *(fctrl) = 0; |
| | | |
| | | set_order_bit(pframe); |
| | | set_frame_sub_type(pframe, WIFI_ACTION_NOACK); |
| | | |
| | | _rtw_memcpy(pwlanhdr->addr1, ra, ETH_ALEN); |
| | | _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(Adapter), ETH_ALEN); |
| | | _rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); |
| | | |
| | | if (pmlmeext->cur_wireless_mode == WIRELESS_11B) |
| | | aSifsTime = 10; |
| | | else |
| | | aSifsTime = 16; |
| | | |
| | | duration = 2 * aSifsTime + 40; |
| | | |
| | | if (bw == CHANNEL_WIDTH_40) |
| | | duration += 87; |
| | | else |
| | | duration += 180; |
| | | |
| | | set_duration(pframe, duration); |
| | | |
| | | /*HT control field*/ |
| | | SET_HT_CTRL_CSI_STEERING(pframe + 24, 3); |
| | | SET_HT_CTRL_NDP_ANNOUNCEMENT(pframe + 24, 1); |
| | | |
| | | _rtw_memcpy(pframe + 28, ActionHdr, 4); |
| | | |
| | | pattrib->pktlen = 32; |
| | | |
| | | pattrib->last_txcmdsz = pattrib->pktlen; |
| | | |
| | | dump_mgntframe(Adapter, pmgntframe); |
| | | |
| | | return _TRUE; |
| | | |
| | | |
| | | } |
| | | BOOLEAN issue_ht_ndpa_packet(PADAPTER Adapter, u8 *ra, CHANNEL_WIDTH bw, u8 qidx) |
| | | { |
| | | struct xmit_frame *pmgntframe; |
| | | struct pkt_attrib *pattrib; |
| | | struct rtw_ieee80211_hdr *pwlanhdr; |
| | | struct xmit_priv *pxmitpriv = &(Adapter->xmitpriv); |
| | | struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; |
| | | struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); |
| | | u8 ActionHdr[4] = {ACT_CAT_VENDOR, 0x00, 0xe0, 0x4c}; |
| | | u8 *pframe; |
| | | u16 *fctrl; |
| | | u16 duration = 0; |
| | | u8 aSifsTime = 0; |
| | | |
| | | pmgntframe = alloc_mgtxmitframe(pxmitpriv); |
| | | |
| | | if (pmgntframe == NULL) |
| | | return _FALSE; |
| | | |
| | | /*update attribute*/ |
| | | pattrib = &pmgntframe->attrib; |
| | | update_mgntframe_attrib(Adapter, pattrib); |
| | | |
| | | if (qidx == BCN_QUEUE_INX) |
| | | pattrib->qsel = QSLT_BEACON; |
| | | pattrib->rate = MGN_MCS8; |
| | | pattrib->bwmode = bw; |
| | | pattrib->order = 1; |
| | | pattrib->subtype = WIFI_ACTION_NOACK; |
| | | |
| | | _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); |
| | | |
| | | pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; |
| | | |
| | | pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; |
| | | |
| | | fctrl = &pwlanhdr->frame_ctl; |
| | | *(fctrl) = 0; |
| | | |
| | | set_order_bit(pframe); |
| | | set_frame_sub_type(pframe, WIFI_ACTION_NOACK); |
| | | |
| | | _rtw_memcpy(pwlanhdr->addr1, ra, ETH_ALEN); |
| | | _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(Adapter), ETH_ALEN); |
| | | _rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); |
| | | |
| | | if (pmlmeext->cur_wireless_mode == WIRELESS_11B) |
| | | aSifsTime = 10; |
| | | else |
| | | aSifsTime = 16; |
| | | |
| | | duration = 2 * aSifsTime + 40; |
| | | |
| | | if (bw == CHANNEL_WIDTH_40) |
| | | duration += 87; |
| | | else |
| | | duration += 180; |
| | | |
| | | set_duration(pframe, duration); |
| | | |
| | | /* HT control field */ |
| | | SET_HT_CTRL_CSI_STEERING(pframe + 24, 3); |
| | | SET_HT_CTRL_NDP_ANNOUNCEMENT(pframe + 24, 1); |
| | | |
| | | _rtw_memcpy(pframe + 28, ActionHdr, 4); |
| | | |
| | | pattrib->pktlen = 32; |
| | | |
| | | pattrib->last_txcmdsz = pattrib->pktlen; |
| | | |
| | | dump_mgntframe(Adapter, pmgntframe); |
| | | |
| | | return _TRUE; |
| | | } |
| | | |
| | | BOOLEAN beamforming_send_ht_ndpa_packet(PADAPTER Adapter, u8 *ra, CHANNEL_WIDTH bw, u8 qidx) |
| | | { |
| | | return issue_ht_ndpa_packet(Adapter, ra, bw, qidx); |
| | | } |
| | | BOOLEAN issue_vht_sw_ndpa_packet(PADAPTER Adapter, u8 *ra, u16 aid, CHANNEL_WIDTH bw, u8 qidx) |
| | | { |
| | | struct xmit_frame *pmgntframe; |
| | | struct pkt_attrib *pattrib; |
| | | struct rtw_ieee80211_hdr *pwlanhdr; |
| | | struct xmit_priv *pxmitpriv = &(Adapter->xmitpriv); |
| | | struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; |
| | | struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); |
| | | struct mlme_priv *pmlmepriv = &(Adapter->mlmepriv); |
| | | struct beamforming_info *pBeamInfo = GET_BEAMFORM_INFO(pmlmepriv); |
| | | struct rtw_ndpa_sta_info sta_info; |
| | | u8 NDPTxRate = 0; |
| | | |
| | | u8 *pframe; |
| | | u16 *fctrl; |
| | | u16 duration = 0; |
| | | u8 sequence = 0, aSifsTime = 0; |
| | | |
| | | RTW_INFO("%s: issue_vht_sw_ndpa_packet!\n", __func__); |
| | | |
| | | |
| | | NDPTxRate = MGN_VHT2SS_MCS0; |
| | | RTW_INFO("%s: NDPTxRate =%d\n", __func__, NDPTxRate); |
| | | pmgntframe = alloc_mgtxmitframe(pxmitpriv); |
| | | |
| | | if (pmgntframe == NULL) { |
| | | RTW_INFO("%s, alloc mgnt frame fail\n", __func__); |
| | | return _FALSE; |
| | | } |
| | | |
| | | /*update attribute*/ |
| | | pattrib = &pmgntframe->attrib; |
| | | update_mgntframe_attrib(Adapter, pattrib); |
| | | pattrib->qsel = QSLT_MGNT; |
| | | pattrib->rate = NDPTxRate; |
| | | pattrib->bwmode = bw; |
| | | pattrib->subtype = WIFI_NDPA; |
| | | |
| | | _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); |
| | | |
| | | pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; |
| | | |
| | | pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; |
| | | |
| | | fctrl = &pwlanhdr->frame_ctl; |
| | | *(fctrl) = 0; |
| | | |
| | | set_frame_sub_type(pframe, WIFI_NDPA); |
| | | |
| | | _rtw_memcpy(pwlanhdr->addr1, ra, ETH_ALEN); |
| | | _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(Adapter), ETH_ALEN); |
| | | |
| | | if (is_supported_5g(pmlmeext->cur_wireless_mode) || is_supported_ht(pmlmeext->cur_wireless_mode)) |
| | | aSifsTime = 16; |
| | | else |
| | | aSifsTime = 10; |
| | | |
| | | duration = 2 * aSifsTime + 44; |
| | | |
| | | if (bw == CHANNEL_WIDTH_80) |
| | | duration += 40; |
| | | else if (bw == CHANNEL_WIDTH_40) |
| | | duration += 87; |
| | | else |
| | | duration += 180; |
| | | |
| | | set_duration(pframe, duration); |
| | | |
| | | sequence = pBeamInfo->sounding_sequence << 2; |
| | | if (pBeamInfo->sounding_sequence >= 0x3f) |
| | | pBeamInfo->sounding_sequence = 0; |
| | | else |
| | | pBeamInfo->sounding_sequence++; |
| | | |
| | | _rtw_memcpy(pframe + 16, &sequence, 1); |
| | | if (((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) || ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE)) |
| | | aid = 0; |
| | | |
| | | sta_info.aid = aid; |
| | | sta_info.feedback_type = 0; |
| | | sta_info.nc_index = 0; |
| | | |
| | | _rtw_memcpy(pframe + 17, (u8 *)&sta_info, 2); |
| | | |
| | | pattrib->pktlen = 19; |
| | | |
| | | pattrib->last_txcmdsz = pattrib->pktlen; |
| | | |
| | | dump_mgntframe(Adapter, pmgntframe); |
| | | |
| | | |
| | | return _TRUE; |
| | | |
| | | } |
| | | BOOLEAN issue_vht_ndpa_packet(PADAPTER Adapter, u8 *ra, u16 aid, CHANNEL_WIDTH bw, u8 qidx) |
| | | { |
| | | struct xmit_frame *pmgntframe; |
| | | struct pkt_attrib *pattrib; |
| | | struct rtw_ieee80211_hdr *pwlanhdr; |
| | | struct xmit_priv *pxmitpriv = &(Adapter->xmitpriv); |
| | | struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; |
| | | struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); |
| | | struct mlme_priv *pmlmepriv = &(Adapter->mlmepriv); |
| | | struct beamforming_info *pBeamInfo = GET_BEAMFORM_INFO(pmlmepriv); |
| | | struct rtw_ndpa_sta_info sta_info; |
| | | u8 *pframe; |
| | | u16 *fctrl; |
| | | u16 duration = 0; |
| | | u8 sequence = 0, aSifsTime = 0; |
| | | |
| | | pmgntframe = alloc_mgtxmitframe(pxmitpriv); |
| | | if (pmgntframe == NULL) |
| | | return _FALSE; |
| | | |
| | | /*update attribute*/ |
| | | pattrib = &pmgntframe->attrib; |
| | | update_mgntframe_attrib(Adapter, pattrib); |
| | | |
| | | if (qidx == BCN_QUEUE_INX) |
| | | pattrib->qsel = QSLT_BEACON; |
| | | pattrib->rate = MGN_VHT2SS_MCS0; |
| | | pattrib->bwmode = bw; |
| | | pattrib->subtype = WIFI_NDPA; |
| | | |
| | | _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); |
| | | |
| | | pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; |
| | | |
| | | pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; |
| | | |
| | | fctrl = &pwlanhdr->frame_ctl; |
| | | *(fctrl) = 0; |
| | | |
| | | set_frame_sub_type(pframe, WIFI_NDPA); |
| | | |
| | | _rtw_memcpy(pwlanhdr->addr1, ra, ETH_ALEN); |
| | | _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(Adapter), ETH_ALEN); |
| | | |
| | | if (is_supported_5g(pmlmeext->cur_wireless_mode) || is_supported_ht(pmlmeext->cur_wireless_mode)) |
| | | aSifsTime = 16; |
| | | else |
| | | aSifsTime = 10; |
| | | |
| | | duration = 2 * aSifsTime + 44; |
| | | |
| | | if (bw == CHANNEL_WIDTH_80) |
| | | duration += 40; |
| | | else if (bw == CHANNEL_WIDTH_40) |
| | | duration += 87; |
| | | else |
| | | duration += 180; |
| | | |
| | | set_duration(pframe, duration); |
| | | |
| | | sequence = pBeamInfo->sounding_sequence << 2; |
| | | if (pBeamInfo->sounding_sequence >= 0x3f) |
| | | pBeamInfo->sounding_sequence = 0; |
| | | else |
| | | pBeamInfo->sounding_sequence++; |
| | | |
| | | _rtw_memcpy(pframe + 16, &sequence, 1); |
| | | |
| | | if (((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) || ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE)) |
| | | aid = 0; |
| | | |
| | | sta_info.aid = aid; |
| | | sta_info.feedback_type = 0; |
| | | sta_info.nc_index = 0; |
| | | |
| | | _rtw_memcpy(pframe + 17, (u8 *)&sta_info, 2); |
| | | |
| | | pattrib->pktlen = 19; |
| | | |
| | | pattrib->last_txcmdsz = pattrib->pktlen; |
| | | |
| | | dump_mgntframe(Adapter, pmgntframe); |
| | | |
| | | return _TRUE; |
| | | } |
| | | |
| | | BOOLEAN beamforming_send_vht_ndpa_packet(PADAPTER Adapter, u8 *ra, u16 aid, CHANNEL_WIDTH bw, u8 qidx) |
| | | { |
| | | return issue_vht_ndpa_packet(Adapter, ra, aid, bw, qidx); |
| | | } |
| | | |
| | | BOOLEAN beamfomring_bSounding(struct beamforming_info *pBeamInfo) |
| | | { |
| | | BOOLEAN bSounding = _FALSE; |
| | | |
| | | if ((beamforming_get_beamform_cap(pBeamInfo) & BEAMFORMER_CAP) == 0) |
| | | bSounding = _FALSE; |
| | | else |
| | | bSounding = _TRUE; |
| | | |
| | | return bSounding; |
| | | } |
| | | |
| | | u8 beamforming_sounding_idx(struct beamforming_info *pBeamInfo) |
| | | { |
| | | u8 idx = 0; |
| | | u8 i; |
| | | |
| | | for (i = 0; i < BEAMFORMING_ENTRY_NUM; i++) { |
| | | if (pBeamInfo->beamforming_entry[i].bUsed && |
| | | (_FALSE == pBeamInfo->beamforming_entry[i].bSound)) { |
| | | idx = i; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | return idx; |
| | | } |
| | | |
| | | SOUNDING_MODE beamforming_sounding_mode(struct beamforming_info *pBeamInfo, u8 idx) |
| | | { |
| | | struct beamforming_entry BeamEntry = pBeamInfo->beamforming_entry[idx]; |
| | | SOUNDING_MODE mode; |
| | | |
| | | if (BeamEntry.beamforming_entry_cap & BEAMFORMER_CAP_VHT_SU) |
| | | mode = SOUNDING_FW_VHT_TIMER; |
| | | else if (BeamEntry.beamforming_entry_cap & BEAMFORMER_CAP_HT_EXPLICIT) |
| | | mode = SOUNDING_FW_HT_TIMER; |
| | | else |
| | | mode = SOUNDING_STOP_All_TIMER; |
| | | |
| | | return mode; |
| | | } |
| | | |
| | | u16 beamforming_sounding_time(struct beamforming_info *pBeamInfo, SOUNDING_MODE mode, u8 idx) |
| | | { |
| | | u16 sounding_time = 0xffff; |
| | | struct beamforming_entry BeamEntry = pBeamInfo->beamforming_entry[idx]; |
| | | |
| | | sounding_time = BeamEntry.sound_period; |
| | | |
| | | return sounding_time; |
| | | } |
| | | |
| | | CHANNEL_WIDTH beamforming_sounding_bw(struct beamforming_info *pBeamInfo, SOUNDING_MODE mode, u8 idx) |
| | | { |
| | | CHANNEL_WIDTH sounding_bw = CHANNEL_WIDTH_20; |
| | | struct beamforming_entry BeamEntry = pBeamInfo->beamforming_entry[idx]; |
| | | |
| | | sounding_bw = BeamEntry.sound_bw; |
| | | |
| | | return sounding_bw; |
| | | } |
| | | |
| | | BOOLEAN beamforming_select_beam_entry(struct beamforming_info *pBeamInfo) |
| | | { |
| | | struct sounding_info *pSoundInfo = &(pBeamInfo->sounding_info); |
| | | |
| | | pSoundInfo->sound_idx = beamforming_sounding_idx(pBeamInfo); |
| | | |
| | | if (pSoundInfo->sound_idx < BEAMFORMING_ENTRY_NUM) |
| | | pSoundInfo->sound_mode = beamforming_sounding_mode(pBeamInfo, pSoundInfo->sound_idx); |
| | | else |
| | | pSoundInfo->sound_mode = SOUNDING_STOP_All_TIMER; |
| | | |
| | | if (SOUNDING_STOP_All_TIMER == pSoundInfo->sound_mode) |
| | | return _FALSE; |
| | | else { |
| | | pSoundInfo->sound_bw = beamforming_sounding_bw(pBeamInfo, pSoundInfo->sound_mode, pSoundInfo->sound_idx); |
| | | pSoundInfo->sound_period = beamforming_sounding_time(pBeamInfo, pSoundInfo->sound_mode, pSoundInfo->sound_idx); |
| | | return _TRUE; |
| | | } |
| | | } |
| | | |
| | | BOOLEAN beamforming_start_fw(PADAPTER adapter, u8 idx) |
| | | { |
| | | u8 *RA = NULL; |
| | | struct beamforming_entry *pEntry; |
| | | BOOLEAN ret = _TRUE; |
| | | struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); |
| | | struct beamforming_info *pBeamInfo = GET_BEAMFORM_INFO(pmlmepriv); |
| | | |
| | | pEntry = &(pBeamInfo->beamforming_entry[idx]); |
| | | if (pEntry->bUsed == _FALSE) { |
| | | RTW_INFO("Skip Beamforming, no entry for Idx =%d\n", idx); |
| | | return _FALSE; |
| | | } |
| | | |
| | | pEntry->beamforming_entry_state = BEAMFORMING_ENTRY_STATE_PROGRESSING; |
| | | pEntry->bSound = _TRUE; |
| | | rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_FW_NDPA, (u8 *)&idx); |
| | | |
| | | return _TRUE; |
| | | } |
| | | |
| | | void beamforming_end_fw(PADAPTER adapter) |
| | | { |
| | | u8 idx = 0; |
| | | |
| | | rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_FW_NDPA, (u8 *)&idx); |
| | | |
| | | RTW_INFO("%s\n", __FUNCTION__); |
| | | } |
| | | |
| | | BOOLEAN beamforming_start_period(PADAPTER adapter) |
| | | { |
| | | BOOLEAN ret = _TRUE; |
| | | struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); |
| | | struct beamforming_info *pBeamInfo = GET_BEAMFORM_INFO(pmlmepriv); |
| | | struct sounding_info *pSoundInfo = &(pBeamInfo->sounding_info); |
| | | |
| | | beamforming_dym_ndpa_rate(adapter); |
| | | |
| | | beamforming_select_beam_entry(pBeamInfo); |
| | | |
| | | if (pSoundInfo->sound_mode == SOUNDING_FW_VHT_TIMER || pSoundInfo->sound_mode == SOUNDING_FW_HT_TIMER) |
| | | ret = beamforming_start_fw(adapter, pSoundInfo->sound_idx); |
| | | else |
| | | ret = _FALSE; |
| | | |
| | | RTW_INFO("%s Idx %d Mode %d BW %d Period %d\n", __FUNCTION__, |
| | | pSoundInfo->sound_idx, pSoundInfo->sound_mode, pSoundInfo->sound_bw, pSoundInfo->sound_period); |
| | | |
| | | return ret; |
| | | } |
| | | |
| | | void beamforming_end_period(PADAPTER adapter) |
| | | { |
| | | u8 idx = 0; |
| | | struct beamforming_entry *pBeamformEntry; |
| | | struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); |
| | | struct beamforming_info *pBeamInfo = GET_BEAMFORM_INFO(pmlmepriv); |
| | | struct sounding_info *pSoundInfo = &(pBeamInfo->sounding_info); |
| | | |
| | | |
| | | if (pSoundInfo->sound_mode == SOUNDING_FW_VHT_TIMER || pSoundInfo->sound_mode == SOUNDING_FW_HT_TIMER) |
| | | beamforming_end_fw(adapter); |
| | | } |
| | | |
| | | void beamforming_notify(PADAPTER adapter) |
| | | { |
| | | BOOLEAN bSounding = _FALSE; |
| | | struct beamforming_info *pBeamInfo = GET_BEAMFORM_INFO(&(adapter->mlmepriv)); |
| | | |
| | | bSounding = beamfomring_bSounding(pBeamInfo); |
| | | |
| | | if (pBeamInfo->beamforming_state == BEAMFORMING_STATE_IDLE) { |
| | | if (bSounding) { |
| | | if (beamforming_start_period(adapter) == _TRUE) |
| | | pBeamInfo->beamforming_state = BEAMFORMING_STATE_START; |
| | | } |
| | | } else if (pBeamInfo->beamforming_state == BEAMFORMING_STATE_START) { |
| | | if (bSounding) { |
| | | if (beamforming_start_period(adapter) == _FALSE) |
| | | pBeamInfo->beamforming_state = BEAMFORMING_STATE_END; |
| | | } else { |
| | | beamforming_end_period(adapter); |
| | | pBeamInfo->beamforming_state = BEAMFORMING_STATE_END; |
| | | } |
| | | } else if (pBeamInfo->beamforming_state == BEAMFORMING_STATE_END) { |
| | | if (bSounding) { |
| | | if (beamforming_start_period(adapter) == _TRUE) |
| | | pBeamInfo->beamforming_state = BEAMFORMING_STATE_START; |
| | | } |
| | | } else |
| | | RTW_INFO("%s BeamformState %d\n", __FUNCTION__, pBeamInfo->beamforming_state); |
| | | |
| | | RTW_INFO("%s BeamformState %d bSounding %d\n", __FUNCTION__, pBeamInfo->beamforming_state, bSounding); |
| | | } |
| | | |
| | | BOOLEAN beamforming_init_entry(PADAPTER adapter, struct sta_info *psta, u8 *idx) |
| | | { |
| | | struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); |
| | | struct ht_priv *phtpriv = &(pmlmepriv->htpriv); |
| | | #ifdef CONFIG_80211AC_VHT |
| | | struct vht_priv *pvhtpriv = &(pmlmepriv->vhtpriv); |
| | | #endif |
| | | struct mlme_ext_priv *pmlmeext = &(adapter->mlmeextpriv); |
| | | struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); |
| | | struct beamforming_entry *pBeamformEntry = NULL; |
| | | u8 *ra; |
| | | u16 aid, mac_id; |
| | | u8 wireless_mode; |
| | | CHANNEL_WIDTH bw = CHANNEL_WIDTH_20; |
| | | BEAMFORMING_CAP beamform_cap = BEAMFORMING_CAP_NONE; |
| | | |
| | | /* The current setting does not support Beaforming */ |
| | | if (0 == phtpriv->beamform_cap |
| | | #ifdef CONFIG_80211AC_VHT |
| | | && 0 == pvhtpriv->beamform_cap |
| | | #endif |
| | | ) { |
| | | RTW_INFO("The configuration disabled Beamforming! Skip...\n"); |
| | | return _FALSE; |
| | | } |
| | | |
| | | aid = psta->aid; |
| | | ra = psta->hwaddr; |
| | | mac_id = psta->mac_id; |
| | | wireless_mode = psta->wireless_mode; |
| | | bw = psta->bw_mode; |
| | | |
| | | if (is_supported_ht(wireless_mode) || is_supported_vht(wireless_mode)) { |
| | | /* 3 */ /* HT */ |
| | | u8 cur_beamform; |
| | | |
| | | cur_beamform = psta->htpriv.beamform_cap; |
| | | |
| | | /* We are Beamformee because the STA is Beamformer */ |
| | | if (TEST_FLAG(cur_beamform, BEAMFORMING_HT_BEAMFORMER_ENABLE)) |
| | | beamform_cap = (BEAMFORMING_CAP)(beamform_cap | BEAMFORMEE_CAP_HT_EXPLICIT); |
| | | |
| | | /* We are Beamformer because the STA is Beamformee */ |
| | | if (TEST_FLAG(cur_beamform, BEAMFORMING_HT_BEAMFORMEE_ENABLE)) |
| | | beamform_cap = (BEAMFORMING_CAP)(beamform_cap | BEAMFORMER_CAP_HT_EXPLICIT); |
| | | #ifdef CONFIG_80211AC_VHT |
| | | if (is_supported_vht(wireless_mode)) { |
| | | /* 3 */ /* VHT */ |
| | | cur_beamform = psta->vhtpriv.beamform_cap; |
| | | |
| | | /* We are Beamformee because the STA is Beamformer */ |
| | | if (TEST_FLAG(cur_beamform, BEAMFORMING_VHT_BEAMFORMER_ENABLE)) |
| | | beamform_cap = (BEAMFORMING_CAP)(beamform_cap | BEAMFORMEE_CAP_VHT_SU); |
| | | /* We are Beamformer because the STA is Beamformee */ |
| | | if (TEST_FLAG(cur_beamform, BEAMFORMING_VHT_BEAMFORMEE_ENABLE)) |
| | | beamform_cap = (BEAMFORMING_CAP)(beamform_cap | BEAMFORMER_CAP_VHT_SU); |
| | | } |
| | | #endif /* CONFIG_80211AC_VHT */ |
| | | |
| | | if (beamform_cap == BEAMFORMING_CAP_NONE) |
| | | return _FALSE; |
| | | |
| | | RTW_INFO("Beamforming Config Capability = 0x%02X\n", beamform_cap); |
| | | |
| | | pBeamformEntry = beamforming_get_entry_by_addr(pmlmepriv, ra, idx); |
| | | if (pBeamformEntry == NULL) { |
| | | pBeamformEntry = beamforming_add_entry(adapter, ra, aid, mac_id, bw, beamform_cap, idx); |
| | | if (pBeamformEntry == NULL) |
| | | return _FALSE; |
| | | else |
| | | pBeamformEntry->beamforming_entry_state = BEAMFORMING_ENTRY_STATE_INITIALIZEING; |
| | | } else { |
| | | /* Entry has been created. If entry is initialing or progressing then errors occur. */ |
| | | if (pBeamformEntry->beamforming_entry_state != BEAMFORMING_ENTRY_STATE_INITIALIZED && |
| | | pBeamformEntry->beamforming_entry_state != BEAMFORMING_ENTRY_STATE_PROGRESSED) { |
| | | RTW_INFO("Error State of Beamforming"); |
| | | return _FALSE; |
| | | } else |
| | | pBeamformEntry->beamforming_entry_state = BEAMFORMING_ENTRY_STATE_INITIALIZEING; |
| | | } |
| | | |
| | | pBeamformEntry->beamforming_entry_state = BEAMFORMING_ENTRY_STATE_INITIALIZED; |
| | | psta->txbf_paid = pBeamformEntry->p_aid; |
| | | psta->txbf_gid = pBeamformEntry->g_id; |
| | | |
| | | RTW_INFO("%s Idx %d\n", __FUNCTION__, *idx); |
| | | } else |
| | | return _FALSE; |
| | | |
| | | return _SUCCESS; |
| | | } |
| | | |
| | | void beamforming_deinit_entry(PADAPTER adapter, u8 *ra) |
| | | { |
| | | u8 idx = 0; |
| | | struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); |
| | | |
| | | if (beamforming_remove_entry(pmlmepriv, ra, &idx) == _TRUE) |
| | | rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_LEAVE, (u8 *)&idx); |
| | | |
| | | RTW_INFO("%s Idx %d\n", __FUNCTION__, idx); |
| | | } |
| | | |
| | | void beamforming_reset(PADAPTER adapter) |
| | | { |
| | | u8 idx = 0; |
| | | struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); |
| | | struct beamforming_info *pBeamInfo = GET_BEAMFORM_INFO(pmlmepriv); |
| | | |
| | | for (idx = 0; idx < BEAMFORMING_ENTRY_NUM; idx++) { |
| | | if (pBeamInfo->beamforming_entry[idx].bUsed == _TRUE) { |
| | | pBeamInfo->beamforming_entry[idx].bUsed = _FALSE; |
| | | pBeamInfo->beamforming_entry[idx].beamforming_entry_cap = BEAMFORMING_CAP_NONE; |
| | | pBeamInfo->beamforming_entry[idx].beamforming_entry_state = BEAMFORMING_ENTRY_STATE_UNINITIALIZE; |
| | | rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_LEAVE, (u8 *)&idx); |
| | | } |
| | | } |
| | | |
| | | RTW_INFO("%s\n", __FUNCTION__); |
| | | } |
| | | |
| | | void beamforming_sounding_fail(PADAPTER Adapter) |
| | | { |
| | | struct mlme_priv *pmlmepriv = &(Adapter->mlmepriv); |
| | | struct beamforming_info *pBeamInfo = GET_BEAMFORM_INFO(pmlmepriv); |
| | | struct beamforming_entry *pEntry = &(pBeamInfo->beamforming_entry[pBeamInfo->beamforming_cur_idx]); |
| | | |
| | | pEntry->bSound = _FALSE; |
| | | rtw_hal_set_hwreg(Adapter, HW_VAR_SOUNDING_FW_NDPA, (u8 *)&pBeamInfo->beamforming_cur_idx); |
| | | beamforming_deinit_entry(Adapter, pEntry->mac_addr); |
| | | } |
| | | |
| | | void beamforming_check_sounding_success(PADAPTER Adapter, BOOLEAN status) |
| | | { |
| | | struct mlme_priv *pmlmepriv = &(Adapter->mlmepriv); |
| | | struct beamforming_info *pBeamInfo = GET_BEAMFORM_INFO(pmlmepriv); |
| | | struct beamforming_entry *pEntry = &(pBeamInfo->beamforming_entry[pBeamInfo->beamforming_cur_idx]); |
| | | |
| | | if (status == 1) |
| | | pEntry->LogStatusFailCnt = 0; |
| | | else { |
| | | pEntry->LogStatusFailCnt++; |
| | | RTW_INFO("%s LogStatusFailCnt %d\n", __FUNCTION__, pEntry->LogStatusFailCnt); |
| | | } |
| | | if (pEntry->LogStatusFailCnt > 20) { |
| | | RTW_INFO("%s LogStatusFailCnt > 20, Stop SOUNDING\n", __FUNCTION__); |
| | | /* pEntry->bSound = _FALSE; */ |
| | | /* rtw_hal_set_hwreg(Adapter, HW_VAR_SOUNDING_FW_NDPA, (u8 *)&pBeamInfo->beamforming_cur_idx); */ |
| | | /* beamforming_deinit_entry(Adapter, pEntry->mac_addr); */ |
| | | beamforming_wk_cmd(Adapter, BEAMFORMING_CTRL_SOUNDING_FAIL, NULL, 0, 1); |
| | | } |
| | | } |
| | | |
| | | void beamforming_enter(PADAPTER adapter, PVOID psta) |
| | | { |
| | | u8 idx = 0xff; |
| | | |
| | | if (beamforming_init_entry(adapter, (struct sta_info *)psta, &idx)) |
| | | rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_ENTER, (u8 *)&idx); |
| | | |
| | | /* RTW_INFO("%s Idx %d\n", __FUNCTION__, idx); */ |
| | | } |
| | | |
| | | void beamforming_leave(PADAPTER adapter, u8 *ra) |
| | | { |
| | | if (ra == NULL) |
| | | beamforming_reset(adapter); |
| | | else |
| | | beamforming_deinit_entry(adapter, ra); |
| | | |
| | | beamforming_notify(adapter); |
| | | } |
| | | |
| | | BEAMFORMING_CAP beamforming_get_beamform_cap(struct beamforming_info *pBeamInfo) |
| | | { |
| | | u8 i; |
| | | BOOLEAN bSelfBeamformer = _FALSE; |
| | | BOOLEAN bSelfBeamformee = _FALSE; |
| | | struct beamforming_entry beamforming_entry; |
| | | BEAMFORMING_CAP beamform_cap = BEAMFORMING_CAP_NONE; |
| | | |
| | | for (i = 0; i < BEAMFORMING_ENTRY_NUM; i++) { |
| | | beamforming_entry = pBeamInfo->beamforming_entry[i]; |
| | | |
| | | if (beamforming_entry.bUsed) { |
| | | if ((beamforming_entry.beamforming_entry_cap & BEAMFORMEE_CAP_VHT_SU) || |
| | | (beamforming_entry.beamforming_entry_cap & BEAMFORMEE_CAP_HT_EXPLICIT)) |
| | | bSelfBeamformee = _TRUE; |
| | | if ((beamforming_entry.beamforming_entry_cap & BEAMFORMER_CAP_VHT_SU) || |
| | | (beamforming_entry.beamforming_entry_cap & BEAMFORMER_CAP_HT_EXPLICIT)) |
| | | bSelfBeamformer = _TRUE; |
| | | } |
| | | |
| | | if (bSelfBeamformer && bSelfBeamformee) |
| | | i = BEAMFORMING_ENTRY_NUM; |
| | | } |
| | | |
| | | if (bSelfBeamformer) |
| | | beamform_cap |= BEAMFORMER_CAP; |
| | | if (bSelfBeamformee) |
| | | beamform_cap |= BEAMFORMEE_CAP; |
| | | |
| | | return beamform_cap; |
| | | } |
| | | |
| | | void beamforming_watchdog(PADAPTER Adapter) |
| | | { |
| | | struct beamforming_info *pBeamInfo = GET_BEAMFORM_INFO((&(Adapter->mlmepriv))); |
| | | |
| | | if (pBeamInfo->beamforming_state != BEAMFORMING_STATE_START) |
| | | return; |
| | | |
| | | beamforming_dym_period(Adapter); |
| | | beamforming_dym_ndpa_rate(Adapter); |
| | | } |
| | | #endif/* #if (BEAMFORMING_SUPPORT ==0) - for diver defined beamforming*/ |
| | | |
| | | u32 rtw_beamforming_get_report_frame(PADAPTER Adapter, union recv_frame *precv_frame) |
| | | { |
| | | u32 ret = _SUCCESS; |
| | | #if (BEAMFORMING_SUPPORT == 1) |
| | | PHAL_DATA_TYPE pHalData = GET_HAL_DATA(Adapter); |
| | | struct PHY_DM_STRUCT *pDM_Odm = &(pHalData->odmpriv); |
| | | |
| | | ret = beamforming_get_report_frame(pDM_Odm, precv_frame); |
| | | |
| | | #else /*(BEAMFORMING_SUPPORT == 0)- for drv beamfoming*/ |
| | | struct beamforming_entry *pBeamformEntry = NULL; |
| | | struct mlme_priv *pmlmepriv = &(Adapter->mlmepriv); |
| | | u8 *pframe = precv_frame->u.hdr.rx_data; |
| | | u32 frame_len = precv_frame->u.hdr.len; |
| | | u8 *ta; |
| | | u8 idx, offset; |
| | | |
| | | /*RTW_INFO("rtw_beamforming_get_report_frame\n");*/ |
| | | |
| | | /*Memory comparison to see if CSI report is the same with previous one*/ |
| | | ta = get_addr2_ptr(pframe); |
| | | pBeamformEntry = beamforming_get_entry_by_addr(pmlmepriv, ta, &idx); |
| | | if (pBeamformEntry->beamforming_entry_cap & BEAMFORMER_CAP_VHT_SU) |
| | | offset = 31; /*24+(1+1+3)+2 MAC header+(Category+ActionCode+MIMOControlField)+SNR(Nc=2)*/ |
| | | else if (pBeamformEntry->beamforming_entry_cap & BEAMFORMER_CAP_HT_EXPLICIT) |
| | | offset = 34; /*24+(1+1+6)+2 MAC header+(Category+ActionCode+MIMOControlField)+SNR(Nc=2)*/ |
| | | else |
| | | return ret; |
| | | |
| | | /*RTW_INFO("%s MacId %d offset=%d\n", __FUNCTION__, pBeamformEntry->mac_id, offset);*/ |
| | | |
| | | if (_rtw_memcmp(pBeamformEntry->PreCsiReport + offset, pframe + offset, frame_len - offset) == _FALSE) |
| | | pBeamformEntry->DefaultCsiCnt = 0; |
| | | else |
| | | pBeamformEntry->DefaultCsiCnt++; |
| | | |
| | | _rtw_memcpy(&pBeamformEntry->PreCsiReport, pframe, frame_len); |
| | | |
| | | pBeamformEntry->bDefaultCSI = _FALSE; |
| | | |
| | | if (pBeamformEntry->DefaultCsiCnt > 20) |
| | | pBeamformEntry->bDefaultCSI = _TRUE; |
| | | else |
| | | pBeamformEntry->bDefaultCSI = _FALSE; |
| | | #endif |
| | | return ret; |
| | | } |
| | | |
| | | void rtw_beamforming_get_ndpa_frame(PADAPTER Adapter, union recv_frame *precv_frame) |
| | | { |
| | | #if (BEAMFORMING_SUPPORT == 1) |
| | | PHAL_DATA_TYPE pHalData = GET_HAL_DATA(Adapter); |
| | | struct PHY_DM_STRUCT *pDM_Odm = &(pHalData->odmpriv); |
| | | |
| | | beamforming_get_ndpa_frame(pDM_Odm, precv_frame); |
| | | |
| | | #else /*(BEAMFORMING_SUPPORT == 0)- for drv beamfoming*/ |
| | | u8 *ta; |
| | | u8 idx, Sequence; |
| | | u8 *pframe = precv_frame->u.hdr.rx_data; |
| | | struct mlme_priv *pmlmepriv = &(Adapter->mlmepriv); |
| | | struct beamforming_entry *pBeamformEntry = NULL; |
| | | |
| | | /*RTW_INFO("rtw_beamforming_get_ndpa_frame\n");*/ |
| | | |
| | | if (IS_HARDWARE_TYPE_8812(Adapter) == _FALSE) |
| | | return; |
| | | else if (get_frame_sub_type(pframe) != WIFI_NDPA) |
| | | return; |
| | | |
| | | ta = get_addr2_ptr(pframe); |
| | | /*Remove signaling TA. */ |
| | | ta[0] = ta[0] & 0xFE; |
| | | |
| | | pBeamformEntry = beamforming_get_entry_by_addr(pmlmepriv, ta, &idx); |
| | | |
| | | if (pBeamformEntry == NULL) |
| | | return; |
| | | else if (!(pBeamformEntry->beamforming_entry_cap & BEAMFORMEE_CAP_VHT_SU)) |
| | | return; |
| | | /*LogSuccess: As long as 8812A receive NDPA and feedback CSI succeed once, clock reset is NO LONGER needed !2015-04-10, Jeffery*/ |
| | | /*ClockResetTimes: While BFer entry always doesn't receive our CSI, clock will reset again and again.So ClockResetTimes is limited to 5 times.2015-04-13, Jeffery*/ |
| | | else if ((pBeamformEntry->LogSuccess == 1) || (pBeamformEntry->ClockResetTimes == 5)) { |
| | | RTW_INFO("[%s] LogSeq=%d, PreLogSeq=%d\n", __func__, pBeamformEntry->LogSeq, pBeamformEntry->PreLogSeq); |
| | | return; |
| | | } |
| | | |
| | | Sequence = (pframe[16]) >> 2; |
| | | RTW_INFO("[%s] Start, Sequence=%d, LogSeq=%d, PreLogSeq=%d, LogRetryCnt=%d, ClockResetTimes=%d, LogSuccess=%d\n", |
| | | __func__, Sequence, pBeamformEntry->LogSeq, pBeamformEntry->PreLogSeq, pBeamformEntry->LogRetryCnt, pBeamformEntry->ClockResetTimes, pBeamformEntry->LogSuccess); |
| | | |
| | | if ((pBeamformEntry->LogSeq != 0) && (pBeamformEntry->PreLogSeq != 0)) { |
| | | /*Success condition*/ |
| | | if ((pBeamformEntry->LogSeq != Sequence) && (pBeamformEntry->PreLogSeq != pBeamformEntry->LogSeq)) { |
| | | /* break option for clcok reset, 2015-03-30, Jeffery */ |
| | | pBeamformEntry->LogRetryCnt = 0; |
| | | /*As long as 8812A receive NDPA and feedback CSI succeed once, clock reset is no longer needed.*/ |
| | | /*That is, LogSuccess is NOT needed to be reset to zero, 2015-04-13, Jeffery*/ |
| | | pBeamformEntry->LogSuccess = 1; |
| | | |
| | | } else {/*Fail condition*/ |
| | | |
| | | if (pBeamformEntry->LogRetryCnt == 5) { |
| | | pBeamformEntry->ClockResetTimes++; |
| | | pBeamformEntry->LogRetryCnt = 0; |
| | | |
| | | RTW_INFO("[%s] Clock Reset!!! ClockResetTimes=%d\n", __func__, pBeamformEntry->ClockResetTimes); |
| | | beamforming_wk_cmd(Adapter, BEAMFORMING_CTRL_SOUNDING_CLK, NULL, 0, 1); |
| | | |
| | | } else |
| | | pBeamformEntry->LogRetryCnt++; |
| | | } |
| | | } |
| | | |
| | | /*Update LogSeq & PreLogSeq*/ |
| | | pBeamformEntry->PreLogSeq = pBeamformEntry->LogSeq; |
| | | pBeamformEntry->LogSeq = Sequence; |
| | | |
| | | #endif |
| | | |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | void beamforming_wk_hdl(_adapter *padapter, u8 type, u8 *pbuf) |
| | | { |
| | | PHAL_DATA_TYPE pHalData = GET_HAL_DATA(padapter); |
| | | struct PHY_DM_STRUCT *pDM_Odm = &(pHalData->odmpriv); |
| | | |
| | | #if (BEAMFORMING_SUPPORT == 1) /*(BEAMFORMING_SUPPORT == 1)- for PHYDM beamfoming*/ |
| | | switch (type) { |
| | | case BEAMFORMING_CTRL_ENTER: { |
| | | struct sta_info *psta = (PVOID)pbuf; |
| | | u16 staIdx = psta->mac_id; |
| | | |
| | | beamforming_enter(pDM_Odm, staIdx); |
| | | break; |
| | | } |
| | | case BEAMFORMING_CTRL_LEAVE: |
| | | beamforming_leave(pDM_Odm, pbuf); |
| | | break; |
| | | default: |
| | | break; |
| | | |
| | | } |
| | | #else /*(BEAMFORMING_SUPPORT == 0)- for drv beamfoming*/ |
| | | switch (type) { |
| | | case BEAMFORMING_CTRL_ENTER: |
| | | beamforming_enter(padapter, (PVOID)pbuf); |
| | | break; |
| | | |
| | | case BEAMFORMING_CTRL_LEAVE: |
| | | beamforming_leave(padapter, pbuf); |
| | | break; |
| | | |
| | | case BEAMFORMING_CTRL_SOUNDING_FAIL: |
| | | beamforming_sounding_fail(padapter); |
| | | break; |
| | | |
| | | case BEAMFORMING_CTRL_SOUNDING_CLK: |
| | | rtw_hal_set_hwreg(padapter, HW_VAR_SOUNDING_CLK, NULL); |
| | | break; |
| | | |
| | | default: |
| | | break; |
| | | } |
| | | #endif |
| | | } |
| | | |
| | | u8 beamforming_wk_cmd(_adapter *padapter, s32 type, u8 *pbuf, s32 size, u8 enqueue) |
| | | { |
| | | struct cmd_obj *ph2c; |
| | | struct drvextra_cmd_parm *pdrvextra_cmd_parm; |
| | | struct cmd_priv *pcmdpriv = &padapter->cmdpriv; |
| | | u8 res = _SUCCESS; |
| | | |
| | | |
| | | if (enqueue) { |
| | | u8 *wk_buf; |
| | | |
| | | ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); |
| | | if (ph2c == NULL) { |
| | | res = _FAIL; |
| | | goto exit; |
| | | } |
| | | |
| | | pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); |
| | | if (pdrvextra_cmd_parm == NULL) { |
| | | rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj)); |
| | | res = _FAIL; |
| | | goto exit; |
| | | } |
| | | |
| | | if (pbuf != NULL) { |
| | | wk_buf = rtw_zmalloc(size); |
| | | if (wk_buf == NULL) { |
| | | rtw_mfree((u8 *)ph2c, sizeof(struct cmd_obj)); |
| | | rtw_mfree((u8 *)pdrvextra_cmd_parm, sizeof(struct drvextra_cmd_parm)); |
| | | res = _FAIL; |
| | | goto exit; |
| | | } |
| | | |
| | | _rtw_memcpy(wk_buf, pbuf, size); |
| | | } else { |
| | | wk_buf = NULL; |
| | | size = 0; |
| | | } |
| | | |
| | | pdrvextra_cmd_parm->ec_id = BEAMFORMING_WK_CID; |
| | | pdrvextra_cmd_parm->type = type; |
| | | pdrvextra_cmd_parm->size = size; |
| | | pdrvextra_cmd_parm->pbuf = wk_buf; |
| | | |
| | | init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); |
| | | |
| | | res = rtw_enqueue_cmd(pcmdpriv, ph2c); |
| | | } else |
| | | beamforming_wk_hdl(padapter, type, pbuf); |
| | | |
| | | exit: |
| | | |
| | | |
| | | return res; |
| | | } |
| | | |
| | | void update_attrib_txbf_info(_adapter *padapter, struct pkt_attrib *pattrib, struct sta_info *psta) |
| | | { |
| | | if (psta) { |
| | | pattrib->txbf_g_id = psta->txbf_gid; |
| | | pattrib->txbf_p_aid = psta->txbf_paid; |
| | | } |
| | | } |
| | | #endif /* !RTW_BEAMFORMING_VERSION_2 */ |
| | | |
| | | #endif /* CONFIG_BEAMFORMING */ |
New file |
| | |
| | | /****************************************************************************** |
| | | * |
| | | * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. |
| | | * |
| | | * This program is free software; you can redistribute it and/or modify it |
| | | * under the terms of version 2 of the GNU General Public License as |
| | | * published by the Free Software Foundation. |
| | | * |
| | | * This program is distributed in the hope that it will be useful, but WITHOUT |
| | | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| | | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
| | | * more details. |
| | | * |
| | | * You should have received a copy of the GNU General Public License along with |
| | | * this program; if not, write to the Free Software Foundation, Inc., |
| | | * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA |
| | | * |
| | | * |
| | | ******************************************************************************/ |
| | | #define _RTW_BR_EXT_C_ |
| | | |
| | | #ifdef __KERNEL__ |
| | | #include <linux/if_arp.h> |
| | | #include <net/ip.h> |
| | | #include <net/ipx.h> |
| | | #include <linux/atalk.h> |
| | | #include <linux/udp.h> |
| | | #include <linux/if_pppox.h> |
| | | #endif |
| | | |
| | | #if 1 /* rtw_wifi_driver */ |
| | | #include <drv_types.h> |
| | | #else /* rtw_wifi_driver */ |
| | | #include "./8192cd_cfg.h" |
| | | |
| | | #ifndef __KERNEL__ |
| | | #include "./sys-support.h" |
| | | #endif |
| | | |
| | | #include "./8192cd.h" |
| | | #include "./8192cd_headers.h" |
| | | #include "./8192cd_br_ext.h" |
| | | #include "./8192cd_debug.h" |
| | | #endif /* rtw_wifi_driver */ |
| | | |
| | | #ifdef CL_IPV6_PASS |
| | | #ifdef __KERNEL__ |
| | | #include <linux/ipv6.h> |
| | | #include <linux/icmpv6.h> |
| | | #include <net/ndisc.h> |
| | | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)) |
| | | #include <net/ip6_checksum.h> |
| | | #else |
| | | #include <net/checksum.h> |
| | | #endif |
| | | #endif |
| | | #endif |
| | | |
| | | #ifdef CONFIG_BR_EXT |
| | | |
| | | /* #define BR_EXT_DEBUG */ |
| | | |
| | | #define NAT25_IPV4 01 |
| | | #define NAT25_IPV6 02 |
| | | #define NAT25_IPX 03 |
| | | #define NAT25_APPLE 04 |
| | | #define NAT25_PPPOE 05 |
| | | |
| | | #define RTL_RELAY_TAG_LEN (ETH_ALEN) |
| | | #define TAG_HDR_LEN 4 |
| | | |
| | | #define MAGIC_CODE 0x8186 |
| | | #define MAGIC_CODE_LEN 2 |
| | | #define WAIT_TIME_PPPOE 5 /* waiting time for pppoe server in sec */ |
| | | |
| | | /*----------------------------------------------------------------- |
| | | How database records network address: |
| | | 0 1 2 3 4 5 6 7 8 9 10 |
| | | |----|----|----|----|----|----|----|----|----|----|----| |
| | | IPv4 |type| | IP addr | |
| | | IPX |type| Net addr | Node addr | |
| | | IPX |type| Net addr |Sckt addr| |
| | | Apple |type| Network |node| |
| | | PPPoE |type| SID | AC MAC | |
| | | -----------------------------------------------------------------*/ |
| | | |
| | | |
| | | /* Find a tag in pppoe frame and return the pointer */ |
| | | static __inline__ unsigned char *__nat25_find_pppoe_tag(struct pppoe_hdr *ph, unsigned short type) |
| | | { |
| | | unsigned char *cur_ptr, *start_ptr; |
| | | unsigned short tagLen, tagType; |
| | | |
| | | start_ptr = cur_ptr = (unsigned char *)ph->tag; |
| | | while ((cur_ptr - start_ptr) < ntohs(ph->length)) { |
| | | /* prevent un-alignment access */ |
| | | tagType = (unsigned short)((cur_ptr[0] << 8) + cur_ptr[1]); |
| | | tagLen = (unsigned short)((cur_ptr[2] << 8) + cur_ptr[3]); |
| | | if (tagType == type) |
| | | return cur_ptr; |
| | | cur_ptr = cur_ptr + TAG_HDR_LEN + tagLen; |
| | | } |
| | | return 0; |
| | | } |
| | | |
| | | |
| | | static __inline__ int __nat25_add_pppoe_tag(struct sk_buff *skb, struct pppoe_tag *tag) |
| | | { |
| | | struct pppoe_hdr *ph = (struct pppoe_hdr *)(skb->data + ETH_HLEN); |
| | | int data_len; |
| | | |
| | | data_len = tag->tag_len + TAG_HDR_LEN; |
| | | if (skb_tailroom(skb) < data_len) { |
| | | _DEBUG_ERR("skb_tailroom() failed in add SID tag!\n"); |
| | | return -1; |
| | | } |
| | | |
| | | skb_put(skb, data_len); |
| | | /* have a room for new tag */ |
| | | memmove(((unsigned char *)ph->tag + data_len), (unsigned char *)ph->tag, ntohs(ph->length)); |
| | | ph->length = htons(ntohs(ph->length) + data_len); |
| | | memcpy((unsigned char *)ph->tag, tag, data_len); |
| | | return data_len; |
| | | } |
| | | |
| | | static int skb_pull_and_merge(struct sk_buff *skb, unsigned char *src, int len) |
| | | { |
| | | int tail_len; |
| | | unsigned long end, tail; |
| | | |
| | | if ((src + len) > skb_tail_pointer(skb) || skb->len < len) |
| | | return -1; |
| | | |
| | | tail = (unsigned long)skb_tail_pointer(skb); |
| | | end = (unsigned long)src + len; |
| | | if (tail < end) |
| | | return -1; |
| | | |
| | | tail_len = (int)(tail - end); |
| | | if (tail_len > 0) |
| | | memmove(src, src + len, tail_len); |
| | | |
| | | skb_trim(skb, skb->len - len); |
| | | return 0; |
| | | } |
| | | |
| | | static __inline__ unsigned long __nat25_timeout(_adapter *priv) |
| | | { |
| | | unsigned long timeout; |
| | | |
| | | timeout = jiffies - NAT25_AGEING_TIME * HZ; |
| | | |
| | | return timeout; |
| | | } |
| | | |
| | | |
| | | static __inline__ int __nat25_has_expired(_adapter *priv, |
| | | struct nat25_network_db_entry *fdb) |
| | | { |
| | | if (time_before_eq(fdb->ageing_timer, __nat25_timeout(priv))) |
| | | return 1; |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | |
| | | static __inline__ void __nat25_generate_ipv4_network_addr(unsigned char *networkAddr, |
| | | unsigned int *ipAddr) |
| | | { |
| | | memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN); |
| | | |
| | | networkAddr[0] = NAT25_IPV4; |
| | | memcpy(networkAddr + 7, (unsigned char *)ipAddr, 4); |
| | | } |
| | | |
| | | |
| | | static __inline__ void __nat25_generate_ipx_network_addr_with_node(unsigned char *networkAddr, |
| | | unsigned int *ipxNetAddr, unsigned char *ipxNodeAddr) |
| | | { |
| | | memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN); |
| | | |
| | | networkAddr[0] = NAT25_IPX; |
| | | memcpy(networkAddr + 1, (unsigned char *)ipxNetAddr, 4); |
| | | memcpy(networkAddr + 5, ipxNodeAddr, 6); |
| | | } |
| | | |
| | | |
| | | static __inline__ void __nat25_generate_ipx_network_addr_with_socket(unsigned char *networkAddr, |
| | | unsigned int *ipxNetAddr, unsigned short *ipxSocketAddr) |
| | | { |
| | | memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN); |
| | | |
| | | networkAddr[0] = NAT25_IPX; |
| | | memcpy(networkAddr + 1, (unsigned char *)ipxNetAddr, 4); |
| | | memcpy(networkAddr + 5, (unsigned char *)ipxSocketAddr, 2); |
| | | } |
| | | |
| | | |
| | | static __inline__ void __nat25_generate_apple_network_addr(unsigned char *networkAddr, |
| | | unsigned short *network, unsigned char *node) |
| | | { |
| | | memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN); |
| | | |
| | | networkAddr[0] = NAT25_APPLE; |
| | | memcpy(networkAddr + 1, (unsigned char *)network, 2); |
| | | networkAddr[3] = *node; |
| | | } |
| | | |
| | | |
| | | static __inline__ void __nat25_generate_pppoe_network_addr(unsigned char *networkAddr, |
| | | unsigned char *ac_mac, unsigned short *sid) |
| | | { |
| | | memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN); |
| | | |
| | | networkAddr[0] = NAT25_PPPOE; |
| | | memcpy(networkAddr + 1, (unsigned char *)sid, 2); |
| | | memcpy(networkAddr + 3, (unsigned char *)ac_mac, 6); |
| | | } |
| | | |
| | | |
| | | #ifdef CL_IPV6_PASS |
| | | static void __nat25_generate_ipv6_network_addr(unsigned char *networkAddr, |
| | | unsigned int *ipAddr) |
| | | { |
| | | memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN); |
| | | |
| | | networkAddr[0] = NAT25_IPV6; |
| | | memcpy(networkAddr + 1, (unsigned char *)ipAddr, 16); |
| | | } |
| | | |
| | | |
| | | static unsigned char *scan_tlv(unsigned char *data, int len, unsigned char tag, unsigned char len8b) |
| | | { |
| | | while (len > 0) { |
| | | if (*data == tag && *(data + 1) == len8b && len >= len8b * 8) |
| | | return data + 2; |
| | | |
| | | len -= (*(data + 1)) * 8; |
| | | data += (*(data + 1)) * 8; |
| | | } |
| | | return NULL; |
| | | } |
| | | |
| | | |
| | | static int update_nd_link_layer_addr(unsigned char *data, int len, unsigned char *replace_mac) |
| | | { |
| | | struct icmp6hdr *icmphdr = (struct icmp6hdr *)data; |
| | | unsigned char *mac; |
| | | |
| | | if (icmphdr->icmp6_type == NDISC_ROUTER_SOLICITATION) { |
| | | if (len >= 8) { |
| | | mac = scan_tlv(&data[8], len - 8, 1, 1); |
| | | if (mac) { |
| | | RTW_INFO("Router Solicitation, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n", |
| | | mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], |
| | | replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]); |
| | | memcpy(mac, replace_mac, 6); |
| | | return 1; |
| | | } |
| | | } |
| | | } else if (icmphdr->icmp6_type == NDISC_ROUTER_ADVERTISEMENT) { |
| | | if (len >= 16) { |
| | | mac = scan_tlv(&data[16], len - 16, 1, 1); |
| | | if (mac) { |
| | | RTW_INFO("Router Advertisement, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n", |
| | | mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], |
| | | replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]); |
| | | memcpy(mac, replace_mac, 6); |
| | | return 1; |
| | | } |
| | | } |
| | | } else if (icmphdr->icmp6_type == NDISC_NEIGHBOUR_SOLICITATION) { |
| | | if (len >= 24) { |
| | | mac = scan_tlv(&data[24], len - 24, 1, 1); |
| | | if (mac) { |
| | | RTW_INFO("Neighbor Solicitation, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n", |
| | | mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], |
| | | replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]); |
| | | memcpy(mac, replace_mac, 6); |
| | | return 1; |
| | | } |
| | | } |
| | | } else if (icmphdr->icmp6_type == NDISC_NEIGHBOUR_ADVERTISEMENT) { |
| | | if (len >= 24) { |
| | | mac = scan_tlv(&data[24], len - 24, 2, 1); |
| | | if (mac) { |
| | | RTW_INFO("Neighbor Advertisement, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n", |
| | | mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], |
| | | replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]); |
| | | memcpy(mac, replace_mac, 6); |
| | | return 1; |
| | | } |
| | | } |
| | | } else if (icmphdr->icmp6_type == NDISC_REDIRECT) { |
| | | if (len >= 40) { |
| | | mac = scan_tlv(&data[40], len - 40, 2, 1); |
| | | if (mac) { |
| | | RTW_INFO("Redirect, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n", |
| | | mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], |
| | | replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]); |
| | | memcpy(mac, replace_mac, 6); |
| | | return 1; |
| | | } |
| | | } |
| | | } |
| | | return 0; |
| | | } |
| | | |
| | | |
| | | static void convert_ipv6_mac_to_mc(struct sk_buff *skb) |
| | | { |
| | | struct ipv6hdr *iph = (struct ipv6hdr *)(skb->data + ETH_HLEN); |
| | | unsigned char *dst_mac = skb->data; |
| | | |
| | | /* dst_mac[0] = 0xff; */ |
| | | /* dst_mac[1] = 0xff; */ |
| | | /*modified by qinjunjie,ipv6 multicast address ix 0x33-33-xx-xx-xx-xx*/ |
| | | dst_mac[0] = 0x33; |
| | | dst_mac[1] = 0x33; |
| | | memcpy(&dst_mac[2], &iph->daddr.s6_addr32[3], 4); |
| | | #if defined(__LINUX_2_6__) |
| | | /*modified by qinjunjie,warning:should not remove next line*/ |
| | | skb->pkt_type = PACKET_MULTICAST; |
| | | #endif |
| | | } |
| | | #endif /* CL_IPV6_PASS */ |
| | | |
| | | |
| | | static __inline__ int __nat25_network_hash(unsigned char *networkAddr) |
| | | { |
| | | if (networkAddr[0] == NAT25_IPV4) { |
| | | unsigned long x; |
| | | |
| | | x = networkAddr[7] ^ networkAddr[8] ^ networkAddr[9] ^ networkAddr[10]; |
| | | |
| | | return x & (NAT25_HASH_SIZE - 1); |
| | | } else if (networkAddr[0] == NAT25_IPX) { |
| | | unsigned long x; |
| | | |
| | | x = networkAddr[1] ^ networkAddr[2] ^ networkAddr[3] ^ networkAddr[4] ^ networkAddr[5] ^ |
| | | networkAddr[6] ^ networkAddr[7] ^ networkAddr[8] ^ networkAddr[9] ^ networkAddr[10]; |
| | | |
| | | return x & (NAT25_HASH_SIZE - 1); |
| | | } else if (networkAddr[0] == NAT25_APPLE) { |
| | | unsigned long x; |
| | | |
| | | x = networkAddr[1] ^ networkAddr[2] ^ networkAddr[3]; |
| | | |
| | | return x & (NAT25_HASH_SIZE - 1); |
| | | } else if (networkAddr[0] == NAT25_PPPOE) { |
| | | unsigned long x; |
| | | |
| | | x = networkAddr[0] ^ networkAddr[1] ^ networkAddr[2] ^ networkAddr[3] ^ networkAddr[4] ^ networkAddr[5] ^ networkAddr[6] ^ networkAddr[7] ^ networkAddr[8]; |
| | | |
| | | return x & (NAT25_HASH_SIZE - 1); |
| | | } |
| | | #ifdef CL_IPV6_PASS |
| | | else if (networkAddr[0] == NAT25_IPV6) { |
| | | unsigned long x; |
| | | |
| | | x = networkAddr[1] ^ networkAddr[2] ^ networkAddr[3] ^ networkAddr[4] ^ networkAddr[5] ^ |
| | | networkAddr[6] ^ networkAddr[7] ^ networkAddr[8] ^ networkAddr[9] ^ networkAddr[10] ^ |
| | | networkAddr[11] ^ networkAddr[12] ^ networkAddr[13] ^ networkAddr[14] ^ networkAddr[15] ^ |
| | | networkAddr[16]; |
| | | |
| | | return x & (NAT25_HASH_SIZE - 1); |
| | | } |
| | | #endif |
| | | else { |
| | | unsigned long x = 0; |
| | | int i; |
| | | |
| | | for (i = 0; i < MAX_NETWORK_ADDR_LEN; i++) |
| | | x ^= networkAddr[i]; |
| | | |
| | | return x & (NAT25_HASH_SIZE - 1); |
| | | } |
| | | } |
| | | |
| | | |
| | | static __inline__ void __network_hash_link(_adapter *priv, |
| | | struct nat25_network_db_entry *ent, int hash) |
| | | { |
| | | /* Caller must _enter_critical_bh already! */ |
| | | /* _irqL irqL; */ |
| | | /* _enter_critical_bh(&priv->br_ext_lock, &irqL); */ |
| | | |
| | | ent->next_hash = priv->nethash[hash]; |
| | | if (ent->next_hash != NULL) |
| | | ent->next_hash->pprev_hash = &ent->next_hash; |
| | | priv->nethash[hash] = ent; |
| | | ent->pprev_hash = &priv->nethash[hash]; |
| | | |
| | | /* _exit_critical_bh(&priv->br_ext_lock, &irqL); */ |
| | | } |
| | | |
| | | |
| | | static __inline__ void __network_hash_unlink(struct nat25_network_db_entry *ent) |
| | | { |
| | | /* Caller must _enter_critical_bh already! */ |
| | | /* _irqL irqL; */ |
| | | /* _enter_critical_bh(&priv->br_ext_lock, &irqL); */ |
| | | |
| | | *(ent->pprev_hash) = ent->next_hash; |
| | | if (ent->next_hash != NULL) |
| | | ent->next_hash->pprev_hash = ent->pprev_hash; |
| | | ent->next_hash = NULL; |
| | | ent->pprev_hash = NULL; |
| | | |
| | | /* _exit_critical_bh(&priv->br_ext_lock, &irqL); */ |
| | | } |
| | | |
| | | |
| | | static int __nat25_db_network_lookup_and_replace(_adapter *priv, |
| | | struct sk_buff *skb, unsigned char *networkAddr) |
| | | { |
| | | struct nat25_network_db_entry *db; |
| | | _irqL irqL; |
| | | _enter_critical_bh(&priv->br_ext_lock, &irqL); |
| | | |
| | | db = priv->nethash[__nat25_network_hash(networkAddr)]; |
| | | while (db != NULL) { |
| | | if (!memcmp(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN)) { |
| | | if (!__nat25_has_expired(priv, db)) { |
| | | /* replace the destination mac address */ |
| | | memcpy(skb->data, db->macAddr, ETH_ALEN); |
| | | atomic_inc(&db->use_count); |
| | | |
| | | #ifdef CL_IPV6_PASS |
| | | RTW_INFO("NAT25: Lookup M:%02x%02x%02x%02x%02x%02x N:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" |
| | | "%02x%02x%02x%02x%02x%02x\n", |
| | | db->macAddr[0], |
| | | db->macAddr[1], |
| | | db->macAddr[2], |
| | | db->macAddr[3], |
| | | db->macAddr[4], |
| | | db->macAddr[5], |
| | | db->networkAddr[0], |
| | | db->networkAddr[1], |
| | | db->networkAddr[2], |
| | | db->networkAddr[3], |
| | | db->networkAddr[4], |
| | | db->networkAddr[5], |
| | | db->networkAddr[6], |
| | | db->networkAddr[7], |
| | | db->networkAddr[8], |
| | | db->networkAddr[9], |
| | | db->networkAddr[10], |
| | | db->networkAddr[11], |
| | | db->networkAddr[12], |
| | | db->networkAddr[13], |
| | | db->networkAddr[14], |
| | | db->networkAddr[15], |
| | | db->networkAddr[16]); |
| | | #else |
| | | RTW_INFO("NAT25: Lookup M:%02x%02x%02x%02x%02x%02x N:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", |
| | | db->macAddr[0], |
| | | db->macAddr[1], |
| | | db->macAddr[2], |
| | | db->macAddr[3], |
| | | db->macAddr[4], |
| | | db->macAddr[5], |
| | | db->networkAddr[0], |
| | | db->networkAddr[1], |
| | | db->networkAddr[2], |
| | | db->networkAddr[3], |
| | | db->networkAddr[4], |
| | | db->networkAddr[5], |
| | | db->networkAddr[6], |
| | | db->networkAddr[7], |
| | | db->networkAddr[8], |
| | | db->networkAddr[9], |
| | | db->networkAddr[10]); |
| | | #endif |
| | | } |
| | | _exit_critical_bh(&priv->br_ext_lock, &irqL); |
| | | return 1; |
| | | } |
| | | |
| | | db = db->next_hash; |
| | | } |
| | | |
| | | _exit_critical_bh(&priv->br_ext_lock, &irqL); |
| | | return 0; |
| | | } |
| | | |
| | | |
| | | static void __nat25_db_network_insert(_adapter *priv, |
| | | unsigned char *macAddr, unsigned char *networkAddr) |
| | | { |
| | | struct nat25_network_db_entry *db; |
| | | int hash; |
| | | _irqL irqL; |
| | | _enter_critical_bh(&priv->br_ext_lock, &irqL); |
| | | |
| | | hash = __nat25_network_hash(networkAddr); |
| | | db = priv->nethash[hash]; |
| | | while (db != NULL) { |
| | | if (!memcmp(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN)) { |
| | | memcpy(db->macAddr, macAddr, ETH_ALEN); |
| | | db->ageing_timer = jiffies; |
| | | _exit_critical_bh(&priv->br_ext_lock, &irqL); |
| | | return; |
| | | } |
| | | |
| | | db = db->next_hash; |
| | | } |
| | | |
| | | db = (struct nat25_network_db_entry *) rtw_malloc(sizeof(*db)); |
| | | if (db == NULL) { |
| | | _exit_critical_bh(&priv->br_ext_lock, &irqL); |
| | | return; |
| | | } |
| | | |
| | | memcpy(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN); |
| | | memcpy(db->macAddr, macAddr, ETH_ALEN); |
| | | atomic_set(&db->use_count, 1); |
| | | db->ageing_timer = jiffies; |
| | | |
| | | __network_hash_link(priv, db, hash); |
| | | |
| | | _exit_critical_bh(&priv->br_ext_lock, &irqL); |
| | | } |
| | | |
| | | |
| | | static void __nat25_db_print(_adapter *priv) |
| | | { |
| | | _irqL irqL; |
| | | _enter_critical_bh(&priv->br_ext_lock, &irqL); |
| | | |
| | | #ifdef BR_EXT_DEBUG |
| | | static int counter = 0; |
| | | int i, j; |
| | | struct nat25_network_db_entry *db; |
| | | |
| | | counter++; |
| | | if ((counter % 16) != 0) |
| | | return; |
| | | |
| | | for (i = 0, j = 0; i < NAT25_HASH_SIZE; i++) { |
| | | db = priv->nethash[i]; |
| | | |
| | | while (db != NULL) { |
| | | #ifdef CL_IPV6_PASS |
| | | panic_printk("NAT25: DB(%d) H(%02d) C(%d) M:%02x%02x%02x%02x%02x%02x N:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" |
| | | "%02x%02x%02x%02x%02x%02x\n", |
| | | j, |
| | | i, |
| | | atomic_read(&db->use_count), |
| | | db->macAddr[0], |
| | | db->macAddr[1], |
| | | db->macAddr[2], |
| | | db->macAddr[3], |
| | | db->macAddr[4], |
| | | db->macAddr[5], |
| | | db->networkAddr[0], |
| | | db->networkAddr[1], |
| | | db->networkAddr[2], |
| | | db->networkAddr[3], |
| | | db->networkAddr[4], |
| | | db->networkAddr[5], |
| | | db->networkAddr[6], |
| | | db->networkAddr[7], |
| | | db->networkAddr[8], |
| | | db->networkAddr[9], |
| | | db->networkAddr[10], |
| | | db->networkAddr[11], |
| | | db->networkAddr[12], |
| | | db->networkAddr[13], |
| | | db->networkAddr[14], |
| | | db->networkAddr[15], |
| | | db->networkAddr[16]); |
| | | #else |
| | | panic_printk("NAT25: DB(%d) H(%02d) C(%d) M:%02x%02x%02x%02x%02x%02x N:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", |
| | | j, |
| | | i, |
| | | atomic_read(&db->use_count), |
| | | db->macAddr[0], |
| | | db->macAddr[1], |
| | | db->macAddr[2], |
| | | db->macAddr[3], |
| | | db->macAddr[4], |
| | | db->macAddr[5], |
| | | db->networkAddr[0], |
| | | db->networkAddr[1], |
| | | db->networkAddr[2], |
| | | db->networkAddr[3], |
| | | db->networkAddr[4], |
| | | db->networkAddr[5], |
| | | db->networkAddr[6], |
| | | db->networkAddr[7], |
| | | db->networkAddr[8], |
| | | db->networkAddr[9], |
| | | db->networkAddr[10]); |
| | | #endif |
| | | j++; |
| | | |
| | | db = db->next_hash; |
| | | } |
| | | } |
| | | #endif |
| | | |
| | | _exit_critical_bh(&priv->br_ext_lock, &irqL); |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | /* |
| | | * NAT2.5 interface |
| | | */ |
| | | |
| | | void nat25_db_cleanup(_adapter *priv) |
| | | { |
| | | int i; |
| | | _irqL irqL; |
| | | _enter_critical_bh(&priv->br_ext_lock, &irqL); |
| | | |
| | | for (i = 0; i < NAT25_HASH_SIZE; i++) { |
| | | struct nat25_network_db_entry *f; |
| | | f = priv->nethash[i]; |
| | | while (f != NULL) { |
| | | struct nat25_network_db_entry *g; |
| | | |
| | | g = f->next_hash; |
| | | if (priv->scdb_entry == f) { |
| | | memset(priv->scdb_mac, 0, ETH_ALEN); |
| | | memset(priv->scdb_ip, 0, 4); |
| | | priv->scdb_entry = NULL; |
| | | } |
| | | __network_hash_unlink(f); |
| | | rtw_mfree((u8 *) f, sizeof(struct nat25_network_db_entry)); |
| | | |
| | | f = g; |
| | | } |
| | | } |
| | | |
| | | _exit_critical_bh(&priv->br_ext_lock, &irqL); |
| | | } |
| | | |
| | | |
| | | void nat25_db_expire(_adapter *priv) |
| | | { |
| | | int i; |
| | | _irqL irqL; |
| | | _enter_critical_bh(&priv->br_ext_lock, &irqL); |
| | | |
| | | /* if(!priv->ethBrExtInfo.nat25_disable) */ |
| | | { |
| | | for (i = 0; i < NAT25_HASH_SIZE; i++) { |
| | | struct nat25_network_db_entry *f; |
| | | f = priv->nethash[i]; |
| | | |
| | | while (f != NULL) { |
| | | struct nat25_network_db_entry *g; |
| | | g = f->next_hash; |
| | | |
| | | if (__nat25_has_expired(priv, f)) { |
| | | if (atomic_dec_and_test(&f->use_count)) { |
| | | #ifdef BR_EXT_DEBUG |
| | | #ifdef CL_IPV6_PASS |
| | | panic_printk("NAT25 Expire H(%02d) M:%02x%02x%02x%02x%02x%02x N:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" |
| | | "%02x%02x%02x%02x%02x%02x\n", |
| | | i, |
| | | f->macAddr[0], |
| | | f->macAddr[1], |
| | | f->macAddr[2], |
| | | f->macAddr[3], |
| | | f->macAddr[4], |
| | | f->macAddr[5], |
| | | f->networkAddr[0], |
| | | f->networkAddr[1], |
| | | f->networkAddr[2], |
| | | f->networkAddr[3], |
| | | f->networkAddr[4], |
| | | f->networkAddr[5], |
| | | f->networkAddr[6], |
| | | f->networkAddr[7], |
| | | f->networkAddr[8], |
| | | f->networkAddr[9], |
| | | f->networkAddr[10], |
| | | f->networkAddr[11], |
| | | f->networkAddr[12], |
| | | f->networkAddr[13], |
| | | f->networkAddr[14], |
| | | f->networkAddr[15], |
| | | f->networkAddr[16]); |
| | | #else |
| | | |
| | | panic_printk("NAT25 Expire H(%02d) M:%02x%02x%02x%02x%02x%02x N:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", |
| | | i, |
| | | f->macAddr[0], |
| | | f->macAddr[1], |
| | | f->macAddr[2], |
| | | f->macAddr[3], |
| | | f->macAddr[4], |
| | | f->macAddr[5], |
| | | f->networkAddr[0], |
| | | f->networkAddr[1], |
| | | f->networkAddr[2], |
| | | f->networkAddr[3], |
| | | f->networkAddr[4], |
| | | f->networkAddr[5], |
| | | f->networkAddr[6], |
| | | f->networkAddr[7], |
| | | f->networkAddr[8], |
| | | f->networkAddr[9], |
| | | f->networkAddr[10]); |
| | | #endif |
| | | #endif |
| | | if (priv->scdb_entry == f) { |
| | | memset(priv->scdb_mac, 0, ETH_ALEN); |
| | | memset(priv->scdb_ip, 0, 4); |
| | | priv->scdb_entry = NULL; |
| | | } |
| | | __network_hash_unlink(f); |
| | | rtw_mfree((u8 *) f, sizeof(struct nat25_network_db_entry)); |
| | | } |
| | | } |
| | | |
| | | f = g; |
| | | } |
| | | } |
| | | } |
| | | |
| | | _exit_critical_bh(&priv->br_ext_lock, &irqL); |
| | | } |
| | | |
| | | |
| | | #ifdef SUPPORT_TX_MCAST2UNI |
| | | static int checkIPMcAndReplace(_adapter *priv, struct sk_buff *skb, unsigned int *dst_ip) |
| | | { |
| | | struct stat_info *pstat; |
| | | struct list_head *phead, *plist; |
| | | int i; |
| | | |
| | | phead = &priv->asoc_list; |
| | | plist = phead->next; |
| | | |
| | | while (plist != phead) { |
| | | pstat = list_entry(plist, struct stat_info, asoc_list); |
| | | plist = plist->next; |
| | | |
| | | if (pstat->ipmc_num == 0) |
| | | continue; |
| | | |
| | | for (i = 0; i < MAX_IP_MC_ENTRY; i++) { |
| | | if (pstat->ipmc[i].used && !memcmp(&pstat->ipmc[i].mcmac[3], ((unsigned char *)dst_ip) + 1, 3)) { |
| | | memcpy(skb->data, pstat->ipmc[i].mcmac, ETH_ALEN); |
| | | return 1; |
| | | } |
| | | } |
| | | } |
| | | return 0; |
| | | } |
| | | #endif |
| | | |
| | | int nat25_db_handle(_adapter *priv, struct sk_buff *skb, int method) |
| | | { |
| | | unsigned short protocol; |
| | | unsigned char networkAddr[MAX_NETWORK_ADDR_LEN]; |
| | | |
| | | if (skb == NULL) |
| | | return -1; |
| | | |
| | | if ((method <= NAT25_MIN) || (method >= NAT25_MAX)) |
| | | return -1; |
| | | |
| | | protocol = *((unsigned short *)(skb->data + 2 * ETH_ALEN)); |
| | | |
| | | /*---------------------------------------------------*/ |
| | | /* Handle IP frame */ |
| | | /*---------------------------------------------------*/ |
| | | if (protocol == __constant_htons(ETH_P_IP)) { |
| | | struct iphdr *iph = (struct iphdr *)(skb->data + ETH_HLEN); |
| | | |
| | | if (((unsigned char *)(iph) + (iph->ihl << 2)) >= (skb->data + ETH_HLEN + skb->len)) { |
| | | DEBUG_WARN("NAT25: malformed IP packet !\n"); |
| | | return -1; |
| | | } |
| | | |
| | | switch (method) { |
| | | case NAT25_CHECK: |
| | | return -1; |
| | | |
| | | case NAT25_INSERT: { |
| | | /* some muticast with source IP is all zero, maybe other case is illegal */ |
| | | /* in class A, B, C, host address is all zero or all one is illegal */ |
| | | if (iph->saddr == 0) |
| | | return 0; |
| | | RTW_INFO("NAT25: Insert IP, SA=%08x, DA=%08x\n", iph->saddr, iph->daddr); |
| | | __nat25_generate_ipv4_network_addr(networkAddr, &iph->saddr); |
| | | /* record source IP address and , source mac address into db */ |
| | | __nat25_db_network_insert(priv, skb->data + ETH_ALEN, networkAddr); |
| | | |
| | | __nat25_db_print(priv); |
| | | } |
| | | return 0; |
| | | |
| | | case NAT25_LOOKUP: { |
| | | RTW_INFO("NAT25: Lookup IP, SA=%08x, DA=%08x\n", iph->saddr, iph->daddr); |
| | | #ifdef SUPPORT_TX_MCAST2UNI |
| | | if (priv->pshare->rf_ft_var.mc2u_disable || |
| | | ((((OPMODE & (WIFI_STATION_STATE | WIFI_ASOC_STATE)) |
| | | == (WIFI_STATION_STATE | WIFI_ASOC_STATE)) && |
| | | !checkIPMcAndReplace(priv, skb, &iph->daddr)) || |
| | | (OPMODE & WIFI_ADHOC_STATE))) |
| | | #endif |
| | | { |
| | | __nat25_generate_ipv4_network_addr(networkAddr, &iph->daddr); |
| | | |
| | | if (!__nat25_db_network_lookup_and_replace(priv, skb, networkAddr)) { |
| | | if (*((unsigned char *)&iph->daddr + 3) == 0xff) { |
| | | /* L2 is unicast but L3 is broadcast, make L2 bacome broadcast */ |
| | | RTW_INFO("NAT25: Set DA as boardcast\n"); |
| | | memset(skb->data, 0xff, ETH_ALEN); |
| | | } else { |
| | | /* forward unknow IP packet to upper TCP/IP */ |
| | | RTW_INFO("NAT25: Replace DA with BR's MAC\n"); |
| | | if ((*(u32 *)priv->br_mac) == 0 && (*(u16 *)(priv->br_mac + 4)) == 0) { |
| | | void netdev_br_init(struct net_device *netdev); |
| | | printk("Re-init netdev_br_init() due to br_mac==0!\n"); |
| | | netdev_br_init(priv->pnetdev); |
| | | } |
| | | memcpy(skb->data, priv->br_mac, ETH_ALEN); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | return 0; |
| | | |
| | | default: |
| | | return -1; |
| | | } |
| | | } |
| | | |
| | | /*---------------------------------------------------*/ |
| | | /* Handle ARP frame */ |
| | | /*---------------------------------------------------*/ |
| | | else if (protocol == __constant_htons(ETH_P_ARP)) { |
| | | struct arphdr *arp = (struct arphdr *)(skb->data + ETH_HLEN); |
| | | unsigned char *arp_ptr = (unsigned char *)(arp + 1); |
| | | unsigned int *sender, *target; |
| | | |
| | | if (arp->ar_pro != __constant_htons(ETH_P_IP)) { |
| | | DEBUG_WARN("NAT25: arp protocol unknown (%4x)!\n", htons(arp->ar_pro)); |
| | | return -1; |
| | | } |
| | | |
| | | switch (method) { |
| | | case NAT25_CHECK: |
| | | return 0; /* skb_copy for all ARP frame */ |
| | | |
| | | case NAT25_INSERT: { |
| | | RTW_INFO("NAT25: Insert ARP, MAC=%02x%02x%02x%02x%02x%02x\n", arp_ptr[0], |
| | | arp_ptr[1], arp_ptr[2], arp_ptr[3], arp_ptr[4], arp_ptr[5]); |
| | | |
| | | /* change to ARP sender mac address to wlan STA address */ |
| | | memcpy(arp_ptr, GET_MY_HWADDR(priv), ETH_ALEN); |
| | | |
| | | arp_ptr += arp->ar_hln; |
| | | sender = (unsigned int *)arp_ptr; |
| | | |
| | | __nat25_generate_ipv4_network_addr(networkAddr, sender); |
| | | |
| | | __nat25_db_network_insert(priv, skb->data + ETH_ALEN, networkAddr); |
| | | |
| | | __nat25_db_print(priv); |
| | | } |
| | | return 0; |
| | | |
| | | case NAT25_LOOKUP: { |
| | | RTW_INFO("NAT25: Lookup ARP\n"); |
| | | |
| | | arp_ptr += arp->ar_hln; |
| | | sender = (unsigned int *)arp_ptr; |
| | | arp_ptr += (arp->ar_hln + arp->ar_pln); |
| | | target = (unsigned int *)arp_ptr; |
| | | |
| | | __nat25_generate_ipv4_network_addr(networkAddr, target); |
| | | |
| | | __nat25_db_network_lookup_and_replace(priv, skb, networkAddr); |
| | | |
| | | /* change to ARP target mac address to Lookup result */ |
| | | arp_ptr = (unsigned char *)(arp + 1); |
| | | arp_ptr += (arp->ar_hln + arp->ar_pln); |
| | | memcpy(arp_ptr, skb->data, ETH_ALEN); |
| | | } |
| | | return 0; |
| | | |
| | | default: |
| | | return -1; |
| | | } |
| | | } |
| | | |
| | | /*---------------------------------------------------*/ |
| | | /* Handle IPX and Apple Talk frame */ |
| | | /*---------------------------------------------------*/ |
| | | else if ((protocol == __constant_htons(ETH_P_IPX)) || |
| | | (protocol == __constant_htons(ETH_P_ATALK)) || |
| | | (protocol == __constant_htons(ETH_P_AARP))) { |
| | | unsigned char ipx_header[2] = {0xFF, 0xFF}; |
| | | struct ipxhdr *ipx = NULL; |
| | | struct elapaarp *ea = NULL; |
| | | struct ddpehdr *ddp = NULL; |
| | | unsigned char *framePtr = skb->data + ETH_HLEN; |
| | | |
| | | if (protocol == __constant_htons(ETH_P_IPX)) { |
| | | RTW_INFO("NAT25: Protocol=IPX (Ethernet II)\n"); |
| | | ipx = (struct ipxhdr *)framePtr; |
| | | } else { /* if(protocol <= __constant_htons(ETH_FRAME_LEN)) */ |
| | | if (!memcmp(ipx_header, framePtr, 2)) { |
| | | RTW_INFO("NAT25: Protocol=IPX (Ethernet 802.3)\n"); |
| | | ipx = (struct ipxhdr *)framePtr; |
| | | } else { |
| | | unsigned char ipx_8022_type = 0xE0; |
| | | unsigned char snap_8022_type = 0xAA; |
| | | |
| | | if (*framePtr == snap_8022_type) { |
| | | unsigned char ipx_snap_id[5] = {0x0, 0x0, 0x0, 0x81, 0x37}; /* IPX SNAP ID */ |
| | | unsigned char aarp_snap_id[5] = {0x00, 0x00, 0x00, 0x80, 0xF3}; /* Apple Talk AARP SNAP ID */ |
| | | unsigned char ddp_snap_id[5] = {0x08, 0x00, 0x07, 0x80, 0x9B}; /* Apple Talk DDP SNAP ID */ |
| | | |
| | | framePtr += 3; /* eliminate the 802.2 header */ |
| | | |
| | | if (!memcmp(ipx_snap_id, framePtr, 5)) { |
| | | framePtr += 5; /* eliminate the SNAP header */ |
| | | |
| | | RTW_INFO("NAT25: Protocol=IPX (Ethernet SNAP)\n"); |
| | | ipx = (struct ipxhdr *)framePtr; |
| | | } else if (!memcmp(aarp_snap_id, framePtr, 5)) { |
| | | framePtr += 5; /* eliminate the SNAP header */ |
| | | |
| | | ea = (struct elapaarp *)framePtr; |
| | | } else if (!memcmp(ddp_snap_id, framePtr, 5)) { |
| | | framePtr += 5; /* eliminate the SNAP header */ |
| | | |
| | | ddp = (struct ddpehdr *)framePtr; |
| | | } else { |
| | | DEBUG_WARN("NAT25: Protocol=Ethernet SNAP %02x%02x%02x%02x%02x\n", framePtr[0], |
| | | framePtr[1], framePtr[2], framePtr[3], framePtr[4]); |
| | | return -1; |
| | | } |
| | | } else if (*framePtr == ipx_8022_type) { |
| | | framePtr += 3; /* eliminate the 802.2 header */ |
| | | |
| | | if (!memcmp(ipx_header, framePtr, 2)) { |
| | | RTW_INFO("NAT25: Protocol=IPX (Ethernet 802.2)\n"); |
| | | ipx = (struct ipxhdr *)framePtr; |
| | | } else |
| | | return -1; |
| | | } |
| | | } |
| | | } |
| | | |
| | | /* IPX */ |
| | | if (ipx != NULL) { |
| | | switch (method) { |
| | | case NAT25_CHECK: |
| | | if (!memcmp(skb->data + ETH_ALEN, ipx->ipx_source.node, ETH_ALEN)) { |
| | | RTW_INFO("NAT25: Check IPX skb_copy\n"); |
| | | return 0; |
| | | } |
| | | return -1; |
| | | |
| | | case NAT25_INSERT: { |
| | | RTW_INFO("NAT25: Insert IPX, Dest=%08x,%02x%02x%02x%02x%02x%02x,%04x Source=%08x,%02x%02x%02x%02x%02x%02x,%04x\n", |
| | | ipx->ipx_dest.net, |
| | | ipx->ipx_dest.node[0], |
| | | ipx->ipx_dest.node[1], |
| | | ipx->ipx_dest.node[2], |
| | | ipx->ipx_dest.node[3], |
| | | ipx->ipx_dest.node[4], |
| | | ipx->ipx_dest.node[5], |
| | | ipx->ipx_dest.sock, |
| | | ipx->ipx_source.net, |
| | | ipx->ipx_source.node[0], |
| | | ipx->ipx_source.node[1], |
| | | ipx->ipx_source.node[2], |
| | | ipx->ipx_source.node[3], |
| | | ipx->ipx_source.node[4], |
| | | ipx->ipx_source.node[5], |
| | | ipx->ipx_source.sock); |
| | | |
| | | if (!memcmp(skb->data + ETH_ALEN, ipx->ipx_source.node, ETH_ALEN)) { |
| | | RTW_INFO("NAT25: Use IPX Net, and Socket as network addr\n"); |
| | | |
| | | __nat25_generate_ipx_network_addr_with_socket(networkAddr, &ipx->ipx_source.net, &ipx->ipx_source.sock); |
| | | |
| | | /* change IPX source node addr to wlan STA address */ |
| | | memcpy(ipx->ipx_source.node, GET_MY_HWADDR(priv), ETH_ALEN); |
| | | } else |
| | | __nat25_generate_ipx_network_addr_with_node(networkAddr, &ipx->ipx_source.net, ipx->ipx_source.node); |
| | | |
| | | __nat25_db_network_insert(priv, skb->data + ETH_ALEN, networkAddr); |
| | | |
| | | __nat25_db_print(priv); |
| | | } |
| | | return 0; |
| | | |
| | | case NAT25_LOOKUP: { |
| | | if (!memcmp(GET_MY_HWADDR(priv), ipx->ipx_dest.node, ETH_ALEN)) { |
| | | RTW_INFO("NAT25: Lookup IPX, Modify Destination IPX Node addr\n"); |
| | | |
| | | __nat25_generate_ipx_network_addr_with_socket(networkAddr, &ipx->ipx_dest.net, &ipx->ipx_dest.sock); |
| | | |
| | | __nat25_db_network_lookup_and_replace(priv, skb, networkAddr); |
| | | |
| | | /* replace IPX destination node addr with Lookup destination MAC addr */ |
| | | memcpy(ipx->ipx_dest.node, skb->data, ETH_ALEN); |
| | | } else { |
| | | __nat25_generate_ipx_network_addr_with_node(networkAddr, &ipx->ipx_dest.net, ipx->ipx_dest.node); |
| | | |
| | | __nat25_db_network_lookup_and_replace(priv, skb, networkAddr); |
| | | } |
| | | } |
| | | return 0; |
| | | |
| | | default: |
| | | return -1; |
| | | } |
| | | } |
| | | |
| | | /* AARP */ |
| | | else if (ea != NULL) { |
| | | /* Sanity check fields. */ |
| | | if (ea->hw_len != ETH_ALEN || ea->pa_len != AARP_PA_ALEN) { |
| | | DEBUG_WARN("NAT25: Appletalk AARP Sanity check fail!\n"); |
| | | return -1; |
| | | } |
| | | |
| | | switch (method) { |
| | | case NAT25_CHECK: |
| | | return 0; |
| | | |
| | | case NAT25_INSERT: { |
| | | /* change to AARP source mac address to wlan STA address */ |
| | | memcpy(ea->hw_src, GET_MY_HWADDR(priv), ETH_ALEN); |
| | | |
| | | RTW_INFO("NAT25: Insert AARP, Source=%d,%d Destination=%d,%d\n", |
| | | ea->pa_src_net, |
| | | ea->pa_src_node, |
| | | ea->pa_dst_net, |
| | | ea->pa_dst_node); |
| | | |
| | | __nat25_generate_apple_network_addr(networkAddr, &ea->pa_src_net, &ea->pa_src_node); |
| | | |
| | | __nat25_db_network_insert(priv, skb->data + ETH_ALEN, networkAddr); |
| | | |
| | | __nat25_db_print(priv); |
| | | } |
| | | return 0; |
| | | |
| | | case NAT25_LOOKUP: { |
| | | RTW_INFO("NAT25: Lookup AARP, Source=%d,%d Destination=%d,%d\n", |
| | | ea->pa_src_net, |
| | | ea->pa_src_node, |
| | | ea->pa_dst_net, |
| | | ea->pa_dst_node); |
| | | |
| | | __nat25_generate_apple_network_addr(networkAddr, &ea->pa_dst_net, &ea->pa_dst_node); |
| | | |
| | | __nat25_db_network_lookup_and_replace(priv, skb, networkAddr); |
| | | |
| | | /* change to AARP destination mac address to Lookup result */ |
| | | memcpy(ea->hw_dst, skb->data, ETH_ALEN); |
| | | } |
| | | return 0; |
| | | |
| | | default: |
| | | return -1; |
| | | } |
| | | } |
| | | |
| | | /* DDP */ |
| | | else if (ddp != NULL) { |
| | | switch (method) { |
| | | case NAT25_CHECK: |
| | | return -1; |
| | | |
| | | case NAT25_INSERT: { |
| | | RTW_INFO("NAT25: Insert DDP, Source=%d,%d Destination=%d,%d\n", |
| | | ddp->deh_snet, |
| | | ddp->deh_snode, |
| | | ddp->deh_dnet, |
| | | ddp->deh_dnode); |
| | | |
| | | __nat25_generate_apple_network_addr(networkAddr, &ddp->deh_snet, &ddp->deh_snode); |
| | | |
| | | __nat25_db_network_insert(priv, skb->data + ETH_ALEN, networkAddr); |
| | | |
| | | __nat25_db_print(priv); |
| | | } |
| | | return 0; |
| | | |
| | | case NAT25_LOOKUP: { |
| | | RTW_INFO("NAT25: Lookup DDP, Source=%d,%d Destination=%d,%d\n", |
| | | ddp->deh_snet, |
| | | ddp->deh_snode, |
| | | ddp->deh_dnet, |
| | | ddp->deh_dnode); |
| | | |
| | | __nat25_generate_apple_network_addr(networkAddr, &ddp->deh_dnet, &ddp->deh_dnode); |
| | | |
| | | __nat25_db_network_lookup_and_replace(priv, skb, networkAddr); |
| | | } |
| | | return 0; |
| | | |
| | | default: |
| | | return -1; |
| | | } |
| | | } |
| | | |
| | | return -1; |
| | | } |
| | | |
| | | /*---------------------------------------------------*/ |
| | | /* Handle PPPoE frame */ |
| | | /*---------------------------------------------------*/ |
| | | else if ((protocol == __constant_htons(ETH_P_PPP_DISC)) || |
| | | (protocol == __constant_htons(ETH_P_PPP_SES))) { |
| | | struct pppoe_hdr *ph = (struct pppoe_hdr *)(skb->data + ETH_HLEN); |
| | | unsigned short *pMagic; |
| | | |
| | | switch (method) { |
| | | case NAT25_CHECK: |
| | | if (ph->sid == 0) |
| | | return 0; |
| | | return 1; |
| | | |
| | | case NAT25_INSERT: |
| | | if (ph->sid == 0) { /* Discovery phase according to tag */ |
| | | if (ph->code == PADI_CODE || ph->code == PADR_CODE) { |
| | | if (priv->ethBrExtInfo.addPPPoETag) { |
| | | struct pppoe_tag *tag, *pOldTag; |
| | | unsigned char tag_buf[40]; |
| | | int old_tag_len = 0; |
| | | |
| | | tag = (struct pppoe_tag *)tag_buf; |
| | | pOldTag = (struct pppoe_tag *)__nat25_find_pppoe_tag(ph, ntohs(PTT_RELAY_SID)); |
| | | if (pOldTag) { /* if SID existed, copy old value and delete it */ |
| | | old_tag_len = ntohs(pOldTag->tag_len); |
| | | if (old_tag_len + TAG_HDR_LEN + MAGIC_CODE_LEN + RTL_RELAY_TAG_LEN > sizeof(tag_buf)) { |
| | | DEBUG_ERR("SID tag length too long!\n"); |
| | | return -1; |
| | | } |
| | | |
| | | memcpy(tag->tag_data + MAGIC_CODE_LEN + RTL_RELAY_TAG_LEN, |
| | | pOldTag->tag_data, old_tag_len); |
| | | |
| | | if (skb_pull_and_merge(skb, (unsigned char *)pOldTag, TAG_HDR_LEN + old_tag_len) < 0) { |
| | | DEBUG_ERR("call skb_pull_and_merge() failed in PADI/R packet!\n"); |
| | | return -1; |
| | | } |
| | | ph->length = htons(ntohs(ph->length) - TAG_HDR_LEN - old_tag_len); |
| | | } |
| | | |
| | | tag->tag_type = PTT_RELAY_SID; |
| | | tag->tag_len = htons(MAGIC_CODE_LEN + RTL_RELAY_TAG_LEN + old_tag_len); |
| | | |
| | | /* insert the magic_code+client mac in relay tag */ |
| | | pMagic = (unsigned short *)tag->tag_data; |
| | | *pMagic = htons(MAGIC_CODE); |
| | | memcpy(tag->tag_data + MAGIC_CODE_LEN, skb->data + ETH_ALEN, ETH_ALEN); |
| | | |
| | | /* Add relay tag */ |
| | | if (__nat25_add_pppoe_tag(skb, tag) < 0) |
| | | return -1; |
| | | |
| | | RTW_INFO("NAT25: Insert PPPoE, forward %s packet\n", |
| | | (ph->code == PADI_CODE ? "PADI" : "PADR")); |
| | | } else { /* not add relay tag */ |
| | | if (priv->pppoe_connection_in_progress && |
| | | memcmp(skb->data + ETH_ALEN, priv->pppoe_addr, ETH_ALEN)) { |
| | | DEBUG_ERR("Discard PPPoE packet due to another PPPoE connection is in progress!\n"); |
| | | return -2; |
| | | } |
| | | |
| | | if (priv->pppoe_connection_in_progress == 0) |
| | | memcpy(priv->pppoe_addr, skb->data + ETH_ALEN, ETH_ALEN); |
| | | |
| | | priv->pppoe_connection_in_progress = WAIT_TIME_PPPOE; |
| | | } |
| | | } else |
| | | return -1; |
| | | } else { /* session phase */ |
| | | RTW_INFO("NAT25: Insert PPPoE, insert session packet to %s\n", skb->dev->name); |
| | | |
| | | __nat25_generate_pppoe_network_addr(networkAddr, skb->data, &(ph->sid)); |
| | | |
| | | __nat25_db_network_insert(priv, skb->data + ETH_ALEN, networkAddr); |
| | | |
| | | __nat25_db_print(priv); |
| | | |
| | | if (!priv->ethBrExtInfo.addPPPoETag && |
| | | priv->pppoe_connection_in_progress && |
| | | !memcmp(skb->data + ETH_ALEN, priv->pppoe_addr, ETH_ALEN)) |
| | | priv->pppoe_connection_in_progress = 0; |
| | | } |
| | | return 0; |
| | | |
| | | case NAT25_LOOKUP: |
| | | if (ph->code == PADO_CODE || ph->code == PADS_CODE) { |
| | | if (priv->ethBrExtInfo.addPPPoETag) { |
| | | struct pppoe_tag *tag; |
| | | unsigned char *ptr; |
| | | unsigned short tagType, tagLen; |
| | | int offset = 0; |
| | | |
| | | ptr = __nat25_find_pppoe_tag(ph, ntohs(PTT_RELAY_SID)); |
| | | if (ptr == 0) { |
| | | DEBUG_ERR("Fail to find PTT_RELAY_SID in FADO!\n"); |
| | | return -1; |
| | | } |
| | | |
| | | tag = (struct pppoe_tag *)ptr; |
| | | tagType = (unsigned short)((ptr[0] << 8) + ptr[1]); |
| | | tagLen = (unsigned short)((ptr[2] << 8) + ptr[3]); |
| | | |
| | | if ((tagType != ntohs(PTT_RELAY_SID)) || (tagLen < (MAGIC_CODE_LEN + RTL_RELAY_TAG_LEN))) { |
| | | DEBUG_ERR("Invalid PTT_RELAY_SID tag length [%d]!\n", tagLen); |
| | | return -1; |
| | | } |
| | | |
| | | pMagic = (unsigned short *)tag->tag_data; |
| | | if (ntohs(*pMagic) != MAGIC_CODE) { |
| | | DEBUG_ERR("Can't find MAGIC_CODE in %s packet!\n", |
| | | (ph->code == PADO_CODE ? "PADO" : "PADS")); |
| | | return -1; |
| | | } |
| | | |
| | | memcpy(skb->data, tag->tag_data + MAGIC_CODE_LEN, ETH_ALEN); |
| | | |
| | | if (tagLen > MAGIC_CODE_LEN + RTL_RELAY_TAG_LEN) |
| | | offset = TAG_HDR_LEN; |
| | | |
| | | if (skb_pull_and_merge(skb, ptr + offset, TAG_HDR_LEN + MAGIC_CODE_LEN + RTL_RELAY_TAG_LEN - offset) < 0) { |
| | | DEBUG_ERR("call skb_pull_and_merge() failed in PADO packet!\n"); |
| | | return -1; |
| | | } |
| | | ph->length = htons(ntohs(ph->length) - (TAG_HDR_LEN + MAGIC_CODE_LEN + RTL_RELAY_TAG_LEN - offset)); |
| | | if (offset > 0) |
| | | tag->tag_len = htons(tagLen - MAGIC_CODE_LEN - RTL_RELAY_TAG_LEN); |
| | | |
| | | RTW_INFO("NAT25: Lookup PPPoE, forward %s Packet from %s\n", |
| | | (ph->code == PADO_CODE ? "PADO" : "PADS"), skb->dev->name); |
| | | } else { /* not add relay tag */ |
| | | if (!priv->pppoe_connection_in_progress) { |
| | | DEBUG_ERR("Discard PPPoE packet due to no connection in progresss!\n"); |
| | | return -1; |
| | | } |
| | | memcpy(skb->data, priv->pppoe_addr, ETH_ALEN); |
| | | priv->pppoe_connection_in_progress = WAIT_TIME_PPPOE; |
| | | } |
| | | } else { |
| | | if (ph->sid != 0) { |
| | | RTW_INFO("NAT25: Lookup PPPoE, lookup session packet from %s\n", skb->dev->name); |
| | | __nat25_generate_pppoe_network_addr(networkAddr, skb->data + ETH_ALEN, &(ph->sid)); |
| | | |
| | | __nat25_db_network_lookup_and_replace(priv, skb, networkAddr); |
| | | |
| | | __nat25_db_print(priv); |
| | | } else |
| | | return -1; |
| | | |
| | | } |
| | | return 0; |
| | | |
| | | default: |
| | | return -1; |
| | | } |
| | | } |
| | | |
| | | /*---------------------------------------------------*/ |
| | | /* Handle EAP frame */ |
| | | /*---------------------------------------------------*/ |
| | | else if (protocol == __constant_htons(0x888e)) { |
| | | switch (method) { |
| | | case NAT25_CHECK: |
| | | return -1; |
| | | |
| | | case NAT25_INSERT: |
| | | return 0; |
| | | |
| | | case NAT25_LOOKUP: |
| | | return 0; |
| | | |
| | | default: |
| | | return -1; |
| | | } |
| | | } |
| | | |
| | | /*---------------------------------------------------*/ |
| | | /* Handle C-Media proprietary frame */ |
| | | /*---------------------------------------------------*/ |
| | | else if ((protocol == __constant_htons(0xe2ae)) || |
| | | (protocol == __constant_htons(0xe2af))) { |
| | | switch (method) { |
| | | case NAT25_CHECK: |
| | | return -1; |
| | | |
| | | case NAT25_INSERT: |
| | | return 0; |
| | | |
| | | case NAT25_LOOKUP: |
| | | return 0; |
| | | |
| | | default: |
| | | return -1; |
| | | } |
| | | } |
| | | |
| | | /*---------------------------------------------------*/ |
| | | /* Handle IPV6 frame */ |
| | | /*---------------------------------------------------*/ |
| | | #ifdef CL_IPV6_PASS |
| | | else if (protocol == __constant_htons(ETH_P_IPV6)) { |
| | | struct ipv6hdr *iph = (struct ipv6hdr *)(skb->data + ETH_HLEN); |
| | | |
| | | if (sizeof(*iph) >= (skb->len - ETH_HLEN)) { |
| | | DEBUG_WARN("NAT25: malformed IPv6 packet !\n"); |
| | | return -1; |
| | | } |
| | | |
| | | switch (method) { |
| | | case NAT25_CHECK: |
| | | if (skb->data[0] & 1) |
| | | return 0; |
| | | return -1; |
| | | |
| | | case NAT25_INSERT: { |
| | | RTW_INFO("NAT25: Insert IP, SA=%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x," |
| | | " DA=%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x\n", |
| | | iph->saddr.s6_addr16[0], iph->saddr.s6_addr16[1], iph->saddr.s6_addr16[2], iph->saddr.s6_addr16[3], |
| | | iph->saddr.s6_addr16[4], iph->saddr.s6_addr16[5], iph->saddr.s6_addr16[6], iph->saddr.s6_addr16[7], |
| | | iph->daddr.s6_addr16[0], iph->daddr.s6_addr16[1], iph->daddr.s6_addr16[2], iph->daddr.s6_addr16[3], |
| | | iph->daddr.s6_addr16[4], iph->daddr.s6_addr16[5], iph->daddr.s6_addr16[6], iph->daddr.s6_addr16[7]); |
| | | |
| | | if (memcmp(&iph->saddr, "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0", 16)) { |
| | | __nat25_generate_ipv6_network_addr(networkAddr, (unsigned int *)&iph->saddr); |
| | | __nat25_db_network_insert(priv, skb->data + ETH_ALEN, networkAddr); |
| | | __nat25_db_print(priv); |
| | | |
| | | if (iph->nexthdr == IPPROTO_ICMPV6 && |
| | | skb->len > (ETH_HLEN + sizeof(*iph) + 4)) { |
| | | if (update_nd_link_layer_addr(skb->data + ETH_HLEN + sizeof(*iph), |
| | | skb->len - ETH_HLEN - sizeof(*iph), GET_MY_HWADDR(priv))) { |
| | | struct icmp6hdr *hdr = (struct icmp6hdr *)(skb->data + ETH_HLEN + sizeof(*iph)); |
| | | hdr->icmp6_cksum = 0; |
| | | hdr->icmp6_cksum = csum_ipv6_magic(&iph->saddr, &iph->daddr, |
| | | iph->payload_len, |
| | | IPPROTO_ICMPV6, |
| | | csum_partial((__u8 *)hdr, iph->payload_len, 0)); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | return 0; |
| | | |
| | | case NAT25_LOOKUP: |
| | | RTW_INFO("NAT25: Lookup IP, SA=%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x," |
| | | " DA=%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x\n", |
| | | iph->saddr.s6_addr16[0], iph->saddr.s6_addr16[1], iph->saddr.s6_addr16[2], iph->saddr.s6_addr16[3], |
| | | iph->saddr.s6_addr16[4], iph->saddr.s6_addr16[5], iph->saddr.s6_addr16[6], iph->saddr.s6_addr16[7], |
| | | iph->daddr.s6_addr16[0], iph->daddr.s6_addr16[1], iph->daddr.s6_addr16[2], iph->daddr.s6_addr16[3], |
| | | iph->daddr.s6_addr16[4], iph->daddr.s6_addr16[5], iph->daddr.s6_addr16[6], iph->daddr.s6_addr16[7]); |
| | | |
| | | |
| | | __nat25_generate_ipv6_network_addr(networkAddr, (unsigned int *)&iph->daddr); |
| | | if (!__nat25_db_network_lookup_and_replace(priv, skb, networkAddr)) { |
| | | #ifdef SUPPORT_RX_UNI2MCAST |
| | | if (iph->daddr.s6_addr[0] == 0xff) |
| | | convert_ipv6_mac_to_mc(skb); |
| | | #endif |
| | | } |
| | | return 0; |
| | | |
| | | default: |
| | | return -1; |
| | | } |
| | | } |
| | | #endif /* CL_IPV6_PASS */ |
| | | |
| | | return -1; |
| | | } |
| | | |
| | | |
| | | int nat25_handle_frame(_adapter *priv, struct sk_buff *skb) |
| | | { |
| | | #ifdef BR_EXT_DEBUG |
| | | if ((!priv->ethBrExtInfo.nat25_disable) && (!(skb->data[0] & 1))) { |
| | | panic_printk("NAT25: Input Frame: DA=%02x%02x%02x%02x%02x%02x SA=%02x%02x%02x%02x%02x%02x\n", |
| | | skb->data[0], |
| | | skb->data[1], |
| | | skb->data[2], |
| | | skb->data[3], |
| | | skb->data[4], |
| | | skb->data[5], |
| | | skb->data[6], |
| | | skb->data[7], |
| | | skb->data[8], |
| | | skb->data[9], |
| | | skb->data[10], |
| | | skb->data[11]); |
| | | } |
| | | #endif |
| | | |
| | | if (!(skb->data[0] & 1)) { |
| | | int is_vlan_tag = 0, i, retval = 0; |
| | | unsigned short vlan_hdr = 0; |
| | | |
| | | if (*((unsigned short *)(skb->data + ETH_ALEN * 2)) == __constant_htons(ETH_P_8021Q)) { |
| | | is_vlan_tag = 1; |
| | | vlan_hdr = *((unsigned short *)(skb->data + ETH_ALEN * 2 + 2)); |
| | | for (i = 0; i < 6; i++) |
| | | *((unsigned short *)(skb->data + ETH_ALEN * 2 + 2 - i * 2)) = *((unsigned short *)(skb->data + ETH_ALEN * 2 - 2 - i * 2)); |
| | | skb_pull(skb, 4); |
| | | } |
| | | |
| | | if (!priv->ethBrExtInfo.nat25_disable) { |
| | | _irqL irqL; |
| | | _enter_critical_bh(&priv->br_ext_lock, &irqL); |
| | | /* |
| | | * This function look up the destination network address from |
| | | * the NAT2.5 database. Return value = -1 means that the |
| | | * corresponding network protocol is NOT support. |
| | | */ |
| | | if (!priv->ethBrExtInfo.nat25sc_disable && |
| | | (*((unsigned short *)(skb->data + ETH_ALEN * 2)) == __constant_htons(ETH_P_IP)) && |
| | | !memcmp(priv->scdb_ip, skb->data + ETH_HLEN + 16, 4)) { |
| | | memcpy(skb->data, priv->scdb_mac, ETH_ALEN); |
| | | |
| | | _exit_critical_bh(&priv->br_ext_lock, &irqL); |
| | | } else { |
| | | _exit_critical_bh(&priv->br_ext_lock, &irqL); |
| | | |
| | | retval = nat25_db_handle(priv, skb, NAT25_LOOKUP); |
| | | } |
| | | } else { |
| | | if (((*((unsigned short *)(skb->data + ETH_ALEN * 2)) == __constant_htons(ETH_P_IP)) && |
| | | !memcmp(priv->br_ip, skb->data + ETH_HLEN + 16, 4)) || |
| | | ((*((unsigned short *)(skb->data + ETH_ALEN * 2)) == __constant_htons(ETH_P_ARP)) && |
| | | !memcmp(priv->br_ip, skb->data + ETH_HLEN + 24, 4))) { |
| | | /* for traffic to upper TCP/IP */ |
| | | retval = nat25_db_handle(priv, skb, NAT25_LOOKUP); |
| | | } |
| | | } |
| | | |
| | | if (is_vlan_tag) { |
| | | skb_push(skb, 4); |
| | | for (i = 0; i < 6; i++) |
| | | *((unsigned short *)(skb->data + i * 2)) = *((unsigned short *)(skb->data + 4 + i * 2)); |
| | | *((unsigned short *)(skb->data + ETH_ALEN * 2)) = __constant_htons(ETH_P_8021Q); |
| | | *((unsigned short *)(skb->data + ETH_ALEN * 2 + 2)) = vlan_hdr; |
| | | } |
| | | |
| | | if (retval == -1) { |
| | | /* DEBUG_ERR("NAT25: Lookup fail!\n"); */ |
| | | return -1; |
| | | } |
| | | } |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | #if 0 |
| | | void mac_clone(_adapter *priv, unsigned char *addr) |
| | | { |
| | | struct sockaddr sa; |
| | | |
| | | memcpy(sa.sa_data, addr, ETH_ALEN); |
| | | RTW_INFO("MAC Clone: Addr=%02x%02x%02x%02x%02x%02x\n", |
| | | addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); |
| | | rtl8192cd_set_hwaddr(priv->dev, &sa); |
| | | } |
| | | |
| | | |
| | | int mac_clone_handle_frame(_adapter *priv, struct sk_buff *skb) |
| | | { |
| | | if (priv->ethBrExtInfo.macclone_enable && !priv->macclone_completed) { |
| | | if (!(skb->data[ETH_ALEN] & 1)) { /* check any other particular MAC add */ |
| | | if (memcmp(skb->data + ETH_ALEN, GET_MY_HWADDR(priv), ETH_ALEN) && |
| | | ((priv->dev->br_port) && |
| | | memcmp(skb->data + ETH_ALEN, priv->br_mac, ETH_ALEN))) { |
| | | mac_clone(priv, skb->data + ETH_ALEN); |
| | | priv->macclone_completed = 1; |
| | | } |
| | | } |
| | | } |
| | | |
| | | return 0; |
| | | } |
| | | #endif /* 0 */ |
| | | |
| | | #define SERVER_PORT 67 |
| | | #define CLIENT_PORT 68 |
| | | #define DHCP_MAGIC 0x63825363 |
| | | #define BROADCAST_FLAG 0x8000 |
| | | |
| | | struct dhcpMessage { |
| | | u_int8_t op; |
| | | u_int8_t htype; |
| | | u_int8_t hlen; |
| | | u_int8_t hops; |
| | | u_int32_t xid; |
| | | u_int16_t secs; |
| | | u_int16_t flags; |
| | | u_int32_t ciaddr; |
| | | u_int32_t yiaddr; |
| | | u_int32_t siaddr; |
| | | u_int32_t giaddr; |
| | | u_int8_t chaddr[16]; |
| | | u_int8_t sname[64]; |
| | | u_int8_t file[128]; |
| | | u_int32_t cookie; |
| | | u_int8_t options[308]; /* 312 - cookie */ |
| | | }; |
| | | |
| | | void dhcp_flag_bcast(_adapter *priv, struct sk_buff *skb) |
| | | { |
| | | if (skb == NULL) |
| | | return; |
| | | |
| | | if (!priv->ethBrExtInfo.dhcp_bcst_disable) { |
| | | unsigned short protocol = *((unsigned short *)(skb->data + 2 * ETH_ALEN)); |
| | | |
| | | if (protocol == __constant_htons(ETH_P_IP)) { /* IP */ |
| | | struct iphdr *iph = (struct iphdr *)(skb->data + ETH_HLEN); |
| | | |
| | | if (iph->protocol == IPPROTO_UDP) { /* UDP */ |
| | | struct udphdr *udph = (struct udphdr *)((SIZE_PTR)iph + (iph->ihl << 2)); |
| | | |
| | | if ((udph->source == __constant_htons(CLIENT_PORT)) |
| | | && (udph->dest == __constant_htons(SERVER_PORT))) { /* DHCP request */ |
| | | struct dhcpMessage *dhcph = |
| | | (struct dhcpMessage *)((SIZE_PTR)udph + sizeof(struct udphdr)); |
| | | |
| | | if (dhcph->cookie == __constant_htonl(DHCP_MAGIC)) { /* match magic word */ |
| | | if (!(dhcph->flags & htons(BROADCAST_FLAG))) { /* if not broadcast */ |
| | | register int sum = 0; |
| | | |
| | | RTW_INFO("DHCP: change flag of DHCP request to broadcast.\n"); |
| | | /* or BROADCAST flag */ |
| | | dhcph->flags |= htons(BROADCAST_FLAG); |
| | | /* recalculate checksum */ |
| | | sum = ~(udph->check) & 0xffff; |
| | | sum += dhcph->flags; |
| | | while (sum >> 16) |
| | | sum = (sum & 0xffff) + (sum >> 16); |
| | | udph->check = ~sum; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | void *scdb_findEntry(_adapter *priv, unsigned char *macAddr, |
| | | unsigned char *ipAddr) |
| | | { |
| | | unsigned char networkAddr[MAX_NETWORK_ADDR_LEN]; |
| | | struct nat25_network_db_entry *db; |
| | | int hash; |
| | | /* _irqL irqL; */ |
| | | /* _enter_critical_bh(&priv->br_ext_lock, &irqL); */ |
| | | |
| | | __nat25_generate_ipv4_network_addr(networkAddr, (unsigned int *)ipAddr); |
| | | hash = __nat25_network_hash(networkAddr); |
| | | db = priv->nethash[hash]; |
| | | while (db != NULL) { |
| | | if (!memcmp(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN)) { |
| | | /* _exit_critical_bh(&priv->br_ext_lock, &irqL); */ |
| | | return (void *)db; |
| | | } |
| | | |
| | | db = db->next_hash; |
| | | } |
| | | |
| | | /* _exit_critical_bh(&priv->br_ext_lock, &irqL); */ |
| | | return NULL; |
| | | } |
| | | |
| | | #endif /* CONFIG_BR_EXT */ |
New file |
| | |
| | | /****************************************************************************** |
| | | * |
| | | * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. |
| | | * |
| | | * This program is free software; you can redistribute it and/or modify it |
| | | * under the terms of version 2 of the GNU General Public License as |
| | | * published by the Free Software Foundation. |
| | | * |
| | | * This program is distributed in the hope that it will be useful, but WITHOUT |
| | | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| | | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
| | | * more details. |
| | | * |
| | | * You should have received a copy of the GNU General Public License along with |
| | | * this program; if not, write to the Free Software Foundation, Inc., |
| | | * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA |
| | | * |
| | | * |
| | | ******************************************************************************/ |
| | | |
| | | |
| | | #include <drv_types.h> |
| | | #include <rtw_bt_mp.h> |
| | | |
| | | #if defined(CONFIG_RTL8723B) |
| | | #include <rtl8723b_hal.h> |
| | | #endif |
| | | |
| | | #if defined(CONFIG_RTL8723B) || defined(CONFIG_RTL8821A) |
| | | void MPh2c_timeout_handle(void *FunctionContext) |
| | | { |
| | | PADAPTER pAdapter; |
| | | PMPT_CONTEXT pMptCtx; |
| | | |
| | | |
| | | RTW_INFO("[MPT], MPh2c_timeout_handle\n"); |
| | | |
| | | pAdapter = (PADAPTER)FunctionContext; |
| | | pMptCtx = &pAdapter->mppriv.mpt_ctx; |
| | | |
| | | pMptCtx->bMPh2c_timeout = _TRUE; |
| | | |
| | | if ((_FALSE == pMptCtx->MptH2cRspEvent) |
| | | || ((_TRUE == pMptCtx->MptH2cRspEvent) |
| | | && (_FALSE == pMptCtx->MptBtC2hEvent))) |
| | | _rtw_up_sema(&pMptCtx->MPh2c_Sema); |
| | | } |
| | | |
| | | u32 WaitC2Hevent(PADAPTER pAdapter, u8 *C2H_event, u32 delay_time) |
| | | { |
| | | PMPT_CONTEXT pMptCtx = &(pAdapter->mppriv.mpt_ctx); |
| | | pMptCtx->bMPh2c_timeout = _FALSE; |
| | | |
| | | if (pAdapter->registrypriv.mp_mode == 0) { |
| | | RTW_INFO("[MPT], Error!! WaitC2Hevent mp_mode == 0!!\n"); |
| | | return _FALSE; |
| | | } |
| | | |
| | | _set_timer(&pMptCtx->MPh2c_timeout_timer, delay_time); |
| | | |
| | | _rtw_down_sema(&pMptCtx->MPh2c_Sema); |
| | | |
| | | if (pMptCtx->bMPh2c_timeout == _TRUE) { |
| | | *C2H_event = _FALSE; |
| | | |
| | | return _FALSE; |
| | | } |
| | | |
| | | /* for safty, cancel timer here again */ |
| | | _cancel_timer_ex(&pMptCtx->MPh2c_timeout_timer); |
| | | |
| | | return _TRUE; |
| | | } |
| | | |
| | | BT_CTRL_STATUS |
| | | mptbt_CheckC2hFrame( |
| | | PADAPTER Adapter, |
| | | PBT_H2C pH2c, |
| | | PBT_EXT_C2H pExtC2h |
| | | ) |
| | | { |
| | | BT_CTRL_STATUS c2hStatus = BT_STATUS_C2H_SUCCESS; |
| | | |
| | | /* RTW_INFO("[MPT], MPT rsp C2H hex: %x %x %x %x %x %x\n"), pExtC2h , pExtC2h+1 ,pExtC2h+2 ,pExtC2h+3 ,pExtC2h+4 ,pExtC2h+5); */ |
| | | |
| | | RTW_INFO("[MPT], statusCode = 0x%x\n", pExtC2h->statusCode); |
| | | RTW_INFO("[MPT], retLen = %d\n", pExtC2h->retLen); |
| | | RTW_INFO("[MPT], opCodeVer : req/rsp=%d/%d\n", pH2c->opCodeVer, pExtC2h->opCodeVer); |
| | | RTW_INFO("[MPT], reqNum : req/rsp=%d/%d\n", pH2c->reqNum, pExtC2h->reqNum); |
| | | if (pExtC2h->reqNum != pH2c->reqNum) { |
| | | c2hStatus = BT_STATUS_C2H_REQNUM_MISMATCH; |
| | | RTW_INFO("[MPT], Error!! C2H reqNum Mismatch!!\n"); |
| | | } else if (pExtC2h->opCodeVer != pH2c->opCodeVer) { |
| | | c2hStatus = BT_STATUS_OPCODE_L_VERSION_MISMATCH; |
| | | RTW_INFO("[MPT], Error!! OPCode version L mismatch!!\n"); |
| | | } |
| | | |
| | | return c2hStatus; |
| | | } |
| | | |
| | | BT_CTRL_STATUS |
| | | mptbt_SendH2c( |
| | | PADAPTER Adapter, |
| | | PBT_H2C pH2c, |
| | | u2Byte h2cCmdLen |
| | | ) |
| | | { |
| | | /* KIRQL OldIrql = KeGetCurrentIrql(); */ |
| | | BT_CTRL_STATUS h2cStatus = BT_STATUS_H2C_SUCCESS; |
| | | PMPT_CONTEXT pMptCtx = &(Adapter->mppriv.mpt_ctx); |
| | | u1Byte i; |
| | | |
| | | RTW_INFO("[MPT], mptbt_SendH2c()=========>\n"); |
| | | |
| | | /* PlatformResetEvent(&pMptCtx->MptH2cRspEvent); */ |
| | | /* PlatformResetEvent(&pMptCtx->MptBtC2hEvent); */ |
| | | |
| | | /* if(OldIrql == PASSIVE_LEVEL) |
| | | * { */ |
| | | /* RTPRINT_DATA(FMPBT, FMPBT_H2C_CONTENT, ("[MPT], MPT H2C hex:\n"), pH2c, h2cCmdLen); */ |
| | | |
| | | for (i = 0; i < BT_H2C_MAX_RETRY; i++) { |
| | | RTW_INFO("[MPT], Send H2C command to wifi!!!\n"); |
| | | |
| | | pMptCtx->MptH2cRspEvent = _FALSE; |
| | | pMptCtx->MptBtC2hEvent = _FALSE; |
| | | |
| | | #if defined(CONFIG_RTL8723B) |
| | | rtl8723b_set_FwBtMpOper_cmd(Adapter, pH2c->opCode, pH2c->opCodeVer, pH2c->reqNum, pH2c->buf); |
| | | #endif |
| | | pMptCtx->h2cReqNum++; |
| | | pMptCtx->h2cReqNum %= 16; |
| | | |
| | | if (WaitC2Hevent(Adapter, &pMptCtx->MptH2cRspEvent, 100)) { |
| | | RTW_INFO("[MPT], Received WiFi MptH2cRspEvent!!!\n"); |
| | | if (WaitC2Hevent(Adapter, &pMptCtx->MptBtC2hEvent, 400)) { |
| | | RTW_INFO("[MPT], Received MptBtC2hEvent!!!\n"); |
| | | break; |
| | | } else { |
| | | RTW_INFO("[MPT], Error!!BT MptBtC2hEvent timeout!!\n"); |
| | | h2cStatus = BT_STATUS_H2C_BT_NO_RSP; |
| | | } |
| | | } else { |
| | | RTW_INFO("[MPT], Error!!WiFi MptH2cRspEvent timeout!!\n"); |
| | | h2cStatus = BT_STATUS_H2C_TIMTOUT; |
| | | } |
| | | } |
| | | /* } |
| | | * else |
| | | * { |
| | | * RT_ASSERT(FALSE, ("[MPT], mptbt_SendH2c() can only run under PASSIVE_LEVEL!!\n")); |
| | | * h2cStatus = BT_STATUS_WRONG_LEVEL; |
| | | * } */ |
| | | |
| | | RTW_INFO("[MPT], mptbt_SendH2c()<=========\n"); |
| | | return h2cStatus; |
| | | } |
| | | |
| | | |
| | | |
| | | BT_CTRL_STATUS |
| | | mptbt_CheckBtRspStatus( |
| | | PADAPTER Adapter, |
| | | PBT_EXT_C2H pExtC2h |
| | | ) |
| | | { |
| | | BT_CTRL_STATUS retStatus = BT_OP_STATUS_SUCCESS; |
| | | |
| | | switch (pExtC2h->statusCode) { |
| | | case BT_OP_STATUS_SUCCESS: |
| | | retStatus = BT_STATUS_BT_OP_SUCCESS; |
| | | RTW_INFO("[MPT], BT status : BT_STATUS_SUCCESS\n"); |
| | | break; |
| | | case BT_OP_STATUS_VERSION_MISMATCH: |
| | | retStatus = BT_STATUS_OPCODE_L_VERSION_MISMATCH; |
| | | RTW_INFO("[MPT], BT status : BT_STATUS_OPCODE_L_VERSION_MISMATCH\n"); |
| | | break; |
| | | case BT_OP_STATUS_UNKNOWN_OPCODE: |
| | | retStatus = BT_STATUS_UNKNOWN_OPCODE_L; |
| | | RTW_INFO("[MPT], BT status : BT_STATUS_UNKNOWN_OPCODE_L\n"); |
| | | break; |
| | | case BT_OP_STATUS_ERROR_PARAMETER: |
| | | retStatus = BT_STATUS_PARAMETER_FORMAT_ERROR_L; |
| | | RTW_INFO("[MPT], BT status : BT_STATUS_PARAMETER_FORMAT_ERROR_L\n"); |
| | | break; |
| | | default: |
| | | retStatus = BT_STATUS_UNKNOWN_STATUS_L; |
| | | RTW_INFO("[MPT], BT status : BT_STATUS_UNKNOWN_STATUS_L\n"); |
| | | break; |
| | | } |
| | | |
| | | return retStatus; |
| | | } |
| | | |
| | | |
| | | |
| | | BT_CTRL_STATUS |
| | | mptbt_BtFwOpCodeProcess( |
| | | PADAPTER Adapter, |
| | | u1Byte btFwOpCode, |
| | | u1Byte opCodeVer, |
| | | pu1Byte pH2cPar, |
| | | u1Byte h2cParaLen |
| | | ) |
| | | { |
| | | u1Byte H2C_Parameter[6] = {0}; |
| | | PBT_H2C pH2c = (PBT_H2C)&H2C_Parameter[0]; |
| | | PMPT_CONTEXT pMptCtx = &(Adapter->mppriv.mpt_ctx); |
| | | PBT_EXT_C2H pExtC2h = (PBT_EXT_C2H)&pMptCtx->c2hBuf[0]; |
| | | u2Byte paraLen = 0, i; |
| | | BT_CTRL_STATUS h2cStatus = BT_STATUS_H2C_SUCCESS, c2hStatus = BT_STATUS_C2H_SUCCESS; |
| | | BT_CTRL_STATUS retStatus = BT_STATUS_H2C_BT_NO_RSP; |
| | | |
| | | if (Adapter->registrypriv.mp_mode == 0) { |
| | | RTW_INFO("[MPT], Error!! mptbt_BtFwOpCodeProces mp_mode == 0!!\n"); |
| | | return _FALSE; |
| | | } |
| | | |
| | | pH2c->opCode = btFwOpCode; |
| | | pH2c->opCodeVer = opCodeVer; |
| | | pH2c->reqNum = pMptCtx->h2cReqNum; |
| | | /* PlatformMoveMemory(&pH2c->buf[0], pH2cPar, h2cParaLen); */ |
| | | /* _rtw_memcpy(&pH2c->buf[0], pH2cPar, h2cParaLen); */ |
| | | _rtw_memcpy(pH2c->buf, pH2cPar, h2cParaLen); |
| | | |
| | | RTW_INFO("[MPT], pH2c->opCode=%d\n", pH2c->opCode); |
| | | RTW_INFO("[MPT], pH2c->opCodeVer=%d\n", pH2c->opCodeVer); |
| | | RTW_INFO("[MPT], pH2c->reqNum=%d\n", pH2c->reqNum); |
| | | RTW_INFO("[MPT], h2c parameter length=%d\n", h2cParaLen); |
| | | for (i = 0; i < h2cParaLen; i++) |
| | | RTW_INFO("[MPT], parameter[%d]=0x%02x\n", i, pH2c->buf[i]); |
| | | |
| | | h2cStatus = mptbt_SendH2c(Adapter, pH2c, h2cParaLen + 2); |
| | | if (BT_STATUS_H2C_SUCCESS == h2cStatus) { |
| | | /* if reach here, it means H2C get the correct c2h response, */ |
| | | c2hStatus = mptbt_CheckC2hFrame(Adapter, pH2c, pExtC2h); |
| | | if (BT_STATUS_C2H_SUCCESS == c2hStatus) |
| | | retStatus = mptbt_CheckBtRspStatus(Adapter, pExtC2h); |
| | | else { |
| | | RTW_INFO("[MPT], Error!! C2H failed for pH2c->opCode=%d\n", pH2c->opCode); |
| | | /* check c2h status error, return error status code to upper layer. */ |
| | | retStatus = c2hStatus; |
| | | } |
| | | } else { |
| | | RTW_INFO("[MPT], Error!! H2C failed for pH2c->opCode=%d\n", pH2c->opCode); |
| | | /* check h2c status error, return error status code to upper layer. */ |
| | | retStatus = h2cStatus; |
| | | } |
| | | |
| | | return retStatus; |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | u2Byte |
| | | mptbt_BtReady( |
| | | PADAPTER Adapter, |
| | | PBT_REQ_CMD pBtReq, |
| | | PBT_RSP_CMD pBtRsp |
| | | ) |
| | | { |
| | | u1Byte h2cParaBuf[6] = {0}; |
| | | u1Byte h2cParaLen = 0; |
| | | u2Byte paraLen = 0; |
| | | u1Byte retStatus = BT_STATUS_BT_OP_SUCCESS; |
| | | u1Byte btOpcode; |
| | | u1Byte btOpcodeVer = 0; |
| | | PMPT_CONTEXT pMptCtx = &(Adapter->mppriv.mpt_ctx); |
| | | PBT_EXT_C2H pExtC2h = (PBT_EXT_C2H)&pMptCtx->c2hBuf[0]; |
| | | u1Byte i; |
| | | u1Byte btFwVer = 0, bdAddr[6] = {0}; |
| | | u2Byte btRealFwVer = 0; |
| | | pu2Byte pu2Tmp = NULL; |
| | | |
| | | /* */ |
| | | /* check upper layer parameters */ |
| | | /* */ |
| | | |
| | | /* 1. check upper layer opcode version */ |
| | | if (pBtReq->opCodeVer != 1) { |
| | | RTW_INFO("[MPT], Error!! Upper OP code version not match!!!\n"); |
| | | pBtRsp->status = BT_STATUS_OPCODE_U_VERSION_MISMATCH; |
| | | return paraLen; |
| | | } |
| | | |
| | | pBtRsp->pParamStart[0] = MP_BT_NOT_READY; |
| | | paraLen = 10; |
| | | /* */ |
| | | /* execute lower layer opcodes */ |
| | | /* */ |
| | | |
| | | /* Get BT FW version */ |
| | | /* fill h2c parameters */ |
| | | btOpcode = BT_LO_OP_GET_BT_VERSION; |
| | | /* execute h2c and check respond c2h from bt fw is correct or not */ |
| | | retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); |
| | | /* ckeck bt return status. */ |
| | | if (BT_STATUS_BT_OP_SUCCESS != retStatus) { |
| | | pBtRsp->status = ((btOpcode << 8) | retStatus); |
| | | RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); |
| | | return paraLen; |
| | | } else { |
| | | pu2Tmp = (pu2Byte)&pExtC2h->buf[0]; |
| | | btRealFwVer = *pu2Tmp; |
| | | btFwVer = pExtC2h->buf[1]; |
| | | RTW_INFO("[MPT], btRealFwVer=0x%x, btFwVer=0x%x\n", btRealFwVer, btFwVer); |
| | | } |
| | | |
| | | /* Get BD Address */ |
| | | /* fill h2c parameters */ |
| | | btOpcode = BT_LO_OP_GET_BD_ADDR_L; |
| | | /* execute h2c and check respond c2h from bt fw is correct or not */ |
| | | retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); |
| | | /* ckeck bt return status. */ |
| | | if (BT_STATUS_BT_OP_SUCCESS != retStatus) { |
| | | pBtRsp->status = ((btOpcode << 8) | retStatus); |
| | | RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); |
| | | return paraLen; |
| | | } else { |
| | | bdAddr[5] = pExtC2h->buf[0]; |
| | | bdAddr[4] = pExtC2h->buf[1]; |
| | | bdAddr[3] = pExtC2h->buf[2]; |
| | | } |
| | | |
| | | /* fill h2c parameters */ |
| | | btOpcode = BT_LO_OP_GET_BD_ADDR_H; |
| | | /* execute h2c and check respond c2h from bt fw is correct or not */ |
| | | retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); |
| | | /* ckeck bt return status. */ |
| | | if (BT_STATUS_BT_OP_SUCCESS != retStatus) { |
| | | pBtRsp->status = ((btOpcode << 8) | retStatus); |
| | | RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); |
| | | return paraLen; |
| | | } else { |
| | | bdAddr[2] = pExtC2h->buf[0]; |
| | | bdAddr[1] = pExtC2h->buf[1]; |
| | | bdAddr[0] = pExtC2h->buf[2]; |
| | | } |
| | | RTW_INFO("[MPT], Local BDAddr:"); |
| | | for (i = 0; i < 6; i++) |
| | | RTW_INFO(" 0x%x ", bdAddr[i]); |
| | | pBtRsp->status = BT_STATUS_SUCCESS; |
| | | pBtRsp->pParamStart[0] = MP_BT_READY; |
| | | pu2Tmp = (pu2Byte)&pBtRsp->pParamStart[1]; |
| | | *pu2Tmp = btRealFwVer; |
| | | pBtRsp->pParamStart[3] = btFwVer; |
| | | for (i = 0; i < 6; i++) |
| | | pBtRsp->pParamStart[4 + i] = bdAddr[5 - i]; |
| | | |
| | | return paraLen; |
| | | } |
| | | |
| | | void mptbt_close_WiFiRF(PADAPTER Adapter) |
| | | { |
| | | phy_set_bb_reg(Adapter, 0x824, 0xF, 0x0); |
| | | phy_set_bb_reg(Adapter, 0x824, 0x700000, 0x0); |
| | | phy_set_rf_reg(Adapter, RF_PATH_A, 0x0, 0xF0000, 0x0); |
| | | } |
| | | |
| | | void mptbt_open_WiFiRF(PADAPTER Adapter) |
| | | { |
| | | phy_set_bb_reg(Adapter, 0x824, 0x700000, 0x3); |
| | | phy_set_bb_reg(Adapter, 0x824, 0xF, 0x2); |
| | | phy_set_rf_reg(Adapter, RF_PATH_A, 0x0, 0xF0000, 0x3); |
| | | } |
| | | |
| | | u4Byte mptbt_switch_RF(PADAPTER Adapter, u1Byte Enter) |
| | | { |
| | | u2Byte tmp_2byte = 0; |
| | | |
| | | /* Enter test mode */ |
| | | if (Enter) { |
| | | /* 1>. close WiFi RF */ |
| | | mptbt_close_WiFiRF(Adapter); |
| | | |
| | | /* 2>. change ant switch to BT */ |
| | | tmp_2byte = rtw_read16(Adapter, 0x860); |
| | | tmp_2byte = tmp_2byte | BIT(9); |
| | | tmp_2byte = tmp_2byte & (~BIT(8)); |
| | | rtw_write16(Adapter, 0x860, tmp_2byte); |
| | | rtw_write16(Adapter, 0x870, 0x300); |
| | | } else { |
| | | /* 1>. Open WiFi RF */ |
| | | mptbt_open_WiFiRF(Adapter); |
| | | |
| | | /* 2>. change ant switch back */ |
| | | tmp_2byte = rtw_read16(Adapter, 0x860); |
| | | tmp_2byte = tmp_2byte | BIT(8); |
| | | tmp_2byte = tmp_2byte & (~BIT(9)); |
| | | rtw_write16(Adapter, 0x860, tmp_2byte); |
| | | rtw_write16(Adapter, 0x870, 0x300); |
| | | } |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | u2Byte |
| | | mptbt_BtSetMode( |
| | | PADAPTER Adapter, |
| | | PBT_REQ_CMD pBtReq, |
| | | PBT_RSP_CMD pBtRsp |
| | | ) |
| | | { |
| | | u1Byte h2cParaBuf[6] = {0}; |
| | | u1Byte h2cParaLen = 0; |
| | | u2Byte paraLen = 0; |
| | | u1Byte retStatus = BT_STATUS_BT_OP_SUCCESS; |
| | | u1Byte btOpcode; |
| | | u1Byte btOpcodeVer = 0; |
| | | u1Byte btModeToSet = 0; |
| | | |
| | | /* */ |
| | | /* check upper layer parameters */ |
| | | /* */ |
| | | /* 1. check upper layer opcode version */ |
| | | if (pBtReq->opCodeVer != 1) { |
| | | RTW_INFO("[MPT], Error!! Upper OP code version not match!!!\n"); |
| | | pBtRsp->status = BT_STATUS_OPCODE_U_VERSION_MISMATCH; |
| | | return paraLen; |
| | | } |
| | | /* 2. check upper layer parameter length */ |
| | | if (1 == pBtReq->paraLength) { |
| | | btModeToSet = pBtReq->pParamStart[0]; |
| | | RTW_INFO("[MPT], BtTestMode=%d\n", btModeToSet); |
| | | } else { |
| | | RTW_INFO("[MPT], Error!! wrong parameter length=%d (should be 1)\n", pBtReq->paraLength); |
| | | pBtRsp->status = BT_STATUS_PARAMETER_FORMAT_ERROR_U; |
| | | return paraLen; |
| | | } |
| | | |
| | | /* */ |
| | | /* execute lower layer opcodes */ |
| | | /* */ |
| | | |
| | | /* 1. fill h2c parameters */ |
| | | /* check bt mode */ |
| | | btOpcode = BT_LO_OP_SET_BT_MODE; |
| | | if (btModeToSet >= MP_BT_MODE_MAX) { |
| | | pBtRsp->status = BT_STATUS_PARAMETER_OUT_OF_RANGE_U; |
| | | return paraLen; |
| | | } else { |
| | | mptbt_switch_RF(Adapter, 1); |
| | | |
| | | h2cParaBuf[0] = btModeToSet; |
| | | h2cParaLen = 1; |
| | | /* 2. execute h2c and check respond c2h from bt fw is correct or not */ |
| | | retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); |
| | | } |
| | | |
| | | /* 3. construct respond status code and data. */ |
| | | if (BT_STATUS_BT_OP_SUCCESS == retStatus) |
| | | pBtRsp->status = BT_STATUS_SUCCESS; |
| | | else { |
| | | pBtRsp->status = ((btOpcode << 8) | retStatus); |
| | | RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); |
| | | } |
| | | |
| | | return paraLen; |
| | | } |
| | | |
| | | |
| | | VOID |
| | | MPTBT_FwC2hBtMpCtrl( |
| | | PADAPTER Adapter, |
| | | pu1Byte tmpBuf, |
| | | u1Byte length |
| | | ) |
| | | { |
| | | u32 i; |
| | | PMPT_CONTEXT pMptCtx = &(Adapter->mppriv.mpt_ctx); |
| | | PBT_EXT_C2H pExtC2h = (PBT_EXT_C2H)tmpBuf; |
| | | |
| | | if (Adapter->bBTFWReady == _FALSE || Adapter->registrypriv.mp_mode == 0) { |
| | | /* RTW_INFO("Ignore C2H BT MP Info since not in MP mode\n"); */ |
| | | return; |
| | | } |
| | | if (length > 32 || length < 3) { |
| | | RTW_INFO("\n [MPT], pExtC2h->buf hex: length=%d > 32 || < 3\n", length); |
| | | return; |
| | | } |
| | | |
| | | /* cancel_timeout for h2c handle */ |
| | | _cancel_timer_ex(&pMptCtx->MPh2c_timeout_timer); |
| | | |
| | | for (i = 0; i < length; i++) |
| | | RTW_INFO("[MPT], %s, buf[%d]=0x%02x ", __FUNCTION__, i, tmpBuf[i]); |
| | | RTW_INFO("[MPT], pExtC2h->extendId=0x%x\n", pExtC2h->extendId); |
| | | |
| | | switch (pExtC2h->extendId) { |
| | | case EXT_C2H_WIFI_FW_ACTIVE_RSP: |
| | | RTW_INFO("[MPT], EXT_C2H_WIFI_FW_ACTIVE_RSP\n"); |
| | | #if 0 |
| | | RTW_INFO("[MPT], pExtC2h->buf hex:\n"); |
| | | for (i = 0; i < (length - 3); i++) |
| | | RTW_INFO(" 0x%x ", pExtC2h->buf[i]); |
| | | #endif |
| | | if ((_FALSE == pMptCtx->bMPh2c_timeout) |
| | | && (_FALSE == pMptCtx->MptH2cRspEvent)) { |
| | | pMptCtx->MptH2cRspEvent = _TRUE; |
| | | _rtw_up_sema(&pMptCtx->MPh2c_Sema); |
| | | } |
| | | break; |
| | | |
| | | case EXT_C2H_TRIG_BY_BT_FW: |
| | | RTW_INFO("[MPT], EXT_C2H_TRIG_BY_BT_FW\n"); |
| | | _rtw_memcpy(&pMptCtx->c2hBuf[0], tmpBuf, length); |
| | | RTW_INFO("[MPT], pExtC2h->statusCode=0x%x\n", pExtC2h->statusCode); |
| | | RTW_INFO("[MPT], pExtC2h->retLen=0x%x\n", pExtC2h->retLen); |
| | | RTW_INFO("[MPT], pExtC2h->opCodeVer=0x%x\n", pExtC2h->opCodeVer); |
| | | RTW_INFO("[MPT], pExtC2h->reqNum=0x%x\n", pExtC2h->reqNum); |
| | | for (i = 0; i < (length - 3); i++) |
| | | RTW_INFO("[MPT], pExtC2h->buf[%d]=0x%02x\n", i, pExtC2h->buf[i]); |
| | | |
| | | if ((_FALSE == pMptCtx->bMPh2c_timeout) |
| | | && (_TRUE == pMptCtx->MptH2cRspEvent) |
| | | && (_FALSE == pMptCtx->MptBtC2hEvent)) { |
| | | pMptCtx->MptBtC2hEvent = _TRUE; |
| | | _rtw_up_sema(&pMptCtx->MPh2c_Sema); |
| | | } |
| | | break; |
| | | |
| | | default: |
| | | RTW_INFO("[MPT], EXT_C2H Target not found,pExtC2h->extendId =%d ,pExtC2h->reqNum=%d\n", pExtC2h->extendId, pExtC2h->reqNum); |
| | | break; |
| | | } |
| | | |
| | | |
| | | |
| | | } |
| | | |
| | | |
| | | u2Byte |
| | | mptbt_BtGetGeneral( |
| | | IN PADAPTER Adapter, |
| | | IN PBT_REQ_CMD pBtReq, |
| | | IN PBT_RSP_CMD pBtRsp |
| | | ) |
| | | { |
| | | PMPT_CONTEXT pMptCtx = &(Adapter->mppriv.mpt_ctx); |
| | | PBT_EXT_C2H pExtC2h = (PBT_EXT_C2H)&pMptCtx->c2hBuf[0]; |
| | | u1Byte h2cParaBuf[6] = {0}; |
| | | u1Byte h2cParaLen = 0; |
| | | u2Byte paraLen = 0; |
| | | u1Byte retStatus = BT_STATUS_BT_OP_SUCCESS; |
| | | u1Byte btOpcode, bdAddr[6] = {0}; |
| | | u1Byte btOpcodeVer = 0; |
| | | u1Byte getType = 0, i; |
| | | u2Byte getParaLen = 0, validParaLen = 0; |
| | | u1Byte regType = 0, reportType = 0; |
| | | u4Byte regAddr = 0, regValue = 0; |
| | | pu4Byte pu4Tmp; |
| | | pu2Byte pu2Tmp; |
| | | pu1Byte pu1Tmp; |
| | | |
| | | /* */ |
| | | /* check upper layer parameters */ |
| | | /* */ |
| | | |
| | | /* check upper layer opcode version */ |
| | | if (pBtReq->opCodeVer != 1) { |
| | | RTW_INFO("[MPT], Error!! Upper OP code version not match!!!\n"); |
| | | pBtRsp->status = BT_STATUS_OPCODE_U_VERSION_MISMATCH; |
| | | return paraLen; |
| | | } |
| | | /* check upper layer parameter length */ |
| | | if (pBtReq->paraLength < 1) { |
| | | RTW_INFO("[MPT], Error!! wrong parameter length=%d (should larger than 1)\n", pBtReq->paraLength); |
| | | pBtRsp->status = BT_STATUS_PARAMETER_FORMAT_ERROR_U; |
| | | return paraLen; |
| | | } |
| | | getParaLen = pBtReq->paraLength - 1; |
| | | getType = pBtReq->pParamStart[0]; |
| | | |
| | | RTW_INFO("[MPT], getType=%d, getParaLen=%d\n", getType, getParaLen); |
| | | |
| | | /* check parameter first */ |
| | | switch (getType) { |
| | | case BT_GGET_REG: |
| | | RTW_INFO("[MPT], [BT_GGET_REG]\n"); |
| | | validParaLen = 5; |
| | | if (getParaLen == validParaLen) { |
| | | btOpcode = BT_LO_OP_READ_REG; |
| | | regType = pBtReq->pParamStart[1]; |
| | | pu4Tmp = (pu4Byte)&pBtReq->pParamStart[2]; |
| | | regAddr = *pu4Tmp; |
| | | RTW_INFO("[MPT], BT_GGET_REG regType=0x%02x, regAddr=0x%08x!!\n", |
| | | regType, regAddr); |
| | | if (regType >= BT_REG_MAX) { |
| | | pBtRsp->status = (btOpcode << 8) | BT_STATUS_PARAMETER_OUT_OF_RANGE_U; |
| | | return paraLen; |
| | | } else { |
| | | if (((BT_REG_RF == regType) && (regAddr > 0x7f)) || |
| | | ((BT_REG_MODEM == regType) && (regAddr > 0x1ff)) || |
| | | ((BT_REG_BLUEWIZE == regType) && (regAddr > 0xfff)) || |
| | | ((BT_REG_VENDOR == regType) && (regAddr > 0xfff)) || |
| | | ((BT_REG_LE == regType) && (regAddr > 0xfff))) { |
| | | pBtRsp->status = (btOpcode << 8) | BT_STATUS_PARAMETER_OUT_OF_RANGE_U; |
| | | return paraLen; |
| | | } |
| | | } |
| | | } |
| | | break; |
| | | case BT_GGET_STATUS: |
| | | RTW_INFO("[MPT], [BT_GGET_STATUS]\n"); |
| | | validParaLen = 0; |
| | | break; |
| | | case BT_GGET_REPORT: |
| | | RTW_INFO("[MPT], [BT_GGET_REPORT]\n"); |
| | | validParaLen = 1; |
| | | if (getParaLen == validParaLen) { |
| | | reportType = pBtReq->pParamStart[1]; |
| | | RTW_INFO("[MPT], BT_GGET_REPORT reportType=0x%x!!\n", reportType); |
| | | if (reportType >= BT_REPORT_MAX) { |
| | | pBtRsp->status = BT_STATUS_PARAMETER_OUT_OF_RANGE_U; |
| | | return paraLen; |
| | | } |
| | | } |
| | | break; |
| | | default: { |
| | | RTW_INFO("[MPT], Error!! getType=%d, out of range\n", getType); |
| | | pBtRsp->status = BT_STATUS_PARAMETER_OUT_OF_RANGE_U; |
| | | return paraLen; |
| | | } |
| | | break; |
| | | } |
| | | if (getParaLen != validParaLen) { |
| | | RTW_INFO("[MPT], Error!! wrong parameter length=%d for BT_GET_GEN_CMD cmd id=0x%x, paraLen should=0x%x\n", |
| | | getParaLen, getType, validParaLen); |
| | | pBtRsp->status = BT_STATUS_PARAMETER_FORMAT_ERROR_U; |
| | | return paraLen; |
| | | } |
| | | |
| | | /* */ |
| | | /* execute lower layer opcodes */ |
| | | /* */ |
| | | if (BT_GGET_REG == getType) { |
| | | /* fill h2c parameters */ |
| | | /* here we should write reg value first then write the address, adviced by Austin */ |
| | | btOpcode = BT_LO_OP_READ_REG; |
| | | h2cParaBuf[0] = regType; |
| | | h2cParaBuf[1] = pBtReq->pParamStart[2]; |
| | | h2cParaBuf[2] = pBtReq->pParamStart[3]; |
| | | h2cParaLen = 3; |
| | | /* execute h2c and check respond c2h from bt fw is correct or not */ |
| | | retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); |
| | | /* construct respond status code and data. */ |
| | | if (BT_STATUS_BT_OP_SUCCESS != retStatus) { |
| | | pBtRsp->status = ((btOpcode << 8) | retStatus); |
| | | RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); |
| | | return paraLen; |
| | | } |
| | | |
| | | pu2Tmp = (pu2Byte)&pExtC2h->buf[0]; |
| | | regValue = *pu2Tmp; |
| | | RTW_INFO("[MPT], read reg regType=0x%02x, regAddr=0x%08x, regValue=0x%04x\n", |
| | | regType, regAddr, regValue); |
| | | |
| | | pu4Tmp = (pu4Byte)&pBtRsp->pParamStart[0]; |
| | | *pu4Tmp = regValue; |
| | | paraLen = 4; |
| | | } else if (BT_GGET_STATUS == getType) { |
| | | btOpcode = BT_LO_OP_GET_BT_STATUS; |
| | | h2cParaLen = 0; |
| | | /* execute h2c and check respond c2h from bt fw is correct or not */ |
| | | retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); |
| | | /* construct respond status code and data. */ |
| | | if (BT_STATUS_BT_OP_SUCCESS != retStatus) { |
| | | pBtRsp->status = ((btOpcode << 8) | retStatus); |
| | | RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); |
| | | return paraLen; |
| | | } |
| | | |
| | | pBtRsp->pParamStart[0] = pExtC2h->buf[0]; |
| | | pBtRsp->pParamStart[1] = pExtC2h->buf[1]; |
| | | RTW_INFO("[MPT], read bt status, testMode=0x%x, testStatus=0x%x\n", |
| | | pBtRsp->pParamStart[0], pBtRsp->pParamStart[1]); |
| | | paraLen = 2; |
| | | } else if (BT_GGET_REPORT == getType) { |
| | | switch (reportType) { |
| | | case BT_REPORT_RX_PACKET_CNT: { |
| | | RTW_INFO("[MPT], [Rx Packet Counts]\n"); |
| | | btOpcode = BT_LO_OP_GET_RX_PKT_CNT_L; |
| | | h2cParaLen = 0; |
| | | /* execute h2c and check respond c2h from bt fw is correct or not */ |
| | | retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); |
| | | /* construct respond status code and data. */ |
| | | if (BT_STATUS_BT_OP_SUCCESS != retStatus) { |
| | | pBtRsp->status = ((btOpcode << 8) | retStatus); |
| | | RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); |
| | | return paraLen; |
| | | } |
| | | pBtRsp->pParamStart[0] = pExtC2h->buf[0]; |
| | | pBtRsp->pParamStart[1] = pExtC2h->buf[1]; |
| | | |
| | | btOpcode = BT_LO_OP_GET_RX_PKT_CNT_H; |
| | | h2cParaLen = 0; |
| | | /* execute h2c and check respond c2h from bt fw is correct or not */ |
| | | retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); |
| | | /* construct respond status code and data. */ |
| | | if (BT_STATUS_BT_OP_SUCCESS != retStatus) { |
| | | pBtRsp->status = ((btOpcode << 8) | retStatus); |
| | | RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); |
| | | return paraLen; |
| | | } |
| | | pBtRsp->pParamStart[2] = pExtC2h->buf[0]; |
| | | pBtRsp->pParamStart[3] = pExtC2h->buf[1]; |
| | | paraLen = 4; |
| | | } |
| | | break; |
| | | case BT_REPORT_RX_ERROR_BITS: { |
| | | RTW_INFO("[MPT], [Rx Error Bits]\n"); |
| | | btOpcode = BT_LO_OP_GET_RX_ERROR_BITS_L; |
| | | h2cParaLen = 0; |
| | | /* execute h2c and check respond c2h from bt fw is correct or not */ |
| | | retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); |
| | | /* construct respond status code and data. */ |
| | | if (BT_STATUS_BT_OP_SUCCESS != retStatus) { |
| | | pBtRsp->status = ((btOpcode << 8) | retStatus); |
| | | RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); |
| | | return paraLen; |
| | | } |
| | | pBtRsp->pParamStart[0] = pExtC2h->buf[0]; |
| | | pBtRsp->pParamStart[1] = pExtC2h->buf[1]; |
| | | |
| | | btOpcode = BT_LO_OP_GET_RX_ERROR_BITS_H; |
| | | h2cParaLen = 0; |
| | | /* execute h2c and check respond c2h from bt fw is correct or not */ |
| | | retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); |
| | | /* construct respond status code and data. */ |
| | | if (BT_STATUS_BT_OP_SUCCESS != retStatus) { |
| | | pBtRsp->status = ((btOpcode << 8) | retStatus); |
| | | RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); |
| | | return paraLen; |
| | | } |
| | | pBtRsp->pParamStart[2] = pExtC2h->buf[0]; |
| | | pBtRsp->pParamStart[3] = pExtC2h->buf[1]; |
| | | paraLen = 4; |
| | | } |
| | | break; |
| | | case BT_REPORT_RSSI: { |
| | | RTW_INFO("[MPT], [RSSI]\n"); |
| | | btOpcode = BT_LO_OP_GET_RSSI; |
| | | h2cParaLen = 0; |
| | | /* execute h2c and check respond c2h from bt fw is correct or not */ |
| | | retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); |
| | | /* construct respond status code and data. */ |
| | | if (BT_STATUS_BT_OP_SUCCESS != retStatus) { |
| | | pBtRsp->status = ((btOpcode << 8) | retStatus); |
| | | RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); |
| | | return paraLen; |
| | | } |
| | | pBtRsp->pParamStart[0] = pExtC2h->buf[0]; |
| | | pBtRsp->pParamStart[1] = pExtC2h->buf[1]; |
| | | paraLen = 2; |
| | | } |
| | | break; |
| | | case BT_REPORT_CFO_HDR_QUALITY: { |
| | | RTW_INFO("[MPT], [CFO & Header Quality]\n"); |
| | | btOpcode = BT_LO_OP_GET_CFO_HDR_QUALITY_L; |
| | | h2cParaLen = 0; |
| | | /* execute h2c and check respond c2h from bt fw is correct or not */ |
| | | retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); |
| | | /* construct respond status code and data. */ |
| | | if (BT_STATUS_BT_OP_SUCCESS != retStatus) { |
| | | pBtRsp->status = ((btOpcode << 8) | retStatus); |
| | | RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); |
| | | return paraLen; |
| | | } |
| | | pBtRsp->pParamStart[0] = pExtC2h->buf[0]; |
| | | pBtRsp->pParamStart[1] = pExtC2h->buf[1]; |
| | | |
| | | btOpcode = BT_LO_OP_GET_CFO_HDR_QUALITY_H; |
| | | h2cParaLen = 0; |
| | | /* execute h2c and check respond c2h from bt fw is correct or not */ |
| | | retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); |
| | | /* construct respond status code and data. */ |
| | | if (BT_STATUS_BT_OP_SUCCESS != retStatus) { |
| | | pBtRsp->status = ((btOpcode << 8) | retStatus); |
| | | RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); |
| | | return paraLen; |
| | | } |
| | | pBtRsp->pParamStart[2] = pExtC2h->buf[0]; |
| | | pBtRsp->pParamStart[3] = pExtC2h->buf[1]; |
| | | paraLen = 4; |
| | | } |
| | | break; |
| | | case BT_REPORT_CONNECT_TARGET_BD_ADDR: { |
| | | RTW_INFO("[MPT], [Connected Target BD ADDR]\n"); |
| | | btOpcode = BT_LO_OP_GET_TARGET_BD_ADDR_L; |
| | | h2cParaLen = 0; |
| | | /* execute h2c and check respond c2h from bt fw is correct or not */ |
| | | retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); |
| | | /* construct respond status code and data. */ |
| | | if (BT_STATUS_BT_OP_SUCCESS != retStatus) { |
| | | pBtRsp->status = ((btOpcode << 8) | retStatus); |
| | | RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); |
| | | return paraLen; |
| | | } |
| | | bdAddr[5] = pExtC2h->buf[0]; |
| | | bdAddr[4] = pExtC2h->buf[1]; |
| | | bdAddr[3] = pExtC2h->buf[2]; |
| | | |
| | | btOpcode = BT_LO_OP_GET_TARGET_BD_ADDR_H; |
| | | h2cParaLen = 0; |
| | | /* execute h2c and check respond c2h from bt fw is correct or not */ |
| | | retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); |
| | | /* construct respond status code and data. */ |
| | | if (BT_STATUS_BT_OP_SUCCESS != retStatus) { |
| | | pBtRsp->status = ((btOpcode << 8) | retStatus); |
| | | RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); |
| | | return paraLen; |
| | | } |
| | | bdAddr[2] = pExtC2h->buf[0]; |
| | | bdAddr[1] = pExtC2h->buf[1]; |
| | | bdAddr[0] = pExtC2h->buf[2]; |
| | | |
| | | RTW_INFO("[MPT], Connected Target BDAddr:%s", bdAddr); |
| | | for (i = 0; i < 6; i++) |
| | | pBtRsp->pParamStart[i] = bdAddr[5 - i]; |
| | | paraLen = 6; |
| | | } |
| | | break; |
| | | default: |
| | | pBtRsp->status = BT_STATUS_PARAMETER_OUT_OF_RANGE_U; |
| | | return paraLen; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | pBtRsp->status = BT_STATUS_SUCCESS; |
| | | return paraLen; |
| | | } |
| | | |
| | | |
| | | |
| | | u2Byte |
| | | mptbt_BtSetGeneral( |
| | | IN PADAPTER Adapter, |
| | | IN PBT_REQ_CMD pBtReq, |
| | | IN PBT_RSP_CMD pBtRsp |
| | | ) |
| | | { |
| | | u1Byte h2cParaBuf[6] = {0}; |
| | | u1Byte h2cParaLen = 0; |
| | | u2Byte paraLen = 0; |
| | | u1Byte retStatus = BT_STATUS_BT_OP_SUCCESS; |
| | | u1Byte btOpcode; |
| | | u1Byte btOpcodeVer = 0; |
| | | u1Byte setType = 0; |
| | | u2Byte setParaLen = 0, validParaLen = 0; |
| | | u1Byte regType = 0, bdAddr[6] = {0}, calVal = 0; |
| | | u4Byte regAddr = 0, regValue = 0; |
| | | pu4Byte pu4Tmp; |
| | | pu2Byte pu2Tmp; |
| | | pu1Byte pu1Tmp; |
| | | |
| | | /* */ |
| | | /* check upper layer parameters */ |
| | | /* */ |
| | | |
| | | /* check upper layer opcode version */ |
| | | if (pBtReq->opCodeVer != 1) { |
| | | RTW_INFO("[MPT], Error!! Upper OP code version not match!!!\n"); |
| | | pBtRsp->status = BT_STATUS_OPCODE_U_VERSION_MISMATCH; |
| | | return paraLen; |
| | | } |
| | | /* check upper layer parameter length */ |
| | | if (pBtReq->paraLength < 1) { |
| | | RTW_INFO("[MPT], Error!! wrong parameter length=%d (should larger than 1)\n", pBtReq->paraLength); |
| | | pBtRsp->status = BT_STATUS_PARAMETER_FORMAT_ERROR_U; |
| | | return paraLen; |
| | | } |
| | | setParaLen = pBtReq->paraLength - 1; |
| | | setType = pBtReq->pParamStart[0]; |
| | | |
| | | RTW_INFO("[MPT], setType=%d, setParaLen=%d\n", setType, setParaLen); |
| | | |
| | | /* check parameter first */ |
| | | switch (setType) { |
| | | case BT_GSET_REG: |
| | | RTW_INFO("[MPT], [BT_GSET_REG]\n"); |
| | | validParaLen = 9; |
| | | if (setParaLen == validParaLen) { |
| | | btOpcode = BT_LO_OP_WRITE_REG_VALUE; |
| | | regType = pBtReq->pParamStart[1]; |
| | | pu4Tmp = (pu4Byte)&pBtReq->pParamStart[2]; |
| | | regAddr = *pu4Tmp; |
| | | pu4Tmp = (pu4Byte)&pBtReq->pParamStart[6]; |
| | | regValue = *pu4Tmp; |
| | | RTW_INFO("[MPT], BT_GSET_REG regType=0x%x, regAddr=0x%x, regValue=0x%x!!\n", |
| | | regType, regAddr, regValue); |
| | | if (regType >= BT_REG_MAX) { |
| | | pBtRsp->status = (btOpcode << 8) | BT_STATUS_PARAMETER_OUT_OF_RANGE_U; |
| | | return paraLen; |
| | | } else { |
| | | if (((BT_REG_RF == regType) && (regAddr > 0x7f)) || |
| | | ((BT_REG_MODEM == regType) && (regAddr > 0x1ff)) || |
| | | ((BT_REG_BLUEWIZE == regType) && (regAddr > 0xfff)) || |
| | | ((BT_REG_VENDOR == regType) && (regAddr > 0xfff)) || |
| | | ((BT_REG_LE == regType) && (regAddr > 0xfff))) { |
| | | pBtRsp->status = (btOpcode << 8) | BT_STATUS_PARAMETER_OUT_OF_RANGE_U; |
| | | return paraLen; |
| | | } |
| | | } |
| | | } |
| | | break; |
| | | case BT_GSET_RESET: |
| | | RTW_INFO("[MPT], [BT_GSET_RESET]\n"); |
| | | validParaLen = 0; |
| | | break; |
| | | case BT_GSET_TARGET_BD_ADDR: |
| | | RTW_INFO("[MPT], [BT_GSET_TARGET_BD_ADDR]\n"); |
| | | validParaLen = 6; |
| | | if (setParaLen == validParaLen) { |
| | | btOpcode = BT_LO_OP_SET_TARGET_BD_ADDR_H; |
| | | if ((pBtReq->pParamStart[1] == 0) && |
| | | (pBtReq->pParamStart[2] == 0) && |
| | | (pBtReq->pParamStart[3] == 0) && |
| | | (pBtReq->pParamStart[4] == 0) && |
| | | (pBtReq->pParamStart[5] == 0) && |
| | | (pBtReq->pParamStart[6] == 0)) { |
| | | RTW_INFO("[MPT], Error!! targetBDAddr=all zero\n"); |
| | | pBtRsp->status = (btOpcode << 8) | BT_STATUS_PARAMETER_OUT_OF_RANGE_U; |
| | | return paraLen; |
| | | } |
| | | if ((pBtReq->pParamStart[1] == 0xff) && |
| | | (pBtReq->pParamStart[2] == 0xff) && |
| | | (pBtReq->pParamStart[3] == 0xff) && |
| | | (pBtReq->pParamStart[4] == 0xff) && |
| | | (pBtReq->pParamStart[5] == 0xff) && |
| | | (pBtReq->pParamStart[6] == 0xff)) { |
| | | RTW_INFO("[MPT], Error!! targetBDAddr=all 0xf\n"); |
| | | pBtRsp->status = (btOpcode << 8) | BT_STATUS_PARAMETER_OUT_OF_RANGE_U; |
| | | return paraLen; |
| | | } |
| | | bdAddr[0] = pBtReq->pParamStart[6]; |
| | | bdAddr[1] = pBtReq->pParamStart[5]; |
| | | bdAddr[2] = pBtReq->pParamStart[4]; |
| | | bdAddr[3] = pBtReq->pParamStart[3]; |
| | | bdAddr[4] = pBtReq->pParamStart[2]; |
| | | bdAddr[5] = pBtReq->pParamStart[1]; |
| | | RTW_INFO("[MPT], target BDAddr:%x,%x,%x,%x,%x,%x\n", |
| | | bdAddr[0], bdAddr[1], bdAddr[2], bdAddr[3], bdAddr[4], bdAddr[5]); |
| | | } |
| | | break; |
| | | case BT_GSET_TX_PWR_FINETUNE: |
| | | RTW_INFO("[MPT], [BT_GSET_TX_PWR_FINETUNE]\n"); |
| | | validParaLen = 1; |
| | | if (setParaLen == validParaLen) { |
| | | btOpcode = BT_LO_OP_SET_TX_POWER_CALIBRATION; |
| | | calVal = pBtReq->pParamStart[1]; |
| | | if ((calVal < 1) || (calVal > 9)) { |
| | | pBtRsp->status = (btOpcode << 8) | BT_STATUS_PARAMETER_OUT_OF_RANGE_U; |
| | | return paraLen; |
| | | } |
| | | RTW_INFO("[MPT], calVal=%d\n", calVal); |
| | | } |
| | | break; |
| | | case BT_SET_TRACKING_INTERVAL: |
| | | RTW_INFO("[MPT], [BT_SET_TRACKING_INTERVAL] setParaLen =%d\n", setParaLen); |
| | | |
| | | validParaLen = 1; |
| | | if (setParaLen == validParaLen) |
| | | calVal = pBtReq->pParamStart[1]; |
| | | break; |
| | | case BT_SET_THERMAL_METER: |
| | | RTW_INFO("[MPT], [BT_SET_THERMAL_METER] setParaLen =%d\n", setParaLen); |
| | | validParaLen = 1; |
| | | if (setParaLen == validParaLen) |
| | | calVal = pBtReq->pParamStart[1]; |
| | | break; |
| | | case BT_ENABLE_CFO_TRACKING: |
| | | RTW_INFO("[MPT], [BT_ENABLE_CFO_TRACKING] setParaLen =%d\n", setParaLen); |
| | | validParaLen = 1; |
| | | if (setParaLen == validParaLen) |
| | | calVal = pBtReq->pParamStart[1]; |
| | | break; |
| | | case BT_GSET_UPDATE_BT_PATCH: |
| | | |
| | | break; |
| | | default: { |
| | | RTW_INFO("[MPT], Error!! setType=%d, out of range\n", setType); |
| | | pBtRsp->status = BT_STATUS_PARAMETER_OUT_OF_RANGE_U; |
| | | return paraLen; |
| | | } |
| | | break; |
| | | } |
| | | if (setParaLen != validParaLen) { |
| | | RTW_INFO("[MPT], Error!! wrong parameter length=%d for BT_SET_GEN_CMD cmd id=0x%x, paraLen should=0x%x\n", |
| | | setParaLen, setType, validParaLen); |
| | | pBtRsp->status = BT_STATUS_PARAMETER_FORMAT_ERROR_U; |
| | | return paraLen; |
| | | } |
| | | |
| | | /* */ |
| | | /* execute lower layer opcodes */ |
| | | /* */ |
| | | if (BT_GSET_REG == setType) { |
| | | /* fill h2c parameters */ |
| | | /* here we should write reg value first then write the address, adviced by Austin */ |
| | | btOpcode = BT_LO_OP_WRITE_REG_VALUE; |
| | | h2cParaBuf[0] = pBtReq->pParamStart[6]; |
| | | h2cParaBuf[1] = pBtReq->pParamStart[7]; |
| | | h2cParaBuf[2] = pBtReq->pParamStart[8]; |
| | | h2cParaLen = 3; |
| | | /* execute h2c and check respond c2h from bt fw is correct or not */ |
| | | retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); |
| | | /* construct respond status code and data. */ |
| | | if (BT_STATUS_BT_OP_SUCCESS != retStatus) { |
| | | pBtRsp->status = ((btOpcode << 8) | retStatus); |
| | | RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); |
| | | return paraLen; |
| | | } |
| | | |
| | | /* write reg address */ |
| | | btOpcode = BT_LO_OP_WRITE_REG_ADDR; |
| | | h2cParaBuf[0] = regType; |
| | | h2cParaBuf[1] = pBtReq->pParamStart[2]; |
| | | h2cParaBuf[2] = pBtReq->pParamStart[3]; |
| | | h2cParaLen = 3; |
| | | /* execute h2c and check respond c2h from bt fw is correct or not */ |
| | | retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); |
| | | /* construct respond status code and data. */ |
| | | if (BT_STATUS_BT_OP_SUCCESS != retStatus) { |
| | | pBtRsp->status = ((btOpcode << 8) | retStatus); |
| | | RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); |
| | | return paraLen; |
| | | } |
| | | } else if (BT_GSET_RESET == setType) { |
| | | btOpcode = BT_LO_OP_RESET; |
| | | h2cParaLen = 0; |
| | | /* execute h2c and check respond c2h from bt fw is correct or not */ |
| | | retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); |
| | | /* construct respond status code and data. */ |
| | | if (BT_STATUS_BT_OP_SUCCESS != retStatus) { |
| | | pBtRsp->status = ((btOpcode << 8) | retStatus); |
| | | RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); |
| | | return paraLen; |
| | | } |
| | | } else if (BT_GSET_TARGET_BD_ADDR == setType) { |
| | | /* fill h2c parameters */ |
| | | btOpcode = BT_LO_OP_SET_TARGET_BD_ADDR_L; |
| | | h2cParaBuf[0] = pBtReq->pParamStart[1]; |
| | | h2cParaBuf[1] = pBtReq->pParamStart[2]; |
| | | h2cParaBuf[2] = pBtReq->pParamStart[3]; |
| | | h2cParaLen = 3; |
| | | retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); |
| | | /* ckeck bt return status. */ |
| | | if (BT_STATUS_BT_OP_SUCCESS != retStatus) { |
| | | pBtRsp->status = ((btOpcode << 8) | retStatus); |
| | | RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); |
| | | return paraLen; |
| | | } |
| | | |
| | | btOpcode = BT_LO_OP_SET_TARGET_BD_ADDR_H; |
| | | h2cParaBuf[0] = pBtReq->pParamStart[4]; |
| | | h2cParaBuf[1] = pBtReq->pParamStart[5]; |
| | | h2cParaBuf[2] = pBtReq->pParamStart[6]; |
| | | h2cParaLen = 3; |
| | | retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); |
| | | /* ckeck bt return status. */ |
| | | if (BT_STATUS_BT_OP_SUCCESS != retStatus) { |
| | | pBtRsp->status = ((btOpcode << 8) | retStatus); |
| | | RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); |
| | | return paraLen; |
| | | } |
| | | } else if (BT_GSET_TX_PWR_FINETUNE == setType) { |
| | | /* fill h2c parameters */ |
| | | btOpcode = BT_LO_OP_SET_TX_POWER_CALIBRATION; |
| | | h2cParaBuf[0] = calVal; |
| | | h2cParaLen = 1; |
| | | retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); |
| | | /* ckeck bt return status. */ |
| | | if (BT_STATUS_BT_OP_SUCCESS != retStatus) { |
| | | pBtRsp->status = ((btOpcode << 8) | retStatus); |
| | | RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); |
| | | return paraLen; |
| | | } |
| | | } else if (BT_SET_TRACKING_INTERVAL == setType) { |
| | | /* BT_LO_OP_SET_TRACKING_INTERVAL = 0x22, */ |
| | | /* BT_LO_OP_SET_THERMAL_METER = 0x23, */ |
| | | /* BT_LO_OP_ENABLE_CFO_TRACKING = 0x24, */ |
| | | btOpcode = BT_LO_OP_SET_TRACKING_INTERVAL; |
| | | h2cParaBuf[0] = calVal; |
| | | h2cParaLen = 1; |
| | | retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); |
| | | /* ckeck bt return status. */ |
| | | if (BT_STATUS_BT_OP_SUCCESS != retStatus) { |
| | | pBtRsp->status = ((btOpcode << 8) | retStatus); |
| | | RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); |
| | | return paraLen; |
| | | } |
| | | } else if (BT_SET_THERMAL_METER == setType) { |
| | | btOpcode = BT_LO_OP_SET_THERMAL_METER; |
| | | h2cParaBuf[0] = calVal; |
| | | h2cParaLen = 1; |
| | | retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); |
| | | /* ckeck bt return status. */ |
| | | if (BT_STATUS_BT_OP_SUCCESS != retStatus) { |
| | | pBtRsp->status = ((btOpcode << 8) | retStatus); |
| | | RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); |
| | | return paraLen; |
| | | } |
| | | } else if (BT_ENABLE_CFO_TRACKING == setType) { |
| | | btOpcode = BT_LO_OP_ENABLE_CFO_TRACKING; |
| | | h2cParaBuf[0] = calVal; |
| | | h2cParaLen = 1; |
| | | retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); |
| | | /* ckeck bt return status. */ |
| | | if (BT_STATUS_BT_OP_SUCCESS != retStatus) { |
| | | pBtRsp->status = ((btOpcode << 8) | retStatus); |
| | | RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); |
| | | return paraLen; |
| | | } |
| | | } |
| | | |
| | | pBtRsp->status = BT_STATUS_SUCCESS; |
| | | return paraLen; |
| | | } |
| | | |
| | | |
| | | |
| | | u2Byte |
| | | mptbt_BtSetTxRxPars( |
| | | IN PADAPTER Adapter, |
| | | IN PBT_REQ_CMD pBtReq, |
| | | IN PBT_RSP_CMD pBtRsp |
| | | ) |
| | | { |
| | | u1Byte h2cParaBuf[6] = {0}; |
| | | u1Byte h2cParaLen = 0; |
| | | u2Byte paraLen = 0; |
| | | u1Byte retStatus = BT_STATUS_BT_OP_SUCCESS; |
| | | u1Byte btOpcode; |
| | | u1Byte btOpcodeVer = 0; |
| | | PBT_TXRX_PARAMETERS pTxRxPars = (PBT_TXRX_PARAMETERS)&pBtReq->pParamStart[0]; |
| | | u2Byte lenTxRx = sizeof(BT_TXRX_PARAMETERS); |
| | | u1Byte i; |
| | | u1Byte bdAddr[6] = {0}; |
| | | |
| | | /* */ |
| | | /* check upper layer parameters */ |
| | | /* */ |
| | | |
| | | /* 1. check upper layer opcode version */ |
| | | if (pBtReq->opCodeVer != 1) { |
| | | RTW_INFO("[MPT], Error!! Upper OP code version not match!!!\n"); |
| | | pBtRsp->status = BT_STATUS_OPCODE_U_VERSION_MISMATCH; |
| | | return paraLen; |
| | | } |
| | | /* 2. check upper layer parameter length */ |
| | | if (pBtReq->paraLength == sizeof(BT_TXRX_PARAMETERS)) { |
| | | RTW_INFO("[MPT], pTxRxPars->txrxChannel=0x%x\n", pTxRxPars->txrxChannel); |
| | | RTW_INFO("[MPT], pTxRxPars->txrxTxPktCnt=0x%8x\n", pTxRxPars->txrxTxPktCnt); |
| | | RTW_INFO("[MPT], pTxRxPars->txrxTxPktInterval=0x%x\n", pTxRxPars->txrxTxPktInterval); |
| | | RTW_INFO("[MPT], pTxRxPars->txrxPayloadType=0x%x\n", pTxRxPars->txrxPayloadType); |
| | | RTW_INFO("[MPT], pTxRxPars->txrxPktType=0x%x\n", pTxRxPars->txrxPktType); |
| | | RTW_INFO("[MPT], pTxRxPars->txrxPayloadLen=0x%x\n", pTxRxPars->txrxPayloadLen); |
| | | RTW_INFO("[MPT], pTxRxPars->txrxPktHeader=0x%x\n", pTxRxPars->txrxPktHeader); |
| | | RTW_INFO("[MPT], pTxRxPars->txrxWhitenCoeff=0x%x\n", pTxRxPars->txrxWhitenCoeff); |
| | | bdAddr[0] = pTxRxPars->txrxBdaddr[5]; |
| | | bdAddr[1] = pTxRxPars->txrxBdaddr[4]; |
| | | bdAddr[2] = pTxRxPars->txrxBdaddr[3]; |
| | | bdAddr[3] = pTxRxPars->txrxBdaddr[2]; |
| | | bdAddr[4] = pTxRxPars->txrxBdaddr[1]; |
| | | bdAddr[5] = pTxRxPars->txrxBdaddr[0]; |
| | | RTW_INFO("[MPT], pTxRxPars->txrxBdaddr: %s", &bdAddr[0]); |
| | | RTW_INFO("[MPT], pTxRxPars->txrxTxGainIndex=0x%x\n", pTxRxPars->txrxTxGainIndex); |
| | | } else { |
| | | RTW_INFO("[MPT], Error!! pBtReq->paraLength=%d, correct Len=%d\n", pBtReq->paraLength, lenTxRx); |
| | | pBtRsp->status = BT_STATUS_PARAMETER_FORMAT_ERROR_U; |
| | | return paraLen; |
| | | } |
| | | |
| | | /* */ |
| | | /* execute lower layer opcodes */ |
| | | /* */ |
| | | |
| | | /* fill h2c parameters */ |
| | | btOpcode = BT_LO_OP_SET_PKT_HEADER; |
| | | if (pTxRxPars->txrxPktHeader > 0x3ffff) { |
| | | RTW_INFO("[MPT], Error!! pTxRxPars->txrxPktHeader=0x%x is out of range, (should be between 0x0~0x3ffff)\n", pTxRxPars->txrxPktHeader); |
| | | pBtRsp->status = (btOpcode << 8) | BT_STATUS_PARAMETER_OUT_OF_RANGE_U; |
| | | return paraLen; |
| | | } else { |
| | | h2cParaBuf[0] = (u1Byte)(pTxRxPars->txrxPktHeader & 0xff); |
| | | h2cParaBuf[1] = (u1Byte)((pTxRxPars->txrxPktHeader & 0xff00) >> 8); |
| | | h2cParaBuf[2] = (u1Byte)((pTxRxPars->txrxPktHeader & 0xff0000) >> 16); |
| | | h2cParaLen = 3; |
| | | retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); |
| | | } |
| | | |
| | | /* ckeck bt return status. */ |
| | | if (BT_STATUS_BT_OP_SUCCESS != retStatus) { |
| | | pBtRsp->status = ((btOpcode << 8) | retStatus); |
| | | RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); |
| | | return paraLen; |
| | | } |
| | | |
| | | /* fill h2c parameters */ |
| | | btOpcode = BT_LO_OP_SET_PKT_TYPE_LEN; |
| | | { |
| | | u2Byte payloadLenLimit = 0; |
| | | switch (pTxRxPars->txrxPktType) { |
| | | case MP_BT_PKT_DH1: |
| | | payloadLenLimit = 27 * 8; |
| | | break; |
| | | case MP_BT_PKT_DH3: |
| | | payloadLenLimit = 183 * 8; |
| | | break; |
| | | case MP_BT_PKT_DH5: |
| | | payloadLenLimit = 339 * 8; |
| | | break; |
| | | case MP_BT_PKT_2DH1: |
| | | payloadLenLimit = 54 * 8; |
| | | break; |
| | | case MP_BT_PKT_2DH3: |
| | | payloadLenLimit = 367 * 8; |
| | | break; |
| | | case MP_BT_PKT_2DH5: |
| | | payloadLenLimit = 679 * 8; |
| | | break; |
| | | case MP_BT_PKT_3DH1: |
| | | payloadLenLimit = 83 * 8; |
| | | break; |
| | | case MP_BT_PKT_3DH3: |
| | | payloadLenLimit = 552 * 8; |
| | | break; |
| | | case MP_BT_PKT_3DH5: |
| | | payloadLenLimit = 1021 * 8; |
| | | break; |
| | | case MP_BT_PKT_LE: |
| | | payloadLenLimit = 39 * 8; |
| | | break; |
| | | default: { |
| | | RTW_INFO("[MPT], Error!! Unknown pTxRxPars->txrxPktType=0x%x\n", pTxRxPars->txrxPktType); |
| | | pBtRsp->status = (btOpcode << 8) | BT_STATUS_PARAMETER_OUT_OF_RANGE_U; |
| | | return paraLen; |
| | | } |
| | | break; |
| | | } |
| | | |
| | | if (pTxRxPars->txrxPayloadLen > payloadLenLimit) { |
| | | RTW_INFO("[MPT], Error!! pTxRxPars->txrxPayloadLen=0x%x, (should smaller than %d)\n", |
| | | pTxRxPars->txrxPayloadLen, payloadLenLimit); |
| | | pBtRsp->status = (btOpcode << 8) | BT_STATUS_PARAMETER_OUT_OF_RANGE_U; |
| | | return paraLen; |
| | | } |
| | | |
| | | h2cParaBuf[0] = pTxRxPars->txrxPktType; |
| | | h2cParaBuf[1] = (u1Byte)((pTxRxPars->txrxPayloadLen & 0xff)); |
| | | h2cParaBuf[2] = (u1Byte)((pTxRxPars->txrxPayloadLen & 0xff00) >> 8); |
| | | h2cParaLen = 3; |
| | | retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); |
| | | } |
| | | |
| | | /* ckeck bt return status. */ |
| | | if (BT_STATUS_BT_OP_SUCCESS != retStatus) { |
| | | pBtRsp->status = ((btOpcode << 8) | retStatus); |
| | | RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); |
| | | return paraLen; |
| | | } |
| | | |
| | | /* fill h2c parameters */ |
| | | btOpcode = BT_LO_OP_SET_PKT_CNT_L_PL_TYPE; |
| | | if (pTxRxPars->txrxPayloadType > MP_BT_PAYLOAD_MAX) { |
| | | RTW_INFO("[MPT], Error!! pTxRxPars->txrxPayloadType=0x%x, (should be between 0~4)\n", pTxRxPars->txrxPayloadType); |
| | | pBtRsp->status = (btOpcode << 8) | BT_STATUS_PARAMETER_OUT_OF_RANGE_U; |
| | | return paraLen; |
| | | } else { |
| | | h2cParaBuf[0] = (u1Byte)((pTxRxPars->txrxTxPktCnt & 0xff)); |
| | | h2cParaBuf[1] = (u1Byte)((pTxRxPars->txrxTxPktCnt & 0xff00) >> 8); |
| | | h2cParaBuf[2] = pTxRxPars->txrxPayloadType; |
| | | h2cParaLen = 3; |
| | | retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); |
| | | } |
| | | |
| | | /* ckeck bt return status. */ |
| | | if (BT_STATUS_BT_OP_SUCCESS != retStatus) { |
| | | pBtRsp->status = ((btOpcode << 8) | retStatus); |
| | | RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); |
| | | return paraLen; |
| | | } |
| | | |
| | | /* fill h2c parameters */ |
| | | btOpcode = BT_LO_OP_SET_PKT_CNT_H_PKT_INTV; |
| | | if (pTxRxPars->txrxTxPktInterval > 15) { |
| | | RTW_INFO("[MPT], Error!! pTxRxPars->txrxTxPktInterval=0x%x, (should be between 0~15)\n", pTxRxPars->txrxTxPktInterval); |
| | | pBtRsp->status = (btOpcode << 8) | BT_STATUS_PARAMETER_OUT_OF_RANGE_U; |
| | | return paraLen; |
| | | } else { |
| | | h2cParaBuf[0] = (u1Byte)((pTxRxPars->txrxTxPktCnt & 0xff0000) >> 16); |
| | | h2cParaBuf[1] = (u1Byte)((pTxRxPars->txrxTxPktCnt & 0xff000000) >> 24); |
| | | h2cParaBuf[2] = pTxRxPars->txrxTxPktInterval; |
| | | h2cParaLen = 3; |
| | | retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); |
| | | } |
| | | |
| | | /* ckeck bt return status. */ |
| | | if (BT_STATUS_BT_OP_SUCCESS != retStatus) { |
| | | pBtRsp->status = ((btOpcode << 8) | retStatus); |
| | | RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); |
| | | return paraLen; |
| | | } |
| | | |
| | | /* fill h2c parameters */ |
| | | btOpcode = BT_LO_OP_SET_WHITENCOEFF; |
| | | { |
| | | h2cParaBuf[0] = pTxRxPars->txrxWhitenCoeff; |
| | | h2cParaLen = 1; |
| | | retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); |
| | | } |
| | | |
| | | /* ckeck bt return status. */ |
| | | if (BT_STATUS_BT_OP_SUCCESS != retStatus) { |
| | | pBtRsp->status = ((btOpcode << 8) | retStatus); |
| | | RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); |
| | | return paraLen; |
| | | } |
| | | |
| | | |
| | | /* fill h2c parameters */ |
| | | btOpcode = BT_LO_OP_SET_CHNL_TX_GAIN; |
| | | if ((pTxRxPars->txrxChannel > 78) || |
| | | (pTxRxPars->txrxTxGainIndex > 7)) { |
| | | RTW_INFO("[MPT], Error!! pTxRxPars->txrxChannel=0x%x, (should be between 0~78)\n", pTxRxPars->txrxChannel); |
| | | RTW_INFO("[MPT], Error!! pTxRxPars->txrxTxGainIndex=0x%x, (should be between 0~7)\n", pTxRxPars->txrxTxGainIndex); |
| | | pBtRsp->status = (btOpcode << 8) | BT_STATUS_PARAMETER_OUT_OF_RANGE_U; |
| | | return paraLen; |
| | | } else { |
| | | h2cParaBuf[0] = pTxRxPars->txrxChannel; |
| | | h2cParaBuf[1] = pTxRxPars->txrxTxGainIndex; |
| | | h2cParaLen = 2; |
| | | retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); |
| | | } |
| | | |
| | | /* ckeck bt return status. */ |
| | | if (BT_STATUS_BT_OP_SUCCESS != retStatus) { |
| | | pBtRsp->status = ((btOpcode << 8) | retStatus); |
| | | RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); |
| | | return paraLen; |
| | | } |
| | | |
| | | /* fill h2c parameters */ |
| | | btOpcode = BT_LO_OP_SET_BD_ADDR_L; |
| | | if ((pTxRxPars->txrxBdaddr[0] == 0) && |
| | | (pTxRxPars->txrxBdaddr[1] == 0) && |
| | | (pTxRxPars->txrxBdaddr[2] == 0) && |
| | | (pTxRxPars->txrxBdaddr[3] == 0) && |
| | | (pTxRxPars->txrxBdaddr[4] == 0) && |
| | | (pTxRxPars->txrxBdaddr[5] == 0)) { |
| | | RTW_INFO("[MPT], Error!! pTxRxPars->txrxBdaddr=all zero\n"); |
| | | pBtRsp->status = (btOpcode << 8) | BT_STATUS_PARAMETER_OUT_OF_RANGE_U; |
| | | return paraLen; |
| | | } |
| | | if ((pTxRxPars->txrxBdaddr[0] == 0xff) && |
| | | (pTxRxPars->txrxBdaddr[1] == 0xff) && |
| | | (pTxRxPars->txrxBdaddr[2] == 0xff) && |
| | | (pTxRxPars->txrxBdaddr[3] == 0xff) && |
| | | (pTxRxPars->txrxBdaddr[4] == 0xff) && |
| | | (pTxRxPars->txrxBdaddr[5] == 0xff)) { |
| | | RTW_INFO("[MPT], Error!! pTxRxPars->txrxBdaddr=all 0xf\n"); |
| | | pBtRsp->status = (btOpcode << 8) | BT_STATUS_PARAMETER_OUT_OF_RANGE_U; |
| | | return paraLen; |
| | | } |
| | | |
| | | { |
| | | h2cParaBuf[0] = pTxRxPars->txrxBdaddr[0]; |
| | | h2cParaBuf[1] = pTxRxPars->txrxBdaddr[1]; |
| | | h2cParaBuf[2] = pTxRxPars->txrxBdaddr[2]; |
| | | h2cParaLen = 3; |
| | | retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); |
| | | } |
| | | /* ckeck bt return status. */ |
| | | if (BT_STATUS_BT_OP_SUCCESS != retStatus) { |
| | | pBtRsp->status = ((btOpcode << 8) | retStatus); |
| | | RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); |
| | | return paraLen; |
| | | } |
| | | |
| | | btOpcode = BT_LO_OP_SET_BD_ADDR_H; |
| | | { |
| | | h2cParaBuf[0] = pTxRxPars->txrxBdaddr[3]; |
| | | h2cParaBuf[1] = pTxRxPars->txrxBdaddr[4]; |
| | | h2cParaBuf[2] = pTxRxPars->txrxBdaddr[5]; |
| | | h2cParaLen = 3; |
| | | retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); |
| | | } |
| | | /* ckeck bt return status. */ |
| | | if (BT_STATUS_BT_OP_SUCCESS != retStatus) { |
| | | pBtRsp->status = ((btOpcode << 8) | retStatus); |
| | | RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); |
| | | return paraLen; |
| | | } |
| | | |
| | | pBtRsp->status = BT_STATUS_SUCCESS; |
| | | return paraLen; |
| | | } |
| | | |
| | | |
| | | |
| | | u2Byte |
| | | mptbt_BtTestCtrl( |
| | | IN PADAPTER Adapter, |
| | | IN PBT_REQ_CMD pBtReq, |
| | | IN PBT_RSP_CMD pBtRsp |
| | | ) |
| | | { |
| | | u1Byte h2cParaBuf[6] = {0}; |
| | | u1Byte h2cParaLen = 0; |
| | | u2Byte paraLen = 0; |
| | | u1Byte retStatus = BT_STATUS_BT_OP_SUCCESS; |
| | | u1Byte btOpcode; |
| | | u1Byte btOpcodeVer = 0; |
| | | u1Byte testCtrl = 0; |
| | | |
| | | /* */ |
| | | /* check upper layer parameters */ |
| | | /* */ |
| | | |
| | | /* 1. check upper layer opcode version */ |
| | | if (pBtReq->opCodeVer != 1) { |
| | | RTW_INFO("[MPT], Error!! Upper OP code version not match!!!\n"); |
| | | pBtRsp->status = BT_STATUS_OPCODE_U_VERSION_MISMATCH; |
| | | return paraLen; |
| | | } |
| | | /* 2. check upper layer parameter length */ |
| | | if (1 == pBtReq->paraLength) { |
| | | testCtrl = pBtReq->pParamStart[0]; |
| | | RTW_INFO("[MPT], testCtrl=%d\n", testCtrl); |
| | | } else { |
| | | RTW_INFO("[MPT], Error!! wrong parameter length=%d (should be 1)\n", pBtReq->paraLength); |
| | | pBtRsp->status = BT_STATUS_PARAMETER_FORMAT_ERROR_U; |
| | | return paraLen; |
| | | } |
| | | |
| | | /* */ |
| | | /* execute lower layer opcodes */ |
| | | /* */ |
| | | |
| | | /* 1. fill h2c parameters */ |
| | | /* check bt mode */ |
| | | btOpcode = BT_LO_OP_TEST_CTRL; |
| | | if (testCtrl >= MP_BT_TEST_MAX) { |
| | | RTW_INFO("[MPT], Error!! testCtrl=0x%x, (should be between smaller or equal to 0x%x)\n", |
| | | testCtrl, MP_BT_TEST_MAX - 1); |
| | | pBtRsp->status = BT_STATUS_PARAMETER_OUT_OF_RANGE_U; |
| | | return paraLen; |
| | | } else { |
| | | h2cParaBuf[0] = testCtrl; |
| | | h2cParaLen = 1; |
| | | retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); |
| | | } |
| | | |
| | | /* 3. construct respond status code and data. */ |
| | | if (BT_STATUS_BT_OP_SUCCESS != retStatus) { |
| | | pBtRsp->status = ((btOpcode << 8) | retStatus); |
| | | RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); |
| | | return paraLen; |
| | | } |
| | | |
| | | pBtRsp->status = BT_STATUS_SUCCESS; |
| | | return paraLen; |
| | | } |
| | | |
| | | |
| | | u2Byte |
| | | mptbt_TestBT( |
| | | IN PADAPTER Adapter, |
| | | IN PBT_REQ_CMD pBtReq, |
| | | IN PBT_RSP_CMD pBtRsp |
| | | ) |
| | | { |
| | | |
| | | u1Byte h2cParaBuf[6] = {0}; |
| | | u1Byte h2cParaLen = 0; |
| | | u2Byte paraLen = 0; |
| | | u1Byte retStatus = BT_STATUS_BT_OP_SUCCESS; |
| | | u1Byte btOpcode; |
| | | u1Byte btOpcodeVer = 0; |
| | | u1Byte testCtrl = 0; |
| | | |
| | | /* 1. fill h2c parameters */ |
| | | btOpcode = 0x11; |
| | | h2cParaBuf[0] = 0x11; |
| | | h2cParaBuf[1] = 0x0; |
| | | h2cParaBuf[2] = 0x0; |
| | | h2cParaBuf[3] = 0x0; |
| | | h2cParaBuf[4] = 0x0; |
| | | h2cParaLen = 1; |
| | | /* retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); */ |
| | | retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, h2cParaBuf, h2cParaLen); |
| | | |
| | | |
| | | /* 3. construct respond status code and data. */ |
| | | if (BT_STATUS_BT_OP_SUCCESS != retStatus) { |
| | | pBtRsp->status = ((btOpcode << 8) | retStatus); |
| | | RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); |
| | | return paraLen; |
| | | } |
| | | |
| | | pBtRsp->status = BT_STATUS_SUCCESS; |
| | | return paraLen; |
| | | } |
| | | |
| | | VOID |
| | | mptbt_BtControlProcess( |
| | | PADAPTER Adapter, |
| | | PVOID pInBuf |
| | | ) |
| | | { |
| | | u1Byte H2C_Parameter[6] = {0}; |
| | | PBT_H2C pH2c = (PBT_H2C)&H2C_Parameter[0]; |
| | | PMPT_CONTEXT pMptCtx = &(Adapter->mppriv.mpt_ctx); |
| | | PBT_REQ_CMD pBtReq = (PBT_REQ_CMD)pInBuf; |
| | | PBT_RSP_CMD pBtRsp; |
| | | u1Byte i; |
| | | |
| | | |
| | | RTW_INFO("[MPT], mptbt_BtControlProcess()=========>\n"); |
| | | |
| | | RTW_INFO("[MPT], input opCodeVer=%d\n", pBtReq->opCodeVer); |
| | | RTW_INFO("[MPT], input OpCode=%d\n", pBtReq->OpCode); |
| | | RTW_INFO("[MPT], paraLength=%d\n", pBtReq->paraLength); |
| | | if (pBtReq->paraLength) { |
| | | /* RTW_INFO("[MPT], parameters(hex):0x%x %d\n",&pBtReq->pParamStart[0], pBtReq->paraLength); */ |
| | | } |
| | | |
| | | _rtw_memset((void *)pMptCtx->mptOutBuf, 0, 100); |
| | | pMptCtx->mptOutLen = 4; /* length of (BT_RSP_CMD.status+BT_RSP_CMD.paraLength) */ |
| | | |
| | | pBtRsp = (PBT_RSP_CMD)pMptCtx->mptOutBuf; |
| | | pBtRsp->status = BT_STATUS_SUCCESS; |
| | | pBtRsp->paraLength = 0x0; |
| | | |
| | | /* The following we should maintain the User OP codes sent by upper layer */ |
| | | switch (pBtReq->OpCode) { |
| | | case BT_UP_OP_BT_READY: |
| | | RTW_INFO("[MPT], OPcode : [BT_READY]\n"); |
| | | pBtRsp->paraLength = mptbt_BtReady(Adapter, pBtReq, pBtRsp); |
| | | break; |
| | | case BT_UP_OP_BT_SET_MODE: |
| | | RTW_INFO("[MPT], OPcode : [BT_SET_MODE]\n"); |
| | | pBtRsp->paraLength = mptbt_BtSetMode(Adapter, pBtReq, pBtRsp); |
| | | break; |
| | | case BT_UP_OP_BT_SET_TX_RX_PARAMETER: |
| | | RTW_INFO("[MPT], OPcode : [BT_SET_TXRX_PARAMETER]\n"); |
| | | pBtRsp->paraLength = mptbt_BtSetTxRxPars(Adapter, pBtReq, pBtRsp); |
| | | break; |
| | | case BT_UP_OP_BT_SET_GENERAL: |
| | | RTW_INFO("[MPT], OPcode : [BT_SET_GENERAL]\n"); |
| | | pBtRsp->paraLength = mptbt_BtSetGeneral(Adapter, pBtReq, pBtRsp); |
| | | break; |
| | | case BT_UP_OP_BT_GET_GENERAL: |
| | | RTW_INFO("[MPT], OPcode : [BT_GET_GENERAL]\n"); |
| | | pBtRsp->paraLength = mptbt_BtGetGeneral(Adapter, pBtReq, pBtRsp); |
| | | break; |
| | | case BT_UP_OP_BT_TEST_CTRL: |
| | | RTW_INFO("[MPT], OPcode : [BT_TEST_CTRL]\n"); |
| | | pBtRsp->paraLength = mptbt_BtTestCtrl(Adapter, pBtReq, pBtRsp); |
| | | break; |
| | | case BT_UP_OP_TEST_BT: |
| | | RTW_INFO("[MPT], OPcode : [TEST_BT]\n"); |
| | | pBtRsp->paraLength = mptbt_TestBT(Adapter, pBtReq, pBtRsp); |
| | | break; |
| | | default: |
| | | RTW_INFO("[MPT], Error!! OPcode : UNDEFINED!!!!\n"); |
| | | pBtRsp->status = BT_STATUS_UNKNOWN_OPCODE_U; |
| | | pBtRsp->paraLength = 0x0; |
| | | break; |
| | | } |
| | | |
| | | pMptCtx->mptOutLen += pBtRsp->paraLength; |
| | | |
| | | RTW_INFO("[MPT], pMptCtx->mptOutLen=%d, pBtRsp->paraLength=%d\n", pMptCtx->mptOutLen, pBtRsp->paraLength); |
| | | RTW_INFO("[MPT], mptbt_BtControlProcess()<=========\n"); |
| | | } |
| | | |
| | | #endif |
New file |
| | |
| | | /****************************************************************************** |
| | | * |
| | | * Copyright(c) 2013 Realtek Corporation. All rights reserved. |
| | | * |
| | | * This program is free software; you can redistribute it and/or modify it |
| | | * under the terms of version 2 of the GNU General Public License as |
| | | * published by the Free Software Foundation. |
| | | * |
| | | * This program is distributed in the hope that it will be useful, but WITHOUT |
| | | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| | | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
| | | * more details. |
| | | * |
| | | * You should have received a copy of the GNU General Public License along with |
| | | * this program; if not, write to the Free Software Foundation, Inc., |
| | | * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA |
| | | * |
| | | * |
| | | ******************************************************************************/ |
| | | #ifdef CONFIG_BT_COEXIST |
| | | |
| | | #include <drv_types.h> |
| | | #include <hal_btcoex.h> |
| | | #include <hal_data.h> |
| | | |
| | | |
| | | void rtw_btcoex_Initialize(PADAPTER padapter) |
| | | { |
| | | hal_btcoex_Initialize(padapter); |
| | | } |
| | | |
| | | void rtw_btcoex_PowerOnSetting(PADAPTER padapter) |
| | | { |
| | | hal_btcoex_PowerOnSetting(padapter); |
| | | } |
| | | |
| | | void rtw_btcoex_PreLoadFirmware(PADAPTER padapter) |
| | | { |
| | | hal_btcoex_PreLoadFirmware(padapter); |
| | | } |
| | | |
| | | void rtw_btcoex_HAL_Initialize(PADAPTER padapter, u8 bWifiOnly) |
| | | { |
| | | hal_btcoex_InitHwConfig(padapter, bWifiOnly); |
| | | } |
| | | |
| | | void rtw_btcoex_IpsNotify(PADAPTER padapter, u8 type) |
| | | { |
| | | PHAL_DATA_TYPE pHalData; |
| | | |
| | | pHalData = GET_HAL_DATA(padapter); |
| | | if (_FALSE == pHalData->EEPROMBluetoothCoexist) |
| | | return; |
| | | |
| | | hal_btcoex_IpsNotify(padapter, type); |
| | | } |
| | | |
| | | void rtw_btcoex_LpsNotify(PADAPTER padapter, u8 type) |
| | | { |
| | | PHAL_DATA_TYPE pHalData; |
| | | |
| | | pHalData = GET_HAL_DATA(padapter); |
| | | if (_FALSE == pHalData->EEPROMBluetoothCoexist) |
| | | return; |
| | | |
| | | hal_btcoex_LpsNotify(padapter, type); |
| | | } |
| | | |
| | | void rtw_btcoex_ScanNotify(PADAPTER padapter, u8 type) |
| | | { |
| | | PHAL_DATA_TYPE pHalData; |
| | | #ifdef CONFIG_BT_COEXIST_SOCKET_TRX |
| | | struct bt_coex_info *pcoex_info = &padapter->coex_info; |
| | | PBT_MGNT pBtMgnt = &pcoex_info->BtMgnt; |
| | | #endif /* CONFIG_BT_COEXIST_SOCKET_TRX */ |
| | | |
| | | pHalData = GET_HAL_DATA(padapter); |
| | | if (_FALSE == pHalData->EEPROMBluetoothCoexist) |
| | | return; |
| | | |
| | | if (_FALSE == type) { |
| | | #ifdef CONFIG_CONCURRENT_MODE |
| | | if (rtw_mi_buddy_check_fwstate(padapter, WIFI_SITE_MONITOR)) |
| | | return; |
| | | #endif |
| | | |
| | | if (DEV_MGMT_TX_NUM(adapter_to_dvobj(padapter)) |
| | | || DEV_ROCH_NUM(adapter_to_dvobj(padapter))) |
| | | return; |
| | | } |
| | | |
| | | #ifdef CONFIG_BT_COEXIST_SOCKET_TRX |
| | | if (pBtMgnt->ExtConfig.bEnableWifiScanNotify) |
| | | rtw_btcoex_SendScanNotify(padapter, type); |
| | | #endif /* CONFIG_BT_COEXIST_SOCKET_TRX */ |
| | | |
| | | hal_btcoex_ScanNotify(padapter, type); |
| | | } |
| | | |
| | | void rtw_btcoex_ConnectNotify(PADAPTER padapter, u8 action) |
| | | { |
| | | PHAL_DATA_TYPE pHalData; |
| | | |
| | | pHalData = GET_HAL_DATA(padapter); |
| | | if (_FALSE == pHalData->EEPROMBluetoothCoexist) |
| | | return; |
| | | |
| | | #ifdef DBG_CONFIG_ERROR_RESET |
| | | if (_TRUE == rtw_hal_sreset_inprogress(padapter)) { |
| | | RTW_INFO(FUNC_ADPT_FMT ": [BTCoex] under reset, skip notify!\n", |
| | | FUNC_ADPT_ARG(padapter)); |
| | | return; |
| | | } |
| | | #endif /* DBG_CONFIG_ERROR_RESET */ |
| | | |
| | | #ifdef CONFIG_CONCURRENT_MODE |
| | | if (_FALSE == action) { |
| | | if (rtw_mi_buddy_check_fwstate(padapter, WIFI_UNDER_LINKING)) |
| | | return; |
| | | } |
| | | #endif |
| | | |
| | | hal_btcoex_ConnectNotify(padapter, action); |
| | | } |
| | | |
| | | void rtw_btcoex_MediaStatusNotify(PADAPTER padapter, u8 mediaStatus) |
| | | { |
| | | PHAL_DATA_TYPE pHalData; |
| | | |
| | | pHalData = GET_HAL_DATA(padapter); |
| | | if (_FALSE == pHalData->EEPROMBluetoothCoexist) |
| | | return; |
| | | |
| | | #ifdef DBG_CONFIG_ERROR_RESET |
| | | if (_TRUE == rtw_hal_sreset_inprogress(padapter)) { |
| | | RTW_INFO(FUNC_ADPT_FMT ": [BTCoex] under reset, skip notify!\n", |
| | | FUNC_ADPT_ARG(padapter)); |
| | | return; |
| | | } |
| | | #endif /* DBG_CONFIG_ERROR_RESET */ |
| | | |
| | | #ifdef CONFIG_CONCURRENT_MODE |
| | | if (RT_MEDIA_DISCONNECT == mediaStatus) { |
| | | if (rtw_mi_buddy_check_fwstate(padapter, WIFI_ASOC_STATE)) |
| | | return; |
| | | } |
| | | #endif /* CONFIG_CONCURRENT_MODE */ |
| | | |
| | | if ((RT_MEDIA_CONNECT == mediaStatus) |
| | | && (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == _TRUE)) |
| | | rtw_hal_set_hwreg(padapter, HW_VAR_DL_RSVD_PAGE, NULL); |
| | | |
| | | hal_btcoex_MediaStatusNotify(padapter, mediaStatus); |
| | | } |
| | | |
| | | void rtw_btcoex_SpecialPacketNotify(PADAPTER padapter, u8 pktType) |
| | | { |
| | | PHAL_DATA_TYPE pHalData; |
| | | |
| | | pHalData = GET_HAL_DATA(padapter); |
| | | if (_FALSE == pHalData->EEPROMBluetoothCoexist) |
| | | return; |
| | | |
| | | hal_btcoex_SpecialPacketNotify(padapter, pktType); |
| | | } |
| | | |
| | | void rtw_btcoex_IQKNotify(PADAPTER padapter, u8 state) |
| | | { |
| | | PHAL_DATA_TYPE pHalData; |
| | | |
| | | pHalData = GET_HAL_DATA(padapter); |
| | | if (_FALSE == pHalData->EEPROMBluetoothCoexist) |
| | | return; |
| | | |
| | | hal_btcoex_IQKNotify(padapter, state); |
| | | } |
| | | |
| | | void rtw_btcoex_BtInfoNotify(PADAPTER padapter, u8 length, u8 *tmpBuf) |
| | | { |
| | | PHAL_DATA_TYPE pHalData; |
| | | |
| | | pHalData = GET_HAL_DATA(padapter); |
| | | if (_FALSE == pHalData->EEPROMBluetoothCoexist) |
| | | return; |
| | | |
| | | hal_btcoex_BtInfoNotify(padapter, length, tmpBuf); |
| | | } |
| | | |
| | | void rtw_btcoex_BtMpRptNotify(PADAPTER padapter, u8 length, u8 *tmpBuf) |
| | | { |
| | | PHAL_DATA_TYPE pHalData; |
| | | |
| | | pHalData = GET_HAL_DATA(padapter); |
| | | if (_FALSE == pHalData->EEPROMBluetoothCoexist) |
| | | return; |
| | | |
| | | if (padapter->registrypriv.mp_mode == 1) |
| | | return; |
| | | |
| | | hal_btcoex_BtMpRptNotify(padapter, length, tmpBuf); |
| | | } |
| | | |
| | | void rtw_btcoex_SuspendNotify(PADAPTER padapter, u8 state) |
| | | { |
| | | PHAL_DATA_TYPE pHalData; |
| | | |
| | | pHalData = GET_HAL_DATA(padapter); |
| | | if (_FALSE == pHalData->EEPROMBluetoothCoexist) |
| | | return; |
| | | |
| | | hal_btcoex_SuspendNotify(padapter, state); |
| | | } |
| | | |
| | | void rtw_btcoex_HaltNotify(PADAPTER padapter) |
| | | { |
| | | PHAL_DATA_TYPE pHalData; |
| | | u8 do_halt = 1; |
| | | |
| | | pHalData = GET_HAL_DATA(padapter); |
| | | if (_FALSE == pHalData->EEPROMBluetoothCoexist) |
| | | do_halt = 0; |
| | | |
| | | if (_FALSE == padapter->bup) { |
| | | RTW_INFO(FUNC_ADPT_FMT ": bup=%d Skip!\n", |
| | | FUNC_ADPT_ARG(padapter), padapter->bup); |
| | | do_halt = 0; |
| | | } |
| | | |
| | | if (rtw_is_surprise_removed(padapter)) { |
| | | RTW_INFO(FUNC_ADPT_FMT ": bSurpriseRemoved=%s Skip!\n", |
| | | FUNC_ADPT_ARG(padapter), rtw_is_surprise_removed(padapter) ? "True" : "False"); |
| | | do_halt = 0; |
| | | } |
| | | |
| | | hal_btcoex_HaltNotify(padapter, do_halt); |
| | | } |
| | | |
| | | void rtw_btcoex_switchband_notify(u8 under_scan, u8 band_type) |
| | | { |
| | | hal_btcoex_switchband_notify(under_scan, band_type); |
| | | } |
| | | |
| | | void rtw_btcoex_SwitchBtTRxMask(PADAPTER padapter) |
| | | { |
| | | hal_btcoex_SwitchBtTRxMask(padapter); |
| | | } |
| | | |
| | | void rtw_btcoex_Switch(PADAPTER padapter, u8 enable) |
| | | { |
| | | hal_btcoex_SetBTCoexist(padapter, enable); |
| | | } |
| | | |
| | | u8 rtw_btcoex_IsBtDisabled(PADAPTER padapter) |
| | | { |
| | | return hal_btcoex_IsBtDisabled(padapter); |
| | | } |
| | | |
| | | void rtw_btcoex_Handler(PADAPTER padapter) |
| | | { |
| | | PHAL_DATA_TYPE pHalData; |
| | | |
| | | pHalData = GET_HAL_DATA(padapter); |
| | | |
| | | if (_FALSE == pHalData->EEPROMBluetoothCoexist) |
| | | return; |
| | | |
| | | hal_btcoex_Hanlder(padapter); |
| | | } |
| | | |
| | | s32 rtw_btcoex_IsBTCoexRejectAMPDU(PADAPTER padapter) |
| | | { |
| | | s32 coexctrl; |
| | | |
| | | coexctrl = hal_btcoex_IsBTCoexRejectAMPDU(padapter); |
| | | |
| | | return coexctrl; |
| | | } |
| | | |
| | | s32 rtw_btcoex_IsBTCoexCtrlAMPDUSize(PADAPTER padapter) |
| | | { |
| | | s32 coexctrl; |
| | | |
| | | coexctrl = hal_btcoex_IsBTCoexCtrlAMPDUSize(padapter); |
| | | |
| | | return coexctrl; |
| | | } |
| | | |
| | | u32 rtw_btcoex_GetAMPDUSize(PADAPTER padapter) |
| | | { |
| | | u32 size; |
| | | |
| | | size = hal_btcoex_GetAMPDUSize(padapter); |
| | | |
| | | return size; |
| | | } |
| | | |
| | | void rtw_btcoex_SetManualControl(PADAPTER padapter, u8 manual) |
| | | { |
| | | if (_TRUE == manual) |
| | | hal_btcoex_SetManualControl(padapter, _TRUE); |
| | | else |
| | | hal_btcoex_SetManualControl(padapter, _FALSE); |
| | | } |
| | | |
| | | u8 rtw_btcoex_1Ant(PADAPTER padapter) |
| | | { |
| | | return hal_btcoex_1Ant(padapter); |
| | | } |
| | | |
| | | u8 rtw_btcoex_IsBtControlLps(PADAPTER padapter) |
| | | { |
| | | return hal_btcoex_IsBtControlLps(padapter); |
| | | } |
| | | |
| | | u8 rtw_btcoex_IsLpsOn(PADAPTER padapter) |
| | | { |
| | | return hal_btcoex_IsLpsOn(padapter); |
| | | } |
| | | |
| | | u8 rtw_btcoex_RpwmVal(PADAPTER padapter) |
| | | { |
| | | return hal_btcoex_RpwmVal(padapter); |
| | | } |
| | | |
| | | u8 rtw_btcoex_LpsVal(PADAPTER padapter) |
| | | { |
| | | return hal_btcoex_LpsVal(padapter); |
| | | } |
| | | |
| | | u32 rtw_btcoex_GetRaMask(PADAPTER padapter) |
| | | { |
| | | return hal_btcoex_GetRaMask(padapter); |
| | | } |
| | | |
| | | void rtw_btcoex_RecordPwrMode(PADAPTER padapter, u8 *pCmdBuf, u8 cmdLen) |
| | | { |
| | | hal_btcoex_RecordPwrMode(padapter, pCmdBuf, cmdLen); |
| | | } |
| | | |
| | | void rtw_btcoex_DisplayBtCoexInfo(PADAPTER padapter, u8 *pbuf, u32 bufsize) |
| | | { |
| | | hal_btcoex_DisplayBtCoexInfo(padapter, pbuf, bufsize); |
| | | } |
| | | |
| | | void rtw_btcoex_SetDBG(PADAPTER padapter, u32 *pDbgModule) |
| | | { |
| | | hal_btcoex_SetDBG(padapter, pDbgModule); |
| | | } |
| | | |
| | | u32 rtw_btcoex_GetDBG(PADAPTER padapter, u8 *pStrBuf, u32 bufSize) |
| | | { |
| | | return hal_btcoex_GetDBG(padapter, pStrBuf, bufSize); |
| | | } |
| | | |
| | | u8 rtw_btcoex_IncreaseScanDeviceNum(PADAPTER padapter) |
| | | { |
| | | return hal_btcoex_IncreaseScanDeviceNum(padapter); |
| | | } |
| | | |
| | | u8 rtw_btcoex_IsBtLinkExist(PADAPTER padapter) |
| | | { |
| | | return hal_btcoex_IsBtLinkExist(padapter); |
| | | } |
| | | |
| | | void rtw_btcoex_SetBtPatchVersion(PADAPTER padapter, u16 btHciVer, u16 btPatchVer) |
| | | { |
| | | hal_btcoex_SetBtPatchVersion(padapter, btHciVer, btPatchVer); |
| | | } |
| | | |
| | | void rtw_btcoex_SetHciVersion(PADAPTER padapter, u16 hciVersion) |
| | | { |
| | | hal_btcoex_SetHciVersion(padapter, hciVersion); |
| | | } |
| | | |
| | | void rtw_btcoex_StackUpdateProfileInfo(void) |
| | | { |
| | | hal_btcoex_StackUpdateProfileInfo(); |
| | | } |
| | | |
| | | void rtw_btcoex_pta_off_on_notify(PADAPTER padapter, u8 bBTON) |
| | | { |
| | | hal_btcoex_pta_off_on_notify(padapter, bBTON); |
| | | } |
| | | |
| | | /* ================================================== |
| | | * Below Functions are called by BT-Coex |
| | | * ================================================== */ |
| | | void rtw_btcoex_rx_ampdu_apply(PADAPTER padapter) |
| | | { |
| | | rtw_rx_ampdu_apply(padapter); |
| | | } |
| | | |
| | | void rtw_btcoex_LPS_Enter(PADAPTER padapter) |
| | | { |
| | | struct pwrctrl_priv *pwrpriv; |
| | | u8 lpsVal; |
| | | |
| | | |
| | | pwrpriv = adapter_to_pwrctl(padapter); |
| | | |
| | | pwrpriv->bpower_saving = _TRUE; |
| | | lpsVal = rtw_btcoex_LpsVal(padapter); |
| | | rtw_set_ps_mode(padapter, PS_MODE_MIN, 0, lpsVal, "BTCOEX"); |
| | | } |
| | | |
| | | void rtw_btcoex_LPS_Leave(PADAPTER padapter) |
| | | { |
| | | struct pwrctrl_priv *pwrpriv; |
| | | |
| | | |
| | | pwrpriv = adapter_to_pwrctl(padapter); |
| | | |
| | | if (pwrpriv->pwr_mode != PS_MODE_ACTIVE) { |
| | | rtw_set_ps_mode(padapter, PS_MODE_ACTIVE, 0, 0, "BTCOEX"); |
| | | LPS_RF_ON_check(padapter, 100); |
| | | pwrpriv->bpower_saving = _FALSE; |
| | | } |
| | | } |
| | | |
| | | u16 rtw_btcoex_btreg_read(PADAPTER padapter, u8 type, u16 addr, u32 *data) |
| | | { |
| | | return hal_btcoex_btreg_read(padapter, type, addr, data); |
| | | } |
| | | |
| | | u16 rtw_btcoex_btreg_write(PADAPTER padapter, u8 type, u16 addr, u16 val) |
| | | { |
| | | return hal_btcoex_btreg_write(padapter, type, addr, val); |
| | | } |
| | | |
| | | u8 rtw_btcoex_get_bt_coexist(PADAPTER padapter) |
| | | { |
| | | HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); |
| | | |
| | | return pHalData->EEPROMBluetoothCoexist; |
| | | } |
| | | |
| | | u8 rtw_btcoex_get_chip_type(PADAPTER padapter) |
| | | { |
| | | HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); |
| | | |
| | | return pHalData->EEPROMBluetoothType; |
| | | } |
| | | |
| | | u8 rtw_btcoex_get_pg_ant_num(PADAPTER padapter) |
| | | { |
| | | HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); |
| | | |
| | | return pHalData->EEPROMBluetoothAntNum == Ant_x2 ? 2 : 1; |
| | | } |
| | | |
| | | u8 rtw_btcoex_get_pg_single_ant_path(PADAPTER padapter) |
| | | { |
| | | HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); |
| | | |
| | | return pHalData->ant_path; |
| | | } |
| | | |
| | | u8 rtw_btcoex_get_pg_rfe_type(PADAPTER padapter) |
| | | { |
| | | HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); |
| | | |
| | | return pHalData->rfe_type; |
| | | } |
| | | |
| | | u8 rtw_btcoex_is_tfbga_package_type(PADAPTER padapter) |
| | | { |
| | | HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); |
| | | |
| | | #ifdef CONFIG_RTL8723B |
| | | if ((pHalData->PackageType == PACKAGE_TFBGA79) || (pHalData->PackageType == PACKAGE_TFBGA80) |
| | | || (pHalData->PackageType == PACKAGE_TFBGA90)) |
| | | return _TRUE; |
| | | #endif |
| | | |
| | | return _FALSE; |
| | | } |
| | | |
| | | u8 rtw_btcoex_get_ant_div_cfg(PADAPTER padapter) |
| | | { |
| | | PHAL_DATA_TYPE pHalData; |
| | | |
| | | pHalData = GET_HAL_DATA(padapter); |
| | | |
| | | return (pHalData->AntDivCfg == 0) ? _FALSE : _TRUE; |
| | | } |
| | | |
| | | /* ================================================== |
| | | * Below Functions are BT-Coex socket related function |
| | | * ================================================== */ |
| | | |
| | | #ifdef CONFIG_BT_COEXIST_SOCKET_TRX |
| | | _adapter *pbtcoexadapter; /* = NULL; */ /* do not initialise globals to 0 or NULL */ |
| | | u8 rtw_btcoex_btinfo_cmd(_adapter *adapter, u8 *buf, u16 len) |
| | | { |
| | | struct cmd_obj *ph2c; |
| | | struct drvextra_cmd_parm *pdrvextra_cmd_parm; |
| | | u8 *btinfo; |
| | | struct cmd_priv *pcmdpriv = &adapter->cmdpriv; |
| | | u8 res = _SUCCESS; |
| | | |
| | | ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); |
| | | if (ph2c == NULL) { |
| | | res = _FAIL; |
| | | goto exit; |
| | | } |
| | | |
| | | pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); |
| | | if (pdrvextra_cmd_parm == NULL) { |
| | | rtw_mfree((u8 *)ph2c, sizeof(struct cmd_obj)); |
| | | res = _FAIL; |
| | | goto exit; |
| | | } |
| | | |
| | | btinfo = rtw_zmalloc(len); |
| | | if (btinfo == NULL) { |
| | | rtw_mfree((u8 *)ph2c, sizeof(struct cmd_obj)); |
| | | rtw_mfree((u8 *)pdrvextra_cmd_parm, sizeof(struct drvextra_cmd_parm)); |
| | | res = _FAIL; |
| | | goto exit; |
| | | } |
| | | |
| | | pdrvextra_cmd_parm->ec_id = BTINFO_WK_CID; |
| | | pdrvextra_cmd_parm->type = 0; |
| | | pdrvextra_cmd_parm->size = len; |
| | | pdrvextra_cmd_parm->pbuf = btinfo; |
| | | |
| | | _rtw_memcpy(btinfo, buf, len); |
| | | |
| | | init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); |
| | | |
| | | res = rtw_enqueue_cmd(pcmdpriv, ph2c); |
| | | |
| | | exit: |
| | | return res; |
| | | } |
| | | |
| | | u8 rtw_btcoex_send_event_to_BT(_adapter *padapter, u8 status, u8 event_code, u8 opcode_low, u8 opcode_high, u8 *dbg_msg) |
| | | { |
| | | u8 localBuf[6] = ""; |
| | | u8 *pRetPar; |
| | | u8 len = 0, tx_event_length = 0; |
| | | rtw_HCI_event *pEvent; |
| | | |
| | | pEvent = (rtw_HCI_event *)(&localBuf[0]); |
| | | |
| | | pEvent->EventCode = event_code; |
| | | pEvent->Data[0] = 0x1; /* packet # */ |
| | | pEvent->Data[1] = opcode_low; |
| | | pEvent->Data[2] = opcode_high; |
| | | len = len + 3; |
| | | |
| | | /* Return parameters starts from here */ |
| | | pRetPar = &pEvent->Data[len]; |
| | | pRetPar[0] = status; /* status */ |
| | | |
| | | len++; |
| | | pEvent->Length = len; |
| | | |
| | | /* total tx event length + EventCode length + sizeof(length) */ |
| | | tx_event_length = pEvent->Length + 2; |
| | | #if 0 |
| | | rtw_btcoex_dump_tx_msg((u8 *)pEvent, tx_event_length, dbg_msg); |
| | | #endif |
| | | status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); |
| | | |
| | | return status; |
| | | } |
| | | |
| | | /* |
| | | Ref: |
| | | Realtek Wi-Fi Driver |
| | | Host Controller Interface for |
| | | Bluetooth 3.0 + HS V1.4 2013/02/07 |
| | | |
| | | Window team code & BT team code |
| | | */ |
| | | |
| | | |
| | | u8 rtw_btcoex_parse_BT_info_notify_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen) |
| | | { |
| | | #define BT_INFO_LENGTH 8 |
| | | |
| | | u8 curPollEnable = pcmd[0]; |
| | | u8 curPollTime = pcmd[1]; |
| | | u8 btInfoReason = pcmd[2]; |
| | | u8 btInfoLen = pcmd[3]; |
| | | u8 btinfo[BT_INFO_LENGTH]; |
| | | |
| | | u8 localBuf[6] = ""; |
| | | u8 *pRetPar; |
| | | u8 len = 0, tx_event_length = 0; |
| | | RTW_HCI_STATUS status = HCI_STATUS_SUCCESS; |
| | | rtw_HCI_event *pEvent; |
| | | |
| | | /* RTW_INFO("%s\n",__func__); |
| | | RTW_INFO("current Poll Enable: %d, currrent Poll Time: %d\n",curPollEnable,curPollTime); |
| | | RTW_INFO("BT Info reason: %d, BT Info length: %d\n",btInfoReason,btInfoLen); |
| | | RTW_INFO("%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n" |
| | | ,pcmd[4],pcmd[5],pcmd[6],pcmd[7],pcmd[8],pcmd[9],pcmd[10],pcmd[11]);*/ |
| | | |
| | | _rtw_memset(btinfo, 0, BT_INFO_LENGTH); |
| | | |
| | | #if 1 |
| | | if (BT_INFO_LENGTH != btInfoLen) { |
| | | status = HCI_STATUS_INVALID_HCI_CMD_PARA_VALUE; |
| | | RTW_INFO("Error BT Info Length: %d\n", btInfoLen); |
| | | /* return _FAIL; */ |
| | | } else |
| | | #endif |
| | | { |
| | | if (0x1 == btInfoReason || 0x2 == btInfoReason) { |
| | | _rtw_memcpy(btinfo, &pcmd[4], btInfoLen); |
| | | btinfo[0] = btInfoReason; |
| | | rtw_btcoex_btinfo_cmd(padapter, btinfo, btInfoLen); |
| | | } else |
| | | RTW_INFO("Other BT info reason\n"); |
| | | } |
| | | |
| | | /* send complete event to BT */ |
| | | { |
| | | |
| | | pEvent = (rtw_HCI_event *)(&localBuf[0]); |
| | | |
| | | pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE; |
| | | pEvent->Data[0] = 0x1; /* packet # */ |
| | | pEvent->Data[1] = HCIOPCODELOW(HCI_BT_INFO_NOTIFY, OGF_EXTENSION); |
| | | pEvent->Data[2] = HCIOPCODEHIGHT(HCI_BT_INFO_NOTIFY, OGF_EXTENSION); |
| | | len = len + 3; |
| | | |
| | | /* Return parameters starts from here */ |
| | | pRetPar = &pEvent->Data[len]; |
| | | pRetPar[0] = status; /* status */ |
| | | |
| | | len++; |
| | | pEvent->Length = len; |
| | | |
| | | /* total tx event length + EventCode length + sizeof(length) */ |
| | | tx_event_length = pEvent->Length + 2; |
| | | #if 0 |
| | | rtw_btcoex_dump_tx_msg((u8 *)pEvent, tx_event_length, "BT_info_event"); |
| | | #endif |
| | | status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); |
| | | |
| | | return status; |
| | | /* bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2); */ |
| | | } |
| | | } |
| | | |
| | | u8 rtw_btcoex_parse_BT_patch_ver_info_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen) |
| | | { |
| | | RTW_HCI_STATUS status = HCI_STATUS_SUCCESS; |
| | | u16 btPatchVer = 0x0, btHciVer = 0x0; |
| | | /* u16 *pU2tmp; */ |
| | | |
| | | u8 localBuf[6] = ""; |
| | | u8 *pRetPar; |
| | | u8 len = 0, tx_event_length = 0; |
| | | rtw_HCI_event *pEvent; |
| | | |
| | | btHciVer = pcmd[0] | pcmd[1] << 8; |
| | | btPatchVer = pcmd[2] | pcmd[3] << 8; |
| | | |
| | | |
| | | RTW_INFO("%s, cmd:%02x %02x %02x %02x\n", __func__, pcmd[0] , pcmd[1] , pcmd[2] , pcmd[3]); |
| | | RTW_INFO("%s, HCI Ver:%d, Patch Ver:%d\n", __func__, btHciVer, btPatchVer); |
| | | |
| | | rtw_btcoex_SetBtPatchVersion(padapter, btHciVer, btPatchVer); |
| | | |
| | | |
| | | /* send complete event to BT */ |
| | | { |
| | | pEvent = (rtw_HCI_event *)(&localBuf[0]); |
| | | |
| | | |
| | | pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE; |
| | | pEvent->Data[0] = 0x1; /* packet # */ |
| | | pEvent->Data[1] = HCIOPCODELOW(HCI_BT_PATCH_VERSION_NOTIFY, OGF_EXTENSION); |
| | | pEvent->Data[2] = HCIOPCODEHIGHT(HCI_BT_PATCH_VERSION_NOTIFY, OGF_EXTENSION); |
| | | len = len + 3; |
| | | |
| | | /* Return parameters starts from here */ |
| | | pRetPar = &pEvent->Data[len]; |
| | | pRetPar[0] = status; /* status */ |
| | | |
| | | len++; |
| | | pEvent->Length = len; |
| | | |
| | | /* total tx event length + EventCode length + sizeof(length) */ |
| | | tx_event_length = pEvent->Length + 2; |
| | | #if 0 |
| | | rtw_btcoex_dump_tx_msg((u8 *)pEvent, tx_event_length, "BT_patch_event"); |
| | | #endif |
| | | status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); |
| | | return status; |
| | | /* bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2); */ |
| | | } |
| | | } |
| | | |
| | | u8 rtw_btcoex_parse_HCI_Ver_notify_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen) |
| | | { |
| | | RTW_HCI_STATUS status = HCI_STATUS_SUCCESS; |
| | | u16 hciver = pcmd[0] | pcmd[1] << 8; |
| | | |
| | | u8 localBuf[6] = ""; |
| | | u8 *pRetPar; |
| | | u8 len = 0, tx_event_length = 0; |
| | | rtw_HCI_event *pEvent; |
| | | |
| | | struct bt_coex_info *pcoex_info = &padapter->coex_info; |
| | | PBT_MGNT pBtMgnt = &pcoex_info->BtMgnt; |
| | | pBtMgnt->ExtConfig.HCIExtensionVer = hciver; |
| | | RTW_INFO("%s, HCI Version: %d\n", __func__, pBtMgnt->ExtConfig.HCIExtensionVer); |
| | | if (pBtMgnt->ExtConfig.HCIExtensionVer < 4) { |
| | | status = HCI_STATUS_INVALID_HCI_CMD_PARA_VALUE; |
| | | RTW_INFO("%s, Version = %d, HCI Version < 4\n", __func__, pBtMgnt->ExtConfig.HCIExtensionVer); |
| | | } else |
| | | rtw_btcoex_SetHciVersion(padapter, hciver); |
| | | /* send complete event to BT */ |
| | | { |
| | | pEvent = (rtw_HCI_event *)(&localBuf[0]); |
| | | |
| | | |
| | | pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE; |
| | | pEvent->Data[0] = 0x1; /* packet # */ |
| | | pEvent->Data[1] = HCIOPCODELOW(HCI_EXTENSION_VERSION_NOTIFY, OGF_EXTENSION); |
| | | pEvent->Data[2] = HCIOPCODEHIGHT(HCI_EXTENSION_VERSION_NOTIFY, OGF_EXTENSION); |
| | | len = len + 3; |
| | | |
| | | /* Return parameters starts from here */ |
| | | pRetPar = &pEvent->Data[len]; |
| | | pRetPar[0] = status; /* status */ |
| | | |
| | | len++; |
| | | pEvent->Length = len; |
| | | |
| | | /* total tx event length + EventCode length + sizeof(length) */ |
| | | tx_event_length = pEvent->Length + 2; |
| | | |
| | | status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); |
| | | return status; |
| | | /* bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2); */ |
| | | } |
| | | |
| | | } |
| | | |
| | | u8 rtw_btcoex_parse_WIFI_scan_notify_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen) |
| | | { |
| | | RTW_HCI_STATUS status = HCI_STATUS_SUCCESS; |
| | | |
| | | u8 localBuf[6] = ""; |
| | | u8 *pRetPar; |
| | | u8 len = 0, tx_event_length = 0; |
| | | rtw_HCI_event *pEvent; |
| | | |
| | | struct bt_coex_info *pcoex_info = &padapter->coex_info; |
| | | PBT_MGNT pBtMgnt = &pcoex_info->BtMgnt; |
| | | pBtMgnt->ExtConfig.bEnableWifiScanNotify = pcmd[0]; |
| | | RTW_INFO("%s, bEnableWifiScanNotify: %d\n", __func__, pBtMgnt->ExtConfig.bEnableWifiScanNotify); |
| | | |
| | | /* send complete event to BT */ |
| | | { |
| | | pEvent = (rtw_HCI_event *)(&localBuf[0]); |
| | | |
| | | |
| | | pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE; |
| | | pEvent->Data[0] = 0x1; /* packet # */ |
| | | pEvent->Data[1] = HCIOPCODELOW(HCI_ENABLE_WIFI_SCAN_NOTIFY, OGF_EXTENSION); |
| | | pEvent->Data[2] = HCIOPCODEHIGHT(HCI_ENABLE_WIFI_SCAN_NOTIFY, OGF_EXTENSION); |
| | | len = len + 3; |
| | | |
| | | /* Return parameters starts from here */ |
| | | pRetPar = &pEvent->Data[len]; |
| | | pRetPar[0] = status; /* status */ |
| | | |
| | | len++; |
| | | pEvent->Length = len; |
| | | |
| | | /* total tx event length + EventCode length + sizeof(length) */ |
| | | tx_event_length = pEvent->Length + 2; |
| | | |
| | | status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); |
| | | return status; |
| | | /* bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2); */ |
| | | } |
| | | } |
| | | |
| | | u8 rtw_btcoex_parse_HCI_link_status_notify_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen) |
| | | { |
| | | RTW_HCI_STATUS status = HCI_STATUS_SUCCESS; |
| | | struct bt_coex_info *pcoex_info = &padapter->coex_info; |
| | | PBT_MGNT pBtMgnt = &pcoex_info->BtMgnt; |
| | | /* PBT_DBG pBtDbg=&padapter->MgntInfo.BtInfo.BtDbg; */ |
| | | u8 i, numOfHandle = 0, numOfAcl = 0; |
| | | u16 conHandle; |
| | | u8 btProfile, btCoreSpec, linkRole; |
| | | u8 *pTriple; |
| | | |
| | | u8 localBuf[6] = ""; |
| | | u8 *pRetPar; |
| | | u8 len = 0, tx_event_length = 0; |
| | | rtw_HCI_event *pEvent; |
| | | |
| | | /* pBtDbg->dbgHciInfo.hciCmdCntLinkStatusNotify++; */ |
| | | /* RT_DISP_DATA(FIOCTL, IOCTL_BT_HCICMD_EXT, "LinkStatusNotify, Hex Data :\n", */ |
| | | /* &pHciCmd->Data[0], pHciCmd->Length); */ |
| | | |
| | | RTW_INFO("BTLinkStatusNotify\n"); |
| | | |
| | | /* Current only RTL8723 support this command. */ |
| | | /* pBtMgnt->bSupportProfile = TRUE; */ |
| | | pBtMgnt->bSupportProfile = _FALSE; |
| | | |
| | | pBtMgnt->ExtConfig.NumberOfACL = 0; |
| | | pBtMgnt->ExtConfig.NumberOfSCO = 0; |
| | | |
| | | numOfHandle = pcmd[0]; |
| | | /* RT_DISP(FIOCTL, IOCTL_BT_HCICMD_EXT, ("numOfHandle = 0x%x\n", numOfHandle)); */ |
| | | /* RT_DISP(FIOCTL, IOCTL_BT_HCICMD_EXT, ("HCIExtensionVer = %d\n", pBtMgnt->ExtConfig.HCIExtensionVer)); */ |
| | | RTW_INFO("numOfHandle = 0x%x\n", numOfHandle); |
| | | RTW_INFO("HCIExtensionVer = %d\n", pBtMgnt->ExtConfig.HCIExtensionVer); |
| | | |
| | | pTriple = &pcmd[1]; |
| | | for (i = 0; i < numOfHandle; i++) { |
| | | if (pBtMgnt->ExtConfig.HCIExtensionVer < 1) { |
| | | conHandle = *((u8 *)&pTriple[0]); |
| | | btProfile = pTriple[2]; |
| | | btCoreSpec = pTriple[3]; |
| | | if (BT_PROFILE_SCO == btProfile) |
| | | pBtMgnt->ExtConfig.NumberOfSCO++; |
| | | else { |
| | | pBtMgnt->ExtConfig.NumberOfACL++; |
| | | pBtMgnt->ExtConfig.aclLink[i].ConnectHandle = conHandle; |
| | | pBtMgnt->ExtConfig.aclLink[i].BTProfile = btProfile; |
| | | pBtMgnt->ExtConfig.aclLink[i].BTCoreSpec = btCoreSpec; |
| | | } |
| | | /* RT_DISP(FIOCTL, IOCTL_BT_HCICMD_EXT, */ |
| | | /* ("Connection_Handle=0x%x, BTProfile=%d, BTSpec=%d\n", */ |
| | | /* conHandle, btProfile, btCoreSpec)); */ |
| | | RTW_INFO("Connection_Handle=0x%x, BTProfile=%d, BTSpec=%d\n", conHandle, btProfile, btCoreSpec); |
| | | pTriple += 4; |
| | | } else if (pBtMgnt->ExtConfig.HCIExtensionVer >= 1) { |
| | | conHandle = *((pu2Byte)&pTriple[0]); |
| | | btProfile = pTriple[2]; |
| | | btCoreSpec = pTriple[3]; |
| | | linkRole = pTriple[4]; |
| | | if (BT_PROFILE_SCO == btProfile) |
| | | pBtMgnt->ExtConfig.NumberOfSCO++; |
| | | else { |
| | | pBtMgnt->ExtConfig.NumberOfACL++; |
| | | pBtMgnt->ExtConfig.aclLink[i].ConnectHandle = conHandle; |
| | | pBtMgnt->ExtConfig.aclLink[i].BTProfile = btProfile; |
| | | pBtMgnt->ExtConfig.aclLink[i].BTCoreSpec = btCoreSpec; |
| | | pBtMgnt->ExtConfig.aclLink[i].linkRole = linkRole; |
| | | } |
| | | /* RT_DISP(FIOCTL, IOCTL_BT_HCICMD_EXT, */ |
| | | RTW_INFO("Connection_Handle=0x%x, BTProfile=%d, BTSpec=%d, LinkRole=%d\n", |
| | | conHandle, btProfile, btCoreSpec, linkRole); |
| | | pTriple += 5; |
| | | } |
| | | } |
| | | rtw_btcoex_StackUpdateProfileInfo(); |
| | | |
| | | /* send complete event to BT */ |
| | | { |
| | | pEvent = (rtw_HCI_event *)(&localBuf[0]); |
| | | |
| | | |
| | | pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE; |
| | | pEvent->Data[0] = 0x1; /* packet # */ |
| | | pEvent->Data[1] = HCIOPCODELOW(HCI_LINK_STATUS_NOTIFY, OGF_EXTENSION); |
| | | pEvent->Data[2] = HCIOPCODEHIGHT(HCI_LINK_STATUS_NOTIFY, OGF_EXTENSION); |
| | | len = len + 3; |
| | | |
| | | /* Return parameters starts from here */ |
| | | pRetPar = &pEvent->Data[len]; |
| | | pRetPar[0] = status; /* status */ |
| | | |
| | | len++; |
| | | pEvent->Length = len; |
| | | |
| | | /* total tx event length + EventCode length + sizeof(length) */ |
| | | tx_event_length = pEvent->Length + 2; |
| | | |
| | | status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); |
| | | return status; |
| | | /* bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2); */ |
| | | } |
| | | |
| | | |
| | | } |
| | | |
| | | u8 rtw_btcoex_parse_HCI_BT_coex_notify_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen) |
| | | { |
| | | u8 localBuf[6] = ""; |
| | | u8 *pRetPar; |
| | | u8 len = 0, tx_event_length = 0; |
| | | rtw_HCI_event *pEvent; |
| | | RTW_HCI_STATUS status = HCI_STATUS_SUCCESS; |
| | | |
| | | { |
| | | pEvent = (rtw_HCI_event *)(&localBuf[0]); |
| | | |
| | | |
| | | pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE; |
| | | pEvent->Data[0] = 0x1; /* packet # */ |
| | | pEvent->Data[1] = HCIOPCODELOW(HCI_BT_COEX_NOTIFY, OGF_EXTENSION); |
| | | pEvent->Data[2] = HCIOPCODEHIGHT(HCI_BT_COEX_NOTIFY, OGF_EXTENSION); |
| | | len = len + 3; |
| | | |
| | | /* Return parameters starts from here */ |
| | | pRetPar = &pEvent->Data[len]; |
| | | pRetPar[0] = status; /* status */ |
| | | |
| | | len++; |
| | | pEvent->Length = len; |
| | | |
| | | /* total tx event length + EventCode length + sizeof(length) */ |
| | | tx_event_length = pEvent->Length + 2; |
| | | |
| | | status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); |
| | | return status; |
| | | /* bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2); */ |
| | | } |
| | | } |
| | | |
| | | u8 rtw_btcoex_parse_HCI_BT_operation_notify_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen) |
| | | { |
| | | u8 localBuf[6] = ""; |
| | | u8 *pRetPar; |
| | | u8 len = 0, tx_event_length = 0; |
| | | rtw_HCI_event *pEvent; |
| | | RTW_HCI_STATUS status = HCI_STATUS_SUCCESS; |
| | | |
| | | RTW_INFO("%s, OP code: %d\n", __func__, pcmd[0]); |
| | | |
| | | switch (pcmd[0]) { |
| | | case HCI_BT_OP_NONE: |
| | | RTW_INFO("[bt operation] : Operation None!!\n"); |
| | | break; |
| | | case HCI_BT_OP_INQUIRY_START: |
| | | RTW_INFO("[bt operation] : Inquiry start!!\n"); |
| | | break; |
| | | case HCI_BT_OP_INQUIRY_FINISH: |
| | | RTW_INFO("[bt operation] : Inquiry finished!!\n"); |
| | | break; |
| | | case HCI_BT_OP_PAGING_START: |
| | | RTW_INFO("[bt operation] : Paging is started!!\n"); |
| | | break; |
| | | case HCI_BT_OP_PAGING_SUCCESS: |
| | | RTW_INFO("[bt operation] : Paging complete successfully!!\n"); |
| | | break; |
| | | case HCI_BT_OP_PAGING_UNSUCCESS: |
| | | RTW_INFO("[bt operation] : Paging complete unsuccessfully!!\n"); |
| | | break; |
| | | case HCI_BT_OP_PAIRING_START: |
| | | RTW_INFO("[bt operation] : Pairing start!!\n"); |
| | | break; |
| | | case HCI_BT_OP_PAIRING_FINISH: |
| | | RTW_INFO("[bt operation] : Pairing finished!!\n"); |
| | | break; |
| | | case HCI_BT_OP_BT_DEV_ENABLE: |
| | | RTW_INFO("[bt operation] : BT Device is enabled!!\n"); |
| | | break; |
| | | case HCI_BT_OP_BT_DEV_DISABLE: |
| | | RTW_INFO("[bt operation] : BT Device is disabled!!\n"); |
| | | break; |
| | | default: |
| | | RTW_INFO("[bt operation] : Unknown, error!!\n"); |
| | | break; |
| | | } |
| | | |
| | | /* send complete event to BT */ |
| | | { |
| | | pEvent = (rtw_HCI_event *)(&localBuf[0]); |
| | | |
| | | |
| | | pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE; |
| | | pEvent->Data[0] = 0x1; /* packet # */ |
| | | pEvent->Data[1] = HCIOPCODELOW(HCI_BT_OPERATION_NOTIFY, OGF_EXTENSION); |
| | | pEvent->Data[2] = HCIOPCODEHIGHT(HCI_BT_OPERATION_NOTIFY, OGF_EXTENSION); |
| | | len = len + 3; |
| | | |
| | | /* Return parameters starts from here */ |
| | | pRetPar = &pEvent->Data[len]; |
| | | pRetPar[0] = status; /* status */ |
| | | |
| | | len++; |
| | | pEvent->Length = len; |
| | | |
| | | /* total tx event length + EventCode length + sizeof(length) */ |
| | | tx_event_length = pEvent->Length + 2; |
| | | |
| | | status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); |
| | | return status; |
| | | /* bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2); */ |
| | | } |
| | | } |
| | | |
| | | u8 rtw_btcoex_parse_BT_AFH_MAP_notify_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen) |
| | | { |
| | | u8 localBuf[6] = ""; |
| | | u8 *pRetPar; |
| | | u8 len = 0, tx_event_length = 0; |
| | | rtw_HCI_event *pEvent; |
| | | RTW_HCI_STATUS status = HCI_STATUS_SUCCESS; |
| | | |
| | | { |
| | | pEvent = (rtw_HCI_event *)(&localBuf[0]); |
| | | |
| | | |
| | | pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE; |
| | | pEvent->Data[0] = 0x1; /* packet # */ |
| | | pEvent->Data[1] = HCIOPCODELOW(HCI_BT_AFH_MAP_NOTIFY, OGF_EXTENSION); |
| | | pEvent->Data[2] = HCIOPCODEHIGHT(HCI_BT_AFH_MAP_NOTIFY, OGF_EXTENSION); |
| | | len = len + 3; |
| | | |
| | | /* Return parameters starts from here */ |
| | | pRetPar = &pEvent->Data[len]; |
| | | pRetPar[0] = status; /* status */ |
| | | |
| | | len++; |
| | | pEvent->Length = len; |
| | | |
| | | /* total tx event length + EventCode length + sizeof(length) */ |
| | | tx_event_length = pEvent->Length + 2; |
| | | |
| | | status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); |
| | | return status; |
| | | /* bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2); */ |
| | | } |
| | | } |
| | | |
| | | u8 rtw_btcoex_parse_BT_register_val_notify_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen) |
| | | { |
| | | |
| | | u8 localBuf[6] = ""; |
| | | u8 *pRetPar; |
| | | u8 len = 0, tx_event_length = 0; |
| | | rtw_HCI_event *pEvent; |
| | | RTW_HCI_STATUS status = HCI_STATUS_SUCCESS; |
| | | |
| | | { |
| | | pEvent = (rtw_HCI_event *)(&localBuf[0]); |
| | | |
| | | |
| | | pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE; |
| | | pEvent->Data[0] = 0x1; /* packet # */ |
| | | pEvent->Data[1] = HCIOPCODELOW(HCI_BT_REGISTER_VALUE_NOTIFY, OGF_EXTENSION); |
| | | pEvent->Data[2] = HCIOPCODEHIGHT(HCI_BT_REGISTER_VALUE_NOTIFY, OGF_EXTENSION); |
| | | len = len + 3; |
| | | |
| | | /* Return parameters starts from here */ |
| | | pRetPar = &pEvent->Data[len]; |
| | | pRetPar[0] = status; /* status */ |
| | | |
| | | len++; |
| | | pEvent->Length = len; |
| | | |
| | | /* total tx event length + EventCode length + sizeof(length) */ |
| | | tx_event_length = pEvent->Length + 2; |
| | | |
| | | status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); |
| | | return status; |
| | | /* bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2); */ |
| | | } |
| | | } |
| | | |
| | | u8 rtw_btcoex_parse_HCI_BT_abnormal_notify_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen) |
| | | { |
| | | u8 localBuf[6] = ""; |
| | | u8 *pRetPar; |
| | | u8 len = 0, tx_event_length = 0; |
| | | rtw_HCI_event *pEvent; |
| | | RTW_HCI_STATUS status = HCI_STATUS_SUCCESS; |
| | | |
| | | { |
| | | pEvent = (rtw_HCI_event *)(&localBuf[0]); |
| | | |
| | | |
| | | pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE; |
| | | pEvent->Data[0] = 0x1; /* packet # */ |
| | | pEvent->Data[1] = HCIOPCODELOW(HCI_BT_ABNORMAL_NOTIFY, OGF_EXTENSION); |
| | | pEvent->Data[2] = HCIOPCODEHIGHT(HCI_BT_ABNORMAL_NOTIFY, OGF_EXTENSION); |
| | | len = len + 3; |
| | | |
| | | /* Return parameters starts from here */ |
| | | pRetPar = &pEvent->Data[len]; |
| | | pRetPar[0] = status; /* status */ |
| | | |
| | | len++; |
| | | pEvent->Length = len; |
| | | |
| | | /* total tx event length + EventCode length + sizeof(length) */ |
| | | tx_event_length = pEvent->Length + 2; |
| | | |
| | | status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); |
| | | return status; |
| | | /* bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2); */ |
| | | } |
| | | } |
| | | |
| | | u8 rtw_btcoex_parse_HCI_query_RF_status_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen) |
| | | { |
| | | u8 localBuf[6] = ""; |
| | | u8 *pRetPar; |
| | | u8 len = 0, tx_event_length = 0; |
| | | rtw_HCI_event *pEvent; |
| | | RTW_HCI_STATUS status = HCI_STATUS_SUCCESS; |
| | | |
| | | { |
| | | pEvent = (rtw_HCI_event *)(&localBuf[0]); |
| | | |
| | | |
| | | pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE; |
| | | pEvent->Data[0] = 0x1; /* packet # */ |
| | | pEvent->Data[1] = HCIOPCODELOW(HCI_QUERY_RF_STATUS, OGF_EXTENSION); |
| | | pEvent->Data[2] = HCIOPCODEHIGHT(HCI_QUERY_RF_STATUS, OGF_EXTENSION); |
| | | len = len + 3; |
| | | |
| | | /* Return parameters starts from here */ |
| | | pRetPar = &pEvent->Data[len]; |
| | | pRetPar[0] = status; /* status */ |
| | | |
| | | len++; |
| | | pEvent->Length = len; |
| | | |
| | | /* total tx event length + EventCode length + sizeof(length) */ |
| | | tx_event_length = pEvent->Length + 2; |
| | | |
| | | status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); |
| | | return status; |
| | | /* bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2); */ |
| | | } |
| | | } |
| | | |
| | | /***************************************** |
| | | * HCI cmd format : |
| | | *| 15 - 0 | |
| | | *| OPcode (OCF|OGF<<10) | |
| | | *| 15 - 8 |7 - 0 | |
| | | *|Cmd para |Cmd para Length | |
| | | *|Cmd para...... | |
| | | ******************************************/ |
| | | |
| | | /* bit 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
| | | * | OCF | OGF | */ |
| | | void rtw_btcoex_parse_hci_extend_cmd(_adapter *padapter, u8 *pcmd, u16 len, const u16 hci_OCF) |
| | | { |
| | | |
| | | RTW_INFO("%s: OCF: %x\n", __func__, hci_OCF); |
| | | switch (hci_OCF) { |
| | | case HCI_EXTENSION_VERSION_NOTIFY: |
| | | RTW_INFO("HCI_EXTENSION_VERSION_NOTIFY\n"); |
| | | rtw_btcoex_parse_HCI_Ver_notify_cmd(padapter, pcmd, len); |
| | | break; |
| | | case HCI_LINK_STATUS_NOTIFY: |
| | | RTW_INFO("HCI_LINK_STATUS_NOTIFY\n"); |
| | | rtw_btcoex_parse_HCI_link_status_notify_cmd(padapter, pcmd, len); |
| | | break; |
| | | case HCI_BT_OPERATION_NOTIFY: |
| | | /* only for 8723a 2ant */ |
| | | RTW_INFO("HCI_BT_OPERATION_NOTIFY\n"); |
| | | rtw_btcoex_parse_HCI_BT_operation_notify_cmd(padapter, pcmd, len); |
| | | /* */ |
| | | break; |
| | | case HCI_ENABLE_WIFI_SCAN_NOTIFY: |
| | | RTW_INFO("HCI_ENABLE_WIFI_SCAN_NOTIFY\n"); |
| | | rtw_btcoex_parse_WIFI_scan_notify_cmd(padapter, pcmd, len); |
| | | break; |
| | | case HCI_QUERY_RF_STATUS: |
| | | /* only for 8723b 2ant */ |
| | | RTW_INFO("HCI_QUERY_RF_STATUS\n"); |
| | | rtw_btcoex_parse_HCI_query_RF_status_cmd(padapter, pcmd, len); |
| | | break; |
| | | case HCI_BT_ABNORMAL_NOTIFY: |
| | | RTW_INFO("HCI_BT_ABNORMAL_NOTIFY\n"); |
| | | rtw_btcoex_parse_HCI_BT_abnormal_notify_cmd(padapter, pcmd, len); |
| | | break; |
| | | case HCI_BT_INFO_NOTIFY: |
| | | RTW_INFO("HCI_BT_INFO_NOTIFY\n"); |
| | | rtw_btcoex_parse_BT_info_notify_cmd(padapter, pcmd, len); |
| | | break; |
| | | case HCI_BT_COEX_NOTIFY: |
| | | RTW_INFO("HCI_BT_COEX_NOTIFY\n"); |
| | | rtw_btcoex_parse_HCI_BT_coex_notify_cmd(padapter, pcmd, len); |
| | | break; |
| | | case HCI_BT_PATCH_VERSION_NOTIFY: |
| | | RTW_INFO("HCI_BT_PATCH_VERSION_NOTIFY\n"); |
| | | rtw_btcoex_parse_BT_patch_ver_info_cmd(padapter, pcmd, len); |
| | | break; |
| | | case HCI_BT_AFH_MAP_NOTIFY: |
| | | RTW_INFO("HCI_BT_AFH_MAP_NOTIFY\n"); |
| | | rtw_btcoex_parse_BT_AFH_MAP_notify_cmd(padapter, pcmd, len); |
| | | break; |
| | | case HCI_BT_REGISTER_VALUE_NOTIFY: |
| | | RTW_INFO("HCI_BT_REGISTER_VALUE_NOTIFY\n"); |
| | | rtw_btcoex_parse_BT_register_val_notify_cmd(padapter, pcmd, len); |
| | | break; |
| | | default: |
| | | RTW_INFO("ERROR!!! Unknown OCF: %x\n", hci_OCF); |
| | | break; |
| | | |
| | | } |
| | | } |
| | | |
| | | void rtw_btcoex_parse_hci_cmd(_adapter *padapter, u8 *pcmd, u16 len) |
| | | { |
| | | u16 opcode = pcmd[0] | pcmd[1] << 8; |
| | | u16 hci_OGF = HCI_OGF(opcode); |
| | | u16 hci_OCF = HCI_OCF(opcode); |
| | | u8 cmdlen = len - 3; |
| | | u8 pare_len = pcmd[2]; |
| | | |
| | | RTW_INFO("%s OGF: %x,OCF: %x\n", __func__, hci_OGF, hci_OCF); |
| | | switch (hci_OGF) { |
| | | case OGF_EXTENSION: |
| | | RTW_INFO("HCI_EXTENSION_CMD_OGF\n"); |
| | | rtw_btcoex_parse_hci_extend_cmd(padapter, &pcmd[3], cmdlen, hci_OCF); |
| | | break; |
| | | default: |
| | | RTW_INFO("Other OGF: %x\n", hci_OGF); |
| | | break; |
| | | } |
| | | } |
| | | |
| | | u16 rtw_btcoex_parse_recv_data(u8 *msg, u8 msg_size) |
| | | { |
| | | u8 cmp_msg1[32] = attend_ack; |
| | | u8 cmp_msg2[32] = leave_ack; |
| | | u8 cmp_msg3[32] = bt_leave; |
| | | u8 cmp_msg4[32] = invite_req; |
| | | u8 cmp_msg5[32] = attend_req; |
| | | u8 cmp_msg6[32] = invite_rsp; |
| | | u8 res = OTHER; |
| | | |
| | | if (_rtw_memcmp(cmp_msg1, msg, msg_size) == _TRUE) { |
| | | /*RTW_INFO("%s, msg:%s\n",__func__,msg);*/ |
| | | res = RX_ATTEND_ACK; |
| | | } else if (_rtw_memcmp(cmp_msg2, msg, msg_size) == _TRUE) { |
| | | /*RTW_INFO("%s, msg:%s\n",__func__,msg);*/ |
| | | res = RX_LEAVE_ACK; |
| | | } else if (_rtw_memcmp(cmp_msg3, msg, msg_size) == _TRUE) { |
| | | /*RTW_INFO("%s, msg:%s\n",__func__,msg);*/ |
| | | res = RX_BT_LEAVE; |
| | | } else if (_rtw_memcmp(cmp_msg4, msg, msg_size) == _TRUE) { |
| | | /*RTW_INFO("%s, msg:%s\n",__func__,msg);*/ |
| | | res = RX_INVITE_REQ; |
| | | } else if (_rtw_memcmp(cmp_msg5, msg, msg_size) == _TRUE) |
| | | res = RX_ATTEND_REQ; |
| | | else if (_rtw_memcmp(cmp_msg6, msg, msg_size) == _TRUE) |
| | | res = RX_INVITE_RSP; |
| | | else { |
| | | /*RTW_INFO("%s, %s\n", __func__, msg);*/ |
| | | res = OTHER; |
| | | } |
| | | |
| | | /*RTW_INFO("%s, res:%d\n", __func__, res);*/ |
| | | |
| | | return res; |
| | | } |
| | | |
| | | void rtw_btcoex_recvmsgbysocket(void *data) |
| | | { |
| | | u8 recv_data[255]; |
| | | u8 tx_msg[255] = leave_ack; |
| | | u32 len = 0; |
| | | u16 recv_length = 0; |
| | | u16 parse_res = 0; |
| | | #if 0 |
| | | u8 para_len = 0, polling_enable = 0, poling_interval = 0, reason = 0, btinfo_len = 0; |
| | | u8 btinfo[BT_INFO_LEN] = {0}; |
| | | #endif |
| | | |
| | | struct bt_coex_info *pcoex_info = NULL; |
| | | struct sock *sk = NULL; |
| | | struct sk_buff *skb = NULL; |
| | | |
| | | /*RTW_INFO("%s\n",__func__);*/ |
| | | |
| | | if (pbtcoexadapter == NULL) { |
| | | RTW_INFO("%s: btcoexadapter NULL!\n", __func__); |
| | | return; |
| | | } |
| | | |
| | | pcoex_info = &pbtcoexadapter->coex_info; |
| | | sk = pcoex_info->sk_store; |
| | | |
| | | if (sk == NULL) { |
| | | RTW_INFO("%s: critical error when receive socket data!\n", __func__); |
| | | return; |
| | | } |
| | | |
| | | len = skb_queue_len(&sk->sk_receive_queue); |
| | | while (len > 0) { |
| | | skb = skb_dequeue(&sk->sk_receive_queue); |
| | | |
| | | /*important: cut the udp header from skb->data! header length is 8 byte*/ |
| | | recv_length = skb->len - 8; |
| | | _rtw_memset(recv_data, 0, sizeof(recv_data)); |
| | | _rtw_memcpy(recv_data, skb->data + 8, recv_length); |
| | | |
| | | parse_res = rtw_btcoex_parse_recv_data(recv_data, recv_length); |
| | | #if 0 |
| | | if (RX_ATTEND_ACK == parse_res) { |
| | | /* attend ack */ |
| | | pcoex_info->BT_attend = _TRUE; |
| | | RTW_INFO("RX_ATTEND_ACK!,sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend); |
| | | } else if (RX_ATTEND_REQ == parse_res) { |
| | | /* attend req from BT */ |
| | | pcoex_info->BT_attend = _TRUE; |
| | | RTW_INFO("RX_BT_ATTEND_REQ!,sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend); |
| | | rtw_btcoex_sendmsgbysocket(pbtcoexadapter, attend_ack, sizeof(attend_ack), _FALSE); |
| | | } else if (RX_INVITE_REQ == parse_res) { |
| | | /* invite req from BT */ |
| | | pcoex_info->BT_attend = _TRUE; |
| | | RTW_INFO("RX_INVITE_REQ!,sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend); |
| | | rtw_btcoex_sendmsgbysocket(pbtcoexadapter, invite_rsp, sizeof(invite_rsp), _FALSE); |
| | | } else if (RX_INVITE_RSP == parse_res) { |
| | | /* invite rsp */ |
| | | pcoex_info->BT_attend = _TRUE; |
| | | RTW_INFO("RX_INVITE_RSP!,sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend); |
| | | } else if (RX_LEAVE_ACK == parse_res) { |
| | | /* mean BT know wifi will leave */ |
| | | pcoex_info->BT_attend = _FALSE; |
| | | RTW_INFO("RX_LEAVE_ACK!,sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend); |
| | | } else if (RX_BT_LEAVE == parse_res) { |
| | | /* BT leave */ |
| | | rtw_btcoex_sendmsgbysocket(pbtcoexadapter, leave_ack, sizeof(leave_ack), _FALSE); /* no ack */ |
| | | pcoex_info->BT_attend = _FALSE; |
| | | RTW_INFO("RX_BT_LEAVE!sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend); |
| | | } else { |
| | | /* todo: check if recv data are really hci cmds */ |
| | | if (_TRUE == pcoex_info->BT_attend) |
| | | rtw_btcoex_parse_hci_cmd(pbtcoexadapter, recv_data, recv_length); |
| | | } |
| | | #endif |
| | | switch (parse_res) { |
| | | case RX_ATTEND_ACK: |
| | | /* attend ack */ |
| | | pcoex_info->BT_attend = _TRUE; |
| | | RTW_INFO("RX_ATTEND_ACK!,sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend); |
| | | rtw_btcoex_pta_off_on_notify(pbtcoexadapter, pcoex_info->BT_attend); |
| | | break; |
| | | |
| | | case RX_ATTEND_REQ: |
| | | pcoex_info->BT_attend = _TRUE; |
| | | RTW_INFO("RX_BT_ATTEND_REQ!,sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend); |
| | | rtw_btcoex_sendmsgbysocket(pbtcoexadapter, attend_ack, sizeof(attend_ack), _FALSE); |
| | | rtw_btcoex_pta_off_on_notify(pbtcoexadapter, pcoex_info->BT_attend); |
| | | break; |
| | | |
| | | case RX_INVITE_REQ: |
| | | /* invite req from BT */ |
| | | pcoex_info->BT_attend = _TRUE; |
| | | RTW_INFO("RX_INVITE_REQ!,sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend); |
| | | rtw_btcoex_sendmsgbysocket(pbtcoexadapter, invite_rsp, sizeof(invite_rsp), _FALSE); |
| | | rtw_btcoex_pta_off_on_notify(pbtcoexadapter, pcoex_info->BT_attend); |
| | | break; |
| | | |
| | | case RX_INVITE_RSP: |
| | | /*invite rsp*/ |
| | | pcoex_info->BT_attend = _TRUE; |
| | | RTW_INFO("RX_INVITE_RSP!,sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend); |
| | | rtw_btcoex_pta_off_on_notify(pbtcoexadapter, pcoex_info->BT_attend); |
| | | break; |
| | | |
| | | case RX_LEAVE_ACK: |
| | | /* mean BT know wifi will leave */ |
| | | pcoex_info->BT_attend = _FALSE; |
| | | RTW_INFO("RX_LEAVE_ACK!,sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend); |
| | | rtw_btcoex_pta_off_on_notify(pbtcoexadapter, pcoex_info->BT_attend); |
| | | break; |
| | | |
| | | case RX_BT_LEAVE: |
| | | /* BT leave */ |
| | | rtw_btcoex_sendmsgbysocket(pbtcoexadapter, leave_ack, sizeof(leave_ack), _FALSE); /* no ack */ |
| | | pcoex_info->BT_attend = _FALSE; |
| | | RTW_INFO("RX_BT_LEAVE!sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend); |
| | | rtw_btcoex_pta_off_on_notify(pbtcoexadapter, pcoex_info->BT_attend); |
| | | break; |
| | | |
| | | default: |
| | | if (_TRUE == pcoex_info->BT_attend) |
| | | rtw_btcoex_parse_hci_cmd(pbtcoexadapter, recv_data, recv_length); |
| | | else |
| | | RTW_INFO("ERROR!! BT is UP\n"); |
| | | break; |
| | | |
| | | } |
| | | |
| | | len--; |
| | | kfree_skb(skb); |
| | | } |
| | | } |
| | | |
| | | #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 15, 0)) |
| | | void rtw_btcoex_recvmsg_init(struct sock *sk_in, s32 bytes) |
| | | #else |
| | | void rtw_btcoex_recvmsg_init(struct sock *sk_in) |
| | | #endif |
| | | { |
| | | struct bt_coex_info *pcoex_info = NULL; |
| | | |
| | | if (pbtcoexadapter == NULL) { |
| | | RTW_INFO("%s: btcoexadapter NULL\n", __func__); |
| | | return; |
| | | } |
| | | pcoex_info = &pbtcoexadapter->coex_info; |
| | | pcoex_info->sk_store = sk_in; |
| | | if (pcoex_info->btcoex_wq != NULL) |
| | | queue_delayed_work(pcoex_info->btcoex_wq, &pcoex_info->recvmsg_work, 0); |
| | | else |
| | | RTW_INFO("%s: BTCOEX workqueue NULL\n", __func__); |
| | | } |
| | | |
| | | u8 rtw_btcoex_sendmsgbysocket(_adapter *padapter, u8 *msg, u8 msg_size, bool force) |
| | | { |
| | | u8 error; |
| | | struct msghdr udpmsg; |
| | | mm_segment_t oldfs; |
| | | struct iovec iov; |
| | | struct bt_coex_info *pcoex_info = &padapter->coex_info; |
| | | |
| | | /* RTW_INFO("%s: msg:%s, force:%s\n", __func__, msg, force == _TRUE?"TRUE":"FALSE"); */ |
| | | if (_FALSE == force) { |
| | | if (_FALSE == pcoex_info->BT_attend) { |
| | | RTW_INFO("TX Blocked: WiFi-BT disconnected\n"); |
| | | return _FAIL; |
| | | } |
| | | } |
| | | |
| | | iov.iov_base = (void *)msg; |
| | | iov.iov_len = msg_size; |
| | | udpmsg.msg_name = &pcoex_info->bt_sockaddr; |
| | | udpmsg.msg_namelen = sizeof(struct sockaddr_in); |
| | | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) |
| | | /* referece:sock_xmit in kernel code |
| | | * WRITE for sock_sendmsg, READ for sock_recvmsg |
| | | * third parameter for msg_iovlen |
| | | * last parameter for iov_len |
| | | */ |
| | | iov_iter_init(&udpmsg.msg_iter, WRITE, &iov, 1, msg_size); |
| | | #else |
| | | udpmsg.msg_iov = &iov; |
| | | udpmsg.msg_iovlen = 1; |
| | | #endif |
| | | udpmsg.msg_control = NULL; |
| | | udpmsg.msg_controllen = 0; |
| | | udpmsg.msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL; |
| | | oldfs = get_fs(); |
| | | set_fs(KERNEL_DS); |
| | | |
| | | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) |
| | | error = sock_sendmsg(pcoex_info->udpsock, &udpmsg); |
| | | #else |
| | | error = sock_sendmsg(pcoex_info->udpsock, &udpmsg, msg_size); |
| | | #endif |
| | | set_fs(oldfs); |
| | | if (error < 0) { |
| | | RTW_INFO("Error when sendimg msg, error:%d\n", error); |
| | | return _FAIL; |
| | | } else |
| | | return _SUCCESS; |
| | | } |
| | | |
| | | u8 rtw_btcoex_create_kernel_socket(_adapter *padapter) |
| | | { |
| | | s8 kernel_socket_err; |
| | | u8 tx_msg[255] = attend_req; |
| | | struct bt_coex_info *pcoex_info = &padapter->coex_info; |
| | | s32 sock_reuse = 1; |
| | | u8 status = _FAIL; |
| | | |
| | | RTW_INFO("%s CONNECT_PORT %d\n", __func__, CONNECT_PORT); |
| | | |
| | | if (NULL == pcoex_info) { |
| | | RTW_INFO("coex_info: NULL\n"); |
| | | status = _FAIL; |
| | | } |
| | | |
| | | kernel_socket_err = sock_create(PF_INET, SOCK_DGRAM, 0, &pcoex_info->udpsock); |
| | | |
| | | if (kernel_socket_err < 0) { |
| | | RTW_INFO("Error during creation of socket error:%d\n", kernel_socket_err); |
| | | status = _FAIL; |
| | | } else { |
| | | _rtw_memset(&(pcoex_info->wifi_sockaddr), 0, sizeof(pcoex_info->wifi_sockaddr)); |
| | | pcoex_info->wifi_sockaddr.sin_family = AF_INET; |
| | | pcoex_info->wifi_sockaddr.sin_port = htons(CONNECT_PORT); |
| | | pcoex_info->wifi_sockaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); |
| | | |
| | | _rtw_memset(&(pcoex_info->bt_sockaddr), 0, sizeof(pcoex_info->bt_sockaddr)); |
| | | pcoex_info->bt_sockaddr.sin_family = AF_INET; |
| | | pcoex_info->bt_sockaddr.sin_port = htons(CONNECT_PORT_BT); |
| | | pcoex_info->bt_sockaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); |
| | | |
| | | pcoex_info->sk_store = NULL; |
| | | kernel_socket_err = pcoex_info->udpsock->ops->bind(pcoex_info->udpsock, (struct sockaddr *)&pcoex_info->wifi_sockaddr, |
| | | sizeof(pcoex_info->wifi_sockaddr)); |
| | | if (kernel_socket_err == 0) { |
| | | RTW_INFO("binding socket success\n"); |
| | | pcoex_info->udpsock->sk->sk_data_ready = rtw_btcoex_recvmsg_init; |
| | | pcoex_info->sock_open |= KERNEL_SOCKET_OK; |
| | | pcoex_info->BT_attend = _FALSE; |
| | | RTW_INFO("WIFI sending attend_req\n"); |
| | | rtw_btcoex_sendmsgbysocket(padapter, attend_req, sizeof(attend_req), _TRUE); |
| | | status = _SUCCESS; |
| | | } else { |
| | | pcoex_info->BT_attend = _FALSE; |
| | | sock_release(pcoex_info->udpsock); /* bind fail release socket */ |
| | | RTW_INFO("Error binding socket: %d\n", kernel_socket_err); |
| | | status = _FAIL; |
| | | } |
| | | |
| | | } |
| | | |
| | | return status; |
| | | } |
| | | |
| | | void rtw_btcoex_close_kernel_socket(_adapter *padapter) |
| | | { |
| | | struct bt_coex_info *pcoex_info = &padapter->coex_info; |
| | | if (pcoex_info->sock_open & KERNEL_SOCKET_OK) { |
| | | RTW_INFO("release kernel socket\n"); |
| | | sock_release(pcoex_info->udpsock); |
| | | pcoex_info->sock_open &= ~(KERNEL_SOCKET_OK); |
| | | if (_TRUE == pcoex_info->BT_attend) |
| | | pcoex_info->BT_attend = _FALSE; |
| | | |
| | | RTW_INFO("sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend); |
| | | } |
| | | } |
| | | |
| | | void rtw_btcoex_init_socket(_adapter *padapter) |
| | | { |
| | | |
| | | u8 is_invite = _FALSE; |
| | | struct bt_coex_info *pcoex_info = &padapter->coex_info; |
| | | RTW_INFO("%s\n", __func__); |
| | | if (_FALSE == pcoex_info->is_exist) { |
| | | _rtw_memset(pcoex_info, 0, sizeof(struct bt_coex_info)); |
| | | pcoex_info->btcoex_wq = create_workqueue("BTCOEX"); |
| | | INIT_DELAYED_WORK(&pcoex_info->recvmsg_work, |
| | | (void *)rtw_btcoex_recvmsgbysocket); |
| | | pbtcoexadapter = padapter; |
| | | /* We expect BT is off if BT don't send ack to wifi */ |
| | | RTW_INFO("We expect BT is off if BT send ack to wifi\n"); |
| | | rtw_btcoex_pta_off_on_notify(pbtcoexadapter, _FALSE); |
| | | if (rtw_btcoex_create_kernel_socket(padapter) == _SUCCESS) |
| | | pcoex_info->is_exist = _TRUE; |
| | | else { |
| | | pcoex_info->is_exist = _FALSE; |
| | | pbtcoexadapter = NULL; |
| | | } |
| | | |
| | | RTW_INFO("%s: pbtcoexadapter:%p, coex_info->is_exist: %s\n" |
| | | , __func__, pbtcoexadapter, pcoex_info->is_exist == _TRUE ? "TRUE" : "FALSE"); |
| | | } |
| | | } |
| | | |
| | | void rtw_btcoex_close_socket(_adapter *padapter) |
| | | { |
| | | struct bt_coex_info *pcoex_info = &padapter->coex_info; |
| | | |
| | | RTW_INFO("%s--coex_info->is_exist: %s, pcoex_info->BT_attend:%s\n" |
| | | , __func__, pcoex_info->is_exist == _TRUE ? "TRUE" : "FALSE", pcoex_info->BT_attend == _TRUE ? "TRUE" : "FALSE"); |
| | | |
| | | if (_TRUE == pcoex_info->is_exist) { |
| | | if (_TRUE == pcoex_info->BT_attend) { |
| | | /*inform BT wifi leave*/ |
| | | rtw_btcoex_sendmsgbysocket(padapter, wifi_leave, sizeof(wifi_leave), _FALSE); |
| | | msleep(50); |
| | | } |
| | | |
| | | if (pcoex_info->btcoex_wq != NULL) { |
| | | flush_workqueue(pcoex_info->btcoex_wq); |
| | | destroy_workqueue(pcoex_info->btcoex_wq); |
| | | } |
| | | |
| | | rtw_btcoex_close_kernel_socket(padapter); |
| | | pbtcoexadapter = NULL; |
| | | pcoex_info->is_exist = _FALSE; |
| | | } |
| | | } |
| | | |
| | | void rtw_btcoex_dump_tx_msg(u8 *tx_msg, u8 len, u8 *msg_name) |
| | | { |
| | | u8 i = 0; |
| | | RTW_INFO("======> Msg name: %s\n", msg_name); |
| | | for (i = 0; i < len; i++) |
| | | printk("%02x ", tx_msg[i]); |
| | | printk("\n"); |
| | | RTW_INFO("Msg name: %s <======\n", msg_name); |
| | | } |
| | | |
| | | /* Porting from Windows team */ |
| | | void rtw_btcoex_SendEventExtBtCoexControl(PADAPTER padapter, u8 bNeedDbgRsp, u8 dataLen, void *pData) |
| | | { |
| | | u8 len = 0, tx_event_length = 0; |
| | | u8 localBuf[32] = ""; |
| | | u8 *pRetPar; |
| | | u8 opCode = 0; |
| | | u8 *pInBuf = (pu1Byte)pData; |
| | | u8 *pOpCodeContent; |
| | | rtw_HCI_event *pEvent; |
| | | |
| | | opCode = pInBuf[0]; |
| | | |
| | | RTW_INFO("%s, OPCode:%02x\n", __func__, opCode); |
| | | |
| | | pEvent = (rtw_HCI_event *)(&localBuf[0]); |
| | | |
| | | /* len += bthci_ExtensionEventHeaderRtk(&localBuf[0], */ |
| | | /* HCI_EVENT_EXT_BT_COEX_CONTROL); */ |
| | | pEvent->EventCode = HCI_EVENT_EXTENSION_RTK; |
| | | pEvent->Data[0] = HCI_EVENT_EXT_BT_COEX_CONTROL; /* extension event code */ |
| | | len++; |
| | | |
| | | /* Return parameters starts from here */ |
| | | pRetPar = &pEvent->Data[len]; |
| | | _rtw_memcpy(&pRetPar[0], pData, dataLen); |
| | | |
| | | len += dataLen; |
| | | |
| | | pEvent->Length = len; |
| | | |
| | | /* total tx event length + EventCode length + sizeof(length) */ |
| | | tx_event_length = pEvent->Length + 2; |
| | | #if 0 |
| | | rtw_btcoex_dump_tx_msg((u8 *)pEvent, tx_event_length, "BT COEX CONTROL", _FALSE); |
| | | #endif |
| | | rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); |
| | | |
| | | } |
| | | |
| | | /* Porting from Windows team */ |
| | | void rtw_btcoex_SendEventExtBtInfoControl(PADAPTER padapter, u8 dataLen, void *pData) |
| | | { |
| | | rtw_HCI_event *pEvent; |
| | | u8 *pRetPar; |
| | | u8 len = 0, tx_event_length = 0; |
| | | u8 localBuf[32] = ""; |
| | | |
| | | struct bt_coex_info *pcoex_info = &padapter->coex_info; |
| | | PBT_MGNT pBtMgnt = &pcoex_info->BtMgnt; |
| | | |
| | | /* RTW_INFO("%s\n",__func__);*/ |
| | | if (pBtMgnt->ExtConfig.HCIExtensionVer < 4) { /* not support */ |
| | | RTW_INFO("ERROR: HCIExtensionVer = %d, HCIExtensionVer<4 !!!!\n", pBtMgnt->ExtConfig.HCIExtensionVer); |
| | | return; |
| | | } |
| | | |
| | | pEvent = (rtw_HCI_event *)(&localBuf[0]); |
| | | |
| | | /* len += bthci_ExtensionEventHeaderRtk(&localBuf[0], */ |
| | | /* HCI_EVENT_EXT_BT_INFO_CONTROL); */ |
| | | pEvent->EventCode = HCI_EVENT_EXTENSION_RTK; |
| | | pEvent->Data[0] = HCI_EVENT_EXT_BT_INFO_CONTROL; /* extension event code */ |
| | | len++; |
| | | |
| | | /* Return parameters starts from here */ |
| | | pRetPar = &pEvent->Data[len]; |
| | | _rtw_memcpy(&pRetPar[0], pData, dataLen); |
| | | |
| | | len += dataLen; |
| | | |
| | | pEvent->Length = len; |
| | | |
| | | /* total tx event length + EventCode length + sizeof(length) */ |
| | | tx_event_length = pEvent->Length + 2; |
| | | #if 0 |
| | | rtw_btcoex_dump_tx_msg((u8 *)pEvent, tx_event_length, "BT INFO CONTROL"); |
| | | #endif |
| | | rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); |
| | | |
| | | } |
| | | |
| | | void rtw_btcoex_SendScanNotify(PADAPTER padapter, u8 scanType) |
| | | { |
| | | u8 len = 0, tx_event_length = 0; |
| | | u8 localBuf[7] = ""; |
| | | u8 *pRetPar; |
| | | u8 *pu1Temp; |
| | | rtw_HCI_event *pEvent; |
| | | struct bt_coex_info *pcoex_info = &padapter->coex_info; |
| | | PBT_MGNT pBtMgnt = &pcoex_info->BtMgnt; |
| | | |
| | | /* if(!pBtMgnt->BtOperationOn) |
| | | * return; */ |
| | | |
| | | pEvent = (rtw_HCI_event *)(&localBuf[0]); |
| | | |
| | | /* len += bthci_ExtensionEventHeaderRtk(&localBuf[0], |
| | | * HCI_EVENT_EXT_WIFI_SCAN_NOTIFY); */ |
| | | |
| | | pEvent->EventCode = HCI_EVENT_EXTENSION_RTK; |
| | | pEvent->Data[0] = HCI_EVENT_EXT_WIFI_SCAN_NOTIFY; /* extension event code */ |
| | | len++; |
| | | |
| | | /* Return parameters starts from here */ |
| | | /* pRetPar = &PPacketIrpEvent->Data[len]; */ |
| | | /* pu1Temp = (u8 *)&pRetPar[0]; */ |
| | | /* *pu1Temp = scanType; */ |
| | | pEvent->Data[len] = scanType; |
| | | len += 1; |
| | | |
| | | pEvent->Length = len; |
| | | |
| | | /* total tx event length + EventCode length + sizeof(length) */ |
| | | tx_event_length = pEvent->Length + 2; |
| | | #if 0 |
| | | rtw_btcoex_dump_tx_msg((u8 *)pEvent, tx_event_length, "WIFI SCAN OPERATION"); |
| | | #endif |
| | | rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); |
| | | } |
| | | #endif /* CONFIG_BT_COEXIST_SOCKET_TRX */ |
| | | #endif /* CONFIG_BT_COEXIST */ |
linux-bsp/drivers/rtl8188eus/core/rtw_btcoex_wifionly.c
linux-bsp/drivers/rtl8188eus/core/rtw_cmd.c
linux-bsp/drivers/rtl8188eus/core/rtw_debug.c
linux-bsp/drivers/rtl8188eus/core/rtw_eeprom.c
linux-bsp/drivers/rtl8188eus/core/rtw_ieee80211.c
linux-bsp/drivers/rtl8188eus/core/rtw_io.c
linux-bsp/drivers/rtl8188eus/core/rtw_ioctl_query.c
linux-bsp/drivers/rtl8188eus/core/rtw_ioctl_rtl.c
linux-bsp/drivers/rtl8188eus/core/rtw_ioctl_set.c
linux-bsp/drivers/rtl8188eus/core/rtw_iol.c
linux-bsp/drivers/rtl8188eus/core/rtw_mem.c
linux-bsp/drivers/rtl8188eus/core/rtw_mi.c
linux-bsp/drivers/rtl8188eus/core/rtw_mlme.c
linux-bsp/drivers/rtl8188eus/core/rtw_mlme_ext.c
linux-bsp/drivers/rtl8188eus/core/rtw_mp.c
linux-bsp/drivers/rtl8188eus/core/rtw_mp_ioctl.c
linux-bsp/drivers/rtl8188eus/core/rtw_odm.c
linux-bsp/drivers/rtl8188eus/core/rtw_p2p.c
linux-bsp/drivers/rtl8188eus/core/rtw_pwrctrl.c
linux-bsp/drivers/rtl8188eus/core/rtw_recv.c
linux-bsp/drivers/rtl8188eus/core/rtw_rf.c
linux-bsp/drivers/rtl8188eus/core/rtw_sdio.c
linux-bsp/drivers/rtl8188eus/core/rtw_security.c
linux-bsp/drivers/rtl8188eus/core/rtw_sreset.c
linux-bsp/drivers/rtl8188eus/core/rtw_sta_mgt.c
linux-bsp/drivers/rtl8188eus/core/rtw_tdls.c
linux-bsp/drivers/rtl8188eus/core/rtw_vht.c
linux-bsp/drivers/rtl8188eus/core/rtw_wapi.c
linux-bsp/drivers/rtl8188eus/core/rtw_wapi_sms4.c
linux-bsp/drivers/rtl8188eus/core/rtw_wlan_util.c
linux-bsp/drivers/rtl8188eus/core/rtw_xmit.c
linux-bsp/drivers/rtl8188eus/hal/HalPwrSeqCmd.c
linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8188c2Ant.c
linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8188c2Ant.h
linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8192d2Ant.c
linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8192d2Ant.h
linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8192e1Ant.c
linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8192e1Ant.h
linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8192e2Ant.c
linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8192e2Ant.h
linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8723a1Ant.c
linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8723a1Ant.h
linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8723a2Ant.c
linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8723a2Ant.h
linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8723b1Ant.c
linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8723b1Ant.h
linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8723b2Ant.c
linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8723b2Ant.h
linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8812a1Ant.c
linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8812a1Ant.h
linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8812a2Ant.c
linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8812a2Ant.h
linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8821a1Ant.c
linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8821a1Ant.h
linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8821a2Ant.c
linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8821a2Ant.h
linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtcOutSrc.h
linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/Mp_Precomp.h
linux-bsp/drivers/rtl8188eus/hal/OUTSRC/HalPhyRf.c
linux-bsp/drivers/rtl8188eus/hal/OUTSRC/HalPhyRf.h
linux-bsp/drivers/rtl8188eus/hal/OUTSRC/PhyDM_Adaptivity.c
linux-bsp/drivers/rtl8188eus/hal/OUTSRC/PhyDM_Adaptivity.h
linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm.c
linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm.h
linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_AntDiv.c
linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_AntDiv.h
linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_HWConfig.c
linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_HWConfig.h
linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_RegDefine11AC.h
linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_RegDefine11N.h
linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_debug.c
linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_debug.h
linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_interface.c
linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_interface.h
linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_precomp.h
linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_reg.h
linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_types.h
linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/Hal8188ERateAdaptive.c
linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/Hal8188ERateAdaptive.h
linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/Hal8188EReg.h
linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/HalHWImg8188E_BB.c
linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/HalHWImg8188E_BB.h
linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/HalHWImg8188E_FW.c
linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/HalHWImg8188E_FW.h
linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/HalHWImg8188E_MAC.c
linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/HalHWImg8188E_MAC.h
linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/HalHWImg8188E_RF.c
linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/HalHWImg8188E_RF.h
linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/HalPhyRf_8188e.c
linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/HalPhyRf_8188e.h
linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/odm_RTL8188E.c
linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/odm_RTL8188E.h
linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/odm_RegConfig8188E.c
linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/odm_RegConfig8188E.h
linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8192e1ant.c
linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8192e1ant.h
linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8192e2ant.c
linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8192e2ant.h
linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8703b1ant.c
linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8703b1ant.h
linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8723b1ant.c
linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8723b1ant.h
linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8723b2ant.c
linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8723b2ant.h
linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8723bwifionly.c
linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8723bwifionly.h
linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8723d1ant.c
linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8723d1ant.h
linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8723d2ant.c
linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8723d2ant.h
linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8812a1ant.c
linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8812a1ant.h
linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8812a2ant.c
linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8812a2ant.h
linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8821a1ant.c
linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8821a1ant.h
linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8821a2ant.c
linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8821a2ant.h
linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8821c1ant.c
linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8821c1ant.h
linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8821c2ant.c
linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8821c2ant.h
linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8821cwifionly.c
linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8821cwifionly.h
linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8822b1ant.c
linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8822b1ant.h
linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8822b2ant.c
linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8822b2ant.h
linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8822bwifionly.c
linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8822bwifionly.h
linux-bsp/drivers/rtl8188eus/hal/btc/halbtcoutsrc.h
linux-bsp/drivers/rtl8188eus/hal/btc/mp_precomp.h
linux-bsp/drivers/rtl8188eus/hal/efuse/efuse_mask.h
linux-bsp/drivers/rtl8188eus/hal/efuse/rtl8188e/HalEfuseMask8188E_PCIE.c
linux-bsp/drivers/rtl8188eus/hal/efuse/rtl8188e/HalEfuseMask8188E_PCIE.h
linux-bsp/drivers/rtl8188eus/hal/efuse/rtl8188e/HalEfuseMask8188E_SDIO.c
linux-bsp/drivers/rtl8188eus/hal/efuse/rtl8188e/HalEfuseMask8188E_SDIO.h
linux-bsp/drivers/rtl8188eus/hal/efuse/rtl8188e/HalEfuseMask8188E_USB.c
linux-bsp/drivers/rtl8188eus/hal/efuse/rtl8188e/HalEfuseMask8188E_USB.h
linux-bsp/drivers/rtl8188eus/hal/hal_btcoex.c
linux-bsp/drivers/rtl8188eus/hal/hal_btcoex_wifionly.c
linux-bsp/drivers/rtl8188eus/hal/hal_com.c
linux-bsp/drivers/rtl8188eus/hal/hal_com_c2h.h
linux-bsp/drivers/rtl8188eus/hal/hal_com_phycfg.c
linux-bsp/drivers/rtl8188eus/hal/hal_dm.c
linux-bsp/drivers/rtl8188eus/hal/hal_dm.h
linux-bsp/drivers/rtl8188eus/hal/hal_halmac.c
linux-bsp/drivers/rtl8188eus/hal/hal_halmac.h
linux-bsp/drivers/rtl8188eus/hal/hal_hci/hal_usb.c
linux-bsp/drivers/rtl8188eus/hal/hal_intf.c
linux-bsp/drivers/rtl8188eus/hal/hal_mcc.c
linux-bsp/drivers/rtl8188eus/hal/hal_mp.c
linux-bsp/drivers/rtl8188eus/hal/hal_phy.c
linux-bsp/drivers/rtl8188eus/hal/led/hal_usb_led.c
linux-bsp/drivers/rtl8188eus/hal/phydm/halhwimg.h
linux-bsp/drivers/rtl8188eus/hal/phydm/halphyrf_ap.c
linux-bsp/drivers/rtl8188eus/hal/phydm/halphyrf_ap.h
linux-bsp/drivers/rtl8188eus/hal/phydm/halphyrf_ce.c
linux-bsp/drivers/rtl8188eus/hal/phydm/halphyrf_ce.h
linux-bsp/drivers/rtl8188eus/hal/phydm/halphyrf_win.c
linux-bsp/drivers/rtl8188eus/hal/phydm/halphyrf_win.h
linux-bsp/drivers/rtl8188eus/hal/phydm/mp_precomp.h
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm.c
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm.h
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_acs.c
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_acs.h
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_adaptivity.c
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_adaptivity.h
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_adc_sampling.c
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_adc_sampling.h
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_antdect.c
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_antdect.h
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_antdiv.c
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_antdiv.h
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_beamforming.c
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_beamforming.h
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_ccx.c
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_ccx.h
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_cfotracking.c
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_cfotracking.h
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_debug.c
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_debug.h
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_dfs.c
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_dfs.h
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_dig.c
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_dig.h
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_dynamic_rx_path.c
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_dynamic_rx_path.h
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_dynamicbbpowersaving.c
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_dynamicbbpowersaving.h
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_dynamictxpower.c
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_dynamictxpower.h
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_edcaturbocheck.c
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_edcaturbocheck.h
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_features.h
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_hwconfig.c
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_hwconfig.h
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_interface.c
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_interface.h
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_iqk.h
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_kfree.c
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_kfree.h
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_noisemonitor.c
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_noisemonitor.h
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_pathdiv.c
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_pathdiv.h
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_powertracking_ap.c
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_powertracking_ap.h
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_powertracking_ce.c
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_powertracking_ce.h
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_powertracking_win.c
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_powertracking_win.h
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_pre_define.h
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_precomp.h
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_rainfo.c
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_rainfo.h
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_reg.h
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_regdefine11ac.h
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_regdefine11n.h
linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_types.h
linux-bsp/drivers/rtl8188eus/hal/phydm/rtchnlplan.c
linux-bsp/drivers/rtl8188eus/hal/phydm/rtchnlplan.h
linux-bsp/drivers/rtl8188eus/hal/phydm/rtl8188e/hal8188erateadaptive.c
linux-bsp/drivers/rtl8188eus/hal/phydm/rtl8188e/hal8188erateadaptive.h
linux-bsp/drivers/rtl8188eus/hal/phydm/rtl8188e/hal8188ereg.h
linux-bsp/drivers/rtl8188eus/hal/phydm/rtl8188e/halhwimg8188e_bb.c
linux-bsp/drivers/rtl8188eus/hal/phydm/rtl8188e/halhwimg8188e_bb.h
linux-bsp/drivers/rtl8188eus/hal/phydm/rtl8188e/halhwimg8188e_mac.c
linux-bsp/drivers/rtl8188eus/hal/phydm/rtl8188e/halhwimg8188e_mac.h
linux-bsp/drivers/rtl8188eus/hal/phydm/rtl8188e/halhwimg8188e_rf.c
linux-bsp/drivers/rtl8188eus/hal/phydm/rtl8188e/halhwimg8188e_rf.h
linux-bsp/drivers/rtl8188eus/hal/phydm/rtl8188e/halhwimg8188e_s_fw.c
linux-bsp/drivers/rtl8188eus/hal/phydm/rtl8188e/halhwimg8188e_s_fw.h
linux-bsp/drivers/rtl8188eus/hal/phydm/rtl8188e/halhwimg8188e_t_fw.c
linux-bsp/drivers/rtl8188eus/hal/phydm/rtl8188e/halhwimg8188e_t_fw.h
linux-bsp/drivers/rtl8188eus/hal/phydm/rtl8188e/halphyrf_8188e_ap.c
linux-bsp/drivers/rtl8188eus/hal/phydm/rtl8188e/halphyrf_8188e_ap.h
linux-bsp/drivers/rtl8188eus/hal/phydm/rtl8188e/halphyrf_8188e_ce.c
linux-bsp/drivers/rtl8188eus/hal/phydm/rtl8188e/halphyrf_8188e_ce.h
linux-bsp/drivers/rtl8188eus/hal/phydm/rtl8188e/halphyrf_8188e_win.c
linux-bsp/drivers/rtl8188eus/hal/phydm/rtl8188e/halphyrf_8188e_win.h
linux-bsp/drivers/rtl8188eus/hal/phydm/rtl8188e/phydm_regconfig8188e.c
linux-bsp/drivers/rtl8188eus/hal/phydm/rtl8188e/phydm_regconfig8188e.h
linux-bsp/drivers/rtl8188eus/hal/phydm/rtl8188e/phydm_rtl8188e.c
linux-bsp/drivers/rtl8188eus/hal/phydm/rtl8188e/phydm_rtl8188e.h
linux-bsp/drivers/rtl8188eus/hal/phydm/rtl8188e/version_rtl8188e.h
linux-bsp/drivers/rtl8188eus/hal/phydm/txbf/halcomtxbf.c
linux-bsp/drivers/rtl8188eus/hal/phydm/txbf/halcomtxbf.h
linux-bsp/drivers/rtl8188eus/hal/phydm/txbf/haltxbf8192e.c
linux-bsp/drivers/rtl8188eus/hal/phydm/txbf/haltxbf8192e.h
linux-bsp/drivers/rtl8188eus/hal/phydm/txbf/haltxbf8814a.c
linux-bsp/drivers/rtl8188eus/hal/phydm/txbf/haltxbf8814a.h
linux-bsp/drivers/rtl8188eus/hal/phydm/txbf/haltxbf8822b.c
linux-bsp/drivers/rtl8188eus/hal/phydm/txbf/haltxbf8822b.h
linux-bsp/drivers/rtl8188eus/hal/phydm/txbf/haltxbfinterface.c
linux-bsp/drivers/rtl8188eus/hal/phydm/txbf/haltxbfinterface.h
linux-bsp/drivers/rtl8188eus/hal/phydm/txbf/haltxbfjaguar.c
linux-bsp/drivers/rtl8188eus/hal/phydm/txbf/haltxbfjaguar.h
linux-bsp/drivers/rtl8188eus/hal/phydm/txbf/phydm_hal_txbf_api.c
linux-bsp/drivers/rtl8188eus/hal/phydm/txbf/phydm_hal_txbf_api.h
linux-bsp/drivers/rtl8188eus/hal/rtl8188e/Hal8188EPwrSeq.c
linux-bsp/drivers/rtl8188eus/hal/rtl8188e/hal8188e_s_fw.c
linux-bsp/drivers/rtl8188eus/hal/rtl8188e/hal8188e_s_fw.h
linux-bsp/drivers/rtl8188eus/hal/rtl8188e/hal8188e_t_fw.c
linux-bsp/drivers/rtl8188eus/hal/rtl8188e/hal8188e_t_fw.h
linux-bsp/drivers/rtl8188eus/hal/rtl8188e/rtl8188e_cmd.c
linux-bsp/drivers/rtl8188eus/hal/rtl8188e/rtl8188e_dm.c
linux-bsp/drivers/rtl8188eus/hal/rtl8188e/rtl8188e_hal_init.c
linux-bsp/drivers/rtl8188eus/hal/rtl8188e/rtl8188e_mp.c
linux-bsp/drivers/rtl8188eus/hal/rtl8188e/rtl8188e_phycfg.c
linux-bsp/drivers/rtl8188eus/hal/rtl8188e/rtl8188e_rf6052.c
linux-bsp/drivers/rtl8188eus/hal/rtl8188e/rtl8188e_rxdesc.c
linux-bsp/drivers/rtl8188eus/hal/rtl8188e/rtl8188e_sreset.c
linux-bsp/drivers/rtl8188eus/hal/rtl8188e/rtl8188e_xmit.c
linux-bsp/drivers/rtl8188eus/hal/rtl8188e/usb/rtl8188eu_led.c
linux-bsp/drivers/rtl8188eus/hal/rtl8188e/usb/rtl8188eu_recv.c
linux-bsp/drivers/rtl8188eus/hal/rtl8188e/usb/rtl8188eu_xmit.c
linux-bsp/drivers/rtl8188eus/hal/rtl8188e/usb/usb_halinit.c
linux-bsp/drivers/rtl8188eus/hal/rtl8188e/usb/usb_ops_linux.c
linux-bsp/drivers/rtl8188eus/include/Hal8188EPhyCfg.h
linux-bsp/drivers/rtl8188eus/include/Hal8188EPhyReg.h
linux-bsp/drivers/rtl8188eus/include/Hal8188EPwrSeq.h
linux-bsp/drivers/rtl8188eus/include/Hal8188FPhyCfg.h
linux-bsp/drivers/rtl8188eus/include/Hal8188FPhyReg.h
linux-bsp/drivers/rtl8188eus/include/Hal8188FPwrSeq.h
linux-bsp/drivers/rtl8188eus/include/Hal8192CPhyCfg.h
linux-bsp/drivers/rtl8188eus/include/Hal8192CPhyReg.h
linux-bsp/drivers/rtl8188eus/include/Hal8192DPhyCfg.h
linux-bsp/drivers/rtl8188eus/include/Hal8192DPhyReg.h
linux-bsp/drivers/rtl8188eus/include/Hal8192EPhyCfg.h
linux-bsp/drivers/rtl8188eus/include/Hal8192EPhyReg.h
linux-bsp/drivers/rtl8188eus/include/Hal8192EPwrSeq.h
linux-bsp/drivers/rtl8188eus/include/Hal8703BPhyCfg.h
linux-bsp/drivers/rtl8188eus/include/Hal8703BPhyReg.h
linux-bsp/drivers/rtl8188eus/include/Hal8703BPwrSeq.h
linux-bsp/drivers/rtl8188eus/include/Hal8723APhyCfg.h
linux-bsp/drivers/rtl8188eus/include/Hal8723APhyReg.h
linux-bsp/drivers/rtl8188eus/include/Hal8723BPhyCfg.h
linux-bsp/drivers/rtl8188eus/include/Hal8723BPhyReg.h
linux-bsp/drivers/rtl8188eus/include/Hal8723BPwrSeq.h
linux-bsp/drivers/rtl8188eus/include/Hal8723DPhyCfg.h
linux-bsp/drivers/rtl8188eus/include/Hal8723DPhyReg.h
linux-bsp/drivers/rtl8188eus/include/Hal8723DPwrSeq.h
linux-bsp/drivers/rtl8188eus/include/Hal8723PwrSeq.h
linux-bsp/drivers/rtl8188eus/include/Hal8812PhyCfg.h
linux-bsp/drivers/rtl8188eus/include/Hal8812PhyReg.h
linux-bsp/drivers/rtl8188eus/include/Hal8812PwrSeq.h
linux-bsp/drivers/rtl8188eus/include/Hal8814PhyCfg.h
linux-bsp/drivers/rtl8188eus/include/Hal8814PhyReg.h
linux-bsp/drivers/rtl8188eus/include/Hal8814PwrSeq.h
linux-bsp/drivers/rtl8188eus/include/Hal8821APwrSeq.h
linux-bsp/drivers/rtl8188eus/include/HalPwrSeqCmd.h
linux-bsp/drivers/rtl8188eus/include/HalVerDef.h
linux-bsp/drivers/rtl8188eus/include/autoconf.h
linux-bsp/drivers/rtl8188eus/include/basic_types.h
linux-bsp/drivers/rtl8188eus/include/byteorder/big_endian.h
linux-bsp/drivers/rtl8188eus/include/byteorder/generic.h
linux-bsp/drivers/rtl8188eus/include/byteorder/little_endian.h
linux-bsp/drivers/rtl8188eus/include/byteorder/swab.h
linux-bsp/drivers/rtl8188eus/include/byteorder/swabb.h
linux-bsp/drivers/rtl8188eus/include/circ_buf.h
linux-bsp/drivers/rtl8188eus/include/cmd_osdep.h
linux-bsp/drivers/rtl8188eus/include/custom_gpio.h
linux-bsp/drivers/rtl8188eus/include/drv_conf.h
linux-bsp/drivers/rtl8188eus/include/drv_types.h
linux-bsp/drivers/rtl8188eus/include/drv_types_ce.h
linux-bsp/drivers/rtl8188eus/include/drv_types_gspi.h
linux-bsp/drivers/rtl8188eus/include/drv_types_linux.h
linux-bsp/drivers/rtl8188eus/include/drv_types_pci.h
linux-bsp/drivers/rtl8188eus/include/drv_types_sdio.h
linux-bsp/drivers/rtl8188eus/include/drv_types_xp.h
linux-bsp/drivers/rtl8188eus/include/ethernet.h
linux-bsp/drivers/rtl8188eus/include/gspi_hal.h
linux-bsp/drivers/rtl8188eus/include/gspi_ops.h
linux-bsp/drivers/rtl8188eus/include/gspi_ops_linux.h
linux-bsp/drivers/rtl8188eus/include/gspi_osintf.h
linux-bsp/drivers/rtl8188eus/include/h2clbk.h
linux-bsp/drivers/rtl8188eus/include/hal_btcoex.h
linux-bsp/drivers/rtl8188eus/include/hal_btcoex_wifionly.h
linux-bsp/drivers/rtl8188eus/include/hal_com.h
linux-bsp/drivers/rtl8188eus/include/hal_com_h2c.h
linux-bsp/drivers/rtl8188eus/include/hal_com_led.h
linux-bsp/drivers/rtl8188eus/include/hal_com_phycfg.h
linux-bsp/drivers/rtl8188eus/include/hal_com_reg.h
linux-bsp/drivers/rtl8188eus/include/hal_data.h
linux-bsp/drivers/rtl8188eus/include/hal_gspi.h
linux-bsp/drivers/rtl8188eus/include/hal_ic_cfg.h
linux-bsp/drivers/rtl8188eus/include/hal_intf.h
linux-bsp/drivers/rtl8188eus/include/hal_pg.h
linux-bsp/drivers/rtl8188eus/include/hal_phy.h
linux-bsp/drivers/rtl8188eus/include/hal_phy_reg.h
linux-bsp/drivers/rtl8188eus/include/hal_sdio.h
linux-bsp/drivers/rtl8188eus/include/ieee80211.h
linux-bsp/drivers/rtl8188eus/include/ieee80211_ext.h
linux-bsp/drivers/rtl8188eus/include/if_ether.h
linux-bsp/drivers/rtl8188eus/include/ioctl_cfg80211.h
linux-bsp/drivers/rtl8188eus/include/ip.h
linux-bsp/drivers/rtl8188eus/include/linux/wireless.h
linux-bsp/drivers/rtl8188eus/include/mlme_osdep.h
linux-bsp/drivers/rtl8188eus/include/mp_custom_oid.h
linux-bsp/drivers/rtl8188eus/include/nic_spec.h
linux-bsp/drivers/rtl8188eus/include/osdep_intf.h
linux-bsp/drivers/rtl8188eus/include/osdep_service.h
linux-bsp/drivers/rtl8188eus/include/osdep_service_bsd.h
linux-bsp/drivers/rtl8188eus/include/osdep_service_ce.h
linux-bsp/drivers/rtl8188eus/include/osdep_service_linux.h
linux-bsp/drivers/rtl8188eus/include/osdep_service_xp.h
linux-bsp/drivers/rtl8188eus/include/pci_hal.h
linux-bsp/drivers/rtl8188eus/include/pci_ops.h
linux-bsp/drivers/rtl8188eus/include/pci_osintf.h
linux-bsp/drivers/rtl8188eus/include/recv_osdep.h
linux-bsp/drivers/rtl8188eus/include/rtl8188e_cmd.h
linux-bsp/drivers/rtl8188eus/include/rtl8188e_dm.h
linux-bsp/drivers/rtl8188eus/include/rtl8188e_hal.h
linux-bsp/drivers/rtl8188eus/include/rtl8188e_led.h
linux-bsp/drivers/rtl8188eus/include/rtl8188e_recv.h
linux-bsp/drivers/rtl8188eus/include/rtl8188e_rf.h
linux-bsp/drivers/rtl8188eus/include/rtl8188e_spec.h
linux-bsp/drivers/rtl8188eus/include/rtl8188e_sreset.h
linux-bsp/drivers/rtl8188eus/include/rtl8188e_xmit.h
linux-bsp/drivers/rtl8188eus/include/rtl8188f_cmd.h
linux-bsp/drivers/rtl8188eus/include/rtl8188f_dm.h
linux-bsp/drivers/rtl8188eus/include/rtl8188f_hal.h
linux-bsp/drivers/rtl8188eus/include/rtl8188f_led.h
linux-bsp/drivers/rtl8188eus/include/rtl8188f_recv.h
linux-bsp/drivers/rtl8188eus/include/rtl8188f_rf.h
linux-bsp/drivers/rtl8188eus/include/rtl8188f_spec.h
linux-bsp/drivers/rtl8188eus/include/rtl8188f_sreset.h
linux-bsp/drivers/rtl8188eus/include/rtl8188f_xmit.h
linux-bsp/drivers/rtl8188eus/include/rtl8192c_cmd.h
linux-bsp/drivers/rtl8188eus/include/rtl8192c_dm.h
linux-bsp/drivers/rtl8188eus/include/rtl8192c_event.h
linux-bsp/drivers/rtl8188eus/include/rtl8192c_hal.h
linux-bsp/drivers/rtl8188eus/include/rtl8192c_led.h
linux-bsp/drivers/rtl8188eus/include/rtl8192c_recv.h
linux-bsp/drivers/rtl8188eus/include/rtl8192c_rf.h
linux-bsp/drivers/rtl8188eus/include/rtl8192c_spec.h
linux-bsp/drivers/rtl8188eus/include/rtl8192c_sreset.h
linux-bsp/drivers/rtl8188eus/include/rtl8192c_xmit.h
linux-bsp/drivers/rtl8188eus/include/rtl8192d_cmd.h
linux-bsp/drivers/rtl8188eus/include/rtl8192d_dm.h
linux-bsp/drivers/rtl8188eus/include/rtl8192d_hal.h
linux-bsp/drivers/rtl8188eus/include/rtl8192d_led.h
linux-bsp/drivers/rtl8188eus/include/rtl8192d_recv.h
linux-bsp/drivers/rtl8188eus/include/rtl8192d_rf.h
linux-bsp/drivers/rtl8188eus/include/rtl8192d_spec.h
linux-bsp/drivers/rtl8188eus/include/rtl8192d_xmit.h
linux-bsp/drivers/rtl8188eus/include/rtl8192e_cmd.h
linux-bsp/drivers/rtl8188eus/include/rtl8192e_dm.h
linux-bsp/drivers/rtl8188eus/include/rtl8192e_hal.h
linux-bsp/drivers/rtl8188eus/include/rtl8192e_led.h
linux-bsp/drivers/rtl8188eus/include/rtl8192e_recv.h
linux-bsp/drivers/rtl8188eus/include/rtl8192e_rf.h
linux-bsp/drivers/rtl8188eus/include/rtl8192e_spec.h
linux-bsp/drivers/rtl8188eus/include/rtl8192e_sreset.h
linux-bsp/drivers/rtl8188eus/include/rtl8192e_xmit.h
linux-bsp/drivers/rtl8188eus/include/rtl8703b_cmd.h
linux-bsp/drivers/rtl8188eus/include/rtl8703b_dm.h
linux-bsp/drivers/rtl8188eus/include/rtl8703b_hal.h
linux-bsp/drivers/rtl8188eus/include/rtl8703b_led.h
linux-bsp/drivers/rtl8188eus/include/rtl8703b_recv.h
linux-bsp/drivers/rtl8188eus/include/rtl8703b_rf.h
linux-bsp/drivers/rtl8188eus/include/rtl8703b_spec.h
linux-bsp/drivers/rtl8188eus/include/rtl8703b_sreset.h
linux-bsp/drivers/rtl8188eus/include/rtl8703b_xmit.h
linux-bsp/drivers/rtl8188eus/include/rtl8723a_cmd.h
linux-bsp/drivers/rtl8188eus/include/rtl8723a_dm.h
linux-bsp/drivers/rtl8188eus/include/rtl8723a_hal.h
linux-bsp/drivers/rtl8188eus/include/rtl8723a_led.h
linux-bsp/drivers/rtl8188eus/include/rtl8723a_pg.h
linux-bsp/drivers/rtl8188eus/include/rtl8723a_recv.h
linux-bsp/drivers/rtl8188eus/include/rtl8723a_rf.h
linux-bsp/drivers/rtl8188eus/include/rtl8723a_spec.h
linux-bsp/drivers/rtl8188eus/include/rtl8723a_sreset.h
linux-bsp/drivers/rtl8188eus/include/rtl8723a_xmit.h
linux-bsp/drivers/rtl8188eus/include/rtl8723b_cmd.h
linux-bsp/drivers/rtl8188eus/include/rtl8723b_dm.h
linux-bsp/drivers/rtl8188eus/include/rtl8723b_hal.h
linux-bsp/drivers/rtl8188eus/include/rtl8723b_led.h
linux-bsp/drivers/rtl8188eus/include/rtl8723b_recv.h
linux-bsp/drivers/rtl8188eus/include/rtl8723b_rf.h
linux-bsp/drivers/rtl8188eus/include/rtl8723b_spec.h
linux-bsp/drivers/rtl8188eus/include/rtl8723b_sreset.h
linux-bsp/drivers/rtl8188eus/include/rtl8723b_xmit.h
linux-bsp/drivers/rtl8188eus/include/rtl8723d_cmd.h
linux-bsp/drivers/rtl8188eus/include/rtl8723d_dm.h
linux-bsp/drivers/rtl8188eus/include/rtl8723d_hal.h
linux-bsp/drivers/rtl8188eus/include/rtl8723d_led.h
linux-bsp/drivers/rtl8188eus/include/rtl8723d_lps_poff.h
linux-bsp/drivers/rtl8188eus/include/rtl8723d_recv.h
linux-bsp/drivers/rtl8188eus/include/rtl8723d_rf.h
linux-bsp/drivers/rtl8188eus/include/rtl8723d_spec.h
linux-bsp/drivers/rtl8188eus/include/rtl8723d_sreset.h
linux-bsp/drivers/rtl8188eus/include/rtl8723d_xmit.h
linux-bsp/drivers/rtl8188eus/include/rtl8812a_cmd.h
linux-bsp/drivers/rtl8188eus/include/rtl8812a_dm.h
linux-bsp/drivers/rtl8188eus/include/rtl8812a_hal.h
linux-bsp/drivers/rtl8188eus/include/rtl8812a_led.h
linux-bsp/drivers/rtl8188eus/include/rtl8812a_recv.h
linux-bsp/drivers/rtl8188eus/include/rtl8812a_rf.h
linux-bsp/drivers/rtl8188eus/include/rtl8812a_spec.h
linux-bsp/drivers/rtl8188eus/include/rtl8812a_sreset.h
linux-bsp/drivers/rtl8188eus/include/rtl8812a_xmit.h
linux-bsp/drivers/rtl8188eus/include/rtl8814a_cmd.h
linux-bsp/drivers/rtl8188eus/include/rtl8814a_dm.h
linux-bsp/drivers/rtl8188eus/include/rtl8814a_hal.h
linux-bsp/drivers/rtl8188eus/include/rtl8814a_led.h
linux-bsp/drivers/rtl8188eus/include/rtl8814a_recv.h
linux-bsp/drivers/rtl8188eus/include/rtl8814a_rf.h
linux-bsp/drivers/rtl8188eus/include/rtl8814a_spec.h
linux-bsp/drivers/rtl8188eus/include/rtl8814a_sreset.h
linux-bsp/drivers/rtl8188eus/include/rtl8814a_xmit.h
linux-bsp/drivers/rtl8188eus/include/rtl8821a_spec.h
linux-bsp/drivers/rtl8188eus/include/rtl8821a_xmit.h
linux-bsp/drivers/rtl8188eus/include/rtl8821c_dm.h
linux-bsp/drivers/rtl8188eus/include/rtl8821c_hal.h
linux-bsp/drivers/rtl8188eus/include/rtl8821c_spec.h
linux-bsp/drivers/rtl8188eus/include/rtl8821ce_hal.h
linux-bsp/drivers/rtl8188eus/include/rtl8821cs_hal.h
linux-bsp/drivers/rtl8188eus/include/rtl8821cu_hal.h
linux-bsp/drivers/rtl8188eus/include/rtl8822b_hal.h
linux-bsp/drivers/rtl8188eus/include/rtl8822be_hal.h
linux-bsp/drivers/rtl8188eus/include/rtl8822bs_hal.h
linux-bsp/drivers/rtl8188eus/include/rtl8822bu_hal.h
linux-bsp/drivers/rtl8188eus/include/rtw_android.h
linux-bsp/drivers/rtl8188eus/include/rtw_ap.h
linux-bsp/drivers/rtl8188eus/include/rtw_beamforming.h
linux-bsp/drivers/rtl8188eus/include/rtw_br_ext.h
linux-bsp/drivers/rtl8188eus/include/rtw_bt_mp.h
linux-bsp/drivers/rtl8188eus/include/rtw_btcoex.h
linux-bsp/drivers/rtl8188eus/include/rtw_btcoex_wifionly.h
linux-bsp/drivers/rtl8188eus/include/rtw_byteorder.h
linux-bsp/drivers/rtl8188eus/include/rtw_cmd.h
linux-bsp/drivers/rtl8188eus/include/rtw_debug.h
linux-bsp/drivers/rtl8188eus/include/rtw_eeprom.h
linux-bsp/drivers/rtl8188eus/include/rtw_efuse.h
linux-bsp/drivers/rtl8188eus/include/rtw_event.h
linux-bsp/drivers/rtl8188eus/include/rtw_ht.h
linux-bsp/drivers/rtl8188eus/include/rtw_io.h
linux-bsp/drivers/rtl8188eus/include/rtw_ioctl.h
linux-bsp/drivers/rtl8188eus/include/rtw_ioctl_query.h
linux-bsp/drivers/rtl8188eus/include/rtw_ioctl_rtl.h
linux-bsp/drivers/rtl8188eus/include/rtw_ioctl_set.h
linux-bsp/drivers/rtl8188eus/include/rtw_iol.h
linux-bsp/drivers/rtl8188eus/include/rtw_mcc.h
linux-bsp/drivers/rtl8188eus/include/rtw_mem.h
linux-bsp/drivers/rtl8188eus/include/rtw_mi.h
linux-bsp/drivers/rtl8188eus/include/rtw_mlme.h
linux-bsp/drivers/rtl8188eus/include/rtw_mlme_ext.h
linux-bsp/drivers/rtl8188eus/include/rtw_mp.h
linux-bsp/drivers/rtl8188eus/include/rtw_mp_ioctl.h
linux-bsp/drivers/rtl8188eus/include/rtw_mp_phy_regdef.h
linux-bsp/drivers/rtl8188eus/include/rtw_odm.h
linux-bsp/drivers/rtl8188eus/include/rtw_p2p.h
linux-bsp/drivers/rtl8188eus/include/rtw_pwrctrl.h
linux-bsp/drivers/rtl8188eus/include/rtw_qos.h
linux-bsp/drivers/rtl8188eus/include/rtw_recv.h
linux-bsp/drivers/rtl8188eus/include/rtw_rf.h
linux-bsp/drivers/rtl8188eus/include/rtw_sdio.h
linux-bsp/drivers/rtl8188eus/include/rtw_security.h
linux-bsp/drivers/rtl8188eus/include/rtw_sreset.h
linux-bsp/drivers/rtl8188eus/include/rtw_tdls.h
linux-bsp/drivers/rtl8188eus/include/rtw_version.h
linux-bsp/drivers/rtl8188eus/include/rtw_vht.h
linux-bsp/drivers/rtl8188eus/include/rtw_wapi.h
linux-bsp/drivers/rtl8188eus/include/rtw_wifi_regd.h
linux-bsp/drivers/rtl8188eus/include/rtw_xmit.h
linux-bsp/drivers/rtl8188eus/include/sdio_hal.h
linux-bsp/drivers/rtl8188eus/include/sdio_ops.h
linux-bsp/drivers/rtl8188eus/include/sdio_ops_ce.h
linux-bsp/drivers/rtl8188eus/include/sdio_ops_linux.h
linux-bsp/drivers/rtl8188eus/include/sdio_ops_xp.h
linux-bsp/drivers/rtl8188eus/include/sdio_osintf.h
linux-bsp/drivers/rtl8188eus/include/sta_info.h
linux-bsp/drivers/rtl8188eus/include/usb_hal.h
linux-bsp/drivers/rtl8188eus/include/usb_ops.h
linux-bsp/drivers/rtl8188eus/include/usb_ops_linux.h
linux-bsp/drivers/rtl8188eus/include/usb_osintf.h
linux-bsp/drivers/rtl8188eus/include/usb_vendor_req.h
linux-bsp/drivers/rtl8188eus/include/wifi.h
linux-bsp/drivers/rtl8188eus/include/wlan_bssdef.h
linux-bsp/drivers/rtl8188eus/include/xmit_osdep.h
linux-bsp/drivers/rtl8188eus/os_dep/linux/custom_gpio_linux.c
linux-bsp/drivers/rtl8188eus/os_dep/linux/ioctl_cfg80211.c
linux-bsp/drivers/rtl8188eus/os_dep/linux/ioctl_cfg80211.h
linux-bsp/drivers/rtl8188eus/os_dep/linux/ioctl_linux.c
linux-bsp/drivers/rtl8188eus/os_dep/linux/ioctl_mp.c
linux-bsp/drivers/rtl8188eus/os_dep/linux/mlme_linux.c
linux-bsp/drivers/rtl8188eus/os_dep/linux/os_intfs.c
linux-bsp/drivers/rtl8188eus/os_dep/linux/recv_linux.c
linux-bsp/drivers/rtl8188eus/os_dep/linux/rtw_android.c
linux-bsp/drivers/rtl8188eus/os_dep/linux/rtw_cfgvendor.c
linux-bsp/drivers/rtl8188eus/os_dep/linux/rtw_cfgvendor.h
linux-bsp/drivers/rtl8188eus/os_dep/linux/rtw_proc.c
linux-bsp/drivers/rtl8188eus/os_dep/linux/rtw_proc.h
linux-bsp/drivers/rtl8188eus/os_dep/linux/usb_intf.c
linux-bsp/drivers/rtl8188eus/os_dep/linux/usb_ops_linux.c
linux-bsp/drivers/rtl8188eus/os_dep/linux/wifi_regd.c
linux-bsp/drivers/rtl8188eus/os_dep/linux/xmit_linux.c
linux-bsp/drivers/rtl8188eus/os_dep/osdep_service.c
linux-bsp/drivers/rtl8188eus/platform/custom_country_chplan.h
linux-bsp/drivers/rtl8188eus/platform/platform_ARM_SUN50IW1P1_sdio.c
linux-bsp/drivers/rtl8188eus/platform/platform_ARM_SUNnI_sdio.c
linux-bsp/drivers/rtl8188eus/platform/platform_ARM_SUNxI_sdio.c
linux-bsp/drivers/rtl8188eus/platform/platform_ARM_SUNxI_usb.c
linux-bsp/drivers/rtl8188eus/platform/platform_ARM_WMT_sdio.c
linux-bsp/drivers/rtl8188eus/platform/platform_RTK_DMP_usb.c
linux-bsp/drivers/rtl8188eus/platform/platform_arm_act_sdio.c
linux-bsp/drivers/rtl8188eus/platform/platform_ops.c
linux-bsp/drivers/rtl8188eus/platform/platform_ops.h
linux-bsp/drivers/rtl8188eus/platform/platform_sprd_sdio.c |