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 + -
显示快捷键?