/*
 * Copyright 2007-2010	Luis R. Rodriguez <mcgrof@winlab.rutgers.edu>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * Backport functionality introduced in Linux 2.6.29.
 */

#include <linux/compat.h>
#include <linux/usb.h>
#include <linux/etherdevice.h>

/*
 * If you don't see your net_device_ops implemented on
 * netdev_attach_ops() then you are shit out of luck and
 * you must do the nasty ifdef magic, unless you figure
 * out a way to squeze your hacks into this routine :)
 */
void netdev_attach_ops(struct net_device *dev,
		       const struct net_device_ops *ops)
{
	if (!ops)
		return;

	dev->open = ops->ndo_open;
	dev->init = ops->ndo_init;
	dev->stop = ops->ndo_stop;
	dev->hard_start_xmit = ops->ndo_start_xmit;
	dev->change_rx_flags = ops->ndo_change_rx_flags;
	dev->set_multicast_list = ops->ndo_set_multicast_list;
	dev->validate_addr = ops->ndo_validate_addr;
	dev->do_ioctl = ops->ndo_do_ioctl;
	dev->set_config = ops->ndo_set_config;
	dev->change_mtu = ops->ndo_change_mtu;
	dev->set_mac_address = ops->ndo_set_mac_address;
	dev->tx_timeout = ops->ndo_tx_timeout;
	if (ops->ndo_get_stats)
		dev->get_stats = ops->ndo_get_stats;
	dev->vlan_rx_register = ops->ndo_vlan_rx_register;
	dev->vlan_rx_add_vid = ops->ndo_vlan_rx_add_vid;
	dev->vlan_rx_kill_vid = ops->ndo_vlan_rx_kill_vid;
#ifdef CONFIG_NET_POLL_CONTROLLER
	dev->poll_controller = ops->ndo_poll_controller;
#endif

#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))
	dev->select_queue = ops->ndo_select_queue;
#endif
}
EXPORT_SYMBOL_GPL(netdev_attach_ops);

#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23))
#if defined(CONFIG_USB) || defined(CONFIG_USB_MODULE)
/**
 * usb_unpoison_anchored_urbs - let an anchor be used successfully again
 * @anchor: anchor the requests are bound to
 *
 * Reverses the effect of usb_poison_anchored_urbs
 * the anchor can be used normally after it returns
 */
void usb_unpoison_anchored_urbs(struct usb_anchor *anchor)
{
	unsigned long flags;
	struct urb *lazarus;

	spin_lock_irqsave(&anchor->lock, flags);
	list_for_each_entry(lazarus, &anchor->urb_list, anchor_list) {
		usb_unpoison_urb(lazarus);
	}
	//anchor->poisoned = 0; /* XXX: cannot backport */
	spin_unlock_irqrestore(&anchor->lock, flags);
}
EXPORT_SYMBOL_GPL(usb_unpoison_anchored_urbs);
#endif /* CONFIG_USB */
#endif

/**
 * eth_mac_addr - set new Ethernet hardware address
 * @dev: network device
 * @p: socket address
 * Change hardware address of device.
 *
 * This doesn't change hardware matching, so needs to be overridden
 * for most real devices.
 */
int eth_mac_addr(struct net_device *dev, void *p)
{
	struct sockaddr *addr = p;

	if (netif_running(dev))
		return -EBUSY;
	if (!is_valid_ether_addr(addr->sa_data))
		return -EADDRNOTAVAIL;
	memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
	return 0;
}
EXPORT_SYMBOL_GPL(eth_mac_addr);

/**
 * eth_change_mtu - set new MTU size
 * @dev: network device
 * @new_mtu: new Maximum Transfer Unit
 *
 * Allow changing MTU size. Needs to be overridden for devices
 * supporting jumbo frames.
 */
int eth_change_mtu(struct net_device *dev, int new_mtu)
{
	if (new_mtu < 68 || new_mtu > ETH_DATA_LEN)
		return -EINVAL;
	dev->mtu = new_mtu;
	return 0;
}
EXPORT_SYMBOL_GPL(eth_change_mtu);

int eth_validate_addr(struct net_device *dev)
{
	if (!is_valid_ether_addr(dev->dev_addr))
		return -EADDRNOTAVAIL;

	return 0;
}
EXPORT_SYMBOL_GPL(eth_validate_addr);
/* Source: net/ethernet/eth.c */

#define NETREG_DUMMY 5
/**
 *	init_dummy_netdev	- init a dummy network device for NAPI
 *	@dev: device to init
 *
 *	This takes a network device structure and initialize the minimum
 *	amount of fields so it can be used to schedule NAPI polls without
 *	registering a full blown interface. This is to be used by drivers
 *	that need to tie several hardware interfaces to a single NAPI
 *	poll scheduler due to HW limitations.
 */
int init_dummy_netdev(struct net_device *dev)
{
	/* Clear everything. Note we don't initialize spinlocks
	 * are they aren't supposed to be taken by any of the
	 * NAPI code and this dummy netdev is supposed to be
	 * only ever used for NAPI polls
	 */
	memset(dev, 0, sizeof(struct net_device));

	/* make sure we BUG if trying to hit standard
	 * register/unregister code path
	 */
	dev->reg_state = NETREG_DUMMY;

	/* initialize the ref count */
	atomic_set(&dev->refcnt, 1);

#ifdef CONFIG_NETPOLL
	/* NAPI wants this */
	INIT_LIST_HEAD(&dev->napi_list);
#endif

	/* a dummy interface is started by default */
	set_bit(__LINK_STATE_PRESENT, &dev->state);
	set_bit(__LINK_STATE_START, &dev->state);

	return 0;
}
EXPORT_SYMBOL_GPL(init_dummy_netdev);
/* Source: net/core/dev.c */

