Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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