📄 orinoco.c
字号:
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 "%s: Multicast list is " "longer than mc_count\n", dev->name); 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;}/* 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; 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 */ netif_carrier_off(dev); orinoco_unlock(priv, &flags); /* Scanning support: Cleanup of driver struct */ kfree(priv->scan_result); priv->scan_result = NULL; priv->scan_inprogress = 0; 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); goto disable; } } err = orinoco_reinit_firmware(dev); if (err) { printk(KERN_ERR "%s: orinoco_reset: Error %d re-initializing firmware\n", dev->name, err); goto disable; } 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; disable: hermes_set_irqmask(hw, 0); netif_device_detach(dev); printk(KERN_ERR "%s: Device has been disabled!\n", dev->name);}/********************************************************************//* 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, evstat); evstat = hermes_read_regn(hw, EVSTAT); events = evstat & hw->inten; }; orinoco_unlock(priv, &flags); return IRQ_HANDLED;}/********************************************************************//* Initialization *//********************************************************************/struct comp_id { u16 id, variant, major, minor;} __attribute__ ((packed));static inline fwtype_t determine_firmware_type(struct comp_id *nic_id){ if (nic_id->id < 0x8000) return FIRMWARE_TYPE_AGERE; else if (nic_id->id == 0x8000 && nic_id->major == 0) return FIRMWARE_TYPE_SYMBOL; else return FIRMWARE_TYPE_INTERSIL;}/* Set priv->firmware type, determine firmware properties */static int determine_firmware(struct net_device *dev){ struct orinoco_private *priv = netdev_priv(dev); hermes_t *hw = &priv->hw; int err; struct comp_id nic_id, sta_id; unsigned int firmver; char tmp[SYMBOL_MAX_VER_LEN+1]; /* Get the hardware version */ err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_NICID, &nic_id); if (err) { printk(KERN_ERR "%s: Cannot read hardware identity: error %d\n", dev->name, err); return err; } le16_to_cpus(&nic_id.id); le16_to_cpus(&nic_id.variant); le16_to_cpus(&nic_id.major); le16_to_cpus(&nic_id.minor); printk(KERN_DEBUG "%s: Hardware identity %04x:%04x:%04x:%04x\n", dev->name, nic_id.id, nic_id.variant, nic_id.major, nic_id.minor); priv->firmware_type = determine_firmware_type(&nic_id); /* Get the firmware version */ err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_STAID, &sta_id); if (err) { printk(KERN_ERR "%s: Cannot read station identity: error %d\n", dev->name, err); return err; } 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); switch (sta_id.id) { case 0x15: printk(KERN_ERR "%s: Primary firmware is active\n", dev->name); return -ENODEV; case 0x14b: printk(KERN_ERR "%s: Tertiary firmware is active\n", dev->name); return -ENODEV; case 0x1f: /* Intersil, Agere, Symbol Spectrum24 */ case 0x21: /* Symbol Spectrum24 Trilogy */ break; default: printk(KERN_NOTICE "%s: Unknown station ID, please report\n", dev->name); break; } /* Default capabilities */ priv->has_sensitivity = 1; priv->has_mwo = 0; priv->has_preamble = 0; priv->has_port3 = 1; priv->has_ibss = 1; 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 */ snprintf(priv->fw_name, sizeof(priv->fw_name) - 1, "Lucent/Agere %d.%02d", sta_id.major, sta_id.minor); firmver = ((unsigned long)sta_id.major << 16) | sta_id.minor; priv->has_ibss = (firmver >= 0x60006); 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_port = 1; priv->has_hostscan = (firmver >= 0x8000a); priv->broken_monitor = (firmver >= 0x80000); /* Tested with Agere firmware : * 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II * Tested CableTron firmware : 4.32 => Anton */ break; case FIRMWARE_TYPE_SYMBOL: /* Symbol , 3Com AirConnect, Intel, Ericsson WLAN */ /* Intel MAC : 00:02:B3:* */ /* 3Com MAC : 00:50:DA:* */ memset(tmp, 0, sizeof(tmp)); /* Get the Symbol firmware version */ err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_SECONDARYVERSION_SYMBOL, SYMBOL_MAX_VER_LEN, NULL, &tmp); if (err) { printk(KERN_WARNING "%s: Error %d reading Symbol firmware info. Wildly guessing capabilities...\n", dev->name, err); firmver = 0; tmp[0] = '\0'; } else { /* The firmware revision is a string, the format is * something like : "V2.20-01". * Quick and dirty parsing... - Jean II */ firmver = ((tmp[1] - '0') << 16) | ((tmp[3] - '0') << 12) | ((tmp[4] - '0') << 8) | ((tmp[6] - '0') << 4) | (tmp[7] - '0'); tmp[SYMBOL_MAX_VER_LEN] = '\0'; } snprintf(priv->fw_name, sizeof(priv->fw_name) - 1, "Symbol %s", tmp); priv->has_ibss = (firmver >= 0x20000); priv->has_wep = (firmver >= 0x15012); priv->has_big_wep = (firmver >= 0x20000); priv->has_pm = (firmver >= 0x20000 && firmver < 0x22000) || (firmver >= 0x29000 && firmver < 0x30000) || firmver >= 0x31000; priv->has_preamble = (firmver >= 0x20000); priv->ibss_port = 4; priv->broken_disableport = (firmver == 0x25013) || (firmver >= 0x30000 && firmver <= 0x31000); priv->has_hostscan = (firmver >= 0x31001) || (firmver >= 0x29057 && firmver < 0x30000); /* Tested with Intel firmware : 0x20015 => Jean II */ /* Tested with 3Com firmware : 0x15012 & 0x22001 => Jean II */ break; case FIRMWARE_TYPE_INTERSIL: /* D-Link, Linksys, Adtron, ZoomAir, and many others... * Samsung, Compaq 100/200 and Proxim are slightly * different and less well tested */ /* D-Link MAC : 00:40:05:* */ /* Addtron MAC : 00:90:D1:* */ snprintf(priv->fw_name, sizeof(priv->fw_name) - 1, "Intersil %d.%d.%d", sta_id.major, sta_id.minor, sta_id.variant); firmver = ((unsigned long)sta_id.major << 16) | ((unsigned long)sta_id.minor << 8) | sta_id.variant; priv->has_ibss = (firmver >= 0x000700); /* FIXME */ priv->has_big_wep = priv->has_wep = (firmver >= 0x000800); priv->has_pm = (firmver >= 0x000700); priv->has_hostscan = (firmver >= 0x010301); if (firmver >= 0x000800) priv->ibss_port = 0; else { printk(KERN_NOTICE "%s: Intersil firmware earlier " "than v0.8.x - several features not supported\n", dev->name); priv->ibss_port = 1; } break; } printk(KERN_DEBUG "%s: Firmware determined as %s\n", dev->name, priv->fw_name); return 0;}static int orinoco_init(struct net_device *dev){ struct orinoco_private *priv = netdev_priv(dev); hermes_t *hw = &priv->hw; int err = 0; struct hermes_idstring nickbuf; u16 reclen; int len; TRACE_ENTER(dev->name); /* No need to lock, the hw_unavailable flag is already set in * alloc_orinocodev() */ priv->nicbuf_size = IEEE80211_FRAME_LEN + ETH_HLEN; /* Initialize the firmware */ err = orinoco_reinit_firmware(dev); if (err != 0) { printk(KERN_ERR "%s: failed to initialize firmware (err = %d)\n", dev->name, err); goto out; } err = determine_firmware(dev); if (err != 0) { printk(KERN_ERR "%s: Incompatible firmware, aborting\n", dev->name); goto out; } if (priv->has_port3) printk(KERN_DEBUG "%s: Ad-hoc demo mode supported\n", dev->name); if (priv->has_ibss) printk(KERN_DEBUG "%s: IEEE standard IBSS ad-hoc mode supported\n", dev->name); if (priv->has_wep) { printk(KERN_DEBUG "%s: WEP supported, ", dev->name); if (priv->has_big_wep) printk("104-bit key\n"); else printk("40-bit key\n"); } /* Get the MAC address */ err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR, ETH_ALEN, NULL, dev->dev_addr); if (err) { printk(KERN_WARNING "%s: failed to read MAC address!\n", dev->name); goto out; } printk(KERN_DEBUG "%s: MAC address %02X:%02X:%02X:%02X:%02X:%02X\n", dev->name, dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); /* Get the station name */ err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME, sizeof(nickbuf), &reclen, &nickbuf); if (err) { printk(KERN_ERR "%s: failed to read station name\n", dev->name); goto out; } if (nickbuf.len) len = min(IW_ESSID_MAX_SIZE, (int)le16_to_cpu(nickbuf
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -