/*
* 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 const struct ieee80211_rate rtl818x_rates[] = {
{ .bitrate = 10, .hw_value = 0, },
{ .bitrate = 20, .hw_value = 1, },
{ .bitrate = 55, .hw_value = 2, },
{ .bitrate = 110, .hw_value = 3, },
{ .bitrate = 60, .hw_value = 4, },
{ .bitrate = 90, .hw_value = 5, },
{ .bitrate = 120, .hw_value = 6, },
{ .bitrate = 180, .hw_value = 7, },
{ .bitrate = 240, .hw_value = 8, },
{ .bitrate = 360, .hw_value = 9, },
{ .bitrate = 480, .hw_value = 10, },
{ .bitrate = 540, .hw_value = 11, },
};
static const struct ieee80211_channel rtl818x_channels[] = {
{ .center_freq = 2412 },
{ .center_freq = 2417 },
{ .center_freq = 2422 },
{ .center_freq = 2427 },
{ .center_freq = 2432 },
{ .center_freq = 2437 },
{ .center_freq = 2442 },
{ .center_freq = 2447 },
{ .center_freq = 2452 },
{ .center_freq = 2457 },
{ .center_freq = 2462 },
{ .center_freq = 2467 },
{ .center_freq = 2472 },
{ .center_freq = 2484 },
};
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;
int rc;
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);
rc = usb_submit_urb(urb, GFP_ATOMIC);
if (rc < 0) {
kfree(buf);
usb_free_urb(urb);
}
}
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 >>