Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f55d4517 authored by Dan Williams's avatar Dan Williams Committed by John W. Linville
Browse files

airo: clean up and clarify interrupt-time task handling



Split each specific interrupt-time task out into its own function to
make airo_interrupt() actually readable.

Signed-off-by: default avatarDan Williams <dcbw@redhat.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 0d21044e
Loading
Loading
Loading
Loading
+327 −286
Original line number Original line Diff line number Diff line
@@ -981,6 +981,14 @@ typedef struct {
	dma_addr_t host_addr;
	dma_addr_t host_addr;
} TxFid;
} TxFid;


struct rx_hdr {
	__le16 status, len;
	u8 rssi[2];
	u8 rate;
	u8 freq;
	__le16 tmp[4];
} __attribute__ ((packed));

typedef struct {
typedef struct {
	unsigned int  ctl: 15;
	unsigned int  ctl: 15;
	unsigned int  rdy: 1;
	unsigned int  rdy: 1;
@@ -3123,314 +3131,354 @@ static int header_len(__le16 ctl)
	return 24;
	return 24;
}
}


static irqreturn_t airo_interrupt(int irq, void *dev_id)
static void airo_handle_cisco_mic(struct airo_info *ai)
{
{
	struct net_device *dev = dev_id;
	if (test_bit(FLAG_MIC_CAPABLE, &ai->flags)) {
	u16 status;
		set_bit(JOB_MIC, &ai->jobs);
	u16 fid;
		wake_up_interruptible(&ai->thr_wait);
	struct airo_info *apriv = dev->ml_priv;
	}
	u16 savedInterrupts = 0;
}
	int handled = 0;

	if (!netif_device_present(dev))
		return IRQ_NONE;


	for (;;) {
/* Airo Status codes */
		status = IN4500( apriv, EVSTAT );
#define STAT_NOBEACON	0x8000 /* Loss of sync - missed beacons */
		if ( !(status & STATUS_INTS) || status == 0xffff ) break;
#define STAT_MAXRETRIES	0x8001 /* Loss of sync - max retries */
#define STAT_MAXARL	0x8002 /* Loss of sync - average retry level exceeded*/
#define STAT_FORCELOSS	0x8003 /* Loss of sync - host request */
#define STAT_TSFSYNC	0x8004 /* Loss of sync - TSF synchronization */
#define STAT_DEAUTH	0x8100 /* low byte is 802.11 reason code */
#define STAT_DISASSOC	0x8200 /* low byte is 802.11 reason code */
#define STAT_ASSOC_FAIL	0x8400 /* low byte is 802.11 reason code */
#define STAT_AUTH_FAIL	0x0300 /* low byte is 802.11 reason code */
#define STAT_ASSOC	0x0400 /* Associated */
#define STAT_REASSOC    0x0600 /* Reassociated?  Only on firmware >= 5.30.17 */


		handled = 1;
static void airo_print_status(const char *devname, u16 status)
{
	u8 reason = status & 0xFF;


		if ( status & EV_AWAKE ) {
	switch (status) {
			OUT4500( apriv, EVACK, EV_AWAKE );
	case STAT_NOBEACON:
			OUT4500( apriv, EVACK, EV_AWAKE );
		airo_print_dbg(devname, "link lost (missed beacons)");
		break;
	case STAT_MAXRETRIES:
	case STAT_MAXARL:
		airo_print_dbg(devname, "link lost (max retries)");
		break;
	case STAT_FORCELOSS:
		airo_print_dbg(devname, "link lost (local choice)");
		break;
	case STAT_TSFSYNC:
		airo_print_dbg(devname, "link lost (TSF sync lost)");
		break;
	case STAT_DEAUTH:
		airo_print_dbg(devname, "deauthenticated (reason: %d)", reason);
		break;
	case STAT_DISASSOC:
		airo_print_dbg(devname, "disassociated (reason: %d)", reason);
		break;
	case STAT_ASSOC_FAIL:
		airo_print_dbg(devname, "association failed (reason: %d)",
			       reason);
		break;
	case STAT_AUTH_FAIL:
		airo_print_dbg(devname, "authentication failed (reason: %d)",
			       reason);
		break;
	default:
		break;
	}
	}

		if (!savedInterrupts) {
			savedInterrupts = IN4500( apriv, EVINTEN );
			OUT4500( apriv, EVINTEN, 0 );
}
}


		if ( status & EV_MIC ) {
static void airo_handle_link(struct airo_info *ai)
			OUT4500( apriv, EVACK, EV_MIC );
{
			if (test_bit(FLAG_MIC_CAPABLE, &apriv->flags)) {
				set_bit(JOB_MIC, &apriv->jobs);
				wake_up_interruptible(&apriv->thr_wait);
			}
		}
		if ( status & EV_LINK ) {
	union iwreq_data wrqu;
	union iwreq_data wrqu;
	int scan_forceloss = 0;
	int scan_forceloss = 0;
			/* The link status has changed, if you want to put a
	u16 status;
			   monitor hook in, do it here.  (Remember that

			   interrupts are still disabled!)
	/* Get new status and acknowledge the link change */
			*/
	status = le16_to_cpu(IN4500(ai, LINKSTAT));
			u16 newStatus = IN4500(apriv, LINKSTAT);
	OUT4500(ai, EVACK, EV_LINK);
			OUT4500( apriv, EVACK, EV_LINK);

			/* Here is what newStatus means: */
	if ((status == STAT_FORCELOSS) && (ai->scan_timeout > 0))
#define NOBEACON 0x8000 /* Loss of sync - missed beacons */
#define MAXRETRIES 0x8001 /* Loss of sync - max retries */
#define MAXARL 0x8002 /* Loss of sync - average retry level exceeded*/
#define FORCELOSS 0x8003 /* Loss of sync - host request */
#define TSFSYNC 0x8004 /* Loss of sync - TSF synchronization */
#define DEAUTH 0x8100 /* Deauthentication (low byte is reason code) */
#define DISASS 0x8200 /* Disassociation (low byte is reason code) */
#define ASSFAIL 0x8400 /* Association failure (low byte is reason
			  code) */
#define AUTHFAIL 0x0300 /* Authentication failure (low byte is reason
			   code) */
#define ASSOCIATED 0x0400 /* Associated */
#define REASSOCIATED 0x0600 /* Reassociated?  Only on firmware >= 5.30.17 */
#define RC_RESERVED 0 /* Reserved return code */
#define RC_NOREASON 1 /* Unspecified reason */
#define RC_AUTHINV 2 /* Previous authentication invalid */
#define RC_DEAUTH 3 /* Deauthenticated because sending station is
		       leaving */
#define RC_NOACT 4 /* Disassociated due to inactivity */
#define RC_MAXLOAD 5 /* Disassociated because AP is unable to handle
			all currently associated stations */
#define RC_BADCLASS2 6 /* Class 2 frame received from
			  non-Authenticated station */
#define RC_BADCLASS3 7 /* Class 3 frame received from
			  non-Associated station */
#define RC_STATLEAVE 8 /* Disassociated because sending station is
			  leaving BSS */
#define RC_NOAUTH 9 /* Station requesting (Re)Association is not
		       Authenticated with the responding station */
			if (newStatus == FORCELOSS && apriv->scan_timeout > 0)
		scan_forceloss = 1;
		scan_forceloss = 1;
			if(newStatus == ASSOCIATED || newStatus == REASSOCIATED) {

	airo_print_status(ai->dev->name, status);

	if ((status == STAT_ASSOC) || (status == STAT_REASSOC)) {
		if (auto_wep)
		if (auto_wep)
					apriv->expires = 0;
			ai->expires = 0;
				if (apriv->list_bss_task)
		if (ai->list_bss_task)
					wake_up_process(apriv->list_bss_task);
			wake_up_process(ai->list_bss_task);
				set_bit(FLAG_UPDATE_UNI, &apriv->flags);
		set_bit(FLAG_UPDATE_UNI, &ai->flags);
				set_bit(FLAG_UPDATE_MULTI, &apriv->flags);
		set_bit(FLAG_UPDATE_MULTI, &ai->flags);


				if (down_trylock(&apriv->sem) != 0) {
		if (down_trylock(&ai->sem) != 0) {
					set_bit(JOB_EVENT, &apriv->jobs);
			set_bit(JOB_EVENT, &ai->jobs);
					wake_up_interruptible(&apriv->thr_wait);
			wake_up_interruptible(&ai->thr_wait);
		} else
		} else
					airo_send_event(dev);
			airo_send_event(ai->dev);
	} else if (!scan_forceloss) {
	} else if (!scan_forceloss) {
				if (auto_wep && !apriv->expires) {
		if (auto_wep && !ai->expires) {
					apriv->expires = RUN_AT(3*HZ);
			ai->expires = RUN_AT(3*HZ);
					wake_up_interruptible(&apriv->thr_wait);
			wake_up_interruptible(&ai->thr_wait);
		}
		}


		/* Send event to user space */
		/* Send event to user space */
		memset(wrqu.ap_addr.sa_data, '\0', ETH_ALEN);
		memset(wrqu.ap_addr.sa_data, '\0', ETH_ALEN);
		wrqu.ap_addr.sa_family = ARPHRD_ETHER;
		wrqu.ap_addr.sa_family = ARPHRD_ETHER;
				wireless_send_event(dev, SIOCGIWAP, &wrqu,NULL);
		wireless_send_event(ai->dev, SIOCGIWAP, &wrqu, NULL);
	}
	}
}
}


		/* Check to see if there is something to receive */
