diff options
Diffstat (limited to 'drivers/net/wireless/rtl8187_dev.c')
-rw-r--r-- | drivers/net/wireless/rtl8187_dev.c | 129 |
1 files changed, 110 insertions, 19 deletions
diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c index bf9f0cc5a645..b0a92f543da4 100644 --- a/drivers/net/wireless/rtl8187_dev.c +++ b/drivers/net/wireless/rtl8187_dev.c | |||
@@ -41,6 +41,57 @@ static struct usb_device_id rtl8187_table[] __devinitdata = { | |||
41 | 41 | ||
42 | MODULE_DEVICE_TABLE(usb, rtl8187_table); | 42 | MODULE_DEVICE_TABLE(usb, rtl8187_table); |
43 | 43 | ||
44 | static void rtl8187_iowrite_async_cb(struct urb *urb) | ||
45 | { | ||
46 | kfree(urb->context); | ||
47 | usb_free_urb(urb); | ||
48 | } | ||
49 | |||
50 | static void rtl8187_iowrite_async(struct rtl8187_priv *priv, __le16 addr, | ||
51 | void *data, u16 len) | ||
52 | { | ||
53 | struct usb_ctrlrequest *dr; | ||
54 | struct urb *urb; | ||
55 | struct rtl8187_async_write_data { | ||
56 | u8 data[4]; | ||
57 | struct usb_ctrlrequest dr; | ||
58 | } *buf; | ||
59 | |||
60 | buf = kmalloc(sizeof(*buf), GFP_ATOMIC); | ||
61 | if (!buf) | ||
62 | return; | ||
63 | |||
64 | urb = usb_alloc_urb(0, GFP_ATOMIC); | ||
65 | if (!urb) { | ||
66 | kfree(buf); | ||
67 | return; | ||
68 | } | ||
69 | |||
70 | dr = &buf->dr; | ||
71 | |||
72 | dr->bRequestType = RTL8187_REQT_WRITE; | ||
73 | dr->bRequest = RTL8187_REQ_SET_REG; | ||
74 | dr->wValue = addr; | ||
75 | dr->wIndex = 0; | ||
76 | dr->wLength = cpu_to_le16(len); | ||
77 | |||
78 | memcpy(buf, data, len); | ||
79 | |||
80 | usb_fill_control_urb(urb, priv->udev, usb_sndctrlpipe(priv->udev, 0), | ||
81 | (unsigned char *)dr, buf, len, | ||
82 | rtl8187_iowrite_async_cb, buf); | ||
83 | usb_submit_urb(urb, GFP_ATOMIC); | ||
84 | } | ||
85 | |||
86 | static inline void rtl818x_iowrite32_async(struct rtl8187_priv *priv, | ||
87 | __le32 *addr, u32 val) | ||
88 | { | ||
89 | __le32 buf = cpu_to_le32(val); | ||
90 | |||
91 | rtl8187_iowrite_async(priv, cpu_to_le16((unsigned long)addr), | ||
92 | &buf, sizeof(buf)); | ||
93 | } | ||
94 | |||
44 | void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data) | 95 | void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data) |
45 | { | 96 | { |
46 | struct rtl8187_priv *priv = dev->priv; | 97 | struct rtl8187_priv *priv = dev->priv; |
@@ -125,6 +176,7 @@ static void rtl8187_rx_cb(struct urb *urb) | |||
125 | struct rtl8187_rx_hdr *hdr; | 176 | struct rtl8187_rx_hdr *hdr; |
126 | struct ieee80211_rx_status rx_status = { 0 }; | 177 | struct ieee80211_rx_status rx_status = { 0 }; |
127 | int rate, signal; | 178 | int rate, signal; |
179 | u32 flags; | ||
128 | 180 | ||
129 | spin_lock(&priv->rx_queue.lock); | 181 | spin_lock(&priv->rx_queue.lock); |
130 | if (skb->next) | 182 | if (skb->next) |
@@ -143,10 +195,11 @@ static void rtl8187_rx_cb(struct urb *urb) | |||
143 | 195 | ||
144 | skb_put(skb, urb->actual_length); | 196 | skb_put(skb, urb->actual_length); |
145 | hdr = (struct rtl8187_rx_hdr *)(skb_tail_pointer(skb) - sizeof(*hdr)); | 197 | hdr = (struct rtl8187_rx_hdr *)(skb_tail_pointer(skb) - sizeof(*hdr)); |
146 | skb_trim(skb, le16_to_cpu(hdr->len) & 0x0FFF); | 198 | flags = le32_to_cpu(hdr->flags); |
199 | skb_trim(skb, flags & 0x0FFF); | ||
147 | 200 | ||
148 | signal = hdr->agc >> 1; | 201 | signal = hdr->agc >> 1; |
149 | rate = (le16_to_cpu(hdr->rate) >> 4) & 0xF; | 202 | rate = (flags >> 20) & 0xF; |
150 | if (rate > 3) { /* OFDM rate */ | 203 | if (rate > 3) { /* OFDM rate */ |
151 | if (signal > 90) | 204 | if (signal > 90) |
152 | signal = 90; | 205 | signal = 90; |
@@ -169,6 +222,8 @@ static void rtl8187_rx_cb(struct urb *urb) | |||
169 | rx_status.channel = dev->conf.channel; | 222 | rx_status.channel = dev->conf.channel; |
170 | rx_status.phymode = dev->conf.phymode; | 223 | rx_status.phymode = dev->conf.phymode; |
171 | rx_status.mactime = le64_to_cpu(hdr->mac_time); | 224 | rx_status.mactime = le64_to_cpu(hdr->mac_time); |
225 | if (flags & (1 << 13)) | ||
226 | rx_status.flag |= RX_FLAG_FAILED_FCS_CRC; | ||
172 | ieee80211_rx_irqsafe(dev, skb, &rx_status); | 227 | ieee80211_rx_irqsafe(dev, skb, &rx_status); |
173 | 228 | ||
174 | skb = dev_alloc_skb(RTL8187_MAX_RX); | 229 | skb = dev_alloc_skb(RTL8187_MAX_RX); |
@@ -293,8 +348,6 @@ static int rtl8187_init_hw(struct ieee80211_hw *dev) | |||
293 | rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0); | 348 | rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0); |
294 | 349 | ||
295 | rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); | 350 | rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); |
296 | for (i = 0; i < ETH_ALEN; i++) | ||
297 | rtl818x_iowrite8(priv, &priv->map->MAC[i], priv->hwaddr[i]); | ||
298 | 351 | ||
299 | rtl818x_iowrite16(priv, (__le16 *)0xFFF4, 0xFFFF); | 352 | rtl818x_iowrite16(priv, (__le16 *)0xFFF4, 0xFFFF); |
300 | reg = rtl818x_ioread8(priv, &priv->map->CONFIG1); | 353 | reg = rtl818x_ioread8(priv, &priv->map->CONFIG1); |
@@ -365,7 +418,7 @@ static void rtl8187_set_channel(struct ieee80211_hw *dev, int channel) | |||
365 | rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg); | 418 | rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg); |
366 | } | 419 | } |
367 | 420 | ||
368 | static int rtl8187_open(struct ieee80211_hw *dev) | 421 | static int rtl8187_start(struct ieee80211_hw *dev) |
369 | { | 422 | { |
370 | struct rtl8187_priv *priv = dev->priv; | 423 | struct rtl8187_priv *priv = dev->priv; |
371 | u32 reg; | 424 | u32 reg; |
@@ -383,16 +436,13 @@ static int rtl8187_open(struct ieee80211_hw *dev) | |||
383 | RTL818X_RX_CONF_RX_AUTORESETPHY | | 436 | RTL818X_RX_CONF_RX_AUTORESETPHY | |
384 | RTL818X_RX_CONF_BSSID | | 437 | RTL818X_RX_CONF_BSSID | |
385 | RTL818X_RX_CONF_MGMT | | 438 | RTL818X_RX_CONF_MGMT | |
386 | RTL818X_RX_CONF_CTRL | | ||
387 | RTL818X_RX_CONF_DATA | | 439 | RTL818X_RX_CONF_DATA | |
388 | (7 << 13 /* RX FIFO threshold NONE */) | | 440 | (7 << 13 /* RX FIFO threshold NONE */) | |
389 | (7 << 10 /* MAX RX DMA */) | | 441 | (7 << 10 /* MAX RX DMA */) | |
390 | RTL818X_RX_CONF_BROADCAST | | 442 | RTL818X_RX_CONF_BROADCAST | |
391 | RTL818X_RX_CONF_MULTICAST | | ||
392 | RTL818X_RX_CONF_NICMAC; | 443 | RTL818X_RX_CONF_NICMAC; |
393 | if (priv->mode == IEEE80211_IF_TYPE_MNTR) | ||
394 | reg |= RTL818X_RX_CONF_MONITOR; | ||
395 | 444 | ||
445 | priv->rx_conf = reg; | ||
396 | rtl818x_iowrite32(priv, &priv->map->RX_CONF, reg); | 446 | rtl818x_iowrite32(priv, &priv->map->RX_CONF, reg); |
397 | 447 | ||
398 | reg = rtl818x_ioread8(priv, &priv->map->CW_CONF); | 448 | reg = rtl818x_ioread8(priv, &priv->map->CW_CONF); |
@@ -419,7 +469,7 @@ static int rtl8187_open(struct ieee80211_hw *dev) | |||
419 | return 0; | 469 | return 0; |
420 | } | 470 | } |
421 | 471 | ||
422 | static int rtl8187_stop(struct ieee80211_hw *dev) | 472 | static void rtl8187_stop(struct ieee80211_hw *dev) |
423 | { | 473 | { |
424 | struct rtl8187_priv *priv = dev->priv; | 474 | struct rtl8187_priv *priv = dev->priv; |
425 | struct rtl8187_rx_info *info; | 475 | struct rtl8187_rx_info *info; |
@@ -445,28 +495,31 @@ static int rtl8187_stop(struct ieee80211_hw *dev) | |||
445 | usb_kill_urb(info->urb); | 495 | usb_kill_urb(info->urb); |
446 | kfree_skb(skb); | 496 | kfree_skb(skb); |
447 | } | 497 | } |
448 | return 0; | 498 | return; |
449 | } | 499 | } |
450 | 500 | ||
451 | static int rtl8187_add_interface(struct ieee80211_hw *dev, | 501 | static int rtl8187_add_interface(struct ieee80211_hw *dev, |
452 | struct ieee80211_if_init_conf *conf) | 502 | struct ieee80211_if_init_conf *conf) |
453 | { | 503 | { |
454 | struct rtl8187_priv *priv = dev->priv; | 504 | struct rtl8187_priv *priv = dev->priv; |
505 | int i; | ||
455 | 506 | ||
456 | /* NOTE: using IEEE80211_IF_TYPE_MGMT to indicate no mode selected */ | 507 | if (priv->mode != IEEE80211_IF_TYPE_MNTR) |
457 | if (priv->mode != IEEE80211_IF_TYPE_MGMT) | 508 | return -EOPNOTSUPP; |
458 | return -1; | ||
459 | 509 | ||
460 | switch (conf->type) { | 510 | switch (conf->type) { |
461 | case IEEE80211_IF_TYPE_STA: | 511 | case IEEE80211_IF_TYPE_STA: |
462 | case IEEE80211_IF_TYPE_MNTR: | ||
463 | priv->mode = conf->type; | 512 | priv->mode = conf->type; |
464 | break; | 513 | break; |
465 | default: | 514 | default: |
466 | return -EOPNOTSUPP; | 515 | return -EOPNOTSUPP; |
467 | } | 516 | } |
468 | 517 | ||
469 | priv->hwaddr = conf->mac_addr ? conf->mac_addr : dev->wiphy->perm_addr; | 518 | rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); |
519 | for (i = 0; i < ETH_ALEN; i++) | ||
520 | rtl818x_iowrite8(priv, &priv->map->MAC[i], | ||
521 | ((u8 *)conf->mac_addr)[i]); | ||
522 | rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); | ||
470 | 523 | ||
471 | return 0; | 524 | return 0; |
472 | } | 525 | } |
@@ -475,7 +528,7 @@ static void rtl8187_remove_interface(struct ieee80211_hw *dev, | |||
475 | struct ieee80211_if_init_conf *conf) | 528 | struct ieee80211_if_init_conf *conf) |
476 | { | 529 | { |
477 | struct rtl8187_priv *priv = dev->priv; | 530 | struct rtl8187_priv *priv = dev->priv; |
478 | priv->mode = IEEE80211_IF_TYPE_MGMT; | 531 | priv->mode = IEEE80211_IF_TYPE_MNTR; |
479 | } | 532 | } |
480 | 533 | ||
481 | static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) | 534 | static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) |
@@ -523,14 +576,52 @@ static int rtl8187_config_interface(struct ieee80211_hw *dev, int if_id, | |||
523 | return 0; | 576 | return 0; |
524 | } | 577 | } |
525 | 578 | ||
579 | static void rtl8187_configure_filter(struct ieee80211_hw *dev, | ||
580 | unsigned int changed_flags, | ||
581 | unsigned int *total_flags, | ||
582 | int mc_count, struct dev_addr_list *mc_list) | ||
583 | { | ||
584 | struct rtl8187_priv *priv = dev->priv; | ||
585 | |||
586 | *total_flags = 0; | ||
587 | |||
588 | if (changed_flags & FIF_PROMISC_IN_BSS) | ||
589 | priv->rx_conf ^= RTL818X_RX_CONF_NICMAC; | ||
590 | if (changed_flags & FIF_ALLMULTI) | ||
591 | priv->rx_conf ^= RTL818X_RX_CONF_MULTICAST; | ||
592 | if (changed_flags & FIF_FCSFAIL) | ||
593 | priv->rx_conf ^= RTL818X_RX_CONF_FCS; | ||
594 | if (changed_flags & FIF_CONTROL) | ||
595 | priv->rx_conf ^= RTL818X_RX_CONF_CTRL; | ||
596 | if (changed_flags & FIF_OTHER_BSS) | ||
597 | priv->rx_conf ^= RTL818X_RX_CONF_MONITOR; | ||
598 | |||
599 | if (mc_count > 0) | ||
600 | priv->rx_conf |= RTL818X_RX_CONF_MULTICAST; | ||
601 | |||
602 | if (priv->rx_conf & RTL818X_RX_CONF_NICMAC) | ||
603 | *total_flags |= FIF_PROMISC_IN_BSS; | ||
604 | if (priv->rx_conf & RTL818X_RX_CONF_MULTICAST) | ||
605 | *total_flags |= FIF_ALLMULTI; | ||
606 | if (priv->rx_conf & RTL818X_RX_CONF_FCS) | ||
607 | *total_flags |= FIF_FCSFAIL; | ||
608 | if (priv->rx_conf & RTL818X_RX_CONF_CTRL) | ||
609 | *total_flags |= FIF_CONTROL; | ||
610 | if (priv->rx_conf & RTL818X_RX_CONF_MONITOR) | ||
611 | *total_flags |= FIF_OTHER_BSS; | ||
612 | |||
613 | rtl818x_iowrite32_async(priv, &priv->map->RX_CONF, priv->rx_conf); | ||
614 | } | ||
615 | |||
526 | static const struct ieee80211_ops rtl8187_ops = { | 616 | static const struct ieee80211_ops rtl8187_ops = { |
527 | .tx = rtl8187_tx, | 617 | .tx = rtl8187_tx, |
528 | .open = rtl8187_open, | 618 | .start = rtl8187_start, |
529 | .stop = rtl8187_stop, | 619 | .stop = rtl8187_stop, |
530 | .add_interface = rtl8187_add_interface, | 620 | .add_interface = rtl8187_add_interface, |
531 | .remove_interface = rtl8187_remove_interface, | 621 | .remove_interface = rtl8187_remove_interface, |
532 | .config = rtl8187_config, | 622 | .config = rtl8187_config, |
533 | .config_interface = rtl8187_config_interface, | 623 | .config_interface = rtl8187_config_interface, |
624 | .configure_filter = rtl8187_configure_filter, | ||
534 | }; | 625 | }; |
535 | 626 | ||
536 | static void rtl8187_eeprom_register_read(struct eeprom_93cx6 *eeprom) | 627 | static void rtl8187_eeprom_register_read(struct eeprom_93cx6 *eeprom) |
@@ -604,7 +695,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, | |||
604 | priv->modes[1].rates = priv->rates; | 695 | priv->modes[1].rates = priv->rates; |
605 | priv->modes[1].num_channels = ARRAY_SIZE(rtl818x_channels); | 696 | priv->modes[1].num_channels = ARRAY_SIZE(rtl818x_channels); |
606 | priv->modes[1].channels = priv->channels; | 697 | priv->modes[1].channels = priv->channels; |
607 | priv->mode = IEEE80211_IF_TYPE_MGMT; | 698 | priv->mode = IEEE80211_IF_TYPE_MNTR; |
608 | dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | | 699 | dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | |
609 | IEEE80211_HW_RX_INCLUDES_FCS; | 700 | IEEE80211_HW_RX_INCLUDES_FCS; |
610 | dev->extra_tx_headroom = sizeof(struct rtl8187_tx_hdr); | 701 | dev->extra_tx_headroom = sizeof(struct rtl8187_tx_hdr); |