📄 orinoco.c
字号:
HERMES_RID_CNFPMENABLED, priv->pm_on); if (err) { printk(KERN_ERR "%s: Error %d setting up PM\n", dev->name, err); return err; } err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFMULTICASTRECEIVE, priv->pm_mcast); if (err) { printk(KERN_ERR "%s: Error %d setting up PM\n", dev->name, err); return err; } err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFMAXSLEEPDURATION, priv->pm_period); if (err) { printk(KERN_ERR "%s: Error %d setting up PM\n", dev->name, err); return err; } err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPMHOLDOVERDURATION, priv->pm_timeout); if (err) { printk(KERN_ERR "%s: Error %d setting up PM\n", dev->name, err); return err; } } /* Set preamble - only for Symbol so far... */ if (priv->has_preamble) { err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPREAMBLE_SYMBOL, priv->preamble); if (err) { printk(KERN_ERR "%s: Error %d setting preamble\n", dev->name, err); return err; } } /* Set up encryption */ if (priv->has_wep) { err = __orinoco_hw_setup_wep(priv); if (err) { printk(KERN_ERR "%s: Error %d activating WEP\n", dev->name, err); return err; } } /* Set promiscuity / multicast*/ priv->promiscuous = 0; priv->mc_count = 0; __orinoco_set_multicast_list(dev); /* FIXME: what about the xmit_lock */ return 0;}/* FIXME: return int? */static void__orinoco_set_multicast_list(struct net_device *dev){ struct orinoco_private *priv = netdev_priv(dev); hermes_t *hw = &priv->hw; int err = 0; int promisc, mc_count; /* The Hermes doesn't seem to have an allmulti mode, so we go * into promiscuous mode and let the upper levels deal. */ if ( (dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI) || (dev->mc_count > MAX_MULTICAST(priv)) ) { promisc = 1; mc_count = 0; } else { promisc = 0; mc_count = dev->mc_count; } if (promisc != priv->promiscuous) { err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPROMISCUOUSMODE, promisc); if (err) { printk(KERN_ERR "%s: Error %d setting PROMISCUOUSMODE to 1.\n", dev->name, err); } else priv->promiscuous = promisc; } if (! promisc && (mc_count || priv->mc_count) ) { struct dev_mc_list *p = dev->mc_list; struct hermes_multicast mclist; int i; for (i = 0; i < mc_count; i++) { /* paranoia: is list shorter than mc_count? */ BUG_ON(! p); /* paranoia: bad address size in list? */ BUG_ON(p->dmi_addrlen != ETH_ALEN); memcpy(mclist.addr[i], p->dmi_addr, ETH_ALEN); p = p->next; } if (p) printk(KERN_WARNING "Multicast list is longer than mc_count\n"); err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFGROUPADDRESSES, HERMES_BYTES_TO_RECLEN(priv->mc_count * ETH_ALEN), &mclist); if (err) printk(KERN_ERR "%s: Error %d setting multicast list.\n", dev->name, err); else priv->mc_count = mc_count; } /* Since we can set the promiscuous flag when it wasn't asked for, make sure the net_device knows about it. */ if (priv->promiscuous) dev->flags |= IFF_PROMISC; else dev->flags &= ~IFF_PROMISC;}static int orinoco_reconfigure(struct net_device *dev){ struct orinoco_private *priv = netdev_priv(dev); struct hermes *hw = &priv->hw; unsigned long flags; int err = 0; if (priv->broken_disableport) { schedule_work(&priv->reset_work); return 0; } if (orinoco_lock(priv, &flags) != 0) return -EBUSY; err = hermes_disable_port(hw, 0); if (err) { printk(KERN_WARNING "%s: Unable to disable port while reconfiguring card\n", dev->name); priv->broken_disableport = 1; goto out; } err = __orinoco_program_rids(dev); if (err) { printk(KERN_WARNING "%s: Unable to reconfigure card\n", dev->name); goto out; } err = hermes_enable_port(hw, 0); if (err) { printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n", dev->name); goto out; } out: if (err) { printk(KERN_WARNING "%s: Resetting instead...\n", dev->name); schedule_work(&priv->reset_work); err = 0; } orinoco_unlock(priv, &flags); return err;}/* This must be called from user context, without locks held - use * schedule_work() */static void orinoco_reset(struct net_device *dev){ struct orinoco_private *priv = netdev_priv(dev); struct hermes *hw = &priv->hw; int err = 0; unsigned long flags; if (orinoco_lock(priv, &flags) != 0) /* When the hardware becomes available again, whatever * detects that is responsible for re-initializing * it. So no need for anything further */ return; netif_stop_queue(dev); /* Shut off interrupts. Depending on what state the hardware * is in, this might not work, but we'll try anyway */ hermes_set_irqmask(hw, 0); hermes_write_regn(hw, EVACK, 0xffff); priv->hw_unavailable++; priv->last_linkstatus = 0xffff; /* firmware will have to reassociate */ priv->connected = 0; orinoco_unlock(priv, &flags); if (priv->hard_reset) err = (*priv->hard_reset)(priv); if (err) { printk(KERN_ERR "%s: orinoco_reset: Error %d " "performing hard reset\n", dev->name, err); /* FIXME: shutdown of some sort */ return; } err = orinoco_reinit_firmware(dev); if (err) { printk(KERN_ERR "%s: orinoco_reset: Error %d re-initializing firmware\n", dev->name, err); return; } spin_lock_irq(&priv->lock); /* This has to be called from user context */ priv->hw_unavailable--; /* priv->open or priv->hw_unavailable might have changed while * we dropped the lock */ if (priv->open && (! priv->hw_unavailable)) { err = __orinoco_up(dev); if (err) { printk(KERN_ERR "%s: orinoco_reset: Error %d reenabling card\n", dev->name, err); } else dev->trans_start = jiffies; } spin_unlock_irq(&priv->lock); return;}/********************************************************************//* Interrupt handler *//********************************************************************/static void __orinoco_ev_tick(struct net_device *dev, hermes_t *hw){ printk(KERN_DEBUG "%s: TICK\n", dev->name);}static void __orinoco_ev_wterr(struct net_device *dev, hermes_t *hw){ /* This seems to happen a fair bit under load, but ignoring it seems to work fine...*/ printk(KERN_DEBUG "%s: MAC controller error (WTERR). Ignoring.\n", dev->name);}irqreturn_t orinoco_interrupt(int irq, void *dev_id, struct pt_regs *regs){ struct net_device *dev = (struct net_device *)dev_id; struct orinoco_private *priv = netdev_priv(dev); hermes_t *hw = &priv->hw; int count = MAX_IRQLOOPS_PER_IRQ; u16 evstat, events; /* These are used to detect a runaway interrupt situation */ /* If we get more than MAX_IRQLOOPS_PER_JIFFY iterations in a jiffy, * we panic and shut down the hardware */ static int last_irq_jiffy = 0; /* jiffies value the last time * we were called */ static int loops_this_jiffy = 0; unsigned long flags; if (orinoco_lock(priv, &flags) != 0) { /* If hw is unavailable - we don't know if the irq was * for us or not */ return IRQ_HANDLED; } evstat = hermes_read_regn(hw, EVSTAT); events = evstat & hw->inten; if (! events) { orinoco_unlock(priv, &flags); return IRQ_NONE; } if (jiffies != last_irq_jiffy) loops_this_jiffy = 0; last_irq_jiffy = jiffies; while (events && count--) { if (++loops_this_jiffy > MAX_IRQLOOPS_PER_JIFFY) { printk(KERN_WARNING "%s: IRQ handler is looping too " "much! Resetting.\n", dev->name); /* Disable interrupts for now */ hermes_set_irqmask(hw, 0); schedule_work(&priv->reset_work); break; } /* Check the card hasn't been removed */ if (! hermes_present(hw)) { DEBUG(0, "orinoco_interrupt(): card removed\n"); break; } if (events & HERMES_EV_TICK) __orinoco_ev_tick(dev, hw); if (events & HERMES_EV_WTERR) __orinoco_ev_wterr(dev, hw); if (events & HERMES_EV_INFDROP) __orinoco_ev_infdrop(dev, hw); if (events & HERMES_EV_INFO) __orinoco_ev_info(dev, hw); if (events & HERMES_EV_RX) __orinoco_ev_rx(dev, hw); if (events & HERMES_EV_TXEXC) __orinoco_ev_txexc(dev, hw); if (events & HERMES_EV_TX) __orinoco_ev_tx(dev, hw); if (events & HERMES_EV_ALLOC) __orinoco_ev_alloc(dev, hw); hermes_write_regn(hw, EVACK, events); evstat = hermes_read_regn(hw, EVSTAT); events = evstat & hw->inten; }; orinoco_unlock(priv, &flags); return IRQ_HANDLED;}/********************************************************************//* Initialization *//********************************************************************/struct sta_id { u16 id, variant, major, minor;} __attribute__ ((packed));static int determine_firmware_type(struct net_device *dev, struct sta_id *sta_id){ /* FIXME: this is fundamentally broken */ unsigned int firmver = ((u32)sta_id->major << 16) | sta_id->minor; if (sta_id->variant == 1) return FIRMWARE_TYPE_AGERE; else if ((sta_id->variant == 2) && ((firmver == 0x10001) || (firmver == 0x20001))) return FIRMWARE_TYPE_SYMBOL; else return FIRMWARE_TYPE_INTERSIL;}static void determine_firmware(struct net_device *dev){ struct orinoco_private *priv = netdev_priv(dev); hermes_t *hw = &priv->hw; int err; struct sta_id sta_id; unsigned int firmver; char tmp[SYMBOL_MAX_VER_LEN+1]; /* Get the firmware version */ err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_STAID, &sta_id); if (err) { printk(KERN_WARNING "%s: Error %d reading firmware info. Wildly guessing capabilities...\n", dev->name, err); memset(&sta_id, 0, sizeof(sta_id)); } le16_to_cpus(&sta_id.id); le16_to_cpus(&sta_id.variant); le16_to_cpus(&sta_id.major); le16_to_cpus(&sta_id.minor); printk(KERN_DEBUG "%s: Station identity %04x:%04x:%04x:%04x\n", dev->name, sta_id.id, sta_id.variant, sta_id.major, sta_id.minor); if (! priv->firmware_type) priv->firmware_type = determine_firmware_type(dev, &sta_id); /* Default capabilities */ priv->has_sensitivity = 1; priv->has_mwo = 0; priv->has_preamble = 0; priv->has_port3 = 1; priv->has_ibss = 1; priv->has_ibss_any = 0; priv->has_wep = 0; priv->has_big_wep = 0; /* Determine capabilities from the firmware version */ switch (priv->firmware_type) { case FIRMWARE_TYPE_AGERE: /* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout, ELSA, Melco, HP, IBM, Dell 1150, Compaq 110/210 */ printk(KERN_DEBUG "%s: Looks like a Lucent/Agere firmware " "version %d.%02d\n", dev->name, sta_id.major, sta_id.minor); firmver = ((unsigned long)sta_id.major << 16) | sta_id.minor; priv->has_ibss = (firmver >= 0x60006); priv->has_ibss_any = (firmver >= 0x60010); priv->has_wep = (firmver >= 0x40020); priv->has_big_wep = 1; /* FIXME: this is wrong - how do we tell Gold cards from the others? */ priv->has_mwo = (firmver >= 0x60000); priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */ priv->ibss_por
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -