[go: nahoru, domu]

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