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

📄 hostap_hw.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
		prism2_check_sta_fw_version(local);		if (hfa384x_get_rid(dev, HFA384X_RID_CNFOWNMACADDR,				    &dev->dev_addr, 6, 1) < 0) {			printk("%s: could not get own MAC address\n",			       dev->name);		}		list_for_each(ptr, &local->hostap_interfaces) {			iface = list_entry(ptr, struct hostap_interface, list);			memcpy(iface->dev->dev_addr, dev->dev_addr, ETH_ALEN);		}	} else if (local->fw_ap)		prism2_check_sta_fw_version(local);	prism2_setup_rids(dev);	/* MAC is now configured, but port 0 is not yet enabled */	return 0; failed:	if (!local->no_pri)		printk(KERN_WARNING "%s: Initialization failed\n", dev_info);	return 1;}static int prism2_hw_enable(struct net_device *dev, int initial){	struct hostap_interface *iface;	local_info_t *local;	int was_resetting;	iface = netdev_priv(dev);	local = iface->local;	was_resetting = local->hw_resetting;	if (hfa384x_cmd(dev, HFA384X_CMDCODE_ENABLE, 0, NULL, NULL)) {		printk("%s: MAC port 0 enabling failed\n", dev->name);		return 1;	}	local->hw_ready = 1;	local->hw_reset_tries = 0;	local->hw_resetting = 0;	hfa384x_enable_interrupts(dev);	/* at least D-Link DWL-650 seems to require additional port reset	 * before it starts acting as an AP, so reset port automatically	 * here just in case */	if (initial && prism2_reset_port(dev)) {		printk("%s: MAC port 0 reseting failed\n", dev->name);		return 1;	}	if (was_resetting && netif_queue_stopped(dev)) {		/* If hw_reset() was called during pending transmit, netif		 * queue was stopped. Wake it up now since the wlan card has		 * been resetted. */		netif_wake_queue(dev);	}	return 0;}static int prism2_hw_config(struct net_device *dev, int initial){	struct hostap_interface *iface;	local_info_t *local;	iface = netdev_priv(dev);	local = iface->local;	if (local->hw_downloading)		return 1;	if (prism2_hw_init(dev, initial)) {		return local->no_pri ? 0 : 1;	}	if (prism2_hw_init2(dev, initial))		return 1;	/* Enable firmware if secondary image is loaded and at least one of the	 * netdevices is up. */	if (!local->pri_only &&	    (initial == 0 || (initial == 2 && local->num_dev_open > 0))) {		if (!local->dev_enabled)			prism2_callback(local, PRISM2_CALLBACK_ENABLE);		local->dev_enabled = 1;		return prism2_hw_enable(dev, initial);	}	return 0;}static void prism2_hw_shutdown(struct net_device *dev, int no_disable){	struct hostap_interface *iface;	local_info_t *local;	iface = netdev_priv(dev);	local = iface->local;	/* Allow only command completion events during disable */	hfa384x_events_only_cmd(dev);	local->hw_ready = 0;	if (local->dev_enabled)		prism2_callback(local, PRISM2_CALLBACK_DISABLE);	local->dev_enabled = 0;	if (local->func->card_present && !local->func->card_present(local)) {		printk(KERN_DEBUG "%s: card already removed or not configured "		       "during shutdown\n", dev->name);		return;	}	if ((no_disable & HOSTAP_HW_NO_DISABLE) == 0 &&	    hfa384x_cmd(dev, HFA384X_CMDCODE_DISABLE, 0, NULL, NULL))		printk(KERN_WARNING "%s: Shutdown failed\n", dev_info);	hfa384x_disable_interrupts(dev);	if (no_disable & HOSTAP_HW_ENABLE_CMDCOMPL)		hfa384x_events_only_cmd(dev);	else		prism2_clear_cmd_queue(local);}static void prism2_hw_reset(struct net_device *dev){	struct hostap_interface *iface;	local_info_t *local;#if 0	static long last_reset = 0;	/* do not reset card more than once per second to avoid ending up in a	 * busy loop reseting the card */	if (time_before_eq(jiffies, last_reset + HZ))		return;	last_reset = jiffies;#endif	iface = netdev_priv(dev);	local = iface->local;	if (in_interrupt()) {		printk(KERN_DEBUG "%s: driver bug - prism2_hw_reset() called "		       "in interrupt context\n", dev->name);		return;	}	if (local->hw_downloading)		return;	if (local->hw_resetting) {		printk(KERN_WARNING "%s: %s: already resetting card - "		       "ignoring reset request\n", dev_info, dev->name);		return;	}	local->hw_reset_tries++;	if (local->hw_reset_tries > 10) {		printk(KERN_WARNING "%s: too many reset tries, skipping\n",		       dev->name);		return;	}	printk(KERN_WARNING "%s: %s: resetting card\n", dev_info, dev->name);	hfa384x_disable_interrupts(dev);	local->hw_resetting = 1;	if (local->func->cor_sreset) {		/* Host system seems to hang in some cases with high traffic		 * load or shared interrupts during COR sreset. Disable shared		 * interrupts during reset to avoid these crashes. COS sreset		 * takes quite a long time, so it is unfortunate that this		 * seems to be needed. Anyway, I do not know of any better way		 * of avoiding the crash. */		disable_irq(dev->irq);		local->func->cor_sreset(local);		enable_irq(dev->irq);	}	prism2_hw_shutdown(dev, 1);	prism2_hw_config(dev, 0);	local->hw_resetting = 0;#ifdef PRISM2_DOWNLOAD_SUPPORT	if (local->dl_pri) {		printk(KERN_DEBUG "%s: persistent download of primary "		       "firmware\n", dev->name);		if (prism2_download_genesis(local, local->dl_pri) < 0)			printk(KERN_WARNING "%s: download (PRI) failed\n",			       dev->name);	}	if (local->dl_sec) {		printk(KERN_DEBUG "%s: persistent download of secondary "		       "firmware\n", dev->name);		if (prism2_download_volatile(local, local->dl_sec) < 0)			printk(KERN_WARNING "%s: download (SEC) failed\n",			       dev->name);	}#endif /* PRISM2_DOWNLOAD_SUPPORT */	/* TODO: restore beacon TIM bits for STAs that have buffered frames */}static void prism2_schedule_reset(local_info_t *local){	schedule_work(&local->reset_queue);}/* Called only as scheduled task after noticing card timeout in interrupt * context */static void handle_reset_queue(void *data){	local_info_t *local = (local_info_t *) data;	printk(KERN_DEBUG "%s: scheduled card reset\n", local->dev->name);	prism2_hw_reset(local->dev);	if (netif_queue_stopped(local->dev)) {		int i;		for (i = 0; i < PRISM2_TXFID_COUNT; i++)			if (local->intransmitfid[i] == PRISM2_TXFID_EMPTY) {				PDEBUG(DEBUG_EXTRA, "prism2_tx_timeout: "				       "wake up queue\n");				netif_wake_queue(local->dev);				break;			}	}}static int prism2_get_txfid_idx(local_info_t *local){	int idx, end;	unsigned long flags;	spin_lock_irqsave(&local->txfidlock, flags);	end = idx = local->next_txfid;	do {		if (local->intransmitfid[idx] == PRISM2_TXFID_EMPTY) {			local->intransmitfid[idx] = PRISM2_TXFID_RESERVED;			spin_unlock_irqrestore(&local->txfidlock, flags);			return idx;		}		idx++;		if (idx >= PRISM2_TXFID_COUNT)			idx = 0;	} while (idx != end);	spin_unlock_irqrestore(&local->txfidlock, flags);	PDEBUG(DEBUG_EXTRA2, "prism2_get_txfid_idx: no room in txfid buf: "	       "packet dropped\n");	local->stats.tx_dropped++;	return -1;}/* Called only from hardware IRQ */static void prism2_transmit_cb(struct net_device *dev, long context,			       u16 resp0, u16 res){	struct hostap_interface *iface;	local_info_t *local;	int idx = (int) context;	iface = netdev_priv(dev);	local = iface->local;	if (res) {		printk(KERN_DEBUG "%s: prism2_transmit_cb - res=0x%02x\n",		       dev->name, res);		return;	}	if (idx < 0 || idx >= PRISM2_TXFID_COUNT) {		printk(KERN_DEBUG "%s: prism2_transmit_cb called with invalid "		       "idx=%d\n", dev->name, idx);		return;	}	if (!test_and_clear_bit(HOSTAP_BITS_TRANSMIT, &local->bits)) {		printk(KERN_DEBUG "%s: driver bug: prism2_transmit_cb called "		       "with no pending transmit\n", dev->name);	}	if (netif_queue_stopped(dev)) {		/* ready for next TX, so wake up queue that was stopped in		 * prism2_transmit() */		netif_wake_queue(dev);	}	spin_lock(&local->txfidlock);	/* With reclaim, Resp0 contains new txfid for transmit; the old txfid	 * will be automatically allocated for the next TX frame */	local->intransmitfid[idx] = resp0;	PDEBUG(DEBUG_FID, "%s: prism2_transmit_cb: txfid[%d]=0x%04x, "	       "resp0=0x%04x, transmit_txfid=0x%04x\n",	       dev->name, idx, local->txfid[idx],	       resp0, local->intransmitfid[local->next_txfid]);	idx++;	if (idx >= PRISM2_TXFID_COUNT)		idx = 0;	local->next_txfid = idx;	/* check if all TX buffers are occupied */	do {		if (local->intransmitfid[idx] == PRISM2_TXFID_EMPTY) {			spin_unlock(&local->txfidlock);			return;		}		idx++;		if (idx >= PRISM2_TXFID_COUNT)			idx = 0;	} while (idx != local->next_txfid);	spin_unlock(&local->txfidlock);	/* no empty TX buffers, stop queue */	netif_stop_queue(dev);}/* Called only from software IRQ if PCI bus master is not used (with bus master * this can be called both from software and hardware IRQ) */static int prism2_transmit(struct net_device *dev, int idx){	struct hostap_interface *iface;	local_info_t *local;	int res;	iface = netdev_priv(dev);	local = iface->local;	/* The driver tries to stop netif queue so that there would not be	 * more than one attempt to transmit frames going on; check that this	 * is really the case */	if (test_and_set_bit(HOSTAP_BITS_TRANSMIT, &local->bits)) {		printk(KERN_DEBUG "%s: driver bug - prism2_transmit() called "		       "when previous TX was pending\n", dev->name);		return -1;	}	/* stop the queue for the time that transmit is pending */	netif_stop_queue(dev);	/* transmit packet */	res = hfa384x_cmd_callback(		dev,		HFA384X_CMDCODE_TRANSMIT | HFA384X_CMD_TX_RECLAIM,		local->txfid[idx],		prism2_transmit_cb, (long) idx);	if (res) {		struct net_device_stats *stats;		printk(KERN_DEBUG "%s: prism2_transmit: CMDCODE_TRANSMIT "		       "failed (res=%d)\n", dev->name, res);		stats = hostap_get_stats(dev);		stats->tx_dropped++;		netif_wake_queue(dev);		return -1;	}	dev->trans_start = jiffies;	/* Since we did not wait for command completion, the card continues	 * to process on the background and we will finish handling when	 * command completion event is handled (prism2_cmd_ev() function) */	return 0;}/* Send IEEE 802.11 frame (convert the header into Prism2 TX descriptor and * send the payload with this descriptor) *//* Called only from software IRQ */static int prism2_tx_80211(struct sk_buff *skb, struct net_device *dev){	struct hostap_interface *iface;	local_info_t *local;	struct hfa384x_tx_frame txdesc;	struct hostap_skb_tx_data *meta;	int hdr_len, data_len, idx, res, ret = -1;	u16 tx_control, fc;	iface = netdev_priv(dev);	local = iface->local;	meta = (struct hostap_skb_tx_data *) skb->cb;	prism2_callback(local, PRISM2_CALLBACK_TX_START);	if ((local->func->card_present && !local->func->card_present(local)) ||	    !local->hw_ready || local->hw_downloading || local->pri_only) {		if (net_ratelimit()) {			printk(KERN_DEBUG "%s: prism2_tx_80211: hw not ready -"			       " skipping\n", dev->name);		}		goto fail;	}	memset(&txdesc, 0, sizeof(txdesc));	/* skb->data starts with txdesc->frame_control */	hdr_len = 24;	memcpy(&txdesc.frame_control, skb->data, hdr_len); 	fc = le16_to_cpu(txdesc.frame_control);	if (WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA &&	    (fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS) &&	    skb->len >= 30) {		/* Addr4 */		memcpy(txdesc.addr4, skb->data + hdr_len, ETH_ALEN);		hdr_len += ETH_ALEN;	}	tx_control = local->tx_control;	if (meta->tx_cb_idx) {		tx_control |= HFA384X_TX_CTRL_TX_OK;		txdesc.sw_support = cpu_to_le16(meta->tx_cb_idx);	}	txdesc.tx_control = cpu_to_le16(tx_control);	txdesc.tx_rate = meta->rate;	data_len = skb->len - hdr_len;	txdesc.data_len = cpu_to_le16(data_len);	txdesc.len = cpu_to_be16(data_len);	idx = prism2_get_txfid_idx(local);	if (idx < 0)		goto fail;	if (local->frame_dump & PRISM2_DUMP_TX_HDR)		hostap_dump_tx_header(dev->name, &txdesc);	spin_lock(&local->baplock);	res = hfa384x_setup_bap(dev, BAP0, local->txfid[idx], 0);	if (!res)		res = hfa384x_to_bap(dev, BAP0, &txdesc, sizeof(txdesc));	if (!res)		res = hfa384x_to_bap(dev, BAP0, skb->data + hdr_len,				     skb->len - hdr_len);	spin_unlock(&local->baplock);	if (!res)		res = prism2_transmit(dev, idx);	if (res) {		printk(KERN_DEBUG "%s: prism2_tx_80211 - to BAP0 failed\n",		       dev->name);		local->intransmitfid[idx] = PRISM2_TXFID_EMPTY;		schedule_work(&local->reset_queue);		goto fail;	}	ret = 0;fail:	prism2_callback(local, PRISM2_CALLBACK_TX_END);	return ret;}/* Some SMP systems have reported number of odd errors with hostap_pci. fid

⌨️ 快捷键说明

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