static void airo_handle_rx(struct airo_info *ai)
		if ( status & EV_RX  ) {
{
	struct sk_buff *skb = NULL;
	struct sk_buff *skb = NULL;
			__le16 fc, v;
	__le16 fc, v, *buffer, tmpbuf[4];
			u16 len, hdrlen = 0;
	u16 len, hdrlen = 0, gap, fid;
#pragma pack(1)
	struct rx_hdr hdr;
			struct {
	int success = 0;
				__le16 status, len;
				u8 rssi[2];
				u8 rate;
				u8 freq;
				__le16 tmp[4];
			} hdr;
#pragma pack()
			u16 gap;
			__le16 tmpbuf[4];
			__le16 *buffer;


			if (test_bit(FLAG_MPI,&apriv->flags)) {
	if (test_bit(FLAG_MPI, &ai->flags)) {
				if (test_bit(FLAG_802_11, &apriv->flags))
		if (test_bit(FLAG_802_11, &ai->flags))
					mpi_receive_802_11(apriv);
			mpi_receive_802_11(ai);
		else
		else
					mpi_receive_802_3(apriv);
			mpi_receive_802_3(ai);
				OUT4500(apriv, EVACK, EV_RX);
		OUT4500(ai, EVACK, EV_RX);
				goto exitrx;
		return;
	}
	}


			fid = IN4500( apriv, RXFID );
	fid = IN4500(ai, RXFID);


	/* Get the packet length */
	/* Get the packet length */
			if (test_bit(FLAG_802_11, &apriv->flags)) {
	if (test_bit(FLAG_802_11, &ai->flags)) {
				bap_setup (apriv, fid, 4, BAP0);
		bap_setup (ai, fid, 4, BAP0);
				bap_read (apriv, (__le16*)&hdr, sizeof(hdr), BAP0);
		bap_read (ai, (__le16*)&hdr, sizeof(hdr), BAP0);
		/* Bad CRC. Ignore packet */
		/* Bad CRC. Ignore packet */
		if (le16_to_cpu(hdr.status) & 2)
		if (le16_to_cpu(hdr.status) & 2)
			hdr.len = 0;
			hdr.len = 0;
				if (apriv->wifidev == NULL)
		if (ai->wifidev == NULL)
			hdr.len = 0;
			hdr.len = 0;
	} else {
	} else {
				bap_setup (apriv, fid, 0x36, BAP0);
		bap_setup(ai, fid, 0x36, BAP0);
				bap_read (apriv, &hdr.len, 2, BAP0);
		bap_read(ai, &hdr.len, 2, BAP0);
	}
	}
	len = le16_to_cpu(hdr.len);
	len = le16_to_cpu(hdr.len);


	if (len > AIRO_DEF_MTU) {
	if (len > AIRO_DEF_MTU) {
				airo_print_err(apriv->dev->name, "Bad size %d", len);
		airo_print_err(ai->dev->name, "Bad size %d", len);
				goto badrx;
		goto done;
	}
	}
	if (len == 0)
	if (len == 0)
				goto badrx;
		goto done;


			if (test_bit(FLAG_802_11, &apriv->flags)) {
	if (test_bit(FLAG_802_11, &ai->flags)) {
				bap_read (apriv, &fc, sizeof(fc), BAP0);
		bap_read(ai, &fc, sizeof (fc), BAP0);
		hdrlen = header_len(fc);
		hdrlen = header_len(fc);
	} else
	} else
		hdrlen = ETH_ALEN * 2;
		hdrlen = ETH_ALEN * 2;


	skb = dev_alloc_skb(len + hdrlen + 2 + 2);
	skb = dev_alloc_skb(len + hdrlen + 2 + 2);
	if (!skb) {
	if (!skb) {
				dev->stats.rx_dropped++;
		ai->dev->stats.rx_dropped++;
				goto badrx;
		goto done;
	}
	}

	skb_reserve(skb, 2); /* This way the IP header is aligned */
	skb_reserve(skb, 2); /* This way the IP header is aligned */
	buffer = (__le16 *) skb_put(skb, len + hdrlen);
	buffer = (__le16 *) skb_put(skb, len + hdrlen);
			if (test_bit(FLAG_802_11, &apriv->flags)) {
	if (test_bit(FLAG_802_11, &ai->flags)) {
		buffer[0] = fc;
		buffer[0] = fc;
				bap_read (apriv, buffer + 1, hdrlen - 2, BAP0);
		bap_read(ai, buffer + 1, hdrlen - 2, BAP0);
		if (hdrlen == 24)
		if (hdrlen == 24)
					bap_read (apriv, tmpbuf, 6, BAP0);
			bap_read(ai, tmpbuf, 6, BAP0);


				bap_read (apriv, &v, sizeof(v), BAP0);
		bap_read(ai, &v, sizeof(v), BAP0);
		gap = le16_to_cpu(v);
		gap = le16_to_cpu(v);
		if (gap) {
		if (gap) {
			if (gap <= 8) {
			if (gap <= 8) {
						bap_read (apriv, tmpbuf, gap, BAP0);
				bap_read(ai, tmpbuf, gap, BAP0);
			} else {
			} else {
						airo_print_err(apriv->dev->name, "gaplen too "
				airo_print_err(ai->dev->name, "gaplen too "
					"big. Problems will follow...");
					"big. Problems will follow...");
			}
			}
		}
		}
				bap_read (apriv, buffer + hdrlen/2, len, BAP0);
		bap_read(ai, buffer + hdrlen/2, len, BAP0);
	} else {
	} else {
		MICBuffer micbuf;
		MICBuffer micbuf;
				bap_read (apriv, buffer, ETH_ALEN*2, BAP0);

				if (apriv->micstats.enabled) {
		bap_read(ai, buffer, ETH_ALEN * 2, BAP0);
					bap_read (apriv,(__le16*)&micbuf,sizeof(micbuf),BAP0);
		if (ai->micstats.enabled) {
			bap_read(ai, (__le16 *) &micbuf, sizeof (micbuf), BAP0);
			if (ntohs(micbuf.typelen) > 0x05DC)
			if (ntohs(micbuf.typelen) > 0x05DC)
						bap_setup (apriv, fid, 0x44, BAP0);
				bap_setup(ai, fid, 0x44, BAP0);
			else {
			else {
						if (len <= sizeof(micbuf))
				if (len <= sizeof (micbuf)) {
							goto badmic;
					dev_kfree_skb_irq(skb);
					goto done;
				}


				len -= sizeof(micbuf);
				len -= sizeof(micbuf);
				skb_trim(skb, len + hdrlen);
				skb_trim(skb, len + hdrlen);
			}
			}
		}
		}
				bap_read(apriv,buffer+ETH_ALEN,len,BAP0);

				if (decapsulate(apriv,&micbuf,(etherHead*)buffer,len)) {
		bap_read(ai, buffer + ETH_ALEN, len, BAP0);
badmic:
		if (decapsulate(ai, &micbuf, (etherHead*) buffer, len))
			dev_kfree_skb_irq (skb);
			dev_kfree_skb_irq (skb);
badrx:
		else
					OUT4500( apriv, EVACK, EV_RX);
			success = 1;
					goto exitrx;
				}
	}
	}

#ifdef WIRELESS_SPY
#ifdef WIRELESS_SPY
			if (apriv->spy_data.spy_number > 0) {
	if (success && (ai->spy_data.spy_number > 0)) {
		char *sa;
		char *sa;
		struct iw_quality wstats;
		struct iw_quality wstats;

		/* Prepare spy data : addr + qual */
		/* Prepare spy data : addr + qual */
				if (!test_bit(FLAG_802_11, &apriv->flags)) {
		if (!test_bit(FLAG_802_11, &ai->flags)) {
			sa = (char *) buffer + 6;
			sa = (char *) buffer + 6;
					bap_setup (apriv, fid, 8, BAP0);
			bap_setup(ai, fid, 8, BAP0);
					bap_read (apriv, (__le16*)hdr.rssi, 2, BAP0);
			bap_read(ai, (__le16 *) hdr.rssi, 2, BAP0);
		} else
		} else
			sa = (char *) buffer + 10;
			sa = (char *) buffer + 10;
		wstats.qual = hdr.rssi[0];
		wstats.qual = hdr.rssi[0];
				if (apriv->rssi)
		if (ai->rssi)
					wstats.level = 0x100 - apriv->rssi[hdr.rssi[1]].rssidBm;
			wstats.level = 0x100 - ai->rssi[hdr.rssi[1]].rssidBm;
		else
		else
			wstats.level = (hdr.rssi[1] + 321) / 2;
			wstats.level = (hdr.rssi[1] + 321) / 2;
				wstats.noise = apriv->wstats.qual.noise;
		wstats.noise = ai->wstats.qual.noise;
		wstats.updated =  IW_QUAL_LEVEL_UPDATED
		wstats.updated =  IW_QUAL_LEVEL_UPDATED
				| IW_QUAL_QUAL_UPDATED
				| IW_QUAL_QUAL_UPDATED
				| IW_QUAL_DBM;
				| IW_QUAL_DBM;
		/* Update spy records */
		/* Update spy records */
				wireless_spy_update(dev, sa, &wstats);
		wireless_spy_update(ai->dev, sa, &wstats);
	}
	}
#endif /* WIRELESS_SPY */
#endif /* WIRELESS_SPY */
			OUT4500( apriv, EVACK, EV_RX);


			if (test_bit(FLAG_802_11, &apriv->flags)) {
done:
	OUT4500(ai, EVACK, EV_RX);

	if (success) {
		if (test_bit(FLAG_802_11, &ai->flags)) {
			skb_reset_mac_header(skb);
			skb_reset_mac_header(skb);
			skb->pkt_type = PACKET_OTHERHOST;
			skb->pkt_type = PACKET_OTHERHOST;
				skb->dev = apriv->wifidev;
			skb->dev = ai->wifidev;
			skb->protocol = htons(ETH_P_802_2);
			skb->protocol = htons(ETH_P_802_2);
		} else
		} else
				skb->protocol = eth_type_trans(skb,dev);
			skb->protocol = eth_type_trans(skb, ai->dev);
		skb->ip_summed = CHECKSUM_NONE;
		skb->ip_summed = CHECKSUM_NONE;


		netif_rx(skb);
		netif_rx(skb);
	}
	}
exitrx:
}


		/* Check to see if a packet has been transmitted */
