diff -u -urN orinoco-0.11b/Makefile orinoco-0.11b+1/Makefile --- orinoco-0.11b/Makefile Wed May 1 07:44:29 2002 +++ orinoco-0.11b+1/Makefile Sat May 25 12:55:40 2002 @@ -5,12 +5,12 @@ KERNEL_SRC = /lib/modules/$(KERNEL_VERSION)/build KERNEL_HEADERS = $(KERNEL_SRC)/include -MODULES = hermes.o orinoco.o orinoco_cs.o orinoco_plx.o orinoco_pci.o +MODULES = hermes.o orinoco.o orinoco_cs.o orinoco_plx.o orinoco_pci.o nortel_pci.o ifeq ($(shell uname -m),ppc) MODULES += airport.o endif -SRCS = hermes.c orinoco.c airport.c orinoco_cs.c orinoco_plx.c orinoco_pci.c userhermes.c +SRCS = hermes.c orinoco.c airport.c orinoco_cs.c orinoco_plx.c orinoco_pci.c userhermes.c nortel_pci.c HDRS = hermes.h hermes_rid.h orinoco.h ieee802_11.h CONF = hermes.conf MODULE_DIR = /lib/modules/$(KERNEL_VERSION)/kernel/drivers/net/wireless/ diff -u -urN orinoco-0.11b/hermes.c orinoco-0.11b+1/hermes.c --- orinoco-0.11b/hermes.c Wed May 1 07:44:29 2002 +++ orinoco-0.11b+1/hermes.c Mon May 27 15:12:27 2002 @@ -132,6 +132,8 @@ int io_space, int reg_spacing) { hw->iobase = address; + hw->iobase1 = 0; + hw->iobase2 = 0; hw->io_space = io_space; hw->reg_spacing = reg_spacing; hw->inten = 0x0; diff -u -urN orinoco-0.11b/hermes.h orinoco-0.11b+1/hermes.h --- orinoco-0.11b/hermes.h Wed May 1 07:44:29 2002 +++ orinoco-0.11b+1/hermes.h Mon May 27 14:48:36 2002 @@ -265,7 +265,7 @@ /* Basic control structure */ typedef struct hermes { - ulong iobase; + ulong iobase, iobase1, iobase2; int io_space; /* 1 if we IO-mapped IO, 0 for memory-mapped IO? */ #define HERMES_IO 1 #define HERMES_MEM 0 diff -u -urN orinoco-0.11b/nortel_pci.c orinoco-0.11b+1/nortel_pci.c --- orinoco-0.11b/nortel_pci.c Thu Jan 1 01:00:00 1970 +++ orinoco-0.11b+1/nortel_pci.c Mon May 27 18:51:09 2002 @@ -0,0 +1,397 @@ +/* orinoco_plx.c 0.11b + * + * Driver for Prism II devices which would usually be driven by orinoco_cs, + * but are connected to the PCI bus by a Nortel PCI-PCMCIA-Adapter. + * + * Copyright (C) 2001 Daniel Barlow + * (C) 2002 Tobias Hoffmann + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License version 2 (the "GPL"), in + * which case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use your + * version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "hermes.h" +#include "orinoco.h" + +static char version[] __initdata = "nortel_pci.c 0.11b (Daniel Barlow + Tobias Hoffmann)"; +MODULE_AUTHOR("Daniel Barlow + Tobias Hoffmann"); +MODULE_DESCRIPTION("Driver for wireless LAN cards using the Nortel PCI bridge"); +#ifdef MODULE_LICENSE +MODULE_LICENSE("Dual MPL/GPL"); +#endif + +static char dev_info[] = "nortel_pci"; + +#define COR_OFFSET (0xe0) /* COR attribute offset of Prism2 PC card */ +#define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */ + +static int nortel_pci_open(struct net_device *dev) +{ + struct orinoco_private *priv = (struct orinoco_private *) dev->priv; + int err; + + netif_device_attach(dev); + + err = orinoco_reset(priv); + if (err) + printk(KERN_ERR "%s: orinoco_reset failed in nortel_pci_open()\n", + dev->name); + else + netif_start_queue(dev); + + return err; +} + +static int nortel_pci_stop(struct net_device *dev) +{ + struct orinoco_private *priv = (struct orinoco_private *) dev->priv; + netif_stop_queue(dev); + orinoco_shutdown(priv); + return 0; +} + +static void +nortel_pci_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + orinoco_interrupt(irq, (struct orinoco_private *)dev_id, regs); +} + +/* + * Do a soft reset of the PCI card using the Configuration Option Register + * We need this to get going... + * This is the part of the code that is strongly inspired from wlan-ng + * + * Note : This code is done with irq enabled. This mean that many + * interrupts will occur while we are there. This is why we use the + * jiffies to regulate time instead of a straight mdelay(). Usually we + * need only around 245 iteration of the loop to do 250 ms delay. + * + * Note bis : Don't try to access HERMES_CMD during the reset phase. + * It just won't work ! + */ +static int +nortel_pci_cor_reset(struct orinoco_private *priv) +{ + unsigned long brg1_ioaddr=priv->hw.iobase1; + unsigned long brg2_ioaddr=priv->hw.iobase2; + + TRACE_ENTER(priv->ndev->name); + + /* Assert the reset until the card notice */ + outw_p(8, brg1_ioaddr+2); + inw(brg2_ioaddr+COR_OFFSET); + outw_p(0x80, brg2_ioaddr+COR_OFFSET); + mdelay(1); + printk(KERN_NOTICE "Reset done;\n"); + + /* Give time for the card to recover from this hard effort */ + outw_p(0, brg2_ioaddr+COR_OFFSET); + outw_p(0, brg2_ioaddr+COR_OFFSET); + mdelay(1); + printk(KERN_NOTICE "Clear Reset\n"); + + /* set COR as usual*/ + outw_p(COR_VALUE, brg2_ioaddr+COR_OFFSET); + outw_p(COR_VALUE, brg2_ioaddr+COR_OFFSET); + mdelay(1); + + if (test_bit(ORINOCO_STATE_DOIRQ,&priv->state)) { + outw_p(0x228, brg1_ioaddr+2); + } else { + outw_p(0x28, brg1_ioaddr+2); + } + + TRACE_EXIT(priv->ndev->name); + + return 0; +} + +static int nortel_pci_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + int err = 0; + u16 *attr_mem = NULL; + u32 reg; + struct orinoco_private *priv = NULL; + unsigned long brg1_ioaddr = 0, brg2_ioaddr = 0, pccard_ioaddr = 0; + unsigned long brg1_iolen = 0, brg2_iolen = 0, pccard_iolen = 0; + struct net_device *dev = NULL; + int netdev_registered = 0; + int i; + + TRACE_ENTER("nortel_pci"); + + err = pci_enable_device(pdev); + if (err) + return -EIO; + + brg1_ioaddr = pci_resource_start(pdev, 0); + brg1_iolen = pci_resource_len(pdev, 0); + if (! request_region(brg1_ioaddr, brg1_iolen, dev_info)) { + printk(KERN_ERR "nortel_pci: Bridge I/O resource 1 0x%lx @ 0x%lx busy\n", + brg1_iolen, brg1_ioaddr); + brg1_ioaddr = 0; + err = -EBUSY; + goto fail; + } + + brg2_ioaddr = pci_resource_start(pdev, 1); + brg2_iolen = pci_resource_len(pdev, 1); + if (! request_region(brg2_ioaddr, brg2_iolen, dev_info)) { + printk(KERN_ERR "nortel_pci: Bridge I/O resource 2 0x%lx @ 0x%lx busy\n", + brg2_iolen, brg2_ioaddr); + brg2_ioaddr = 0; + err = -EBUSY; + goto fail; + } + + pccard_ioaddr = pci_resource_start(pdev, 2); + pccard_iolen = pci_resource_len(pdev, 2); + if (! request_region(pccard_ioaddr, pccard_iolen, dev_info)) { + printk(KERN_ERR "nortel_pci: I/O resource 0x%lx @ 0x%lx busy\n", + pccard_iolen, pccard_ioaddr); + pccard_ioaddr = 0; + err = -EBUSY; + goto fail; + } + + /* setup bridge */ + if (inw(brg1_ioaddr)&1) { + printk(KERN_ERR "nortel_pci: brg1 answer1 wrong\n"); + goto fail; + } + outw_p(0x118,brg1_ioaddr+2); + outw_p(0x108,brg1_ioaddr+2); + mdelay(30); + outw_p(0x8,brg1_ioaddr+2); + for (i=0; i<30; i++) { + mdelay(30); + if (inw(brg1_ioaddr)&0x10) { + break; + } + } + if (i==30) { + printk(KERN_ERR "nortel_pci: brg1 timed out\n"); + goto fail; + } + if (inw(brg2_ioaddr+0xe0)&1) { + printk(KERN_ERR "nortel_pci: brg2 answer1 wrong\n"); + goto fail; + } + if (inw(brg2_ioaddr+0xe2)&1) { + printk(KERN_ERR "nortel_pci: brg2 answer2 wrong\n"); + goto fail; + } + if (inw(brg2_ioaddr+0xe4)&1) { + printk(KERN_ERR "nortel_pci: brg2 answer3 wrong\n"); + goto fail; + } + + /* set the PCMCIA COR-Register */ + outw_p(COR_VALUE, brg2_ioaddr+COR_OFFSET); + mdelay(1); + reg = inw(brg2_ioaddr+COR_OFFSET); + if (reg != COR_VALUE) { + printk(KERN_ERR "nortel_pci: Error setting COR value (reg=%x)\n", reg); + goto fail; + } + + /* set leds */ + outw_p(1,brg1_ioaddr+10); + + + dev = alloc_orinocodev(0); + if (! dev) { + err = -ENOMEM; + goto fail; + } + + priv = dev->priv; + dev->base_addr = pccard_ioaddr; + dev->open = nortel_pci_open; + dev->stop = nortel_pci_stop; + priv->hard_reset = nortel_pci_cor_reset; + SET_MODULE_OWNER(dev); + + printk(KERN_DEBUG + "Detected Nortel PCI device at %s irq:%d, io addr:0x%lx\n", + pdev->slot_name, pdev->irq, pccard_ioaddr); + + hermes_struct_init(&(priv->hw), dev->base_addr, + HERMES_IO, HERMES_16BIT_REGSPACING); + pci_set_drvdata(pdev, dev); + priv->hw.iobase1=brg1_ioaddr; + priv->hw.iobase2=brg2_ioaddr; + + err = request_irq(pdev->irq, nortel_pci_interrupt, SA_SHIRQ, dev->name, priv); + if (err) { + printk(KERN_ERR "nortel_pci: Error allocating IRQ %d.\n", pdev->irq); + err = -EBUSY; + goto fail; + } + dev->irq = pdev->irq; + nortel_pci_cor_reset(priv); + + err = register_netdev(dev); + if (err) + goto fail; + netdev_registered = 1; + + err = orinoco_proc_dev_init(priv); + if (err) + goto fail; + + TRACE_EXIT("nortel_pci"); + + return 0; /* succeeded */ + +fail: + if (!err) { + err=-1; + } + printk(KERN_DEBUG "nortel_pci: init_one(), FAIL!\n"); + + if (priv) { + orinoco_proc_dev_cleanup(priv); + + if (netdev_registered) + unregister_netdev(dev); + + if (dev->irq) + free_irq(dev->irq, priv); + + kfree(priv); + } + + if (brg1_ioaddr) + release_region(brg1_ioaddr, brg1_iolen); + if (brg2_ioaddr) + release_region(brg2_ioaddr, brg2_iolen); + if (pccard_ioaddr) + release_region(pccard_ioaddr, pccard_iolen); + + if (attr_mem) + iounmap(attr_mem); + + pci_disable_device(pdev); + + TRACE_EXIT("nortel_pci"); + + return err; +} + +static void __devexit nortel_pci_remove_one(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct orinoco_private *priv = dev->priv; + + TRACE_ENTER("nortel_pci"); + + /* clear leds */ + outw_p(0,priv->hw.iobase1+10); + + if (! dev) + BUG(); + + orinoco_proc_dev_cleanup(priv); + + unregister_netdev(dev); + + if (dev->irq) + free_irq(dev->irq, priv); + + kfree(dev); + + release_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); + release_region(pci_resource_start(pdev, 1), pci_resource_len(pdev, 1)); + release_region(pci_resource_start(pdev, 2), pci_resource_len(pdev, 2)); + + pci_disable_device(pdev); + + TRACE_EXIT("nortel_pci"); +} + + +static struct pci_device_id nortel_pci_id_table[] __devinitdata = { + {0x126c, 0x8030, PCI_ANY_ID, PCI_ANY_ID,}, /* Nortel emobility PCI */ + {0,}, +}; + +MODULE_DEVICE_TABLE(pci, nortel_pci_id_table); + +static struct pci_driver nortel_pci_driver = { + name:"nortel_pci", + id_table:nortel_pci_id_table, + probe:nortel_pci_init_one, + remove:nortel_pci_remove_one, + suspend:0, + resume:0 +}; + +static int __init nortel_pci_init(void) +{ + printk(KERN_DEBUG "%s\n", version); + return pci_module_init(&nortel_pci_driver); +} + +extern void __exit nortel_pci_exit(void) +{ + pci_unregister_driver(&nortel_pci_driver); + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ); +} + +module_init(nortel_pci_init); +module_exit(nortel_pci_exit); + +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ diff -u -urN orinoco-0.11b/orinoco.c orinoco-0.11b+1/orinoco.c --- orinoco-0.11b/orinoco.c Wed May 1 07:44:29 2002 +++ orinoco-0.11b+1/orinoco.c Mon May 27 17:36:06 2002 @@ -521,6 +521,9 @@ { hermes_t *hw = &priv->hw; + if (hw->iobase1) { // Nortel PCI + outw_p(0x28,hw->iobase1+2); + } hermes_set_irqmask(hw, 0); clear_bit(ORINOCO_STATE_DOIRQ, &priv->state); while (test_bit(ORINOCO_STATE_INIRQ, &priv->state)) @@ -536,6 +539,9 @@ __cli(); /* FIXME: is this necessary? */ set_bit(ORINOCO_STATE_DOIRQ, &priv->state); + if (hw->iobase1) { // Nortel PCI + outw_p(0x228,hw->iobase1+2); + } hermes_set_irqmask(hw, irqmask); __sti(); @@ -1142,6 +1148,16 @@ clear_bit(ORINOCO_STATE_INIRQ, &priv->state); return; } +/* leds? */ +if (priv->hw.iobase1) { + if (test_bit(ORINOCO_STATE_LED, &priv->state)) { + outw_p(1,priv->hw.iobase1+10); + clear_bit(ORINOCO_STATE_LED, &priv->state); + } else { + outw_p(3,priv->hw.iobase1+10); + set_bit(ORINOCO_STATE_LED, &priv->state); + } +} DEBUG(3, "%s: orinoco_interrupt()\n", priv->ndev->name); @@ -1791,7 +1807,8 @@ } /* Set up the default configuration */ - priv->iw_mode = IW_MODE_INFRA; +// priv->iw_mode = IW_MODE_INFRA; + priv->iw_mode = IW_MODE_ADHOC; /* By default use IEEE/IBSS ad-hoc mode if we have it */ priv->prefer_port3 = priv->has_port3 && (! priv->has_ibss); set_port_type(priv); diff -u -urN orinoco-0.11b/orinoco.h orinoco-0.11b+1/orinoco.h --- orinoco-0.11b/orinoco.h Wed May 1 07:44:29 2002 +++ orinoco-0.11b+1/orinoco.h Mon May 27 17:21:21 2002 @@ -36,6 +36,7 @@ long state; #define ORINOCO_STATE_INIRQ 0 #define ORINOCO_STATE_DOIRQ 1 +#define ORINOCO_STATE_LED 2 /* Net device stuff */ struct net_device *ndev; diff -u -urN orinoco-0.11b/orinoco_plx.c orinoco-0.11b+1/orinoco_plx.c --- orinoco-0.11b/orinoco_plx.c Wed May 1 07:44:29 2002 +++ orinoco-0.11b+1/orinoco_plx.c Sat May 25 12:53:33 2002 @@ -309,6 +309,7 @@ fail: printk(KERN_DEBUG "orinoco_plx: init_one(), FAIL!\n"); +if (!err) err=-1; if (priv) { orinoco_proc_dev_cleanup(priv);