rtl8187_dev.c
来自「linux 内核源代码」· C语言 代码 · 共 827 行 · 第 1/2 页
C
827 行
/* * Linux device driver for RTL8187 * * Copyright 2007 Michael Wu <flamingice@sourmilk.net> * Copyright 2007 Andrea Merello <andreamrl@tiscali.it> * * Based on the r8187 driver, which is: * Copyright 2005 Andrea Merello <andreamrl@tiscali.it>, et al. * * Magic delays and register offsets below are taken from the original * r8187 driver sources. Thanks to Realtek for their support! * * 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. */#include <linux/init.h>#include <linux/usb.h>#include <linux/delay.h>#include <linux/etherdevice.h>#include <linux/eeprom_93cx6.h>#include <net/mac80211.h>#include "rtl8187.h"#include "rtl8187_rtl8225.h"MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");MODULE_AUTHOR("Andrea Merello <andreamrl@tiscali.it>");MODULE_DESCRIPTION("RTL8187 USB wireless driver");MODULE_LICENSE("GPL");static struct usb_device_id rtl8187_table[] __devinitdata = { /* Realtek */ {USB_DEVICE(0x0bda, 0x8187)}, /* Netgear */ {USB_DEVICE(0x0846, 0x6100)}, {USB_DEVICE(0x0846, 0x6a00)}, /* HP */ {USB_DEVICE(0x03f0, 0xca02)}, /* Sitecom */ {USB_DEVICE(0x0df6, 0x000d)}, {}};MODULE_DEVICE_TABLE(usb, rtl8187_table);static void rtl8187_iowrite_async_cb(struct urb *urb){ kfree(urb->context); usb_free_urb(urb);}static void rtl8187_iowrite_async(struct rtl8187_priv *priv, __le16 addr, void *data, u16 len){ struct usb_ctrlrequest *dr; struct urb *urb; struct rtl8187_async_write_data { u8 data[4]; struct usb_ctrlrequest dr; } *buf; buf = kmalloc(sizeof(*buf), GFP_ATOMIC); if (!buf) return; urb = usb_alloc_urb(0, GFP_ATOMIC); if (!urb) { kfree(buf); return; } dr = &buf->dr; dr->bRequestType = RTL8187_REQT_WRITE; dr->bRequest = RTL8187_REQ_SET_REG; dr->wValue = addr; dr->wIndex = 0; dr->wLength = cpu_to_le16(len); memcpy(buf, data, len); usb_fill_control_urb(urb, priv->udev, usb_sndctrlpipe(priv->udev, 0), (unsigned char *)dr, buf, len, rtl8187_iowrite_async_cb, buf); usb_submit_urb(urb, GFP_ATOMIC);}static inline void rtl818x_iowrite32_async(struct rtl8187_priv *priv, __le32 *addr, u32 val){ __le32 buf = cpu_to_le32(val); rtl8187_iowrite_async(priv, cpu_to_le16((unsigned long)addr), &buf, sizeof(buf));}void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data){ struct rtl8187_priv *priv = dev->priv; data <<= 8; data |= addr | 0x80; rtl818x_iowrite8(priv, &priv->map->PHY[3], (data >> 24) & 0xFF); rtl818x_iowrite8(priv, &priv->map->PHY[2], (data >> 16) & 0xFF); rtl818x_iowrite8(priv, &priv->map->PHY[1], (data >> 8) & 0xFF); rtl818x_iowrite8(priv, &priv->map->PHY[0], data & 0xFF); msleep(1);}static void rtl8187_tx_cb(struct urb *urb){ struct ieee80211_tx_status status = { {0} }; struct sk_buff *skb = (struct sk_buff *)urb->context; struct rtl8187_tx_info *info = (struct rtl8187_tx_info *)skb->cb; usb_free_urb(info->urb); if (info->control) memcpy(&status.control, info->control, sizeof(status.control)); kfree(info->control); skb_pull(skb, sizeof(struct rtl8187_tx_hdr)); status.flags |= IEEE80211_TX_STATUS_ACK; ieee80211_tx_status_irqsafe(info->dev, skb, &status);}static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb, struct ieee80211_tx_control *control){ struct rtl8187_priv *priv = dev->priv; struct rtl8187_tx_hdr *hdr; struct rtl8187_tx_info *info; struct urb *urb; __le16 rts_dur = 0; u32 flags; urb = usb_alloc_urb(0, GFP_ATOMIC); if (!urb) { kfree_skb(skb); return 0; } flags = skb->len; flags |= RTL8187_TX_FLAG_NO_ENCRYPT; flags |= control->rts_cts_rate << 19; flags |= control->tx_rate << 24; if (ieee80211_get_morefrag((struct ieee80211_hdr *)skb->data)) flags |= RTL8187_TX_FLAG_MORE_FRAG; if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) { flags |= RTL8187_TX_FLAG_RTS; rts_dur = ieee80211_rts_duration(dev, priv->if_id, skb->len, control); } if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) flags |= RTL8187_TX_FLAG_CTS; hdr = (struct rtl8187_tx_hdr *)skb_push(skb, sizeof(*hdr)); hdr->flags = cpu_to_le32(flags); hdr->len = 0; hdr->rts_duration = rts_dur; hdr->retry = cpu_to_le32(control->retry_limit << 8); info = (struct rtl8187_tx_info *)skb->cb; info->control = kmemdup(control, sizeof(*control), GFP_ATOMIC); info->urb = urb; info->dev = dev; usb_fill_bulk_urb(urb, priv->udev, usb_sndbulkpipe(priv->udev, 2), hdr, skb->len, rtl8187_tx_cb, skb); usb_submit_urb(urb, GFP_ATOMIC); return 0;}static void rtl8187_rx_cb(struct urb *urb){ struct sk_buff *skb = (struct sk_buff *)urb->context; struct rtl8187_rx_info *info = (struct rtl8187_rx_info *)skb->cb; struct ieee80211_hw *dev = info->dev; struct rtl8187_priv *priv = dev->priv; struct rtl8187_rx_hdr *hdr; struct ieee80211_rx_status rx_status = { 0 }; int rate, signal; u32 flags; spin_lock(&priv->rx_queue.lock); if (skb->next) __skb_unlink(skb, &priv->rx_queue); else { spin_unlock(&priv->rx_queue.lock); return; } spin_unlock(&priv->rx_queue.lock); if (unlikely(urb->status)) { usb_free_urb(urb); dev_kfree_skb_irq(skb); return; } skb_put(skb, urb->actual_length); hdr = (struct rtl8187_rx_hdr *)(skb_tail_pointer(skb) - sizeof(*hdr)); flags = le32_to_cpu(hdr->flags); skb_trim(skb, flags & 0x0FFF); signal = hdr->agc >> 1; rate = (flags >> 20) & 0xF; if (rate > 3) { /* OFDM rate */ if (signal > 90) signal = 90; else if (signal < 25) signal = 25; signal = 90 - signal; } else { /* CCK rate */ if (signal > 95) signal = 95; else if (signal < 30) signal = 30; signal = 95 - signal; } rx_status.antenna = (hdr->signal >> 7) & 1; rx_status.signal = 64 - min(hdr->noise, (u8)64); rx_status.ssi = signal; rx_status.rate = rate; rx_status.freq = dev->conf.freq; rx_status.channel = dev->conf.channel; rx_status.phymode = dev->conf.phymode; rx_status.mactime = le64_to_cpu(hdr->mac_time); if (flags & (1 << 13)) rx_status.flag |= RX_FLAG_FAILED_FCS_CRC; ieee80211_rx_irqsafe(dev, skb, &rx_status); skb = dev_alloc_skb(RTL8187_MAX_RX); if (unlikely(!skb)) { usb_free_urb(urb); /* TODO check rx queue length and refill *somewhere* */ return; } info = (struct rtl8187_rx_info *)skb->cb; info->urb = urb; info->dev = dev; urb->transfer_buffer = skb_tail_pointer(skb); urb->context = skb; skb_queue_tail(&priv->rx_queue, skb); usb_submit_urb(urb, GFP_ATOMIC);}static int rtl8187_init_urbs(struct ieee80211_hw *dev){ struct rtl8187_priv *priv = dev->priv; struct urb *entry; struct sk_buff *skb; struct rtl8187_rx_info *info; while (skb_queue_len(&priv->rx_queue) < 8) { skb = __dev_alloc_skb(RTL8187_MAX_RX, GFP_KERNEL); if (!skb) break; entry = usb_alloc_urb(0, GFP_KERNEL); if (!entry) { kfree_skb(skb); break; } usb_fill_bulk_urb(entry, priv->udev, usb_rcvbulkpipe(priv->udev, 1), skb_tail_pointer(skb), RTL8187_MAX_RX, rtl8187_rx_cb, skb); info = (struct rtl8187_rx_info *)skb->cb; info->urb = entry; info->dev = dev; skb_queue_tail(&priv->rx_queue, skb); usb_submit_urb(entry, GFP_KERNEL); } return 0;}static int rtl8187_init_hw(struct ieee80211_hw *dev){ struct rtl8187_priv *priv = dev->priv; u8 reg; int i; /* reset */ rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE); rtl818x_iowrite32(priv, &priv->map->ANAPARAM, RTL8225_ANAPARAM_ON); rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON); rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE); rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0); msleep(200); rtl818x_iowrite8(priv, (u8 *)0xFE18, 0x10); rtl818x_iowrite8(priv, (u8 *)0xFE18, 0x11); rtl818x_iowrite8(priv, (u8 *)0xFE18, 0x00); msleep(200); reg = rtl818x_ioread8(priv, &priv->map->CMD); reg &= (1 << 1); reg |= RTL818X_CMD_RESET; rtl818x_iowrite8(priv, &priv->map->CMD, reg); i = 10; do { msleep(2); if (!(rtl818x_ioread8(priv, &priv->map->CMD) & RTL818X_CMD_RESET)) break; } while (--i); if (!i) { printk(KERN_ERR "%s: Reset timeout!\n", wiphy_name(dev->wiphy)); return -ETIMEDOUT; } /* reload registers from eeprom */ rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_LOAD); i = 10; do { msleep(4); if (!(rtl818x_ioread8(priv, &priv->map->EEPROM_CMD) & RTL818X_EEPROM_CMD_CONFIG)) break; } while (--i); if (!i) { printk(KERN_ERR "%s: eeprom reset timeout!\n", wiphy_name(dev->wiphy)); return -ETIMEDOUT; } rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE); rtl818x_iowrite32(priv, &priv->map->ANAPARAM, RTL8225_ANAPARAM_ON); rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON); rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE); rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); /* setup card */ rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0); rtl818x_iowrite8(priv, &priv->map->GPIO, 0); rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, (4 << 8)); rtl818x_iowrite8(priv, &priv->map->GPIO, 1); rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0); rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); rtl818x_iowrite16(priv, (__le16 *)0xFFF4, 0xFFFF); reg = rtl818x_ioread8(priv, &priv->map->CONFIG1); reg &= 0x3F; reg |= 0x80; rtl818x_iowrite8(priv, &priv->map->CONFIG1, reg); rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); rtl818x_iowrite32(priv, &priv->map->INT_TIMEOUT, 0); rtl818x_iowrite8(priv, &priv->map->WPA_CONF, 0); rtl818x_iowrite8(priv, &priv->map->RATE_FALLBACK, 0x81); // TODO: set RESP_RATE and BRSR properly rtl818x_iowrite8(priv, &priv->map->RESP_RATE, (8 << 4) | 0); rtl818x_iowrite16(priv, &priv->map->BRSR, 0x01F3); /* host_usb_init */ rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0); rtl818x_iowrite8(priv, &priv->map->GPIO, 0); reg = rtl818x_ioread8(priv, (u8 *)0xFE53); rtl818x_iowrite8(priv, (u8 *)0xFE53, reg | (1 << 7)); rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, (4 << 8)); rtl818x_iowrite8(priv, &priv->map->GPIO, 0x20); rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0); rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x80); rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x80); rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x80); msleep(100); rtl818x_iowrite32(priv, &priv->map->RF_TIMING, 0x000a8008); rtl818x_iowrite16(priv, &priv->map->BRSR, 0xFFFF); rtl818x_iowrite32(priv, &priv->map->RF_PARA, 0x00100044); rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); rtl818x_iowrite8(priv, &priv->map->CONFIG3, 0x44); rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FF7); msleep(100); priv->rf_init(dev); rtl818x_iowrite16(priv, &priv->map->BRSR, 0x01F3); reg = rtl818x_ioread16(priv, &priv->map->PGSELECT) & 0xfffe; rtl818x_iowrite16(priv, &priv->map->PGSELECT, reg | 0x1); rtl818x_iowrite16(priv, (__le16 *)0xFFFE, 0x10); rtl818x_iowrite8(priv, &priv->map->TALLY_SEL, 0x80); rtl818x_iowrite8(priv, (u8 *)0xFFFF, 0x60); rtl818x_iowrite16(priv, &priv->map->PGSELECT, reg); return 0;}static void rtl8187_set_channel(struct ieee80211_hw *dev, int channel){ u32 reg; struct rtl8187_priv *priv = dev->priv; reg = rtl818x_ioread32(priv, &priv->map->TX_CONF); /* Enable TX loopback on MAC level to avoid TX during channel
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?