static void airo_handle_tx(struct airo_info *ai, u16 status)
		if (  status & ( EV_TX|EV_TXCPY|EV_TXEXC ) ) {
{
			int i;
	int i, len = 0, index = -1;
			int len = 0;
	u16 fid;
			int index = -1;


			if (test_bit(FLAG_MPI,&apriv->flags)) {
	if (test_bit(FLAG_MPI, &ai->flags)) {
		unsigned long flags;
		unsigned long flags;


		if (status & EV_TXEXC)
		if (status & EV_TXEXC)
					get_tx_error(apriv, -1);
			get_tx_error(ai, -1);
				spin_lock_irqsave(&apriv->aux_lock, flags);

				if (!skb_queue_empty(&apriv->txq)) {
		spin_lock_irqsave(&ai->aux_lock, flags);
					spin_unlock_irqrestore(&apriv->aux_lock,flags);
		if (!skb_queue_empty(&ai->txq)) {
					mpi_send_packet (dev);
			spin_unlock_irqrestore(&ai->aux_lock,flags);
			mpi_send_packet(ai->dev);
		} else {
		} else {
					clear_bit(FLAG_PENDING_XMIT, &apriv->flags);
			clear_bit(FLAG_PENDING_XMIT, &ai->flags);
					spin_unlock_irqrestore(&apriv->aux_lock,flags);
			spin_unlock_irqrestore(&ai->aux_lock,flags);
					netif_wake_queue (dev);
			netif_wake_queue(ai->dev);
		}
		}
				OUT4500( apriv, EVACK,
		OUT4500(ai, EVACK, status & (EV_TX | EV_TXCPY | EV_TXEXC));
					status & (EV_TX|EV_TXCPY|EV_TXEXC));
		return;
				goto exittx;
	}
	}


			fid = IN4500(apriv, TXCOMPLFID);
	fid = IN4500(ai, TXCOMPLFID);


	for(i = 0; i < MAX_FIDS; i++) {
	for(i = 0; i < MAX_FIDS; i++) {
				if ( ( apriv->fids[i] & 0xffff ) == fid ) {
		if ((ai->fids[i] & 0xffff) == fid) {
					len = apriv->fids[i] >> 16;
			len = ai->fids[i] >> 16;
			index = i;
			index = i;
		}
		}
	}
	}

	if (index != -1) {
	if (index != -1) {
		if (status & EV_TXEXC)
		if (status & EV_TXEXC)
					get_tx_error(apriv, index);
			get_tx_error(ai, index);
				OUT4500( apriv, EVACK, status & (EV_TX | EV_TXEXC));

		OUT4500(ai, EVACK, status & (EV_TX | EV_TXEXC));

		/* Set up to be used again */
		/* Set up to be used again */
				apriv->fids[index] &= 0xffff;
		ai->fids[index] &= 0xffff;
		if (index < MAX_FIDS / 2) {
		if (index < MAX_FIDS / 2) {
					if (!test_bit(FLAG_PENDING_XMIT, &apriv->flags))
			if (!test_bit(FLAG_PENDING_XMIT, &ai->flags))
						netif_wake_queue(dev);
				netif_wake_queue(ai->dev);
		} else {
		} else {
					if (!test_bit(FLAG_PENDING_XMIT11, &apriv->flags))
			if (!test_bit(FLAG_PENDING_XMIT11, &ai->flags))
						netif_wake_queue(apriv->wifidev);
				netif_wake_queue(ai->wifidev);
		}
		}
	} else {
	} else {
				OUT4500( apriv, EVACK, status & (EV_TX | EV_TXCPY | EV_TXEXC));
		OUT4500(ai, EVACK, status & (EV_TX | EV_TXCPY | EV_TXEXC));
				airo_print_err(apriv->dev->name, "Unallocated FID was "
		airo_print_err(ai->dev->name, "Unallocated FID was used to xmit");
					"used to xmit" );
	}
	}
}
}
exittx:

		if ( status & ~STATUS_INTS & ~IGNORE_INTS )
