linux/drivers/net/wireless/hostap/hostap_pci.c
<<
>>
Prefs
   1#define PRISM2_PCI
   2
   3/* Host AP driver's support for Intersil Prism2.5 PCI cards is based on
   4 * driver patches from Reyk Floeter <reyk@vantronix.net> and
   5 * Andy Warner <andyw@pobox.com> */
   6
   7#include <linux/module.h>
   8#include <linux/init.h>
   9#include <linux/if.h>
  10#include <linux/skbuff.h>
  11#include <linux/netdevice.h>
  12#include <linux/slab.h>
  13#include <linux/workqueue.h>
  14#include <linux/wireless.h>
  15#include <net/iw_handler.h>
  16
  17#include <linux/ioport.h>
  18#include <linux/pci.h>
  19#include <asm/io.h>
  20
  21#include "hostap_wlan.h"
  22
  23
  24static char *dev_info = "hostap_pci";
  25
  26
  27MODULE_AUTHOR("Jouni Malinen");
  28MODULE_DESCRIPTION("Support for Intersil Prism2.5-based 802.11 wireless LAN "
  29                   "PCI cards.");
  30MODULE_SUPPORTED_DEVICE("Intersil Prism2.5-based WLAN PCI cards");
  31MODULE_LICENSE("GPL");
  32
  33
  34/* struct local_info::hw_priv */
  35struct hostap_pci_priv {
  36        void __iomem *mem_start;
  37};
  38
  39
  40/* FIX: do we need mb/wmb/rmb with memory operations? */
  41
  42
  43static DEFINE_PCI_DEVICE_TABLE(prism2_pci_id_table) = {
  44        /* Intersil Prism3 ISL3872 11Mb/s WLAN Controller */
  45        { 0x1260, 0x3872, PCI_ANY_ID, PCI_ANY_ID },
  46        /* Intersil Prism2.5 ISL3874 11Mb/s WLAN Controller */
  47        { 0x1260, 0x3873, PCI_ANY_ID, PCI_ANY_ID },
  48        /* Samsung MagicLAN SWL-2210P */
  49        { 0x167d, 0xa000, PCI_ANY_ID, PCI_ANY_ID },
  50        { 0 }
  51};
  52
  53
  54#ifdef PRISM2_IO_DEBUG
  55
  56static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v)
  57{
  58        struct hostap_interface *iface;
  59        struct hostap_pci_priv *hw_priv;
  60        local_info_t *local;
  61        unsigned long flags;
  62
  63        iface = netdev_priv(dev);
  64        local = iface->local;
  65        hw_priv = local->hw_priv;
  66
  67        spin_lock_irqsave(&local->lock, flags);
  68        prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v);
  69        writeb(v, hw_priv->mem_start + a);
  70        spin_unlock_irqrestore(&local->lock, flags);
  71}
  72
  73static inline u8 hfa384x_inb_debug(struct net_device *dev, int a)
  74{
  75        struct hostap_interface *iface;
  76        struct hostap_pci_priv *hw_priv;
  77        local_info_t *local;
  78        unsigned long flags;
  79        u8 v;
  80
  81        iface = netdev_priv(dev);
  82        local = iface->local;
  83        hw_priv = local->hw_priv;
  84
  85        spin_lock_irqsave(&local->lock, flags);
  86        v = readb(hw_priv->mem_start + a);
  87        prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INB, a, v);
  88        spin_unlock_irqrestore(&local->lock, flags);
  89        return v;
  90}
  91
  92static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v)
  93{
  94        struct hostap_interface *iface;
  95        struct hostap_pci_priv *hw_priv;
  96        local_info_t *local;
  97        unsigned long flags;
  98
  99        iface = netdev_priv(dev);
 100        local = iface->local;
 101        hw_priv = local->hw_priv;
 102
 103        spin_lock_irqsave(&local->lock, flags);
 104        prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v);
 105        writew(v, hw_priv->mem_start + a);
 106        spin_unlock_irqrestore(&local->lock, flags);
 107}
 108
 109static inline u16 hfa384x_inw_debug(struct net_device *dev, int a)
 110{
 111        struct hostap_interface *iface;
 112        struct hostap_pci_priv *hw_priv;
 113        local_info_t *local;
 114        unsigned long flags;
 115        u16 v;
 116
 117        iface = netdev_priv(dev);
 118        local = iface->local;
 119        hw_priv = local->hw_priv;
 120
 121        spin_lock_irqsave(&local->lock, flags);
 122        v = readw(hw_priv->mem_start + a);
 123        prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INW, a, v);
 124        spin_unlock_irqrestore(&local->lock, flags);
 125        return v;
 126}
 127
 128#define HFA384X_OUTB(v,a) hfa384x_outb_debug(dev, (a), (v))
 129#define HFA384X_INB(a) hfa384x_inb_debug(dev, (a))
 130#define HFA384X_OUTW(v,a) hfa384x_outw_debug(dev, (a), (v))
 131#define HFA384X_INW(a) hfa384x_inw_debug(dev, (a))
 132#define HFA384X_OUTW_DATA(v,a) hfa384x_outw_debug(dev, (a), le16_to_cpu((v)))
 133#define HFA384X_INW_DATA(a) cpu_to_le16(hfa384x_inw_debug(dev, (a)))
 134
 135#else /* PRISM2_IO_DEBUG */
 136
 137static inline void hfa384x_outb(struct net_device *dev, int a, u8 v)
 138{
 139        struct hostap_interface *iface;
 140        struct hostap_pci_priv *hw_priv;
 141        iface = netdev_priv(dev);
 142        hw_priv = iface->local->hw_priv;
 143        writeb(v, hw_priv->mem_start + a);
 144}
 145
 146static inline u8 hfa384x_inb(struct net_device *dev, int a)
 147{
 148        struct hostap_interface *iface;
 149        struct hostap_pci_priv *hw_priv;
 150        iface = netdev_priv(dev);
 151        hw_priv = iface->local->hw_priv;
 152        return readb(hw_priv->mem_start + a);
 153}
 154
 155static inline void hfa384x_outw(struct net_device *dev, int a, u16 v)
 156{
 157        struct hostap_interface *iface;
 158        struct hostap_pci_priv *hw_priv;
 159        iface = netdev_priv(dev);
 160        hw_priv = iface->local->hw_priv;
 161        writew(v, hw_priv->mem_start + a);
 162}
 163
 164static inline u16 hfa384x_inw(struct net_device *dev, int a)
 165{
 166        struct hostap_interface *iface;
 167        struct hostap_pci_priv *hw_priv;
 168        iface = netdev_priv(dev);
 169        hw_priv = iface->local->hw_priv;
 170        return readw(hw_priv->mem_start + a);
 171}
 172
 173#define HFA384X_OUTB(v,a) hfa384x_outb(dev, (a), (v))
 174#define HFA384X_INB(a) hfa384x_inb(dev, (a))
 175#define HFA384X_OUTW(v,a) hfa384x_outw(dev, (a), (v))
 176#define HFA384X_INW(a) hfa384x_inw(dev, (a))
 177#define HFA384X_OUTW_DATA(v,a) hfa384x_outw(dev, (a), le16_to_cpu((v)))
 178#define HFA384X_INW_DATA(a) cpu_to_le16(hfa384x_inw(dev, (a)))
 179
 180#endif /* PRISM2_IO_DEBUG */
 181
 182
 183static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf,
 184                            int len)
 185{
 186        u16 d_off;
 187        __le16 *pos;
 188
 189        d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
 190        pos = (__le16 *) buf;
 191
 192        for ( ; len > 1; len -= 2)
 193                *pos++ = HFA384X_INW_DATA(d_off);
 194
 195        if (len & 1)
 196                *((char *) pos) = HFA384X_INB(d_off);
 197
 198        return 0;
 199}
 200
 201
 202static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len)
 203{
 204        u16 d_off;
 205        __le16 *pos;
 206
 207        d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
 208        pos = (__le16 *) buf;
 209
 210        for ( ; len > 1; len -= 2)
 211                HFA384X_OUTW_DATA(*pos++, d_off);
 212
 213        if (len & 1)
 214                HFA384X_OUTB(*((char *) pos), d_off);
 215
 216        return 0;
 217}
 218
 219
 220/* FIX: This might change at some point.. */
 221#include "hostap_hw.c"
 222
 223static void prism2_pci_cor_sreset(local_info_t *local)
 224{
 225        struct net_device *dev = local->dev;
 226        u16 reg;
 227
 228        reg = HFA384X_INB(HFA384X_PCICOR_OFF);
 229        printk(KERN_DEBUG "%s: Original COR value: 0x%0x\n", dev->name, reg);
 230
 231        /* linux-wlan-ng uses extremely long hold and settle times for
 232         * COR sreset. A comment in the driver code mentions that the long
 233         * delays appear to be necessary. However, at least IBM 22P6901 seems
 234         * to work fine with shorter delays.
 235         *
 236         * Longer delays can be configured by uncommenting following line: */
 237/* #define PRISM2_PCI_USE_LONG_DELAYS */
 238
 239#ifdef PRISM2_PCI_USE_LONG_DELAYS
 240        int i;
 241
 242        HFA384X_OUTW(reg | 0x0080, HFA384X_PCICOR_OFF);
 243        mdelay(250);
 244
 245        HFA384X_OUTW(reg & ~0x0080, HFA384X_PCICOR_OFF);
 246        mdelay(500);
 247
 248        /* Wait for f/w to complete initialization (CMD:BUSY == 0) */
 249        i = 2000000 / 10;
 250        while ((HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY) && --i)
 251                udelay(10);
 252
 253#else /* PRISM2_PCI_USE_LONG_DELAYS */
 254
 255        HFA384X_OUTW(reg | 0x0080, HFA384X_PCICOR_OFF);
 256        mdelay(2);
 257        HFA384X_OUTW(reg & ~0x0080, HFA384X_PCICOR_OFF);
 258        mdelay(2);
 259
 260#endif /* PRISM2_PCI_USE_LONG_DELAYS */
 261
 262        if (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY) {
 263                printk(KERN_DEBUG "%s: COR sreset timeout\n", dev->name);
 264        }
 265}
 266
 267
 268static void prism2_pci_genesis_reset(local_info_t *local, int hcr)
 269{
 270        struct net_device *dev = local->dev;
 271
 272        HFA384X_OUTW(0x00C5, HFA384X_PCICOR_OFF);
 273        mdelay(10);
 274        HFA384X_OUTW(hcr, HFA384X_PCIHCR_OFF);
 275        mdelay(10);
 276        HFA384X_OUTW(0x0045, HFA384X_PCICOR_OFF);
 277        mdelay(10);
 278}
 279
 280
 281static struct prism2_helper_functions prism2_pci_funcs =
 282{
 283        .card_present   = NULL,
 284        .cor_sreset     = prism2_pci_cor_sreset,
 285        .genesis_reset  = prism2_pci_genesis_reset,
 286        .hw_type        = HOSTAP_HW_PCI,
 287};
 288
 289
 290static int prism2_pci_probe(struct pci_dev *pdev,
 291                            const struct pci_device_id *id)
 292{
 293        unsigned long phymem;
 294        void __iomem *mem = NULL;
 295        local_info_t *local = NULL;
 296        struct net_device *dev = NULL;
 297        static int cards_found /* = 0 */;
 298        int irq_registered = 0;
 299        struct hostap_interface *iface;
 300        struct hostap_pci_priv *hw_priv;
 301
 302        hw_priv = kzalloc(sizeof(*hw_priv), GFP_KERNEL);
 303        if (hw_priv == NULL)
 304                return -ENOMEM;
 305
 306        if (pci_enable_device(pdev))
 307                goto err_out_free;
 308
 309        phymem = pci_resource_start(pdev, 0);
 310
 311        if (!request_mem_region(phymem, pci_resource_len(pdev, 0), "Prism2")) {
 312                printk(KERN_ERR "prism2: Cannot reserve PCI memory region\n");
 313                goto err_out_disable;
 314        }
 315
 316        mem = pci_ioremap_bar(pdev, 0);
 317        if (mem == NULL) {
 318                printk(KERN_ERR "prism2: Cannot remap PCI memory region\n") ;
 319                goto fail;
 320        }
 321
 322        dev = prism2_init_local_data(&prism2_pci_funcs, cards_found,
 323                                     &pdev->dev);
 324        if (dev == NULL)
 325                goto fail;
 326        iface = netdev_priv(dev);
 327        local = iface->local;
 328        local->hw_priv = hw_priv;
 329        cards_found++;
 330
 331        dev->irq = pdev->irq;
 332        hw_priv->mem_start = mem;
 333        dev->base_addr = (unsigned long) mem;
 334
 335        prism2_pci_cor_sreset(local);
 336
 337        pci_set_drvdata(pdev, dev);
 338
 339        if (request_irq(dev->irq, prism2_interrupt, IRQF_SHARED, dev->name,
 340                        dev)) {
 341                printk(KERN_WARNING "%s: request_irq failed\n", dev->name);
 342                goto fail;
 343        } else
 344                irq_registered = 1;
 345
 346        if (!local->pri_only && prism2_hw_config(dev, 1)) {
 347                printk(KERN_DEBUG "%s: hardware initialization failed\n",
 348                       dev_info);
 349                goto fail;
 350        }
 351
 352        printk(KERN_INFO "%s: Intersil Prism2.5 PCI: "
 353               "mem=0x%lx, irq=%d\n", dev->name, phymem, dev->irq);
 354
 355        return hostap_hw_ready(dev);
 356
 357 fail:
 358        if (irq_registered && dev)
 359                free_irq(dev->irq, dev);
 360
 361        if (mem)
 362                iounmap(mem);
 363
 364        release_mem_region(phymem, pci_resource_len(pdev, 0));
 365
 366 err_out_disable:
 367        pci_disable_device(pdev);
 368        prism2_free_local_data(dev);
 369
 370 err_out_free:
 371        kfree(hw_priv);
 372
 373        return -ENODEV;
 374}
 375
 376
 377static void prism2_pci_remove(struct pci_dev *pdev)
 378{
 379        struct net_device *dev;
 380        struct hostap_interface *iface;
 381        void __iomem *mem_start;
 382        struct hostap_pci_priv *hw_priv;
 383
 384        dev = pci_get_drvdata(pdev);
 385        iface = netdev_priv(dev);
 386        hw_priv = iface->local->hw_priv;
 387
 388        /* Reset the hardware, and ensure interrupts are disabled. */
 389        prism2_pci_cor_sreset(iface->local);
 390        hfa384x_disable_interrupts(dev);
 391
 392        if (dev->irq)
 393                free_irq(dev->irq, dev);
 394
 395        mem_start = hw_priv->mem_start;
 396        prism2_free_local_data(dev);
 397        kfree(hw_priv);
 398
 399        iounmap(mem_start);
 400
 401        release_mem_region(pci_resource_start(pdev, 0),
 402                           pci_resource_len(pdev, 0));
 403        pci_disable_device(pdev);
 404}
 405
 406
 407#ifdef CONFIG_PM
 408static int prism2_pci_suspend(struct pci_dev *pdev, pm_message_t state)
 409{
 410        struct net_device *dev = pci_get_drvdata(pdev);
 411
 412        if (netif_running(dev)) {
 413                netif_stop_queue(dev);
 414                netif_device_detach(dev);
 415        }
 416        prism2_suspend(dev);
 417        pci_save_state(pdev);
 418        pci_disable_device(pdev);
 419        pci_set_power_state(pdev, PCI_D3hot);
 420
 421        return 0;
 422}
 423
 424static int prism2_pci_resume(struct pci_dev *pdev)
 425{
 426        struct net_device *dev = pci_get_drvdata(pdev);
 427        int err;
 428
 429        err = pci_enable_device(pdev);
 430        if (err) {
 431                printk(KERN_ERR "%s: pci_enable_device failed on resume\n",
 432                       dev->name);
 433                return err;
 434        }
 435        pci_restore_state(pdev);
 436        prism2_hw_config(dev, 0);
 437        if (netif_running(dev)) {
 438                netif_device_attach(dev);
 439                netif_start_queue(dev);
 440        }
 441
 442        return 0;
 443}
 444#endif /* CONFIG_PM */
 445
 446
 447MODULE_DEVICE_TABLE(pci, prism2_pci_id_table);
 448
 449static struct pci_driver prism2_pci_driver = {
 450        .name           = "hostap_pci",
 451        .id_table       = prism2_pci_id_table,
 452        .probe          = prism2_pci_probe,
 453        .remove         = prism2_pci_remove,
 454#ifdef CONFIG_PM
 455        .suspend        = prism2_pci_suspend,
 456        .resume         = prism2_pci_resume,
 457#endif /* CONFIG_PM */
 458};
 459
 460
 461static int __init init_prism2_pci(void)
 462{
 463        return pci_register_driver(&prism2_pci_driver);
 464}
 465
 466
 467static void __exit exit_prism2_pci(void)
 468{
 469        pci_unregister_driver(&prism2_pci_driver);
 470}
 471
 472
 473module_init(init_prism2_pci);
 474module_exit(exit_prism2_pci);
 475