⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 orinoco.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
			       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 "%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

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -