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

📄 hostap_hw.c

📁 IEEE 802.11a/b/g linux2.4/2.6 驱动程序源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	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 defined(PRISM2_PCI) && defined(PRISM2_BUS_MASTER)	if (!res && skb->len >= local->bus_master_threshold_tx) {		u8 *pos;		int buf_len;		local->bus_m0_tx_idx = idx;		/* FIX: BAP0 should be locked during bus master transfer, but		 * baplock with BH's disabled is not OK for this; netif queue		 * stopping is not enough since BAP0 is used also for RID		 * read/write */		/* stop the queue for the time that bus mastering on BAP0 is		 * in use */		netif_stop_queue(dev);		spin_unlock(&local->baplock);		/* Copy frame data to bus_m0_buf */		pos = local->bus_m0_buf;		memcpy(pos, &txdesc, sizeof(txdesc));		pos += sizeof(txdesc);		memcpy(pos, skb->data + hdr_len, skb->len - hdr_len);		pos += skb->len - hdr_len;		buf_len = pos - local->bus_m0_buf;		if (buf_len & 1)			buf_len++;#ifdef PRISM2_ENABLE_BEFORE_TX_BUS_MASTER		/* Any RX packet seems to break something with TX bus		 * mastering; enable command is enough to fix this.. */		if (hfa384x_cmd_callback(dev, HFA384X_CMDCODE_ENABLE, 0,					 prism2_tx_cb, (long) buf_len)) {			printk(KERN_DEBUG "%s: TX: enable port0 failed\n",			       dev->name);		}#else /* PRISM2_ENABLE_BEFORE_TX_BUS_MASTER */		prism2_tx_cb(dev, (void *) buf_len, 0, 0);#endif /* PRISM2_ENABLE_BEFORE_TX_BUS_MASTER */		/* Bus master transfer will be started from command completion		 * event handler and TX handling will be finished by calling		 * prism2_transmit() from bus master event handler */		goto tx_stats;	}#endif /* PRISM2_PCI and PRISM2_BUS_MASTER */	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;		PRISM2_SCHEDULE_TASK(&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 * register has changed values between consecutive reads for an unknown reason. * This should really not happen, so more debugging is needed. This test * version is a big slower, but it will detect most of such register changes * and will try to get the correct fid eventually. */#define EXTRA_FID_READ_TESTSstatic inline u16 prism2_read_fid_reg(struct net_device *dev, u16 reg){#ifdef EXTRA_FID_READ_TESTS	u16 val, val2, val3;	int i;	for (i = 0; i < 10; i++) {		val = HFA384X_INW(reg);		val2 = HFA384X_INW(reg);		val3 = HFA384X_INW(reg);		if (val == val2 && val == val3)			return val;		printk(KERN_DEBUG "%s: detected fid change (try=%d, reg=%04x):"		       " %04x %04x %04x\n",		       dev->name, i, reg, val, val2, val3);		if ((val == val2 || val == val3) && val != 0)			return val;		if (val2 == val3 && val2 != 0)			return val2;	}	printk(KERN_WARNING "%s: Uhhuh.. could not read good fid from reg "	       "%04x (%04x %04x %04x)\n", dev->name, reg, val, val2, val3);	return val;#else /* EXTRA_FID_READ_TESTS */	return HFA384X_INW(reg);#endif /* EXTRA_FID_READ_TESTS */}/* Called only as a tasklet (software IRQ) */static void prism2_rx(local_info_t *local){	struct net_device *dev = local->dev;	int res, rx_pending = 0;	u16 len, hdr_len, rxfid, status, macport;	struct net_device_stats *stats;	struct hfa384x_rx_frame rxdesc;	struct sk_buff *skb = NULL;	prism2_callback(local, PRISM2_CALLBACK_RX_START);	stats = hostap_get_stats(dev);	rxfid = prism2_read_fid_reg(dev, HFA384X_RXFID_OFF);#ifndef final_version	if (rxfid == 0) {		rxfid = HFA384X_INW(HFA384X_RXFID_OFF);		printk(KERN_DEBUG "prism2_rx: rxfid=0 (next 0x%04x)\n",		       rxfid);		if (rxfid == 0) {			PRISM2_SCHEDULE_TASK(&local->reset_queue);			goto rx_dropped;		}		/* try to continue with the new rxfid value */	}#endif	spin_lock(&local->baplock);	res = hfa384x_setup_bap(dev, BAP0, rxfid, 0);	if (!res)		res = hfa384x_from_bap(dev, BAP0, &rxdesc, sizeof(rxdesc));	if (res) {		spin_unlock(&local->baplock);		printk(KERN_DEBUG "%s: copy from BAP0 failed %d\n", dev->name,		       res);		if (res == -ETIMEDOUT) {			PRISM2_SCHEDULE_TASK(&local->reset_queue);		}		goto rx_dropped;	}	len = le16_to_cpu(rxdesc.data_len);	hdr_len = sizeof(rxdesc);	status = le16_to_cpu(rxdesc.status);	macport = (status >> 8) & 0x07;	/* Drop frames with too large reported payload length. Monitor mode	 * seems to sometimes pass frames (e.g., ctrl::ack) with signed and	 * negative value, so allow also values 65522 .. 65534 (-14 .. -2) for	 * macport 7 */	if (len > PRISM2_DATA_MAXLEN + 8 /* WEP */) {		if (macport == 7 && local->iw_mode == IW_MODE_MONITOR) {			if (len >= (u16) -14) {				hdr_len -= 65535 - len;				hdr_len--;			}			len = 0;		} else {			spin_unlock(&local->baplock);			printk(KERN_DEBUG "%s: Received frame with invalid "			       "length 0x%04x\n", dev->name, len);			hostap_dump_rx_header(dev->name, &rxdesc);			goto rx_dropped;		}	}	skb = dev_alloc_skb(len + hdr_len);	if (!skb) {		spin_unlock(&local->baplock);		printk(KERN_DEBUG "%s: RX failed to allocate skb\n",		       dev->name);		goto rx_dropped;	}	skb->dev = dev;	memcpy(skb_put(skb, hdr_len), &rxdesc, hdr_len);#if defined(PRISM2_PCI) && defined(PRISM2_BUS_MASTER)	if (len >= local->bus_master_threshold_rx) {		unsigned long addr;		hfa384x_events_no_bap1(dev);		local->rx_skb = skb;		/* Internal BAP0 offset points to the byte following rxdesc;		 * copy rest of the data using bus master */		addr = virt_to_phys(skb_put(skb, len));		HFA384X_OUTW((addr & 0xffff0000) >> 16,			     HFA384X_PCI_M0_ADDRH_OFF);		HFA384X_OUTW(addr & 0x0000ffff, HFA384X_PCI_M0_ADDRL_OFF);		if (len & 1)			len++;		HFA384X_OUTW(len / 2, HFA384X_PCI_M0_LEN_OFF);		HFA384X_OUTW(HFA384X_PCI_CTL_FROM_BAP, HFA384X_PCI_M0_CTL_OFF);		/* pci_bus_m1 event will be generated when data transfer is		 * complete and the frame will then be added to rx_list and		 * rx_tasklet is scheduled */		rx_pending = 1;		/* Have to release baplock before returning, although BAP0		 * should really not be used before DMA transfer has been		 * completed. */		spin_unlock(&local->baplock);	} else#endif /* PRISM2_PCI and PRISM2_BUS_MASTER */	{		if (len > 0)			res = hfa384x_from_bap(dev, BAP0, skb_put(skb, len),					       len);		spin_unlock(&local->baplock);		if (res) {			printk(KERN_DEBUG "%s: RX failed to read "			       "frame data\n", dev->name);			goto rx_dropped;		}		skb_queue_tail(&local->rx_list, skb);		tasklet_schedule(&local->rx_tasklet);	} rx_exit:	prism2_callback(local, PRISM2_CALLBACK_RX_END);	if (!rx_pending) {		HFA384X_OUTW(HFA384X_EV_RX, HFA384X_EVACK_OFF);	}	return; rx_dropped:	stats->rx_dropped++;	if (skb)		dev_kfree_skb(skb);	goto rx_exit;}/* Called only as a tasklet (software IRQ) */static void hostap_rx_skb(local_info_t *local, struct sk_buff *skb){	struct hfa384x_rx_frame *rxdesc;	struct net_device *dev = skb->dev;	struct hostap_80211_rx_status stats;	int hdrlen, rx_hdrlen;	rx_hdrlen = sizeof(*rxdesc);	if (skb->len < sizeof(*rxdesc)) {		/* Allow monitor mode to receive shorter frames */		if (local->iw_mode == IW_MODE_MONITOR &&		    skb->len >= sizeof(*rxdesc) - 30) {			rx_hdrlen = skb->len;		} else {			dev_kfree_skb(skb);			return;		}	}	rxdesc = (struct hfa384x_rx_frame *) skb->data;	if (local->frame_dump & PRISM2_DUMP_RX_HDR &&	    skb->len >= sizeof(*rxdesc))		hostap_dump_rx_header(dev->name, rxdesc);	if (le16_to_cpu(rxdesc->status) & HFA384X_RX_STATUS_FCSERR &&	    (!local->monitor_allow_fcserr ||	     local->iw_mode != IW_MODE_MONITOR))		goto drop;	if (skb->len > PRISM2_DATA_MAXLEN) {		printk(KERN_DEBUG "%s: RX: len(%d) > MAX(%d)\n",		       dev->name, skb->len, PRISM2_DATA_MAXLEN);		goto drop;	}	stats.mac_time = le32_to_cpu(rxdesc->time);	stats.signal = rxdesc->signal - local->rssi_to_dBm;	stats.noise = rxdesc->silence - local->rssi_to_dBm;	stats.rate = rxdesc->rate;	/* Convert Prism2 RX structure into IEEE 802.11 header */	hdrlen = hostap_80211_get_hdrlen(le16_to_cpu(rxdesc->frame_control));	if (hdrlen > rx_hdrlen)		hdrlen = rx_hdrlen;	memmove(skb_pull(skb, rx_hdrlen - hdrlen),		&rxdesc->frame_control, hdrlen);	hostap_80211_rx(dev, skb, &stats);	return; drop:	dev_kfree_skb(skb);}/* Called only as a tasklet (software IRQ) */static void hostap_rx_tasklet(unsigned long data){	local_info_t *local = (local_info_t *) data;	struct sk_buff *skb;	while ((skb = skb_dequeue(&local->rx_list)) != NULL)		hostap_rx_skb(local, skb);}/* Called only from hardware IRQ */static void prism2_alloc_ev(struct net_device *dev){	struct hostap_interface *iface = dev->priv;	local_info_t *local = iface->local;	int idx;	u16 fid;	fid = prism2_read_fid_reg(dev, HFA384X_ALLOCFID_OFF);	PDEBUG(DEBUG_FID, "FID: interrupt: ALLOC - fid=0x%04x\n", fid);	spin_lock(&local->txfidlock);	idx = local->next_alloc;	do {		if (local->txfid[idx] == fid) {			PDEBUG(DEBUG_FID, "FID: found matching txfid[%d]\n",			       idx);#ifndef final_version			if (local->intransmitfid[idx] == PRISM2_TXFID_EMPTY)				printk("Already released txfid found at idx "				       "%d\n", idx);			if (local->intransmitfid[idx] == PRISM2_TXFID_RESERVED)				printk("Already reserved txfid found at idx "				       "%d\n", idx);#endif			local->intransmitfid[idx] = PRISM2_TXFID_EMPTY;			idx++;			local->next_alloc = idx >= PRISM2_TXFID_COUNT ? 0 :				idx;			if (!test_bit(HOSTAP_BITS_TRANSMIT, &local->bits) &&			    netif_queue_stopped(dev))				netif_wake_queue(dev);			spin_unlock(&local->txfidlock);			return;		}		idx++;		if (idx >= PRISM2_TXFID_COUNT)			idx = 0;	} while (idx != local->next_alloc);	printk(KERN_WARNING "%s: could not find matching txfid (0x%04x, new "	       "read 0x%04x) for alloc event\n", dev->name, fid,	       HFA384X_INW(HFA384X_ALLOCFID_OFF));	printk(KERN_DEBUG "TXFIDs:");	for (idx = 0; idx < PRISM2_TXFID_COUNT; idx++)		printk(" %04x[%04x]", local->txfid[idx],		       local->intransmitfid[idx]);	printk("\n");	spin_unlock(&local->txfidlock);	/* FIX: should probably schedule reset; reference to one txfid was lost	 * completely.. Bad things will happen if we run out of txfids	 * Actually, this will cause netdev watchdog to notice TX timeout and	 * then card reset after all txfids have been leaked. */}/* Called only as a tasklet (software IRQ) */static void hostap_tx_callback(local_info_t *local,			       struct hfa384x_tx_frame *txdesc, int ok,			       char *payload){	u16 sw_support, hdrlen, len;	struct sk_buff *skb;	struct hostap_tx_callback_info *cb;	/* Make sure that frame was from us. */	if (memcmp(txdesc->addr2, local->dev->dev_addr, ETH_ALEN)) {		printk(KERN_DEBUG "%s: TX callback - foreign frame\n",		       local->dev->name);		return;	}	sw_support = le16_to_cpu(txdesc->sw_support);	spin_lock(&local->lock);	cb = local->tx_callback;	while (cb != NULL && cb->idx != sw_support)		cb = cb->next;	spin_unlock(&local->lock);	if (cb == NULL) {		printk(KERN_DEBUG "%s: could not find TX callback (idx %d)\n",		       local->dev->name, sw_support);		return;	}	hdrlen = hostap_80211_get_hdrlen(le16_to_cpu(txdesc->frame_control));	len = le16_to_cpu(txdesc->data_len);	skb = dev_alloc_skb(hdrlen + len);	if (skb == NULL) {		printk(KERN_DEBUG "%s: hostap_tx_callback failed to allocate "		       "skb\n", local->dev->name);		return;	}	memcpy(skb_put(skb, hdrlen), (void *) &txdesc->frame_control, hdrlen);	if (payload)		memcpy(skb_put(skb, len), payload, len);	skb->dev = local->dev;	skb->mac.raw = skb->data;	cb->func(skb, ok, cb->data);}/* Called only as a tasklet (software IRQ) */static int hostap_tx_compl_read(local_info_t *local, int error,				struct hfa384x_tx_frame *txdesc,				char **payload){	u16 fid, len;	int res, ret = 0;	struct net_device *dev = local->dev;	fid = prism2_read_fid_reg(dev, HFA384X_TXCOMPLFID_OFF);	PDEBUG(DEBUG_FID, "interrupt: TX (err=%d) -

⌨️ 快捷键说明

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