aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPavel Roskin <proski@gnu.org>2005-09-01 20:08:56 -0400
committerJeff Garzik <jgarzik@pobox.com>2005-09-05 18:14:08 -0400
commitec82905177a22b0fe0abaf4ecb76813d3d45d16e (patch)
treee32ab69ce85ed4a4a3f5358e99e4c67f241c5abb
parent8c09e16bd8f816f19cea0920430a1ac26478fcf6 (diff)
[PATCH] orinoco: New driver - orinoco_nortel.
Signed-off-by: Pavel Roskin <proski@gnu.org> diff-tree dce61aef99ceb57370b70222dc34d788666c0ac3 (from ceb6695092be8dcdfe2dec6ee5097d613011489d) Author: Pavel Roskin <proski@gnu.org> Date: Thu Sep 1 15:50:55 2005 -0400 New driver - orinoco_nortel. This is a driver for Nortel emobility PCI adaptors, which consist of an Orinoco compatible PCMCIA card and a simple PCI-to-PCMCIA bridge. The driver initializes the device and uses Orinoco core driver for actual wireless networking. Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
-rw-r--r--drivers/net/wireless/Kconfig9
-rw-r--r--drivers/net/wireless/Makefile1
-rw-r--r--drivers/net/wireless/orinoco_nortel.c324
3 files changed, 334 insertions, 0 deletions
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 3951fbbe9389..ae7c876d6475 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -309,6 +309,15 @@ config TMD_HERMES
309 PCI <-> PCMCIA bridge. Several vendors sell such adaptors so that 309 PCI <-> PCMCIA bridge. Several vendors sell such adaptors so that
310 802.11b PCMCIA cards can be used in desktop machines. 310 802.11b PCMCIA cards can be used in desktop machines.
311 311
312config NORTEL_HERMES
313 tristate "Nortel emobility PCI adaptor support"
314 depends on PCI && HERMES
315 help
316 Enable support for PCMCIA cards supported by the "Hermes" (aka
317 orinoco) driver when used in Nortel emobility PCI adaptors. These
318 adaptors are not full PCMCIA controllers, but act as a more limited
319 PCI <-> PCMCIA bridge.
320
312config PCI_HERMES 321config PCI_HERMES
313 tristate "Prism 2.5 PCI 802.11b adaptor support" 322 tristate "Prism 2.5 PCI 802.11b adaptor support"
314 depends on PCI && HERMES 323 depends on PCI && HERMES
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index 0953cc0cdee6..d2c8ccc21467 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -22,6 +22,7 @@ obj-$(CONFIG_APPLE_AIRPORT) += airport.o
22obj-$(CONFIG_PLX_HERMES) += orinoco_plx.o 22obj-$(CONFIG_PLX_HERMES) += orinoco_plx.o
23obj-$(CONFIG_PCI_HERMES) += orinoco_pci.o 23obj-$(CONFIG_PCI_HERMES) += orinoco_pci.o
24obj-$(CONFIG_TMD_HERMES) += orinoco_tmd.o 24obj-$(CONFIG_TMD_HERMES) += orinoco_tmd.o
25obj-$(CONFIG_NORTEL_HERMES) += orinoco_nortel.o
25 26
26obj-$(CONFIG_AIRO) += airo.o 27obj-$(CONFIG_AIRO) += airo.o
27obj-$(CONFIG_AIRO_CS) += airo_cs.o airo.o 28obj-$(CONFIG_AIRO_CS) += airo_cs.o airo.o
diff --git a/drivers/net/wireless/orinoco_nortel.c b/drivers/net/wireless/orinoco_nortel.c
new file mode 100644
index 000000000000..86fa58e5cfac
--- /dev/null
+++ b/drivers/net/wireless/orinoco_nortel.c
@@ -0,0 +1,324 @@
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 */