Back to home page

OSCL-LXR

 
 

    


0001 /* orinoco_pci.c
0002  *
0003  * Driver for Prism 2.5/3 devices that have a direct PCI interface
0004  * (i.e. these are not PCMCIA cards in a PCMCIA-to-PCI bridge).
0005  * The card contains only one PCI region, which contains all the usual
0006  * hermes registers, as well as the COR register.
0007  *
0008  * Current maintainers are:
0009  *  Pavel Roskin <proski AT gnu.org>
0010  * and  David Gibson <hermes AT gibson.dropbear.id.au>
0011  *
0012  * Some of this code is borrowed from orinoco_plx.c
0013  *  Copyright (C) 2001 Daniel Barlow <dan AT telent.net>
0014  * Some of this code is "inspired" by linux-wlan-ng-0.1.10, but nothing
0015  * has been copied from it. linux-wlan-ng-0.1.10 is originally :
0016  *  Copyright (C) 1999 AbsoluteValue Systems, Inc.  All Rights Reserved.
0017  * This file originally written by:
0018  *  Copyright (C) 2001 Jean Tourrilhes <jt AT hpl.hp.com>
0019  * And is now maintained by:
0020  *  (C) Copyright David Gibson, IBM Corp. 2002-2003.
0021  *
0022  * The contents of this file are subject to the Mozilla Public License
0023  * Version 1.1 (the "License"); you may not use this file except in
0024  * compliance with the License. You may obtain a copy of the License
0025  * at http://www.mozilla.org/MPL/
0026  *
0027  * Software distributed under the License is distributed on an "AS IS"
0028  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
0029  * the License for the specific language governing rights and
0030  * limitations under the License.
0031  *
0032  * Alternatively, the contents of this file may be used under the
0033  * terms of the GNU General Public License version 2 (the "GPL"), in
0034  * which case the provisions of the GPL are applicable instead of the
0035  * above.  If you wish to allow the use of your version of this file
0036  * only under the terms of the GPL and not to allow others to use your
0037  * version of this file under the MPL, indicate your decision by
0038  * deleting the provisions above and replace them with the notice and
0039  * other provisions required by the GPL.  If you do not delete the
0040  * provisions above, a recipient may use your version of this file
0041  * under either the MPL or the GPL.
0042  */
0043 
0044 #define DRIVER_NAME "orinoco_pci"
0045 #define PFX DRIVER_NAME ": "
0046 
0047 #include <linux/module.h>
0048 #include <linux/kernel.h>
0049 #include <linux/init.h>
0050 #include <linux/delay.h>
0051 #include <linux/pci.h>
0052 
0053 #include "orinoco.h"
0054 #include "orinoco_pci.h"
0055 
0056 /* Offset of the COR register of the PCI card */
0057 #define HERMES_PCI_COR      (0x26)
0058 
0059 /* Bitmask to reset the card */
0060 #define HERMES_PCI_COR_MASK (0x0080)
0061 
0062 /* Magic timeouts for doing the reset.
0063  * Those times are straight from wlan-ng, and it is claimed that they
0064  * are necessary. Alan will kill me. Take your time and grab a coffee. */
0065 #define HERMES_PCI_COR_ONT  (250)       /* ms */
0066 #define HERMES_PCI_COR_OFFT (500)       /* ms */
0067 #define HERMES_PCI_COR_BUSYT    (500)       /* ms */
0068 
0069 /*
0070  * Do a soft reset of the card using the Configuration Option Register
0071  * We need this to get going...
0072  * This is the part of the code that is strongly inspired from wlan-ng
0073  *
0074  * Note : This code is done with irq enabled. This mean that many
0075  * interrupts will occur while we are there. This is why we use the
0076  * jiffies to regulate time instead of a straight mdelay(). Usually we
0077  * need only around 245 iteration of the loop to do 250 ms delay.
0078  *
0079  * Note bis : Don't try to access HERMES_CMD during the reset phase.
0080  * It just won't work !
0081  */
0082 static int orinoco_pci_cor_reset(struct orinoco_private *priv)
0083 {
0084     struct hermes *hw = &priv->hw;
0085     unsigned long timeout;
0086     u16 reg;
0087 
0088     /* Assert the reset until the card notices */
0089     hermes_write_regn(hw, PCI_COR, HERMES_PCI_COR_MASK);
0090     mdelay(HERMES_PCI_COR_ONT);
0091 
0092     /* Give time for the card to recover from this hard effort */
0093     hermes_write_regn(hw, PCI_COR, 0x0000);
0094     mdelay(HERMES_PCI_COR_OFFT);
0095 
0096     /* The card is ready when it's no longer busy */
0097     timeout = jiffies + msecs_to_jiffies(HERMES_PCI_COR_BUSYT);
0098     reg = hermes_read_regn(hw, CMD);
0099     while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) {
0100         mdelay(1);
0101         reg = hermes_read_regn(hw, CMD);
0102     }
0103 
0104     /* Still busy? */
0105     if (reg & HERMES_CMD_BUSY) {
0106         printk(KERN_ERR PFX "Busy timeout\n");
0107         return -ETIMEDOUT;
0108     }
0109 
0110     return 0;
0111 }
0112 
0113 static int orinoco_pci_init_one(struct pci_dev *pdev,
0114                 const struct pci_device_id *ent)
0115 {
0116     int err;
0117     struct orinoco_private *priv;
0118     struct orinoco_pci_card *card;
0119     void __iomem *hermes_io;
0120 
0121     err = pci_enable_device(pdev);
0122     if (err) {
0123         printk(KERN_ERR PFX "Cannot enable PCI device\n");
0124         return err;
0125     }
0126 
0127     err = pci_request_regions(pdev, DRIVER_NAME);
0128     if (err) {
0129         printk(KERN_ERR PFX "Cannot obtain PCI resources\n");
0130         goto fail_resources;
0131     }
0132 
0133     hermes_io = pci_iomap(pdev, 0, 0);
0134     if (!hermes_io) {
0135         printk(KERN_ERR PFX "Cannot remap chipset registers\n");
0136         err = -EIO;
0137         goto fail_map_hermes;
0138     }
0139 
0140     /* Allocate network device */
0141     priv = alloc_orinocodev(sizeof(*card), &pdev->dev,
0142                 orinoco_pci_cor_reset, NULL);
0143     if (!priv) {
0144         printk(KERN_ERR PFX "Cannot allocate network device\n");
0145         err = -ENOMEM;
0146         goto fail_alloc;
0147     }
0148 
0149     card = priv->card;
0150 
0151     hermes_struct_init(&priv->hw, hermes_io, HERMES_32BIT_REGSPACING);
0152 
0153     err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
0154               DRIVER_NAME, priv);
0155     if (err) {
0156         printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
0157         err = -EBUSY;
0158         goto fail_irq;
0159     }
0160 
0161     err = orinoco_pci_cor_reset(priv);
0162     if (err) {
0163         printk(KERN_ERR PFX "Initial reset failed\n");
0164         goto fail;
0165     }
0166 
0167     err = orinoco_init(priv);
0168     if (err) {
0169         printk(KERN_ERR PFX "orinoco_init() failed\n");
0170         goto fail;
0171     }
0172 
0173     err = orinoco_if_add(priv, 0, 0, NULL);
0174     if (err) {
0175         printk(KERN_ERR PFX "orinoco_if_add() failed\n");
0176         goto fail_wiphy;
0177     }
0178 
0179     pci_set_drvdata(pdev, priv);
0180 
0181     return 0;
0182 
0183  fail_wiphy:
0184     wiphy_unregister(priv_to_wiphy(priv));
0185  fail:
0186     free_irq(pdev->irq, priv);
0187 
0188  fail_irq:
0189     free_orinocodev(priv);
0190 
0191  fail_alloc:
0192     pci_iounmap(pdev, hermes_io);
0193 
0194  fail_map_hermes:
0195     pci_release_regions(pdev);
0196 
0197  fail_resources:
0198     pci_disable_device(pdev);
0199 
0200     return err;
0201 }
0202 
0203 static void orinoco_pci_remove_one(struct pci_dev *pdev)
0204 {
0205     struct orinoco_private *priv = pci_get_drvdata(pdev);
0206 
0207     orinoco_if_del(priv);
0208     wiphy_unregister(priv_to_wiphy(priv));
0209     free_irq(pdev->irq, priv);
0210     free_orinocodev(priv);
0211     pci_iounmap(pdev, priv->hw.iobase);
0212     pci_release_regions(pdev);
0213     pci_disable_device(pdev);
0214 }
0215 
0216 static const struct pci_device_id orinoco_pci_id_table[] = {
0217     /* Intersil Prism 3 */
0218     {0x1260, 0x3872, PCI_ANY_ID, PCI_ANY_ID,},
0219     /* Intersil Prism 2.5 */
0220     {0x1260, 0x3873, PCI_ANY_ID, PCI_ANY_ID,},
0221     /* Samsung MagicLAN SWL-2210P */
0222     {0x167d, 0xa000, PCI_ANY_ID, PCI_ANY_ID,},
0223     {0,},
0224 };
0225 
0226 MODULE_DEVICE_TABLE(pci, orinoco_pci_id_table);
0227 
0228 static struct pci_driver orinoco_pci_driver = {
0229     .name       = DRIVER_NAME,
0230     .id_table   = orinoco_pci_id_table,
0231     .probe      = orinoco_pci_init_one,
0232     .remove     = orinoco_pci_remove_one,
0233     .driver.pm  = &orinoco_pci_pm_ops,
0234 };
0235 
0236 static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
0237     " (Pavel Roskin <proski@gnu.org>,"
0238     " David Gibson <hermes@gibson.dropbear.id.au> &"
0239     " Jean Tourrilhes <jt@hpl.hp.com>)";
0240 MODULE_AUTHOR("Pavel Roskin <proski@gnu.org> &"
0241           " David Gibson <hermes@gibson.dropbear.id.au>");
0242 MODULE_DESCRIPTION("Driver for wireless LAN cards using direct PCI interface");
0243 MODULE_LICENSE("Dual MPL/GPL");
0244 
0245 static int __init orinoco_pci_init(void)
0246 {
0247     printk(KERN_DEBUG "%s\n", version);
0248     return pci_register_driver(&orinoco_pci_driver);
0249 }
0250 
0251 static void __exit orinoco_pci_exit(void)
0252 {
0253     pci_unregister_driver(&orinoco_pci_driver);
0254 }
0255 
0256 module_init(orinoco_pci_init);
0257 module_exit(orinoco_pci_exit);