static irqreturn_t airo_interrupt(int irq, void *dev_id)
			airo_print_warn(apriv->dev->name, "Got weird status %x",
{
	struct net_device *dev = dev_id;
	u16 status, savedInterrupts = 0;
	struct airo_info *ai = dev->ml_priv;
	int handled = 0;

	if (!netif_device_present(dev))
		return IRQ_NONE;

	for (;;) {
		status = IN4500(ai, EVSTAT);
		if (!(status & STATUS_INTS) || (status == 0xffff))
			break;

		handled = 1;

		if (status & EV_AWAKE) {
			OUT4500(ai, EVACK, EV_AWAKE);
			OUT4500(ai, EVACK, EV_AWAKE);
		}

		if (!savedInterrupts) {
			savedInterrupts = IN4500(ai, EVINTEN);
			OUT4500(ai, EVINTEN, 0);
		}

		if (status & EV_MIC) {
			OUT4500(ai, EVACK, EV_MIC);
			airo_handle_cisco_mic(ai);
		}

		if (status & EV_LINK) {
			/* Link status changed */
			airo_handle_link(ai);
		}

		/* Check to see if there is something to receive */
		if (status & EV_RX)
			airo_handle_rx(ai);

		/* Check to see if a packet has been transmitted */
		if (status & (EV_TX | EV_TXCPY | EV_TXEXC))
			airo_handle_tx(ai, status);

		if ( status & ~STATUS_INTS & ~IGNORE_INTS ) {
			airo_print_warn(ai->dev->name, "Got weird status %x",
				status & ~STATUS_INTS & ~IGNORE_INTS );
				status & ~STATUS_INTS & ~IGNORE_INTS );
		}
		}
	}


	if (savedInterrupts)
	if (savedInterrupts)
		OUT4500( apriv, EVINTEN, savedInterrupts );
		OUT4500(ai, EVINTEN, savedInterrupts);


	/* done.. */
	return IRQ_RETVAL(handled);
	return IRQ_RETVAL(handled);
}
}


