#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) { 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); strcpy(info->driver, DRV_NAME); strcpy(info->version, DRV_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); }