diff options
Diffstat (limited to 'drivers/staging/bcm/Bcmnet.c')
| -rw-r--r-- | drivers/staging/bcm/Bcmnet.c | 241 |
1 files changed, 241 insertions, 0 deletions
diff --git a/drivers/staging/bcm/Bcmnet.c b/drivers/staging/bcm/Bcmnet.c new file mode 100644 index 00000000000..95a2358267b --- /dev/null +++ b/drivers/staging/bcm/Bcmnet.c @@ -0,0 +1,241 @@ +#include "headers.h" + +struct net_device *gblpnetdev; + +static INT bcm_open(struct net_device *dev) +{ + struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(dev); + + if (Adapter->fw_download_done == false) { + pr_notice(PFX "%s: link up failed (download in progress)\n", + dev->name); + return -EBUSY; + } + + if (netif_msg_ifup(Adapter)) + pr_info(PFX "%s: enabling interface\n", dev->name); + + if (Adapter->LinkUpStatus) { + if (netif_msg_link(Adapter)) + pr_info(PFX "%s: link up\n", dev->name); + + netif_carrier_on(Adapter->dev); + netif_start_queue(Adapter->dev); + } + + return 0; +} + +static INT bcm_close(struct net_device *dev) +{ + struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(dev); + + if (netif_msg_ifdown(Adapter)) + pr_info(PFX "%s: disabling interface\n", dev->name); + + netif_carrier_off(dev); + netif_stop_queue(dev); + + return 0; +} + +static u16 bcm_select_queue(struct net_device *dev, struct sk_buff *skb, + void *accel_priv, select_queue_fallback_t fallback) +{ + return ClassifyPacket(netdev_priv(dev), skb); +} + +/******************************************************************* +* Function - bcm_transmit() +* +* Description - This is the main transmit function for our virtual +* interface(eth0). It handles the ARP packets. It +* clones this packet and then Queue it to a suitable +* Queue. Then calls the transmit_packet(). +* +* Parameter - skb - Pointer to the socket buffer structure +* dev - Pointer to the virtual net device structure +* +*********************************************************************/ + +static netdev_tx_t bcm_transmit(struct sk_buff *skb, struct net_device *dev) +{ + struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(dev); + u16 qindex = skb_get_queue_mapping(skb); + + + if (Adapter->device_removed || !Adapter->LinkUpStatus) + goto drop; + + if (Adapter->TransferMode != IP_PACKET_ONLY_MODE) + goto drop; + + if (INVALID_QUEUE_INDEX == qindex) + goto drop; + + if (Adapter->PackInfo[qindex].uiCurrentPacketsOnHost >= + SF_MAX_ALLOWED_PACKETS_TO_BACKUP) + return NETDEV_TX_BUSY; + + /* Now Enqueue the packet */ + if (netif_msg_tx_queued(Adapter)) + pr_info(PFX "%s: enqueueing packet to queue %d\n", + dev->name, qindex); + + spin_lock(&Adapter->PackInfo[qindex].SFQueueLock); + Adapter->PackInfo[qindex].uiCurrentBytesOnHost += skb->len; + Adapter->PackInfo[qindex].uiCurrentPacketsOnHost++; + + *((B_UINT32 *) skb->cb + SKB_CB_LATENCY_OFFSET) = jiffies; + ENQUEUEPACKET(Adapter->PackInfo[qindex].FirstTxQueue, + Adapter->PackInfo[qindex].LastTxQueue, skb); + atomic_inc(&Adapter->TotalPacketCount); + spin_unlock(&Adapter->PackInfo[qindex].SFQueueLock); + + /* FIXME - this is racy and incorrect, replace with work queue */ + if (!atomic_read(&Adapter->TxPktAvail)) { + atomic_set(&Adapter->TxPktAvail, 1); + wake_up(&Adapter->tx_packet_wait_queue); + } + return NETDEV_TX_OK; + + drop: + dev_kfree_skb(skb); + return NETDEV_TX_OK; +} + + + +/** +@ingroup init_functions +Register other driver entry points with the kernel +*/ +static const struct net_device_ops bcmNetDevOps = { + .ndo_open = bcm_open, + .ndo_stop = bcm_close, + .ndo_start_xmit = bcm_transmit, + .ndo_change_mtu = eth_change_mtu, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, + .ndo_select_queue = bcm_select_queue, +}; + +static struct device_type wimax_type = { + .name = "wimax", +}; + +static int bcm_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + cmd->supported = 0; + cmd->advertising = 0; + cmd->speed = SPEED_10000; + cmd->duplex = DUPLEX_FULL; + cmd->port = PORT_TP; + cmd->phy_address = 0; + cmd->transceiver = XCVR_INTERNAL; + cmd->autoneg = AUTONEG_DISABLE; + cmd->maxtxpkt = 0; + cmd->maxrxpkt = 0; + return 0; +} + +static void bcm_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) +{ + struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(dev); + struct bcm_interface_adapter *psIntfAdapter = + Adapter->pvInterfaceAdapter; + struct usb_device *udev = interface_to_usbdev(psIntfAdapter->interface); + + strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); + strlcpy(info->version, DRV_VERSION, sizeof(info->version)); + snprintf(info->fw_version, sizeof(info->fw_version), "%u.%u", + Adapter->uiFlashLayoutMajorVersion, + Adapter->uiFlashLayoutMinorVersion); + + usb_make_path(udev, info->bus_info, sizeof(info->bus_info)); +} + +static u32 bcm_get_link(struct net_device *dev) +{ + struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(dev); + + return Adapter->LinkUpStatus; +} + +static u32 bcm_get_msglevel(struct net_device *dev) +{ + struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(dev); + + return Adapter->msg_enable; +} + +static void bcm_set_msglevel(struct net_device *dev, u32 level) +{ + struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(dev); + + Adapter->msg_enable = level; +} + +static const struct ethtool_ops bcm_ethtool_ops = { + .get_settings = bcm_get_settings, + .get_drvinfo = bcm_get_drvinfo, + .get_link = bcm_get_link, + .get_msglevel = bcm_get_msglevel, + .set_msglevel = bcm_set_msglevel, +}; + +int register_networkdev(struct bcm_mini_adapter *Adapter) +{ + struct net_device *net = Adapter->dev; + struct bcm_interface_adapter *IntfAdapter = Adapter->pvInterfaceAdapter; + struct usb_interface *udev = IntfAdapter->interface; + struct usb_device *xdev = IntfAdapter->udev; + + int result; + + net->netdev_ops = &bcmNetDevOps; + net->ethtool_ops = &bcm_ethtool_ops; + net->mtu = MTU_SIZE; /* 1400 Bytes */ + net->tx_queue_len = TX_QLEN; + net->flags |= IFF_NOARP; + + netif_carrier_off(net); + + SET_NETDEV_DEVTYPE(net, &wimax_type); + + /* Read the MAC Address from EEPROM */ + result = ReadMacAddressFromNVM(Adapter); + if (result != STATUS_SUCCESS) { + dev_err(&udev->dev, + PFX "Error in Reading the mac Address: %d", result); + return -EIO; + } + + result = register_netdev(net); + if (result) + return result; + + gblpnetdev = Adapter->dev; + + if (netif_msg_probe(Adapter)) + dev_info(&udev->dev, PFX "%s: register usb-%s-%s %pM\n", + net->name, xdev->bus->bus_name, xdev->devpath, + net->dev_addr); + + return 0; +} + +void unregister_networkdev(struct bcm_mini_adapter *Adapter) +{ + struct net_device *net = Adapter->dev; + struct bcm_interface_adapter *IntfAdapter = Adapter->pvInterfaceAdapter; + struct usb_interface *udev = IntfAdapter->interface; + struct usb_device *xdev = IntfAdapter->udev; + + if (netif_msg_probe(Adapter)) + dev_info(&udev->dev, PFX "%s: unregister usb-%s%s\n", + net->name, xdev->bus->bus_name, xdev->devpath); + + unregister_netdev(Adapter->dev); +} |