@@ -3609,15 +3657,7 @@ static void mpi_receive_802_11(struct airo_info *ai)
	struct sk_buff *skb = NULL;
	struct sk_buff *skb = NULL;
	u16 len, hdrlen = 0;
	u16 len, hdrlen = 0;
	__le16 fc;
	__le16 fc;
#pragma pack(1)
	struct rx_hdr hdr;
	struct {
		__le16 status, len;
		u8 rssi[2];
		u8 rate;
		u8 freq;
		__le16 tmp[4];
	} hdr;
#pragma pack()
	u16 gap;
	u16 gap;
	u16 *buffer;
	u16 *buffer;
	char *ptr = ai->rxfids[0].virtual_host_addr + 4;
	char *ptr = ai->rxfids[0].virtual_host_addr + 4;
@@ -3687,6 +3727,7 @@ static void mpi_receive_802_11(struct airo_info *ai)
	skb->protocol = htons(ETH_P_802_2);
	skb->protocol = htons(ETH_P_802_2);
	skb->ip_summed = CHECKSUM_NONE;
	skb->ip_summed = CHECKSUM_NONE;
	netif_rx( skb );
	netif_rx( skb );

badrx:
badrx:
	if (rxd.valid == 0) {
	if (rxd.valid == 0) {
		rxd.valid = 1;
		rxd.valid = 1;