X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fnet%2Fwireless%2Forinoco_pci.c;h=97a8b4ff32bd88d59b87a3deeb87d060385cb168;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=3e58b75837097e93892302b30453fa9ff5556d95;hpb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;p=linux-2.6.git diff --git a/drivers/net/wireless/orinoco_pci.c b/drivers/net/wireless/orinoco_pci.c index 3e58b7583..97a8b4ff3 100644 --- a/drivers/net/wireless/orinoco_pci.c +++ b/drivers/net/wireless/orinoco_pci.c @@ -1,11 +1,11 @@ /* orinoco_pci.c * - * Driver for Prism II devices that have a direct PCI interface - * (i.e., not in a Pcmcia or PLX bridge) - * - * Specifically here we're talking about the Linksys WMP11 + * Driver for Prism 2.5/3 devices that have a direct PCI interface + * (i.e. these are not PCMCIA cards in a PCMCIA-to-PCI bridge). + * The card contains only one PCI region, which contains all the usual + * hermes registers, as well as the COR register. * - * Current maintainers (as of 29 September 2003) are: + * Current maintainers are: * Pavel Roskin * and David Gibson * @@ -41,87 +41,24 @@ * under either the MPL or the GPL. */ -/* - * Theory of operation... - * ------------------- - * Maybe you had a look in orinoco_plx. Well, this is totally different... - * - * The card contains only one PCI region, which contains all the usual - * hermes registers. - * - * The driver will memory map this region in normal memory. Because - * the hermes registers are mapped in normal memory and not in ISA I/O - * post space, we can't use the usual inw/outw macros and we need to - * use readw/writew. - * This slight difference force us to compile our own version of - * hermes.c with the register access macro changed. That's a bit - * hackish but works fine. - * - * Note that the PCI region is pretty big (4K). That's much more than - * the usual set of hermes register (0x0 -> 0x3E). I've got a strong - * suspicion that the whole memory space of the adapter is in fact in - * this region. Accessing directly the adapter memory instead of going - * through the usual register would speed up significantely the - * operations... - * - * Finally, the card looks like this : ------------------------ - Bus 0, device 14, function 0: - Network controller: PCI device 1260:3873 (Harris Semiconductor) (rev 1). - IRQ 11. - Master Capable. Latency=248. - Prefetchable 32 bit memory at 0xffbcc000 [0xffbccfff]. ------------------------ -00:0e.0 Network controller: Harris Semiconductor: Unknown device 3873 (rev 01) - Subsystem: Unknown device 1737:3874 - Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- - Status: Cap+ 66Mhz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- SERR- - #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" +#include "orinoco_pci.h" -/* All the magic there is from wlan-ng */ -/* Magic offset of the reset register of the PCI card */ +/* Offset of the COR register of the PCI card */ #define HERMES_PCI_COR (0x26) -/* Magic bitmask to reset the card */ + +/* Bitmask to reset the card */ #define HERMES_PCI_COR_MASK (0x0080) + /* Magic timeouts for doing the reset. * Those times are straight from wlan-ng, and it is claimed that they * are necessary. Alan will kill me. Take your time and grab a coffee. */ @@ -130,7 +67,7 @@ #define HERMES_PCI_COR_BUSYT (500) /* ms */ /* - * Do a soft reset of the PCI card using the Configuration Option Register + * Do a soft reset of the 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 * @@ -142,34 +79,19 @@ * Note bis : Don't try to access HERMES_CMD during the reset phase. * It just won't work ! */ -static int -orinoco_pci_cor_reset(struct orinoco_private *priv) +static int orinoco_pci_cor_reset(struct orinoco_private *priv) { hermes_t *hw = &priv->hw; - unsigned long timeout; - u16 reg; + unsigned long timeout; + u16 reg; - /* Assert the reset until the card notice */ + /* Assert the reset until the card notices */ hermes_write_regn(hw, PCI_COR, HERMES_PCI_COR_MASK); - printk(KERN_NOTICE "Reset done"); - timeout = jiffies + (HERMES_PCI_COR_ONT * HZ / 1000); - while(time_before(jiffies, timeout)) { - printk("."); - mdelay(1); - } - printk(";\n"); - //mdelay(HERMES_PCI_COR_ONT); + mdelay(HERMES_PCI_COR_ONT); /* Give time for the card to recover from this hard effort */ hermes_write_regn(hw, PCI_COR, 0x0000); - printk(KERN_NOTICE "Clear Reset"); - timeout = jiffies + (HERMES_PCI_COR_OFFT * HZ / 1000); - while(time_before(jiffies, timeout)) { - printk("."); - mdelay(1); - } - printk(";\n"); - //mdelay(HERMES_PCI_COR_OFFT); + mdelay(HERMES_PCI_COR_OFFT); /* The card is ready when it's no longer busy */ timeout = jiffies + (HERMES_PCI_COR_BUSYT * HZ / 1000); @@ -178,102 +100,99 @@ orinoco_pci_cor_reset(struct orinoco_private *priv) mdelay(1); reg = hermes_read_regn(hw, CMD); } - /* Did we timeout ? */ - if(time_after_eq(jiffies, timeout)) { + + /* Still busy? */ + if (reg & HERMES_CMD_BUSY) { printk(KERN_ERR PFX "Busy timeout\n"); return -ETIMEDOUT; } - printk(KERN_NOTICE "pci_cor : reg = 0x%X - %lX - %lX\n", reg, timeout, jiffies); return 0; } -/* - * Initialise a card. Mostly similar to PLX code. - */ static int orinoco_pci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { - int err = 0; - unsigned long pci_iorange; - u16 *pci_ioaddr = NULL; - unsigned long pci_iolen; - struct orinoco_private *priv = NULL; - struct net_device *dev = NULL; + int err; + struct orinoco_private *priv; + struct orinoco_pci_card *card; + struct net_device *dev; + void __iomem *hermes_io; err = pci_enable_device(pdev); - if (err) - return -EIO; - - /* Resource 0 is mapped to the hermes registers */ - pci_iorange = pci_resource_start(pdev, 0); - pci_iolen = pci_resource_len(pdev, 0); - pci_ioaddr = ioremap(pci_iorange, pci_iolen); - if (! pci_iorange) - goto fail; + if (err) { + printk(KERN_ERR PFX "Cannot enable PCI device\n"); + return err; + } + + err = pci_request_regions(pdev, DRIVER_NAME); + if (err) { + printk(KERN_ERR PFX "Cannot obtain PCI resources\n"); + goto fail_resources; + } + + hermes_io = pci_iomap(pdev, 0, 0); + if (!hermes_io) { + printk(KERN_ERR PFX "Cannot remap chipset registers\n"); + err = -EIO; + goto fail_map_hermes; + } /* Allocate network device */ - dev = alloc_orinocodev(0, NULL); - if (! dev) { + dev = alloc_orinocodev(sizeof(*card), orinoco_pci_cor_reset); + if (!dev) { + printk(KERN_ERR PFX "Cannot allocate network device\n"); err = -ENOMEM; - goto fail; + goto fail_alloc; } priv = netdev_priv(dev); - dev->base_addr = (unsigned long) pci_ioaddr; - dev->mem_start = pci_iorange; - dev->mem_end = pci_iorange + pci_iolen - 1; + card = priv->card; SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); - printk(KERN_DEBUG PFX - "Detected Orinoco/Prism2 PCI device at %s, mem:0x%lX to 0x%lX -> 0x%p, irq:%d\n", - pci_name(pdev), dev->mem_start, dev->mem_end, pci_ioaddr, pdev->irq); - - hermes_struct_init(&priv->hw, dev->base_addr, - HERMES_MEM, HERMES_32BIT_REGSPACING); - pci_set_drvdata(pdev, dev); + hermes_struct_init(&priv->hw, hermes_io, HERMES_32BIT_REGSPACING); - err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ, + err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED, dev->name, dev); if (err) { - printk(KERN_ERR PFX "Error allocating IRQ %d.\n", - pdev->irq); + printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq); err = -EBUSY; - goto fail; + goto fail_irq; } - dev->irq = pdev->irq; - /* Perform a COR reset to start the card */ - if(orinoco_pci_cor_reset(priv) != 0) { - printk(KERN_ERR "%s: Failed to start the card\n", dev->name); - err = -ETIMEDOUT; + err = orinoco_pci_cor_reset(priv); + if (err) { + printk(KERN_ERR PFX "Initial reset failed\n"); goto fail; } - /* Override the normal firmware detection - the Prism 2.5 PCI - * cards look like Lucent firmware but are actually Intersil */ - priv->firmware_type = FIRMWARE_TYPE_INTERSIL; - err = register_netdev(dev); if (err) { - printk(KERN_ERR "%s: Failed to register net device\n", dev->name); + printk(KERN_ERR PFX "Cannot register network device\n"); goto fail; } + pci_set_drvdata(pdev, dev); + printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name, + pci_name(pdev)); + return 0; fail: - if (dev) { - if (dev->irq) - free_irq(dev->irq, dev); + free_irq(pdev->irq, dev); - free_netdev(dev); - } + fail_irq: + pci_set_drvdata(pdev, NULL); + free_orinocodev(dev); - if (pci_ioaddr) - iounmap(pci_ioaddr); + fail_alloc: + pci_iounmap(pdev, hermes_io); + fail_map_hermes: + pci_release_regions(pdev); + + fail_resources: pci_disable_device(pdev); return err; @@ -285,97 +204,29 @@ static void __devexit orinoco_pci_remove_one(struct pci_dev *pdev) struct orinoco_private *priv = netdev_priv(dev); unregister_netdev(dev); - - if (dev->irq) - free_irq(dev->irq, dev); - - if (priv->hw.iobase) - iounmap((unsigned char *) priv->hw.iobase); - + free_irq(pdev->irq, dev); pci_set_drvdata(pdev, NULL); - free_netdev(dev); - + free_orinocodev(dev); + pci_iounmap(pdev, priv->hw.iobase); + pci_release_regions(pdev); pci_disable_device(pdev); } -static int orinoco_pci_suspend(struct pci_dev *pdev, u32 state) -{ - struct net_device *dev = pci_get_drvdata(pdev); - struct orinoco_private *priv = netdev_priv(dev); - unsigned long flags; - int err; - - printk(KERN_DEBUG "%s: Orinoco-PCI entering sleep mode (state=%d)\n", - dev->name, state); - - err = orinoco_lock(priv, &flags); - if (err) { - printk(KERN_ERR "%s: hw_unavailable on orinoco_pci_suspend\n", - dev->name); - return err; - } - - err = __orinoco_down(dev); - if (err) - printk(KERN_WARNING "%s: orinoco_pci_suspend(): Error %d downing interface\n", - dev->name, err); - - netif_device_detach(dev); - - priv->hw_unavailable++; - - orinoco_unlock(priv, &flags); - - return 0; -} - -static int orinoco_pci_resume(struct pci_dev *pdev) -{ - struct net_device *dev = pci_get_drvdata(pdev); - struct orinoco_private *priv = netdev_priv(dev); - unsigned long flags; - int err; - - printk(KERN_DEBUG "%s: Orinoco-PCI waking up\n", dev->name); - - err = orinoco_reinit_firmware(dev); - if (err) { - printk(KERN_ERR "%s: Error %d re-initializing firmware on orinoco_pci_resume()\n", - dev->name, err); - return err; - } - - spin_lock_irqsave(&priv->lock, flags); - - netif_device_attach(dev); - - priv->hw_unavailable--; - - if (priv->open && (! priv->hw_unavailable)) { - err = __orinoco_up(dev); - if (err) - printk(KERN_ERR "%s: Error %d restarting card on orinoco_pci_resume()\n", - dev->name, err); - } - - spin_unlock_irqrestore(&priv->lock, flags); - - return 0; -} - -static struct pci_device_id orinoco_pci_pci_id_table[] = { +static struct pci_device_id orinoco_pci_id_table[] = { /* Intersil Prism 3 */ {0x1260, 0x3872, PCI_ANY_ID, PCI_ANY_ID,}, /* Intersil Prism 2.5 */ {0x1260, 0x3873, PCI_ANY_ID, PCI_ANY_ID,}, + /* Samsung MagicLAN SWL-2210P */ + {0x167d, 0xa000, PCI_ANY_ID, PCI_ANY_ID,}, {0,}, }; -MODULE_DEVICE_TABLE(pci, orinoco_pci_pci_id_table); +MODULE_DEVICE_TABLE(pci, orinoco_pci_id_table); static struct pci_driver orinoco_pci_driver = { .name = DRIVER_NAME, - .id_table = orinoco_pci_pci_id_table, + .id_table = orinoco_pci_id_table, .probe = orinoco_pci_init_one, .remove = __devexit_p(orinoco_pci_remove_one), .suspend = orinoco_pci_suspend, @@ -393,7 +244,7 @@ MODULE_LICENSE("Dual MPL/GPL"); static int __init orinoco_pci_init(void) { printk(KERN_DEBUG "%s\n", version); - return pci_module_init(&orinoco_pci_driver); + return pci_register_driver(&orinoco_pci_driver); } static void __exit orinoco_pci_exit(void)