root/drivers/net/wireless/intersil/orinoco/orinoco_nortel.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. orinoco_nortel_cor_reset
  2. orinoco_nortel_hw_init
  3. orinoco_nortel_init_one
  4. orinoco_nortel_remove_one
  5. orinoco_nortel_init
  6. orinoco_nortel_exit

   1 /* orinoco_nortel.c
   2  *
   3  * Driver for Prism II devices which would usually be driven by orinoco_cs,
   4  * but are connected to the PCI bus by a PCI-to-PCMCIA adapter used in
   5  * Nortel emobility, Symbol LA-4113 and Symbol LA-4123.
   6  *
   7  * Copyright (C) 2002 Tobias Hoffmann
   8  *           (C) 2003 Christoph Jungegger <disdos@traum404.de>
   9  *
  10  * Some of this code is borrowed from orinoco_plx.c
  11  *      Copyright (C) 2001 Daniel Barlow
  12  * Some of this code is borrowed from orinoco_pci.c
  13  *  Copyright (C) 2001 Jean Tourrilhes
  14  * Some of this code is "inspired" by linux-wlan-ng-0.1.10, but nothing
  15  * has been copied from it. linux-wlan-ng-0.1.10 is originally :
  16  *      Copyright (C) 1999 AbsoluteValue Systems, Inc.  All Rights Reserved.
  17  *
  18  * The contents of this file are subject to the Mozilla Public License
  19  * Version 1.1 (the "License"); you may not use this file except in
  20  * compliance with the License. You may obtain a copy of the License
  21  * at http://www.mozilla.org/MPL/
  22  *
  23  * Software distributed under the License is distributed on an "AS IS"
  24  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  25  * the License for the specific language governing rights and
  26  * limitations under the License.
  27  *
  28  * Alternatively, the contents of this file may be used under the
  29  * terms of the GNU General Public License version 2 (the "GPL"), in
  30  * which case the provisions of the GPL are applicable instead of the
  31  * above.  If you wish to allow the use of your version of this file
  32  * only under the terms of the GPL and not to allow others to use your
  33  * version of this file under the MPL, indicate your decision by
  34  * deleting the provisions above and replace them with the notice and
  35  * other provisions required by the GPL.  If you do not delete the
  36  * provisions above, a recipient may use your version of this file
  37  * under either the MPL or the GPL.
  38  */
  39 
  40 #define DRIVER_NAME "orinoco_nortel"
  41 #define PFX DRIVER_NAME ": "
  42 
  43 #include <linux/module.h>
  44 #include <linux/kernel.h>
  45 #include <linux/init.h>
  46 #include <linux/delay.h>
  47 #include <linux/pci.h>
  48 #include <pcmcia/cisreg.h>
  49 
  50 #include "orinoco.h"
  51 #include "orinoco_pci.h"
  52 
  53 #define COR_OFFSET    (0xe0)    /* COR attribute offset of Prism2 PC card */
  54 #define COR_VALUE     (COR_LEVEL_REQ | COR_FUNC_ENA)    /* Enable PC card with interrupt in level trigger */
  55 
  56 
  57 /*
  58  * Do a soft reset of the card using the Configuration Option Register
  59  * We need this to get going...
  60  * This is the part of the code that is strongly inspired from wlan-ng
  61  *
  62  * Note bis : Don't try to access HERMES_CMD during the reset phase.
  63  * It just won't work !
  64  */
  65 static int orinoco_nortel_cor_reset(struct orinoco_private *priv)
  66 {
  67         struct orinoco_pci_card *card = priv->card;
  68 
  69         /* Assert the reset until the card notices */
  70         iowrite16(8, card->bridge_io + 2);
  71         ioread16(card->attr_io + COR_OFFSET);
  72         iowrite16(0x80, card->attr_io + COR_OFFSET);
  73         mdelay(1);
  74 
  75         /* Give time for the card to recover from this hard effort */
  76         iowrite16(0, card->attr_io + COR_OFFSET);
  77         iowrite16(0, card->attr_io + COR_OFFSET);
  78         mdelay(1);
  79 
  80         /* Set COR as usual */
  81         iowrite16(COR_VALUE, card->attr_io + COR_OFFSET);
  82         iowrite16(COR_VALUE, card->attr_io + COR_OFFSET);
  83         mdelay(1);
  84 
  85         iowrite16(0x228, card->bridge_io + 2);
  86 
  87         return 0;
  88 }
  89 
  90 static int orinoco_nortel_hw_init(struct orinoco_pci_card *card)
  91 {
  92         int i;
  93         u32 reg;
  94 
  95         /* Setup bridge */
  96         if (ioread16(card->bridge_io) & 1) {
  97                 printk(KERN_ERR PFX "brg1 answer1 wrong\n");
  98                 return -EBUSY;
  99         }
 100         iowrite16(0x118, card->bridge_io + 2);
 101         iowrite16(0x108, card->bridge_io + 2);
 102         mdelay(30);
 103         iowrite16(0x8, card->bridge_io + 2);
 104         for (i = 0; i < 30; i++) {
 105                 mdelay(30);
 106                 if (ioread16(card->bridge_io) & 0x10)
 107                         break;
 108         }
 109         if (i == 30) {
 110                 printk(KERN_ERR PFX "brg1 timed out\n");
 111                 return -EBUSY;
 112         }
 113         if (ioread16(card->attr_io + COR_OFFSET) & 1) {
 114                 printk(KERN_ERR PFX "brg2 answer1 wrong\n");
 115                 return -EBUSY;
 116         }
 117         if (ioread16(card->attr_io + COR_OFFSET + 2) & 1) {
 118                 printk(KERN_ERR PFX "brg2 answer2 wrong\n");
 119                 return -EBUSY;
 120         }
 121         if (ioread16(card->attr_io + COR_OFFSET + 4) & 1) {
 122                 printk(KERN_ERR PFX "brg2 answer3 wrong\n");
 123                 return -EBUSY;
 124         }
 125 
 126         /* Set the PCMCIA COR register */
 127         iowrite16(COR_VALUE, card->attr_io + COR_OFFSET);
 128         mdelay(1);
 129         reg = ioread16(card->attr_io + COR_OFFSET);
 130         if (reg != COR_VALUE) {
 131                 printk(KERN_ERR PFX "Error setting COR value (reg=%x)\n",
 132                        reg);
 133                 return -EBUSY;
 134         }
 135 
 136         /* Set LEDs */
 137         iowrite16(1, card->bridge_io + 10);
 138         return 0;
 139 }
 140 
 141 static int orinoco_nortel_init_one(struct pci_dev *pdev,
 142                                    const struct pci_device_id *ent)
 143 {
 144         int err;
 145         struct orinoco_private *priv;
 146         struct orinoco_pci_card *card;
 147         void __iomem *hermes_io, *bridge_io, *attr_io;
 148 
 149         err = pci_enable_device(pdev);
 150         if (err) {
 151                 printk(KERN_ERR PFX "Cannot enable PCI device\n");
 152                 return err;
 153         }
 154 
 155         err = pci_request_regions(pdev, DRIVER_NAME);
 156         if (err) {
 157                 printk(KERN_ERR PFX "Cannot obtain PCI resources\n");
 158                 goto fail_resources;
 159         }
 160 
 161         bridge_io = pci_iomap(pdev, 0, 0);
 162         if (!bridge_io) {
 163                 printk(KERN_ERR PFX "Cannot map bridge registers\n");
 164                 err = -EIO;
 165                 goto fail_map_bridge;
 166         }
 167 
 168         attr_io = pci_iomap(pdev, 1, 0);
 169         if (!attr_io) {
 170                 printk(KERN_ERR PFX "Cannot map PCMCIA attributes\n");
 171                 err = -EIO;
 172                 goto fail_map_attr;
 173         }
 174 
 175         hermes_io = pci_iomap(pdev, 2, 0);
 176         if (!hermes_io) {
 177                 printk(KERN_ERR PFX "Cannot map chipset registers\n");
 178                 err = -EIO;
 179                 goto fail_map_hermes;
 180         }
 181 
 182         /* Allocate network device */
 183         priv = alloc_orinocodev(sizeof(*card), &pdev->dev,
 184                                 orinoco_nortel_cor_reset, NULL);
 185         if (!priv) {
 186                 printk(KERN_ERR PFX "Cannot allocate network device\n");
 187                 err = -ENOMEM;
 188                 goto fail_alloc;
 189         }
 190 
 191         card = priv->card;
 192         card->bridge_io = bridge_io;
 193         card->attr_io = attr_io;
 194 
 195         hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING);
 196 
 197         err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
 198                           DRIVER_NAME, priv);
 199         if (err) {
 200                 printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
 201                 err = -EBUSY;
 202                 goto fail_irq;
 203         }
 204 
 205         err = orinoco_nortel_hw_init(card);
 206         if (err) {
 207                 printk(KERN_ERR PFX "Hardware initialization failed\n");
 208                 goto fail;
 209         }
 210 
 211         err = orinoco_nortel_cor_reset(priv);
 212         if (err) {
 213                 printk(KERN_ERR PFX "Initial reset failed\n");
 214                 goto fail;
 215         }
 216 
 217         err = orinoco_init(priv);
 218         if (err) {
 219                 printk(KERN_ERR PFX "orinoco_init() failed\n");
 220                 goto fail;
 221         }
 222 
 223         err = orinoco_if_add(priv, 0, 0, NULL);
 224         if (err) {
 225                 printk(KERN_ERR PFX "orinoco_if_add() failed\n");
 226                 goto fail_wiphy;
 227         }
 228 
 229         pci_set_drvdata(pdev, priv);
 230 
 231         return 0;
 232 
 233  fail_wiphy:
 234         wiphy_unregister(priv_to_wiphy(priv));
 235  fail:
 236         free_irq(pdev->irq, priv);
 237 
 238  fail_irq:
 239         free_orinocodev(priv);
 240 
 241  fail_alloc:
 242         pci_iounmap(pdev, hermes_io);
 243 
 244  fail_map_hermes:
 245         pci_iounmap(pdev, attr_io);
 246 
 247  fail_map_attr:
 248         pci_iounmap(pdev, bridge_io);
 249 
 250  fail_map_bridge:
 251         pci_release_regions(pdev);
 252 
 253  fail_resources:
 254         pci_disable_device(pdev);
 255 
 256         return err;
 257 }
 258 
 259 static void orinoco_nortel_remove_one(struct pci_dev *pdev)
 260 {
 261         struct orinoco_private *priv = pci_get_drvdata(pdev);
 262         struct orinoco_pci_card *card = priv->card;
 263 
 264         /* Clear LEDs */
 265         iowrite16(0, card->bridge_io + 10);
 266 
 267         orinoco_if_del(priv);
 268         wiphy_unregister(priv_to_wiphy(priv));
 269         free_irq(pdev->irq, priv);
 270         free_orinocodev(priv);
 271         pci_iounmap(pdev, priv->hw.iobase);
 272         pci_iounmap(pdev, card->attr_io);
 273         pci_iounmap(pdev, card->bridge_io);
 274         pci_release_regions(pdev);
 275         pci_disable_device(pdev);
 276 }
 277 
 278 static const struct pci_device_id orinoco_nortel_id_table[] = {
 279         /* Nortel emobility PCI */
 280         {0x126c, 0x8030, PCI_ANY_ID, PCI_ANY_ID,},
 281         /* Symbol LA-4123 PCI */
 282         {0x1562, 0x0001, PCI_ANY_ID, PCI_ANY_ID,},
 283         {0,},
 284 };
 285 
 286 MODULE_DEVICE_TABLE(pci, orinoco_nortel_id_table);
 287 
 288 static struct pci_driver orinoco_nortel_driver = {
 289         .name           = DRIVER_NAME,
 290         .id_table       = orinoco_nortel_id_table,
 291         .probe          = orinoco_nortel_init_one,
 292         .remove         = orinoco_nortel_remove_one,
 293         .suspend        = orinoco_pci_suspend,
 294         .resume         = orinoco_pci_resume,
 295 };
 296 
 297 static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
 298         " (Tobias Hoffmann & Christoph Jungegger <disdos@traum404.de>)";
 299 MODULE_AUTHOR("Christoph Jungegger <disdos@traum404.de>");
 300 MODULE_DESCRIPTION("Driver for wireless LAN cards using the Nortel PCI bridge");
 301 MODULE_LICENSE("Dual MPL/GPL");
 302 
 303 static int __init orinoco_nortel_init(void)
 304 {
 305         printk(KERN_DEBUG "%s\n", version);
 306         return pci_register_driver(&orinoco_nortel_driver);
 307 }
 308 
 309 static void __exit orinoco_nortel_exit(void)
 310 {
 311         pci_unregister_driver(&orinoco_nortel_driver);
 312 }
 313 
 314 module_init(orinoco_nortel_init);
 315 module_exit(orinoco_nortel_exit);
 316 
 317 /*
 318  * Local variables:
 319  *  c-indent-level: 8
 320  *  c-basic-offset: 8
 321  *  tab-width: 8
 322  * End:
 323  */

/* [<][>][^][v][top][bottom][index][help] */