diff options
Diffstat (limited to '')
-rw-r--r-- | drivers/staging/wlags49_h2/wl_netdev.c | 1951 |
1 files changed, 0 insertions, 1951 deletions
diff --git a/drivers/staging/wlags49_h2/wl_netdev.c b/drivers/staging/wlags49_h2/wl_netdev.c deleted file mode 100644 index a10d014365f2..000000000000 --- a/drivers/staging/wlags49_h2/wl_netdev.c +++ /dev/null @@ -1,1951 +0,0 @@ -/******************************************************************************* - * Agere Systems Inc. - * Wireless device driver for Linux (wlags49). - * - * Copyright (c) 1998-2003 Agere Systems Inc. - * All rights reserved. - * http://www.agere.com - * - * Initially developed by TriplePoint, Inc. - * http://www.triplepoint.com - * - *------------------------------------------------------------------------------ - * - * This file contains handler functions registered with the net_device - * structure. - * - *------------------------------------------------------------------------------ - * - * SOFTWARE LICENSE - * - * This software is provided subject to the following terms and conditions, - * which you should read carefully before using the software. Using this - * software indicates your acceptance of these terms and conditions. If you do - * not agree with these terms and conditions, do not use the software. - * - * Copyright © 2003 Agere Systems Inc. - * All rights reserved. - * - * Redistribution and use in source or binary forms, with or without - * modifications, are permitted provided that the following conditions are met: - * - * . Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following Disclaimer as comments in the code as - * well as in the documentation and/or other materials provided with the - * distribution. - * - * . Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following Disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * . Neither the name of Agere Systems Inc. nor the names of the contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * Disclaimer - * - * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY - * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN - * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - ******************************************************************************/ - -/******************************************************************************* - * include files - ******************************************************************************/ -#include <wl_version.h> - -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/netdevice.h> -#include <linux/ethtool.h> -#include <linux/etherdevice.h> - -#include <debug.h> - -#include <hcf.h> -#include <dhf.h> - -#include <wl_if.h> -#include <wl_internal.h> -#include <wl_util.h> -#include <wl_priv.h> -#include <wl_main.h> -#include <wl_netdev.h> -#include <wl_wext.h> - -#ifdef USE_PROFILE -#include <wl_profile.h> -#endif /* USE_PROFILE */ - -#ifdef BUS_PCMCIA -#include <wl_cs.h> -#endif /* BUS_PCMCIA */ - -#ifdef BUS_PCI -#include <wl_pci.h> -#endif /* BUS_PCI */ - -#if HCF_ENCAP -#define MTU_MAX (HCF_MAX_MSG - ETH_HLEN - 8) -#else -#define MTU_MAX (HCF_MAX_MSG - ETH_HLEN) -#endif - -/******************************************************************************* - * macros - ******************************************************************************/ -#define BLOCK_INPUT(buf, len) \ - do { \ - desc->buf_addr = buf; \ - desc->BUF_SIZE = len; \ - status = hcf_rcv_msg(&(lp->hcfCtx), desc, 0); \ - } while (0) - -#define BLOCK_INPUT_DMA(buf, len) memcpy( buf, desc_next->buf_addr, pktlen ) - -/******************************************************************************* - * function prototypes - ******************************************************************************/ - -/******************************************************************************* - * wl_init() - ******************************************************************************* - * - * DESCRIPTION: - * - * We never need to do anything when a "Wireless" device is "initialized" - * by the net software, because we only register already-found cards. - * - * PARAMETERS: - * - * dev - a pointer to the device's net_device structure - * - * RETURNS: - * - * 0 on success - * errno value otherwise - * - ******************************************************************************/ -int wl_init(struct net_device *dev) -{ - DBG_PARAM(DbgInfo, "dev", "%s (0x%p)", dev->name, dev); - return 0; -} /* wl_init */ - -/*============================================================================*/ - -/******************************************************************************* - * wl_config() - ******************************************************************************* - * - * DESCRIPTION: - * - * Implement the SIOCSIFMAP interface. - * - * PARAMETERS: - * - * dev - a pointer to the device's net_device structure - * map - a pointer to the device's ifmap structure - * - * RETURNS: - * - * 0 on success - * errno otherwise - * - ******************************************************************************/ -int wl_config(struct net_device *dev, struct ifmap *map) -{ - DBG_PARAM(DbgInfo, "dev", "%s (0x%p)", dev->name, dev); - DBG_PARAM(DbgInfo, "map", "0x%p", map); - - /* - * The only thing we care about here is a port change. - * Since this not needed, ignore the request. - */ - DBG_TRACE(DbgInfo, "%s: %s called.\n", dev->name, __func__); - - return 0; -} /* wl_config */ - -/*============================================================================*/ - -/******************************************************************************* - * wl_stats() - ******************************************************************************* - * - * DESCRIPTION: - * - * Return the current device statistics. - * - * PARAMETERS: - * - * dev - a pointer to the device's net_device structure - * - * RETURNS: - * - * a pointer to a net_device_stats structure containing the network - * statistics. - * - ******************************************************************************/ -struct net_device_stats *wl_stats(struct net_device *dev) -{ -#ifdef USE_WDS - int count; -#endif /* USE_WDS */ - unsigned long flags; - struct net_device_stats *pStats; - struct wl_private *lp = wl_priv(dev); - - /*DBG_PARAM( DbgInfo, "dev", "%s (0x%p)", dev->name, dev ); */ - - pStats = NULL; - - wl_lock(lp, &flags); - -#ifdef USE_RTS - if (lp->useRTS == 1) { - wl_unlock(lp, &flags); - return NULL; - } -#endif /* USE_RTS */ - - /* Return the statistics for the appropriate device */ -#ifdef USE_WDS - - for (count = 0; count < NUM_WDS_PORTS; count++) { - if (dev == lp->wds_port[count].dev) - pStats = &(lp->wds_port[count].stats); - } - -#endif /* USE_WDS */ - - /* If pStats is still NULL, then the device is not a WDS port */ - if (pStats == NULL) - pStats = &(lp->stats); - - wl_unlock(lp, &flags); - - return pStats; -} /* wl_stats */ - -/*============================================================================*/ - -/******************************************************************************* - * wl_open() - ******************************************************************************* - * - * DESCRIPTION: - * - * Open the device. - * - * PARAMETERS: - * - * dev - a pointer to the device's net_device structure - * - * RETURNS: - * - * 0 on success - * errno otherwise - * - ******************************************************************************/ -int wl_open(struct net_device *dev) -{ - int status = HCF_SUCCESS; - struct wl_private *lp = wl_priv(dev); - unsigned long flags; - - wl_lock(lp, &flags); - -#ifdef USE_RTS - if (lp->useRTS == 1) { - DBG_TRACE(DbgInfo, "Skipping device open, in RTS mode\n"); - wl_unlock(lp, &flags); - return -EIO; - } -#endif /* USE_RTS */ - -#ifdef USE_PROFILE - parse_config(dev); -#endif - - if (lp->portState == WVLAN_PORT_STATE_DISABLED) { - DBG_TRACE(DbgInfo, "Enabling Port 0\n"); - status = wl_enable(lp); - - if (status != HCF_SUCCESS) { - DBG_TRACE(DbgInfo, "Enable port 0 failed: 0x%x\n", - status); - } - } - - /* Holding the lock too long, make a gap to allow other processes */ - wl_unlock(lp, &flags); - wl_lock(lp, &flags); - - if (strlen(lp->fw_image_filename)) { - DBG_TRACE(DbgInfo, ";???? Kludgy way to force a download\n"); - status = wl_go(lp); - } else { - status = wl_apply(lp); - } - - /* Holding the lock too long, make a gap to allow other processes */ - wl_unlock(lp, &flags); - wl_lock(lp, &flags); - - /* Unsuccessful, try reset of the card to recover */ - if (status != HCF_SUCCESS) - status = wl_reset(dev); - - /* Holding the lock too long, make a gap to allow other processes */ - wl_unlock(lp, &flags); - wl_lock(lp, &flags); - - if (status == HCF_SUCCESS) { - netif_carrier_on(dev); - WL_WDS_NETIF_CARRIER_ON(lp); - - /* Start handling interrupts */ - lp->is_handling_int = WL_HANDLING_INT; - wl_act_int_on(lp); - - netif_start_queue(dev); - WL_WDS_NETIF_START_QUEUE(lp); - } else { - wl_hcf_error(dev, status); /* Report the error */ - netif_device_detach(dev); /* Stop the device and queue */ - } - - wl_unlock(lp, &flags); - - return status; -} /* wl_open */ - -/*============================================================================*/ - -/******************************************************************************* - * wl_close() - ******************************************************************************* - * - * DESCRIPTION: - * - * Close the device. - * - * PARAMETERS: - * - * dev - a pointer to the device's net_device structure - * - * RETURNS: - * - * 0 on success - * errno otherwise - * - ******************************************************************************/ -int wl_close(struct net_device *dev) -{ - struct wl_private *lp = wl_priv(dev); - unsigned long flags; - - DBG_PARAM(DbgInfo, "dev", "%s (0x%p)", dev->name, dev); - - /* Mark the adapter as busy */ - netif_stop_queue(dev); - WL_WDS_NETIF_STOP_QUEUE(lp); - - netif_carrier_off(dev); - WL_WDS_NETIF_CARRIER_OFF(lp); - - /* - * Shutdown the adapter: - * Disable adapter interrupts - * Stop Tx/Rx - * Update statistics - * Set low power mode - */ - - wl_lock(lp, &flags); - - wl_act_int_off(lp); - /* Stop handling interrupts */ - lp->is_handling_int = WL_NOT_HANDLING_INT; - -#ifdef USE_RTS - if (lp->useRTS == 1) { - DBG_TRACE(DbgInfo, "Skipping device close, in RTS mode\n"); - wl_unlock(lp, &flags); - return -EIO; - } -#endif /* USE_RTS */ - - /* Disable the ports */ - wl_disable(lp); - - wl_unlock(lp, &flags); - - return 0; -} /* wl_close */ - -/*============================================================================*/ - -static void wl_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) -{ - strlcpy(info->driver, DRIVER_NAME, sizeof(info->driver)); - strlcpy(info->version, DRV_VERSION_STR, sizeof(info->version)); - - if (dev->dev.parent) { - dev_set_name(dev->dev.parent, "%s", info->bus_info); - } else { - snprintf(info->bus_info, sizeof(info->bus_info), - "PCMCIA FIXME"); - } -} /* wl_get_drvinfo */ - -static struct ethtool_ops wl_ethtool_ops = { - .get_drvinfo = wl_get_drvinfo, - .get_link = ethtool_op_get_link, -}; - -/******************************************************************************* - * wl_ioctl() - ******************************************************************************* - * - * DESCRIPTION: - * - * The IOCTL handler for the device. - * - * PARAMETERS: - * - * dev - a pointer to the device's net_device struct. - * rq - a pointer to the IOCTL request buffer. - * cmd - the IOCTL command code. - * - * RETURNS: - * - * 0 on success - * errno value otherwise - * - ******************************************************************************/ -int wl_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -{ - struct wl_private *lp = wl_priv(dev); - unsigned long flags; - int ret = 0; - - DBG_PARAM(DbgInfo, "dev", "%s (0x%p)", dev->name, dev); - DBG_PARAM(DbgInfo, "rq", "0x%p", rq); - DBG_PARAM(DbgInfo, "cmd", "0x%04x", cmd); - - wl_lock(lp, &flags); - - wl_act_int_off(lp); - -#ifdef USE_RTS - if (lp->useRTS == 1) { - /* Handle any RTS IOCTL here */ - if (cmd == WL_IOCTL_RTS) { - DBG_TRACE(DbgInfo, "IOCTL: WL_IOCTL_RTS\n"); - ret = wvlan_rts((struct rtsreq *)rq, dev->base_addr); - } else { - DBG_TRACE(DbgInfo, - "IOCTL not supported in RTS mode: 0x%X\n", - cmd); - ret = -EOPNOTSUPP; - } - - goto out_act_int_on_unlock; - } -#endif /* USE_RTS */ - - /* Only handle UIL IOCTL requests when the UIL has the system blocked. */ - if (!((lp->flags & WVLAN2_UIL_BUSY) && (cmd != WVLAN2_IOCTL_UIL))) { -#ifdef USE_UIL - struct uilreq *urq = (struct uilreq *)rq; -#endif /* USE_UIL */ - - switch (cmd) { - /* ================== Private IOCTLs (up to 16) ================== */ -#ifdef USE_UIL - case WVLAN2_IOCTL_UIL: - DBG_TRACE(DbgInfo, "IOCTL: WVLAN2_IOCTL_UIL\n"); - ret = wvlan_uil(urq, lp); - break; -#endif /* USE_UIL */ - - default: - DBG_TRACE(DbgInfo, "IOCTL CODE NOT SUPPORTED: 0x%X\n", - cmd); - ret = -EOPNOTSUPP; - break; - } - } else { - DBG_WARNING(DbgInfo, - "DEVICE IS BUSY, CANNOT PROCESS REQUEST\n"); - ret = -EBUSY; - } - -#ifdef USE_RTS -out_act_int_on_unlock: -#endif /* USE_RTS */ - wl_act_int_on(lp); - - wl_unlock(lp, &flags); - - return ret; -} /* wl_ioctl */ - -/*============================================================================*/ - -#ifdef CONFIG_NET_POLL_CONTROLLER -static void wl_poll(struct net_device *dev) -{ - struct wl_private *lp = wl_priv(dev); - unsigned long flags; - struct pt_regs regs; - - wl_lock(lp, &flags); - wl_isr(dev->irq, dev, ®s); - wl_unlock(lp, &flags); -} -#endif - -/******************************************************************************* - * wl_tx_timeout() - ******************************************************************************* - * - * DESCRIPTION: - * - * The handler called when, for some reason, a Tx request is not completed. - * - * PARAMETERS: - * - * dev - a pointer to the device's net_device struct. - * - * RETURNS: - * - * N/A - * - ******************************************************************************/ -void wl_tx_timeout(struct net_device *dev) -{ -#ifdef USE_WDS - int count; -#endif /* USE_WDS */ - unsigned long flags; - struct wl_private *lp = wl_priv(dev); - struct net_device_stats *pStats = NULL; - - DBG_WARNING(DbgInfo, "%s: Transmit timeout.\n", dev->name); - - wl_lock(lp, &flags); - -#ifdef USE_RTS - if (lp->useRTS == 1) { - DBG_TRACE(DbgInfo, - "Skipping tx_timeout handler, in RTS mode\n"); - wl_unlock(lp, &flags); - return; - } -#endif /* USE_RTS */ - - /* Figure out which device (the "root" device or WDS port) this timeout - is for */ -#ifdef USE_WDS - - for (count = 0; count < NUM_WDS_PORTS; count++) { - if (dev == lp->wds_port[count].dev) { - pStats = &(lp->wds_port[count].stats); - - /* Break the loop so that we can use the counter to access WDS - information in the private structure */ - break; - } - } - -#endif /* USE_WDS */ - - /* If pStats is still NULL, then the device is not a WDS port */ - if (pStats == NULL) - pStats = &(lp->stats); - - /* Accumulate the timeout error */ - pStats->tx_errors++; - - wl_unlock(lp, &flags); -} /* wl_tx_timeout */ - -/*============================================================================*/ - -/******************************************************************************* - * wl_send() - ******************************************************************************* - * - * DESCRIPTION: - * - * The routine which performs data transmits. - * - * PARAMETERS: - * - * lp - a pointer to the device's wl_private struct. - * - * RETURNS: - * - * 0 on success - * 1 on error - * - ******************************************************************************/ -int wl_send(struct wl_private *lp) -{ - - int status; - DESC_STRCT *desc; - WVLAN_LFRAME *txF = NULL; - struct list_head *element; - int len; - /*------------------------------------------------------------------------*/ - - if (lp == NULL) { - DBG_ERROR(DbgInfo, "Private adapter struct is NULL\n"); - return FALSE; - } - if (lp->dev == NULL) { - DBG_ERROR(DbgInfo, "net_device struct in wl_private is NULL\n"); - return FALSE; - } - - /* - * Check for the availability of FIDs; if none are available, - * don't take any frames off the txQ - */ - if (lp->hcfCtx.IFB_RscInd == 0) - return FALSE; - - /* Reclaim the TxQ Elements and place them back on the free queue */ - if (!list_empty(&(lp->txQ[0]))) { - element = lp->txQ[0].next; - - txF = (WVLAN_LFRAME *) list_entry(element, WVLAN_LFRAME, node); - if (txF != NULL) { - lp->txF.skb = txF->frame.skb; - lp->txF.port = txF->frame.port; - - txF->frame.skb = NULL; - txF->frame.port = 0; - - list_del(&(txF->node)); - list_add(element, &(lp->txFree)); - - lp->txQ_count--; - - if (lp->txQ_count < TX_Q_LOW_WATER_MARK) { - if (lp->netif_queue_on == FALSE) { - DBG_TX(DbgInfo, "Kickstarting Q: %d\n", - lp->txQ_count); - netif_wake_queue(lp->dev); - WL_WDS_NETIF_WAKE_QUEUE(lp); - lp->netif_queue_on = TRUE; - } - } - } - } - - if (lp->txF.skb == NULL) - return FALSE; - - /* If the device has resources (FIDs) available, then Tx the packet */ - /* Format the TxRequest and send it to the adapter */ - len = lp->txF.skb->len < ETH_ZLEN ? ETH_ZLEN : lp->txF.skb->len; - - desc = &(lp->desc_tx); - desc->buf_addr = lp->txF.skb->data; - desc->BUF_CNT = len; - desc->next_desc_addr = NULL; - - status = hcf_send_msg(&(lp->hcfCtx), desc, lp->txF.port); - - if (status == HCF_SUCCESS) { - lp->dev->trans_start = jiffies; - - DBG_TX(DbgInfo, "Transmit...\n"); - - if (lp->txF.port == HCF_PORT_0) { - lp->stats.tx_packets++; - lp->stats.tx_bytes += lp->txF.skb->len; - } -#ifdef USE_WDS - else { - lp->wds_port[((lp->txF.port >> 8) - - 1)].stats.tx_packets++; - lp->wds_port[((lp->txF.port >> 8) - - 1)].stats.tx_bytes += lp->txF.skb->len; - } - -#endif /* USE_WDS */ - - /* Free the skb and perform queue cleanup, as the buffer was - transmitted successfully */ - dev_consume_skb_any( lp->txF.skb ); - - lp->txF.skb = NULL; - lp->txF.port = 0; - } - - return TRUE; -} /* wl_send */ - -/*============================================================================*/ - -/******************************************************************************* - * wl_tx() - ******************************************************************************* - * - * DESCRIPTION: - * - * The Tx handler function for the network layer. - * - * PARAMETERS: - * - * skb - a pointer to the sk_buff structure containing the data to transfer. - * dev - a pointer to the device's net_device structure. - * - * RETURNS: - * - * 0 on success - * 1 on error - * - ******************************************************************************/ -int wl_tx(struct sk_buff *skb, struct net_device *dev, int port) -{ - unsigned long flags; - struct wl_private *lp = wl_priv(dev); - WVLAN_LFRAME *txF = NULL; - struct list_head *element; - /*------------------------------------------------------------------------*/ - - /* Grab the spinlock */ - wl_lock(lp, &flags); - - if (lp->flags & WVLAN2_UIL_BUSY) { - DBG_WARNING(DbgInfo, "UIL has device blocked\n"); - /* Start dropping packets here??? */ - wl_unlock(lp, &flags); - return 1; - } -#ifdef USE_RTS - if (lp->useRTS == 1) { - DBG_PRINT("RTS: we're getting a Tx...\n"); - wl_unlock(lp, &flags); - return 1; - } -#endif /* USE_RTS */ - - if (!lp->use_dma) { - /* Get an element from the queue */ - element = lp->txFree.next; - txF = (WVLAN_LFRAME *) list_entry(element, WVLAN_LFRAME, node); - if (txF == NULL) { - DBG_ERROR(DbgInfo, "Problem with list_entry\n"); - wl_unlock(lp, &flags); - return 1; - } - /* Fill out the frame */ - txF->frame.skb = skb; - txF->frame.port = port; - /* Move the frame to the txQ */ - /* NOTE: Here's where we would do priority queueing */ - list_move(&(txF->node), &(lp->txQ[0])); - - lp->txQ_count++; - if (lp->txQ_count >= DEFAULT_NUM_TX_FRAMES) { - DBG_TX(DbgInfo, "Q Full: %d\n", lp->txQ_count); - if (lp->netif_queue_on == TRUE) { - netif_stop_queue(lp->dev); - WL_WDS_NETIF_STOP_QUEUE(lp); - lp->netif_queue_on = FALSE; - } - } - } - wl_act_int_off(lp); /* Disable Interrupts */ - - /* Send the data to the hardware using the appropriate method */ -#ifdef ENABLE_DMA - if (lp->use_dma) { - wl_send_dma(lp, skb, port); - } else -#endif - { - wl_send(lp); - } - /* Re-enable Interrupts, release the spinlock and return */ - wl_act_int_on(lp); - wl_unlock(lp, &flags); - return 0; -} /* wl_tx */ - -/*============================================================================*/ - -/******************************************************************************* - * wl_rx() - ******************************************************************************* - * - * DESCRIPTION: - * - * The routine which performs data reception. - * - * PARAMETERS: - * - * dev - a pointer to the device's net_device structure. - * - * RETURNS: - * - * 0 on success - * 1 on error - * - ******************************************************************************/ -int wl_rx(struct net_device *dev) -{ - int port; - struct sk_buff *skb; - struct wl_private *lp = wl_priv(dev); - int status; - hcf_16 pktlen; - hcf_16 hfs_stat; - DESC_STRCT *desc; - /*------------------------------------------------------------------------*/ - - DBG_PARAM(DbgInfo, "dev", "%s (0x%p)", dev->name, dev); - - if (!(lp->flags & WVLAN2_UIL_BUSY)) { - -#ifdef USE_RTS - if (lp->useRTS == 1) { - DBG_PRINT("RTS: We're getting an Rx...\n"); - return -EIO; - } -#endif /* USE_RTS */ - - /* Read the HFS_STAT register from the lookahead buffer */ - hfs_stat = (hcf_16) ((lp->lookAheadBuf[HFS_STAT]) | - (lp->lookAheadBuf[HFS_STAT + 1] << 8)); - - /* Make sure the frame isn't bad */ - if ((hfs_stat & HFS_STAT_ERR) != HCF_SUCCESS) { - DBG_WARNING(DbgInfo, - "HFS_STAT_ERROR (0x%x) in Rx Packet\n", - lp->lookAheadBuf[HFS_STAT]); - return -EIO; - } - - /* Determine what port this packet is for */ - port = (hfs_stat >> 8) & 0x0007; - DBG_RX(DbgInfo, "Rx frame for port %d\n", port); - - pktlen = lp->hcfCtx.IFB_RxLen; - if (pktlen != 0) { - skb = ALLOC_SKB(pktlen); - if (skb != NULL) { - /* Set the netdev based on the port */ - switch (port) { -#ifdef USE_WDS - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - skb->dev = lp->wds_port[port - 1].dev; - break; -#endif /* USE_WDS */ - - case 0: - default: - skb->dev = dev; - break; - } - - desc = &(lp->desc_rx); - - desc->next_desc_addr = NULL; - -/* -#define BLOCK_INPUT(buf, len) \ - desc->buf_addr = buf; \ - desc->BUF_SIZE = len; \ - status = hcf_rcv_msg(&(lp->hcfCtx), desc, 0) -*/ - - GET_PACKET(skb->dev, skb, pktlen); - - if (status == HCF_SUCCESS) { - netif_rx(skb); - - if (port == 0) { - lp->stats.rx_packets++; - lp->stats.rx_bytes += pktlen; - } -#ifdef USE_WDS - else { - lp->wds_port[port - - 1].stats. - rx_packets++; - lp->wds_port[port - - 1].stats. - rx_bytes += pktlen; - } -#endif /* USE_WDS */ - - dev->last_rx = jiffies; - -#ifdef WIRELESS_EXT -#ifdef WIRELESS_SPY - if (lp->spydata.spy_number > 0) { - char *srcaddr = - skb->mac.raw + - MAC_ADDR_SIZE; - - wl_spy_gather(dev, srcaddr); - } -#endif /* WIRELESS_SPY */ -#endif /* WIRELESS_EXT */ - } else { - DBG_ERROR(DbgInfo, - "Rx request to card FAILED\n"); - - if (port == 0) - lp->stats.rx_dropped++; -#ifdef USE_WDS - else { - lp->wds_port[port - - 1].stats. - rx_dropped++; - } -#endif /* USE_WDS */ - - dev_kfree_skb(skb); - } - } else { - DBG_ERROR(DbgInfo, "Could not alloc skb\n"); - - if (port == 0) - lp->stats.rx_dropped++; -#ifdef USE_WDS - else { - lp->wds_port[port - - 1].stats.rx_dropped++; - } -#endif /* USE_WDS */ - } - } - } - - return 0; -} /* wl_rx */ - -/*============================================================================*/ - -/******************************************************************************* - * wl_multicast() - ******************************************************************************* - * - * DESCRIPTION: - * - * Function to handle multicast packets - * - * PARAMETERS: - * - * dev - a pointer to the device's net_device structure. - * - * RETURNS: - * - * N/A - * - ******************************************************************************/ -#ifdef NEW_MULTICAST - -void wl_multicast(struct net_device *dev) -{ -#if 1 /* (HCF_TYPE) & HCF_TYPE_STA */ - /* - * should we return an error status in AP mode ? - * seems reasonable that even an AP-only driver - * could afford this small additional footprint - */ - - int x; - struct netdev_hw_addr *ha; - struct wl_private *lp = wl_priv(dev); - unsigned long flags; - - DBG_PARAM(DbgInfo, "dev", "%s (0x%p)", dev->name, dev); - - if (!wl_adapter_is_open(dev)) - return; - -#if DBG - if (DBG_FLAGS(DbgInfo) & DBG_PARAM_ON) { - DBG_PRINT(" flags: %s%s%s\n", - (dev->flags & IFF_PROMISC) ? "Promiscuous " : "", - (dev->flags & IFF_MULTICAST) ? "Multicast " : "", - (dev->flags & IFF_ALLMULTI) ? "All-Multicast" : ""); - - DBG_PRINT(" mc_count: %d\n", netdev_mc_count(dev)); - - netdev_for_each_mc_addr(ha, dev) - DBG_PRINT(" %pM (%d)\n", ha->addr, dev->addr_len); - } -#endif /* DBG */ - - if (!(lp->flags & WVLAN2_UIL_BUSY)) { - -#ifdef USE_RTS - if (lp->useRTS == 1) { - DBG_TRACE(DbgInfo, "Skipping multicast, in RTS mode\n"); - return; - } -#endif /* USE_RTS */ - - wl_lock(lp, &flags); - wl_act_int_off(lp); - - if (CNV_INT_TO_LITTLE(lp->hcfCtx.IFB_FWIdentity.comp_id) == - COMP_ID_FW_STA) { - if (dev->flags & IFF_PROMISC) { - /* Enable promiscuous mode */ - lp->ltvRecord.len = 2; - lp->ltvRecord.typ = CFG_PROMISCUOUS_MODE; - lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE(1); - DBG_PRINT - ("Enabling Promiscuous mode (IFF_PROMISC)\n"); - hcf_put_info(&(lp->hcfCtx), - (LTVP) & (lp->ltvRecord)); - } else if ((netdev_mc_count(dev) > HCF_MAX_MULTICAST) - || (dev->flags & IFF_ALLMULTI)) { - /* Shutting off this filter will enable all multicast frames to - be sent up from the device; however, this is a static RID, so - a call to wl_apply() is needed */ - lp->ltvRecord.len = 2; - lp->ltvRecord.typ = CFG_CNF_RX_ALL_GROUP_ADDR; - lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE(0); - DBG_PRINT - ("Enabling all multicast mode (IFF_ALLMULTI)\n"); - hcf_put_info(&(lp->hcfCtx), - (LTVP) & (lp->ltvRecord)); - wl_apply(lp); - } else if (!netdev_mc_empty(dev)) { - /* Set the multicast addresses */ - lp->ltvRecord.len = - (netdev_mc_count(dev) * 3) + 1; - lp->ltvRecord.typ = CFG_GROUP_ADDR; - - x = 0; - netdev_for_each_mc_addr(ha, dev) - memcpy(& - (lp->ltvRecord.u.u8[x++ * ETH_ALEN]), - ha->addr, ETH_ALEN); - DBG_PRINT("Setting multicast list\n"); - hcf_put_info(&(lp->hcfCtx), - (LTVP) & (lp->ltvRecord)); - } else { - /* Disable promiscuous mode */ - lp->ltvRecord.len = 2; - lp->ltvRecord.typ = CFG_PROMISCUOUS_MODE; - lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE(0); - DBG_PRINT("Disabling Promiscuous mode\n"); - hcf_put_info(&(lp->hcfCtx), - (LTVP) & (lp->ltvRecord)); - - /* Disable multicast mode */ - lp->ltvRecord.len = 2; - lp->ltvRecord.typ = CFG_GROUP_ADDR; - DBG_PRINT("Disabling Multicast mode\n"); - hcf_put_info(&(lp->hcfCtx), - (LTVP) & (lp->ltvRecord)); - - /* - * Turning on this filter will prevent all multicast frames from - * being sent up from the device; however, this is a static RID, - * so a call to wl_apply() is needed - */ - lp->ltvRecord.len = 2; - lp->ltvRecord.typ = CFG_CNF_RX_ALL_GROUP_ADDR; - lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE(1); - DBG_PRINT - ("Disabling all multicast mode (IFF_ALLMULTI)\n"); - hcf_put_info(&(lp->hcfCtx), - (LTVP) & (lp->ltvRecord)); - wl_apply(lp); - } - } - wl_act_int_on(lp); - wl_unlock(lp, &flags); - } -#endif /* HCF_STA */ -} /* wl_multicast */ - -/*============================================================================*/ - -#else /* NEW_MULTICAST */ - -void wl_multicast(struct net_device *dev, int num_addrs, void *addrs) -{ - DBG_PARAM(DbgInfo, "dev", "%s (0x%p)", dev->name, dev); - DBG_PARAM(DbgInfo, "num_addrs", "%d", num_addrs); - DBG_PARAM(DbgInfo, "addrs", "0x%p", addrs); - -#error Obsolete set multicast interface! -} /* wl_multicast */ - -/*============================================================================*/ - -#endif /* NEW_MULTICAST */ - -static const struct net_device_ops wl_netdev_ops = { - .ndo_start_xmit = &wl_tx_port0, - - .ndo_set_config = &wl_config, - .ndo_get_stats = &wl_stats, - .ndo_set_rx_mode = &wl_multicast, - - .ndo_init = &wl_insert, - .ndo_open = &wl_adapter_open, - .ndo_stop = &wl_adapter_close, - .ndo_do_ioctl = &wl_ioctl, - - .ndo_tx_timeout = &wl_tx_timeout, - -#ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller = wl_poll, -#endif -}; - -/******************************************************************************* - * wl_device_alloc() - ******************************************************************************* - * - * DESCRIPTION: - * - * Create instances of net_device and wl_private for the new adapter - * and register the device's entry points in the net_device structure. - * - * PARAMETERS: - * - * N/A - * - * RETURNS: - * - * a pointer to an allocated and initialized net_device struct for this - * device. - * - ******************************************************************************/ -struct net_device *wl_device_alloc(void) -{ - struct net_device *dev = NULL; - struct wl_private *lp = NULL; - - /* Alloc a net_device struct */ - dev = alloc_etherdev(sizeof(struct wl_private)); - if (!dev) - return NULL; - - /* - * Initialize the 'next' pointer in the struct. - * Currently only used for PCI, - * but do it here just in case it's used - * for other buses in the future - */ - lp = wl_priv(dev); - - /* Check MTU */ - if (dev->mtu > MTU_MAX) { - DBG_WARNING(DbgInfo, "%s: MTU set too high, limiting to %d.\n", - dev->name, MTU_MAX); - dev->mtu = MTU_MAX; - } - - /* Setup the function table in the device structure. */ - - dev->wireless_handlers = (struct iw_handler_def *)&wl_iw_handler_def; - lp->wireless_data.spy_data = &lp->spy_data; - dev->wireless_data = &lp->wireless_data; - - dev->netdev_ops = &wl_netdev_ops; - - dev->watchdog_timeo = TX_TIMEOUT; - - dev->ethtool_ops = &wl_ethtool_ops; - - netif_stop_queue(dev); - - /* Allocate virtual devices for WDS support if needed */ - WL_WDS_DEVICE_ALLOC(lp); - - return dev; -} /* wl_device_alloc */ - -/*============================================================================*/ - -/******************************************************************************* - * wl_device_dealloc() - ******************************************************************************* - * - * DESCRIPTION: - * - * Free instances of net_device and wl_private strcutres for an adapter - * and perform basic cleanup. - * - * PARAMETERS: - * - * dev - a pointer to the device's net_device structure. - * - * RETURNS: - * - * N/A - * - ******************************************************************************/ -void wl_device_dealloc(struct net_device *dev) -{ - /* Dealloc the WDS ports */ - WL_WDS_DEVICE_DEALLOC(lp); - - free_netdev(dev); -} /* wl_device_dealloc */ - -/*============================================================================*/ - -/******************************************************************************* - * wl_tx_port0() - ******************************************************************************* - * - * DESCRIPTION: - * - * The handler routine for Tx over HCF_PORT_0. - * - * PARAMETERS: - * - * skb - a pointer to the sk_buff to transmit. - * dev - a pointer to a net_device structure representing HCF_PORT_0. - * - * RETURNS: - * - * N/A - * - ******************************************************************************/ -int wl_tx_port0(struct sk_buff *skb, struct net_device *dev) -{ - DBG_TX(DbgInfo, "Tx on Port 0\n"); - - return wl_tx(skb, dev, HCF_PORT_0); -#ifdef ENABLE_DMA - return wl_tx_dma(skb, dev, HCF_PORT_0); -#endif -} /* wl_tx_port0i */ - -/*============================================================================*/ - -#ifdef USE_WDS - -/******************************************************************************* - * wl_tx_port1() - ******************************************************************************* - * - * DESCRIPTION: - * - * The handler routine for Tx over HCF_PORT_1. - * - * PARAMETERS: - * - * skb - a pointer to the sk_buff to transmit. - * dev - a pointer to a net_device structure representing HCF_PORT_1. - * - * RETURNS: - * - * N/A - * - ******************************************************************************/ -int wl_tx_port1(struct sk_buff *skb, struct net_device *dev) -{ - DBG_TX(DbgInfo, "Tx on Port 1\n"); - return wl_tx(skb, dev, HCF_PORT_1); -} /* wl_tx_port1 */ - -/*============================================================================*/ - -/******************************************************************************* - * wl_tx_port2() - ******************************************************************************* - * - * DESCRIPTION: - * - * The handler routine for Tx over HCF_PORT_2. - * - * PARAMETERS: - * - * skb - a pointer to the sk_buff to transmit. - * dev - a pointer to a net_device structure representing HCF_PORT_2. - * - * RETURNS: - * - * N/A - * - ******************************************************************************/ -int wl_tx_port2(struct sk_buff *skb, struct net_device *dev) -{ - DBG_TX(DbgInfo, "Tx on Port 2\n"); - return wl_tx(skb, dev, HCF_PORT_2); -} /* wl_tx_port2 */ - -/*============================================================================*/ - -/******************************************************************************* - * wl_tx_port3() - ******************************************************************************* - * - * DESCRIPTION: - * - * The handler routine for Tx over HCF_PORT_3. - * - * PARAMETERS: - * - * skb - a pointer to the sk_buff to transmit. - * dev - a pointer to a net_device structure representing HCF_PORT_3. - * - * RETURNS: - * - * N/A - * - ******************************************************************************/ -int wl_tx_port3(struct sk_buff *skb, struct net_device *dev) -{ - DBG_TX(DbgInfo, "Tx on Port 3\n"); - return wl_tx(skb, dev, HCF_PORT_3); -} /* wl_tx_port3 */ - -/*============================================================================*/ - -/******************************************************************************* - * wl_tx_port4() - ******************************************************************************* - * - * DESCRIPTION: - * - * The handler routine for Tx over HCF_PORT_4. - * - * PARAMETERS: - * - * skb - a pointer to the sk_buff to transmit. - * dev - a pointer to a net_device structure representing HCF_PORT_4. - * - * RETURNS: - * - * N/A - * - ******************************************************************************/ -int wl_tx_port4(struct sk_buff *skb, struct net_device *dev) -{ - DBG_TX(DbgInfo, "Tx on Port 4\n"); - return wl_tx(skb, dev, HCF_PORT_4); -} /* wl_tx_port4 */ - -/*============================================================================*/ - -/******************************************************************************* - * wl_tx_port5() - ******************************************************************************* - * - * DESCRIPTION: - * - * The handler routine for Tx over HCF_PORT_5. - * - * PARAMETERS: - * - * skb - a pointer to the sk_buff to transmit. - * dev - a pointer to a net_device structure representing HCF_PORT_5. - * - * RETURNS: - * - * N/A - * - ******************************************************************************/ -int wl_tx_port5(struct sk_buff *skb, struct net_device *dev) -{ - DBG_TX(DbgInfo, "Tx on Port 5\n"); - return wl_tx(skb, dev, HCF_PORT_5); -} /* wl_tx_port5 */ - -/*============================================================================*/ - -/******************************************************************************* - * wl_tx_port6() - ******************************************************************************* - * - * DESCRIPTION: - * - * The handler routine for Tx over HCF_PORT_6. - * - * PARAMETERS: - * - * skb - a pointer to the sk_buff to transmit. - * dev - a pointer to a net_device structure representing HCF_PORT_6. - * - * RETURNS: - * - * N/A - * - ******************************************************************************/ -int wl_tx_port6(struct sk_buff *skb, struct net_device *dev) -{ - DBG_TX(DbgInfo, "Tx on Port 6\n"); - return wl_tx(skb, dev, HCF_PORT_6); -} /* wl_tx_port6 */ - -/*============================================================================*/ - -/******************************************************************************* - * wl_wds_device_alloc() - ******************************************************************************* - * - * DESCRIPTION: - * - * Create instances of net_device to represent the WDS ports, and register - * the device's entry points in the net_device structure. - * - * PARAMETERS: - * - * lp - a pointer to the device's private adapter structure - * - * RETURNS: - * - * N/A, but will place pointers to the allocated and initialized net_device - * structs in the private adapter structure. - * - ******************************************************************************/ -void wl_wds_device_alloc(struct wl_private *lp) -{ - int count; - - /* WDS support requires additional net_device structs to be allocated, - so that user space apps can use these virtual devices to specify the - port on which to Tx/Rx */ - for (count = 0; count < NUM_WDS_PORTS; count++) { - struct net_device *dev_wds = NULL; - - dev_wds = kzalloc(sizeof(struct net_device), GFP_KERNEL); - if (!dev_wds) - return; - - ether_setup(dev_wds); - - lp->wds_port[count].dev = dev_wds; - - /* Re-use wl_init for all the devices, as it currently does nothing, but - * is required. Re-use the stats/tx_timeout handler for all as well; the - * WDS port which is requesting these operations can be determined by - * the net_device pointer. Set the private member of all devices to point - * to the same net_device struct; that way, all information gets - * funnelled through the one "real" net_device. Name the WDS ports - * "wds<n>" - * */ - lp->wds_port[count].dev->init = &wl_init; - lp->wds_port[count].dev->get_stats = &wl_stats; - lp->wds_port[count].dev->tx_timeout = &wl_tx_timeout; - lp->wds_port[count].dev->watchdog_timeo = TX_TIMEOUT; - lp->wds_port[count].dev->priv = lp; - - sprintf(lp->wds_port[count].dev->name, "wds%d", count); - } - - /* Register the Tx handlers */ - lp->wds_port[0].dev->hard_start_xmit = &wl_tx_port1; - lp->wds_port[1].dev->hard_start_xmit = &wl_tx_port2; - lp->wds_port[2].dev->hard_start_xmit = &wl_tx_port3; - lp->wds_port[3].dev->hard_start_xmit = &wl_tx_port4; - lp->wds_port[4].dev->hard_start_xmit = &wl_tx_port5; - lp->wds_port[5].dev->hard_start_xmit = &wl_tx_port6; - - WL_WDS_NETIF_STOP_QUEUE(lp); -} /* wl_wds_device_alloc */ - -/*============================================================================*/ - -/******************************************************************************* - * wl_wds_device_dealloc() - ******************************************************************************* - * - * DESCRIPTION: - * - * Free instances of net_device structures used to support WDS. - * - * PARAMETERS: - * - * lp - a pointer to the device's private adapter structure - * - * RETURNS: - * - * N/A - * - ******************************************************************************/ -void wl_wds_device_dealloc(struct wl_private *lp) -{ - int count; - - for (count = 0; count < NUM_WDS_PORTS; count++) { - struct net_device *dev_wds = NULL; - - dev_wds = lp->wds_port[count].dev; - - if (dev_wds != NULL) { - if (dev_wds->flags & IFF_UP) { - dev_close(dev_wds); - dev_wds->flags &= ~(IFF_UP | IFF_RUNNING); - } - - free_netdev(dev_wds); - lp->wds_port[count].dev = NULL; - } - } -} /* wl_wds_device_dealloc */ - -/*============================================================================*/ - -/******************************************************************************* - * wl_wds_netif_start_queue() - ******************************************************************************* - * - * DESCRIPTION: - * - * Used to start the netif queues of all the "virtual" network devices - * which represent the WDS ports. - * - * PARAMETERS: - * - * lp - a pointer to the device's private adapter structure - * - * RETURNS: - * - * N/A - * - ******************************************************************************/ -void wl_wds_netif_start_queue(struct wl_private *lp) -{ - int count; - /*------------------------------------------------------------------------*/ - - if (lp != NULL) { - for (count = 0; count < NUM_WDS_PORTS; count++) { - if (lp->wds_port[count].is_registered && - lp->wds_port[count].netif_queue_on == FALSE) { - netif_start_queue(lp->wds_port[count].dev); - lp->wds_port[count].netif_queue_on = TRUE; - } - } - } -} /* wl_wds_netif_start_queue */ - -/*============================================================================*/ - -/******************************************************************************* - * wl_wds_netif_stop_queue() - ******************************************************************************* - * - * DESCRIPTION: - * - * Used to stop the netif queues of all the "virtual" network devices - * which represent the WDS ports. - * - * PARAMETERS: - * - * lp - a pointer to the device's private adapter structure - * - * RETURNS: - * - * N/A - * - ******************************************************************************/ -void wl_wds_netif_stop_queue(struct wl_private *lp) -{ - int count; - /*------------------------------------------------------------------------*/ - - if (lp != NULL) { - for (count = 0; count < NUM_WDS_PORTS; count++) { - if (lp->wds_port[count].is_registered && - lp->wds_port[count].netif_queue_on == TRUE) { - netif_stop_queue(lp->wds_port[count].dev); - lp->wds_port[count].netif_queue_on = FALSE; - } - } - } -} /* wl_wds_netif_stop_queue */ - -/*============================================================================*/ - -/******************************************************************************* - * wl_wds_netif_wake_queue() - ******************************************************************************* - * - * DESCRIPTION: - * - * Used to wake the netif queues of all the "virtual" network devices - * which represent the WDS ports. - * - * PARAMETERS: - * - * lp - a pointer to the device's private adapter structure - * - * RETURNS: - * - * N/A - * - ******************************************************************************/ -void wl_wds_netif_wake_queue(struct wl_private *lp) -{ - int count; - /*------------------------------------------------------------------------*/ - - if (lp != NULL) { - for (count = 0; count < NUM_WDS_PORTS; count++) { - if (lp->wds_port[count].is_registered && - lp->wds_port[count].netif_queue_on == FALSE) { - netif_wake_queue(lp->wds_port[count].dev); - lp->wds_port[count].netif_queue_on = TRUE; - } - } - } -} /* wl_wds_netif_wake_queue */ - -/*============================================================================*/ - -/******************************************************************************* - * wl_wds_netif_carrier_on() - ******************************************************************************* - * - * DESCRIPTION: - * - * Used to signal the network layer that carrier is present on all of the - * "virtual" network devices which represent the WDS ports. - * - * PARAMETERS: - * - * lp - a pointer to the device's private adapter structure - * - * RETURNS: - * - * N/A - * - ******************************************************************************/ -void wl_wds_netif_carrier_on(struct wl_private *lp) -{ - int count; - /*------------------------------------------------------------------------*/ - - if (lp != NULL) { - for (count = 0; count < NUM_WDS_PORTS; count++) { - if (lp->wds_port[count].is_registered) - netif_carrier_on(lp->wds_port[count].dev); - } - } -} /* wl_wds_netif_carrier_on */ - -/*============================================================================*/ - -/******************************************************************************* - * wl_wds_netif_carrier_off() - ******************************************************************************* - * - * DESCRIPTION: - * - * Used to signal the network layer that carrier is NOT present on all of - * the "virtual" network devices which represent the WDS ports. - * - * PARAMETERS: - * - * lp - a pointer to the device's private adapter structure - * - * RETURNS: - * - * N/A - * - ******************************************************************************/ -void wl_wds_netif_carrier_off(struct wl_private *lp) -{ - int count; - - if (lp != NULL) { - for (count = 0; count < NUM_WDS_PORTS; count++) { - if (lp->wds_port[count].is_registered) - netif_carrier_off(lp->wds_port[count].dev); - } - } - -} /* wl_wds_netif_carrier_off */ - -/*============================================================================*/ - -#endif /* USE_WDS */ - -#ifdef ENABLE_DMA -/******************************************************************************* - * wl_send_dma() - ******************************************************************************* - * - * DESCRIPTION: - * - * The routine which performs data transmits when using busmaster DMA. - * - * PARAMETERS: - * - * lp - a pointer to the device's wl_private struct. - * skb - a pointer to the network layer's data buffer. - * port - the Hermes port on which to transmit. - * - * RETURNS: - * - * 0 on success - * 1 on error - * - ******************************************************************************/ -int wl_send_dma(struct wl_private *lp, struct sk_buff *skb, int port) -{ - int len; - DESC_STRCT *desc = NULL; - DESC_STRCT *desc_next = NULL; - /*------------------------------------------------------------------------*/ - - if (lp == NULL) { - DBG_ERROR(DbgInfo, "Private adapter struct is NULL\n"); - return FALSE; - } - - if (lp->dev == NULL) { - DBG_ERROR(DbgInfo, "net_device struct in wl_private is NULL\n"); - return FALSE; - } - - /* AGAIN, ALL THE QUEUEING DONE HERE IN I/O MODE IS NOT PERFORMED */ - - if (skb == NULL) { - DBG_WARNING(DbgInfo, "Nothing to send.\n"); - return FALSE; - } - - len = skb->len; - - /* Get a free descriptor */ - desc = wl_pci_dma_get_tx_packet(lp); - - if (desc == NULL) { - if (lp->netif_queue_on == TRUE) { - netif_stop_queue(lp->dev); - WL_WDS_NETIF_STOP_QUEUE(lp); - lp->netif_queue_on = FALSE; - - dev_kfree_skb_any( skb ); - return 0; - } - } - - SET_BUF_CNT(desc, /*HCF_DMA_FD_CNT */ HFS_ADDR_DEST); - SET_BUF_SIZE(desc, HCF_DMA_TX_BUF1_SIZE); - - desc_next = desc->next_desc_addr; - - if (desc_next->buf_addr == NULL) { - DBG_ERROR(DbgInfo, "DMA descriptor buf_addr is NULL\n"); - return FALSE; - } - - /* Copy the payload into the DMA packet */ - memcpy(desc_next->buf_addr, skb->data, len); - - SET_BUF_CNT(desc_next, len); - SET_BUF_SIZE(desc_next, HCF_MAX_PACKET_SIZE); - - hcf_dma_tx_put(&(lp->hcfCtx), desc, 0); - - /* Free the skb and perform queue cleanup, as the buffer was - transmitted successfully */ - dev_consume_skb_any( skb ); - - return TRUE; -} /* wl_send_dma */ - -/*============================================================================*/ - -/******************************************************************************* - * wl_rx_dma() - ******************************************************************************* - * - * DESCRIPTION: - * - * The routine which performs data reception when using busmaster DMA. - * - * PARAMETERS: - * - * dev - a pointer to the device's net_device structure. - * - * RETURNS: - * - * 0 on success - * 1 on error - * - ******************************************************************************/ -int wl_rx_dma(struct net_device *dev) -{ - int port; - hcf_16 pktlen; - hcf_16 hfs_stat; - struct sk_buff *skb; - struct wl_private *lp = NULL; - DESC_STRCT *desc, *desc_next; - /*------------------------------------------------------------------------*/ - - DBG_PARAM(DbgInfo, "dev", "%s (0x%p)", dev->name, dev); - - lp = dev->priv; - if ((lp != NULL) && !(lp->flags & WVLAN2_UIL_BUSY)) { - -#ifdef USE_RTS - if (lp->useRTS == 1) { - DBG_PRINT("RTS: We're getting an Rx...\n"); - return -EIO; - } -#endif /* USE_RTS */ - - /* - *if( lp->dma.status == 0 ) - *{ - */ - desc = hcf_dma_rx_get(&(lp->hcfCtx)); - - if (desc != NULL) { - /* Check and see if we rcvd. a WMP frame */ - /* - if((( *(hcf_8 *)&desc->buf_addr[HFS_STAT] ) & - ( HFS_STAT_MSG_TYPE | HFS_STAT_ERR )) == HFS_STAT_WMP_MSG ) - { - DBG_TRACE( DbgInfo, "Got a WMP frame\n" ); - - x.len = sizeof( CFG_MB_INFO_RANGE2_STRCT ) / sizeof( hcf_16 ); - x.typ = CFG_MB_INFO; - x.base_typ = CFG_WMP; - x.frag_cnt = 2; - x.frag_buf[0].frag_len = GET_BUF_CNT( descp ) / sizeof( hcf_16 ); - x.frag_buf[0].frag_addr = (hcf_8 *) descp->buf_addr ; - x.frag_buf[1].frag_len = ( GET_BUF_CNT( descp->next_desc_addr ) + 1 ) / sizeof( hcf_16 ); - x.frag_buf[1].frag_addr = (hcf_8 *) descp->next_desc_addr->buf_addr ; - - hcf_put_info( &( lp->hcfCtx ), (LTVP)&x ); - } - */ - - desc_next = desc->next_desc_addr; - - /* Make sure the buffer isn't empty */ - if (GET_BUF_CNT(desc) == 0) { - DBG_WARNING(DbgInfo, "Buffer is empty!\n"); - - /* Give the descriptor back to the HCF */ - hcf_dma_rx_put(&(lp->hcfCtx), desc); - return -EIO; - } - - /* Read the HFS_STAT register from the lookahead buffer */ - hfs_stat = (hcf_16) (desc->buf_addr[HFS_STAT / 2]); - - /* Make sure the frame isn't bad */ - if ((hfs_stat & HFS_STAT_ERR) != HCF_SUCCESS) { - DBG_WARNING(DbgInfo, - "HFS_STAT_ERROR (0x%x) in Rx Packet\n", - desc->buf_addr[HFS_STAT / 2]); - - /* Give the descriptor back to the HCF */ - hcf_dma_rx_put(&(lp->hcfCtx), desc); - return -EIO; - } - - /* Determine what port this packet is for */ - port = (hfs_stat >> 8) & 0x0007; - DBG_RX(DbgInfo, "Rx frame for port %d\n", port); - - pktlen = GET_BUF_CNT(desc_next); - if (pktlen != 0) { - skb = ALLOC_SKB(pktlen); - if (skb != NULL) { - switch (port) { -#ifdef USE_WDS - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - skb->dev = - lp->wds_port[port - 1].dev; - break; -#endif /* USE_WDS */ - - case 0: - default: - skb->dev = dev; - break; - } - - GET_PACKET_DMA(skb->dev, skb, pktlen); - - /* Give the descriptor back to the HCF */ - hcf_dma_rx_put(&(lp->hcfCtx), desc); - - netif_rx(skb); - - if (port == 0) { - lp->stats.rx_packets++; - lp->stats.rx_bytes += pktlen; - } -#ifdef USE_WDS - else { - lp->wds_port[port - - 1].stats. - rx_packets++; - lp->wds_port[port - - 1].stats. - rx_bytes += pktlen; - } -#endif /* USE_WDS */ - - dev->last_rx = jiffies; - - } else { - DBG_ERROR(DbgInfo, - "Could not alloc skb\n"); - - if (port == 0) - lp->stats.rx_dropped++; -#ifdef USE_WDS - else { - lp->wds_port[port - - 1].stats. - rx_dropped++; - } -#endif /* USE_WDS */ - } - } - } - /*}*/ - } - - return 0; -} /* wl_rx_dma */ - -/*============================================================================*/ -#endif /* ENABLE_DMA */ |