#ifndef LINUX_COMPATIBILITY_H
#define LINUX_COMPATIBILITY_H

/*
 * Definition and macro
 */

#include <linux/init.h>
#include <linux/version.h>
#include <linux/in.h>
#include <linux/acpi.h>

#if defined(RTL8152_S5_WOL) && defined(CONFIG_PM)
#include <linux/reboot.h>
#endif /* defined(RTL8152_S5_WOL) && defined(CONFIG_PM) */

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31)
	#include <linux/mdio.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
	#include <uapi/linux/mdio.h>
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0) */
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31) */

#if LINUX_VERSION_CODE < KERNEL_VERSION(5,19,0)
	#define TSO_LEGACY_MAX_SIZE		65536
	#define netif_napi_add_weight		netif_napi_add
	#define netif_set_tso_max_size		netif_set_gso_max_size
	#define netif_set_tso_max_segs		netif_set_gso_max_segs
#if LINUX_VERSION_CODE < KERNEL_VERSION(5,17,0)
#if LINUX_VERSION_CODE < KERNEL_VERSION(5,15,0)
#if LINUX_VERSION_CODE < KERNEL_VERSION(5,12,0)
	#define PHY_MAC_INTERRUPT		PHY_IGNORE_INTERRUPT
#if LINUX_VERSION_CODE < KERNEL_VERSION(5,9,0)
	#ifdef CONFIG_PM
	#define pm_ptr(_ptr) (_ptr)
	#else
	#define pm_ptr(_ptr) NULL
	#endif

	#define from_tasklet(var, callback_tasklet, tasklet_fieldname)	\
		container_of((struct tasklet_struct *)callback_tasklet, typeof(*var), tasklet_fieldname)

	#define tasklet_setup(t, fun)	tasklet_init(t, fun, (unsigned long)t)
#if LINUX_VERSION_CODE < KERNEL_VERSION(5,8,0)
#if LINUX_VERSION_CODE < KERNEL_VERSION(5,7,0)
#if LINUX_VERSION_CODE < KERNEL_VERSION(5,6,0)
	/* Iterate through singly-linked GSO fragments of an skb. */
	#define skb_list_walk_safe(first, skb, next_skb)                               \
		for ((skb) = (first), (next_skb) = (skb) ? (skb)->next : NULL; (skb);  \
		     (skb) = (next_skb), (next_skb) = (skb) ? (skb)->next : NULL)
#if LINUX_VERSION_CODE < KERNEL_VERSION(5,4,0)
	#ifndef __has_attribute
	# define __has_attribute(x)         0
	#endif

	#if __has_attribute(__fallthrough__)
	# define fallthrough                    __attribute__((__fallthrough__))
	#else
	# define fallthrough                    do {} while (0)  /* fallthrough */
	#endif

	#define MDIO_EEE_2_5GT			0x0001  /* 2.5GT EEE cap */
	#define MDIO_EEE_5GT			0x0002  /* 5GT EEE cap */
#if LINUX_VERSION_CODE < KERNEL_VERSION(5,2,0)
#if LINUX_VERSION_CODE < KERNEL_VERSION(5,1,0)
	#define MDIO_AN_10GBT_CTRL_ADV2_5G	0x0080  /* Advertise 2.5GBASE-T */
	#define MDIO_AN_10GBT_CTRL_ADV5G	0x0100  /* Advertise 5GBASE-T */
	#define MDIO_AN_10GBT_STAT_LP2_5G	0x0020  /* LP is 2.5GBT capable */
	#define MDIO_AN_10GBT_STAT_LP5G		0x0040  /* LP is 5GBT capable */
#if LINUX_VERSION_CODE < KERNEL_VERSION(5,0,0)
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,20,0)
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,12,0)
	#define SPEED_2500				2500
	#define SPEED_5000				5000
	#define SPEED_25000				25000
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,10,0)
	#ifndef ETHTOOL_LINK_MODE_2500baseT_Full_BIT
	#define ETHTOOL_LINK_MODE_2500baseT_Full_BIT	ETHTOOL_LINK_MODE_2500baseX_Full_BIT
	#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,9,0)
	#define BMCR_SPEED10				0x0000
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,5,0)
	#define NETIF_F_CSUM_MASK			NETIF_F_ALL_CSUM
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,1,0)
	#define IS_REACHABLE(option)			(defined(option) || \
							 (defined(option##_MODULE) && defined(MODULE)))
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0)
	#define skb_vlan_tag_present(__skb)		vlan_tx_tag_present(__skb)
	#define skb_vlan_tag_get(__skb)			vlan_tx_tag_get(__skb)
	#define skb_vlan_tag_get_id(__skb)		vlan_tx_tag_get_id(__skb)
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,19,0)
	#define napi_alloc_skb(napi, length)		netdev_alloc_skb_ip_align(netdev,length)
	#define napi_complete_done(n, d)		napi_complete(n)
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,16,0)
	#ifndef smp_mb__before_atomic
	#define smp_mb__before_atomic()			smp_mb()
	#endif

	#ifndef smp_mb__after_atomic
	#define smp_mb__after_atomic()			smp_mb()
	#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,15,0)
	#define IS_ERR_OR_NULL(ptr)			(!ptr)

#if LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0)
	#define ether_addr_copy(dst, src)		memcpy(dst, src, ETH_ALEN)
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0)
	#define BIT(nr)					(1UL << (nr))
	#define BIT_ULL(nr)				(1ULL << (nr))
	#define BITS_PER_BYTE				8
	#define reinit_completion(x)			((x)->done = 0)
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,12,0)
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,11,0)
	#define DEVICE_ATTR_RW(_name) \
		struct device_attribute dev_attr_##_name = __ATTR(_name, 0644, _name##_show, _name##_store)
	#define DEVICE_ATTR_RO(_name) \
		struct device_attribute dev_attr_##_name = __ATTR_RO(_name)
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0)
	#define NETIF_F_HW_VLAN_CTAG_RX			NETIF_F_HW_VLAN_RX
	#define NETIF_F_HW_VLAN_CTAG_TX			NETIF_F_HW_VLAN_TX
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0)
	#define USB_DEVICE_INTERFACE_CLASS(vend, prod, cl) \
		.match_flags = USB_DEVICE_ID_MATCH_DEVICE | \
			       USB_DEVICE_ID_MATCH_INT_CLASS, \
		.idVendor = (vend), \
		.idProduct = (prod), \
		.bInterfaceClass = (cl)

#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)
	#ifndef SPEED_UNKNOWN
		#define SPEED_UNKNOWN		0
	#endif

	#ifndef DUPLEX_UNKNOWN
		#define DUPLEX_UNKNOWN		0xff
	#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,6,0)
	#define eth_random_addr(addr)			random_ether_addr(addr)
	#define usb_enable_lpm(udev)
	#define MDIO_EEE_100TX				MDIO_AN_EEE_ADV_100TX	/* 100TX EEE cap */
	#define MDIO_EEE_1000T				MDIO_AN_EEE_ADV_1000T	/* 1000T EEE cap */
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,4,0)
	#define ETH_MDIO_SUPPORTS_C22			MDIO_SUPPORTS_C22

#if LINUX_VERSION_CODE < KERNEL_VERSION(3,3,0)
	#define module_usb_driver(__driver) \
	static int __init __driver##_init(void) \
	{ \
		return usb_register(&(__driver)); \
	} \
	module_init(__driver##_init); \
	static void __exit __driver##_exit(void) \
	{ \
		usb_deregister(&(__driver)); \
	} \
	module_exit(__driver##_exit);

	#define netdev_features_t			u32
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,2,0)
	#define PMSG_IS_AUTO(msg)	(((msg).event & PM_EVENT_AUTO) != 0)

#if LINUX_VERSION_CODE < KERNEL_VERSION(3,1,0)
	#define ndo_set_rx_mode				ndo_set_multicast_list
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,39)
	#define NETIF_F_RXCSUM				(1 << 29) /* Receive checksumming offload */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38)
	#define MDIO_AN_EEE_ADV				60	/* EEE advertisement */
	#define MDIO_AN_EEE_ADV_100TX			0x0002	/* Advertise 100TX EEE cap */
	#define MDIO_AN_EEE_ADV_1000T			0x0004	/* Advertise 1000T EEE cap */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)
	#define skb_checksum_none_assert(skb_ptr)	(skb_ptr)->ip_summed = CHECKSUM_NONE

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36)
	#define skb_tx_timestamp(skb)

	#define queue_delayed_work(long_wq, work, delay)	schedule_delayed_work(work, delay)

	#define work_busy(x)				0
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34)
	#define netdev_mc_count(netdev)			((netdev)->mc_count)
	#define netdev_mc_empty(netdev)			(netdev_mc_count(netdev) == 0)

	#define netif_printk(priv, type, level, netdev, fmt, args...)	\
	do {								\
		if (netif_msg_##type(priv))				\
			printk(level "%s: " fmt,(netdev)->name , ##args); \
	} while (0)

	#define netif_emerg(priv, type, netdev, fmt, args...)		\
		netif_printk(priv, type, KERN_EMERG, netdev, fmt, ##args)
	#define netif_alert(priv, type, netdev, fmt, args...)		\
		netif_printk(priv, type, KERN_ALERT, netdev, fmt, ##args)
	#define netif_crit(priv, type, netdev, fmt, args...)		\
		netif_printk(priv, type, KERN_CRIT, netdev, fmt, ##args)
	#define netif_err(priv, type, netdev, fmt, args...)		\
		netif_printk(priv, type, KERN_ERR, netdev, fmt, ##args)
	#define netif_warn(priv, type, netdev, fmt, args...)		\
		netif_printk(priv, type, KERN_WARNING, netdev, fmt, ##args)
	#define netif_notice(priv, type, netdev, fmt, args...)		\
		netif_printk(priv, type, KERN_NOTICE, netdev, fmt, ##args)
	#define netif_info(priv, type, netdev, fmt, args...)		\
		netif_printk(priv, type, KERN_INFO, (netdev), fmt, ##args)

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)
	#define get_sset_count				get_stats_count

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
	#define pm_request_resume(para)
	#define pm_runtime_set_suspended(para)
	#define pm_schedule_suspend(para1, para2)
	#define pm_runtime_get_sync(para)
	#define pm_runtime_put_sync(para)
	#define pm_runtime_put_noidle(para)
	#define pm_runtime_idle(para)
	#define pm_runtime_set_active(para)
	#define pm_runtime_enable(para)
	#define pm_runtime_disable(para)
	typedef int netdev_tx_t;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31)
	#define USB_SPEED_SUPER				(USB_SPEED_VARIABLE + 1)
	#define MDIO_MMD_AN				7	/* Auto-Negotiation */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)
	#define napi_gro_receive(napi, skb)		netif_receive_skb(skb)
	#define vlan_gro_receive(napi, grp, vlan_tci, skb) \
		vlan_hwaccel_receive_skb(skb, grp, vlan_tci)

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
	#define PM_EVENT_AUTO		0x0400

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
	struct napi_struct {
		struct list_head	poll_list;
		unsigned long		state;
		int			weight;
		int			(*poll)(struct napi_struct *, int);
	#ifdef CONFIG_NETPOLL
		spinlock_t		poll_lock;
		int			poll_owner;
		struct net_device	*dev;
		struct list_head	dev_list;
	#endif
	};

	#define napi_enable(napi_ptr)			netif_poll_enable(container_of(napi_ptr, struct r8152, napi)->netdev)
	#define napi_disable(napi_ptr)			netif_poll_disable(container_of(napi_ptr, struct r8152, napi)->netdev)
	#define napi_schedule(napi_ptr)			netif_rx_schedule(container_of(napi_ptr, struct r8152, napi)->netdev)
	#define napi_complete(napi_ptr)			netif_rx_complete(container_of(napi_ptr, struct r8152, napi)->netdev)
	#define netif_napi_add(ndev, napi_ptr, function, weight_t) \
		ndev->poll = function; \
		ndev->weight = weight_t;
	typedef unsigned long				uintptr_t;
	#define DMA_BIT_MASK(value) \
		(value < 64 ? ((1ULL << value) - 1) : 0xFFFFFFFFFFFFFFFFULL)
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
	#define NETIF_F_IPV6_CSUM			16
	#define cancel_delayed_work_sync		cancel_delayed_work

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
	#define ip_hdr(skb_ptr)				(skb_ptr)->nh.iph
	#define ipv6hdr(skb_ptr)			(skb_ptr)->nh.ipv6h

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)
	#define vlan_group_set_device(vlgrp, vid, value) \
		if (vlgrp) \
			(vlgrp)->vlan_devices[vid] = value;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
	#define delayed_work				work_struct
	#define INIT_DELAYED_WORK(a,b)			INIT_WORK(a,b,tp)
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
	#define CHECKSUM_PARTIAL			CHECKSUM_HW

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
	#define skb_is_gso(skb_ptr)			skb_shinfo(skb_ptr)->tso_size
	#define netdev_alloc_skb(dev, len)		dev_alloc_skb(len)
	#define IRQF_SHARED				SA_SHIRQ

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)
	#ifndef __LINUX_MUTEX_H
	#define mutex					semaphore
	#define mutex_lock				down
	#define mutex_unlock				up
	#define mutex_trylock				down_trylock
	#define mutex_lock_interruptible		down_interruptible
	#define mutex_init				init_MUTEX
	#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
	#define ADVERTISED_Pause			(1 << 13)
	#define ADVERTISED_Asym_Pause			(1 << 14)
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12)
	#define skb_header_cloned(skb)			skb_cloned(skb)
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) */
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14) */
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16) */
	static inline struct sk_buff *skb_gso_segment(struct sk_buff *skb, int features)
	{
		return NULL;
	}
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) */
	static inline void *kmemdup(const void *src, size_t len, gfp_t gfp)
	{
		void *p;

		p = kmalloc_track_caller(len, gfp);
		if (p)
			memcpy(p, src, len);
		return p;
	}
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) */
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) */
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21) */
	static inline void skb_copy_from_linear_data(const struct sk_buff *skb,
						     void *to,
						     const unsigned int len)
	{
		memcpy(to, skb->data, len);
	}
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) */
	static inline int skb_cow_head(struct sk_buff *skb, unsigned int headroom)
	{
		int delta = 0;

		if (headroom > skb_headroom(skb))
			delta = headroom - skb_headroom(skb);

		if (delta || skb_header_cloned(skb))
			return pskb_expand_head(skb, ALIGN(delta, NET_SKB_PAD),
						0, GFP_ATOMIC);
		return 0;
	}
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) */
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) */
	static inline void __list_splice2(const struct list_head *list,
					  struct list_head *prev,
					  struct list_head *next)
	{
		struct list_head *first = list->next;
		struct list_head *last = list->prev;

		first->prev = prev;
		prev->next = first;

		last->next = next;
		next->prev = last;
	}

	static inline void list_splice_tail(struct list_head *list,
					    struct list_head *head)
	{
		if (!list_empty(list))
			__list_splice2(list, head->prev, head);
	}

	static inline void netif_napi_del(struct napi_struct *napi)
	{
	#ifdef CONFIG_NETPOLL
		list_del(&napi->dev_list);
	#endif
	}
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) */
	static inline void __skb_queue_splice(const struct sk_buff_head *list,
					      struct sk_buff *prev,
					      struct sk_buff *next)
	{
		struct sk_buff *first = list->next;
		struct sk_buff *last = list->prev;

		first->prev = prev;
		prev->next = first;

		last->next = next;
		next->prev = last;
	}

	static inline void skb_queue_splice(const struct sk_buff_head *list,
					    struct sk_buff_head *head)
	{
		if (!skb_queue_empty(list)) {
			__skb_queue_splice(list, (struct sk_buff *) head, head->next);
			head->qlen += list->qlen;
		}
	}

	static inline void __skb_queue_head_init(struct sk_buff_head *list)
	{
		list->prev = list->next = (struct sk_buff *)list;
		list->qlen = 0;
	}

	static inline void skb_queue_splice_init(struct sk_buff_head *list,
						 struct sk_buff_head *head)
	{
		if (!skb_queue_empty(list)) {
			__skb_queue_splice(list, (struct sk_buff *) head, head->next);
			head->qlen += list->qlen;
			__skb_queue_head_init(list);
		}
	}
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28) */
	static inline void usb_autopm_put_interface_async(struct usb_interface *intf)
	{
		struct usb_device *udev = interface_to_usbdev(intf);
		int status = 0;

		if (intf->condition == USB_INTERFACE_UNBOUND) {
			status = -ENODEV;
		} else {
			udev->last_busy = jiffies;
			--intf->pm_usage_cnt;
			if (udev->autosuspend_disabled || udev->autosuspend_delay < 0)
				status = -EPERM;
		}
	}

	static inline int usb_autopm_get_interface_async(struct usb_interface *intf)
	{
		struct usb_device *udev = interface_to_usbdev(intf);
		int status = 0;

		if (intf->condition == USB_INTERFACE_UNBOUND)
			status = -ENODEV;
		else if (udev->autoresume_disabled)
			status = -EPERM;
		else
			++intf->pm_usage_cnt;
		return status;
	}

	static inline 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;
	}
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29) */
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31) */
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32) */
	static inline
	struct sk_buff *netdev_alloc_skb_ip_align(struct net_device *dev,
						  unsigned int length)
	{
		struct sk_buff *skb = netdev_alloc_skb(dev, length + NET_IP_ALIGN);

		if (NET_IP_ALIGN && skb)
			skb_reserve(skb, NET_IP_ALIGN);
		return skb;
	}
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33) */
	static inline int usb_enable_autosuspend(struct usb_device *udev)
	{ return 0; }
	static inline int usb_disable_autosuspend(struct usb_device *udev)
	{ return 0; }
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34) */
	static inline bool pci_dev_run_wake(struct pci_dev *dev)
	{
		return 1;
	}
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) */
	static inline void usleep_range(unsigned long min, unsigned long max)
	{
		unsigned long ms = min / 1000;

		if (ms)
			mdelay(ms);

		udelay(min % 1000);
	}

#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) */
	static inline __be16 vlan_get_protocol(const struct sk_buff *skb)
	{
		__be16 protocol = 0;

		if (vlan_tx_tag_present(skb) ||
		    skb->protocol != cpu_to_be16(ETH_P_8021Q))
			protocol = skb->protocol;
		else {
			__be16 proto, *protop;
			protop = skb_header_pointer(skb, offsetof(struct vlan_ethhdr,
						    h_vlan_encapsulated_proto),
						    sizeof(proto), &proto);
			if (likely(protop))
				protocol = *protop;
		}

		return protocol;
	}
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37) */
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) */
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,39) */
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3,1,0) */
	static inline struct page *skb_frag_page(const skb_frag_t *frag)
	{
		return frag->page;
	}

	static inline void *skb_frag_address(const skb_frag_t *frag)
	{
		return page_address(skb_frag_page(frag)) + frag->page_offset;
	}

	static inline unsigned int skb_frag_size(const skb_frag_t *frag)
	{
		return frag->size;
	}
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3,2,0) */
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3,3,0) */
	static inline void eth_hw_addr_random(struct net_device *dev)
	{
		random_ether_addr(dev->dev_addr);
	}
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3,4,0) */
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3,6,0) */
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0) */
	static inline __sum16 tcp_v6_check(int len,
					   const struct in6_addr *saddr,
					   const struct in6_addr *daddr,
					   __wsum base)
	{
		return csum_ipv6_magic(saddr, daddr, len, IPPROTO_TCP, base);
	}
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0) */
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) */
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3,11,0) */
	static inline bool usb_device_no_sg_constraint(struct usb_device *udev)
	{
		return 0;
	}
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3,12,0) */
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0) */
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0) */
	static inline int skb_to_sgvec_nomark(struct sk_buff *skb,
					      struct scatterlist *sg,
					      int offset, int len)
	{
		int nsg = skb_to_sgvec(skb, sg, offset, len);

		if (nsg <= 0)
			return nsg;

		sg_unmark_end(&sg[nsg - 1]);

		return nsg;
	}
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3,15,0) */
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3,16,0) */
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3,19,0) */
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) */
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4,1,0) */
	static inline int eth_platform_get_mac_address(struct device *dev, u8 *mac_addr)
	{
		return -EOPNOTSUPP;
	}
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4,5,0) */
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4,9,0) */
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4,10,0) */
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4,12,0) */
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,19,10) && \
    !(LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,217) && LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0))
	static inline void skb_mark_not_on_list(struct sk_buff *skb)
	{
		skb->next = NULL;
	}
#endif
	static inline void linkmode_set_bit(int nr, volatile unsigned long *addr)
	{
		__set_bit(nr, addr);
	}

	static inline void linkmode_clear_bit(int nr, volatile unsigned long *addr)
	{
		__clear_bit(nr, addr);
	}

	static inline int linkmode_test_bit(int nr, volatile unsigned long *addr)
	{
		return test_bit(nr, addr);
	}

#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4,20,0) */
	static inline void linkmode_mod_bit(int nr, volatile unsigned long *addr,
					    int set)
	{
		if (set)
			linkmode_set_bit(nr, addr);
		else
			linkmode_clear_bit(nr, addr);
	}
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5,0,0) */
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5,1,0) */
//	static inline u16 pci_dev_id(struct pci_dev *dev)
//	{
//		return PCI_DEVID(dev->bus->number, dev->devfn);
//	}
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5,2,0) */
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5,4,0) */
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5,6,0) */
	static inline void tcp_v6_gso_csum_prep(struct sk_buff *skb)
	{
		struct ipv6hdr *ipv6h = ipv6_hdr(skb);
		struct tcphdr *th = tcp_hdr(skb);

		ipv6h->payload_len = 0;
		th->check = ~tcp_v6_check(0, &ipv6h->saddr, &ipv6h->daddr, 0);
	}
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5,7,0) */
	static inline void fsleep(unsigned long usecs)
	{
		if (usecs <= 10)
			udelay(usecs);
		else if (usecs <= 20000)
			usleep_range(usecs, 2 * usecs);
		else
			msleep(DIV_ROUND_UP(usecs, 1000));
	}
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5,8,0) */
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5,9,0) */
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5,12,0) */
	#if LINUX_VERSION_CODE < KERNEL_VERSION(5,10,188) || LINUX_VERSION_CODE >= KERNEL_VERSION(5,11,0)
	#if LINUX_VERSION_CODE < KERNEL_VERSION(5,4,251) || LINUX_VERSION_CODE >= KERNEL_VERSION(5,5,0)
	#if LINUX_VERSION_MAJOR != 4 || LINUX_VERSION_PATCHLEVEL != 19 || LINUX_VERSION_SUBLEVEL < 291
	static inline void eth_hw_addr_set(struct net_device *dev, const u8 *addr)
	{
		memcpy(dev->dev_addr, addr, 6);
	}
	#endif /* LINUX_VERSION_MAJOR != 4 || LINUX_VERSION_PATCHLEVEL != 19 || LINUX_VERSION_SUBLEVEL < 291 */
	#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5,4,251) || LINUX_VERSION_CODE >= KERNEL_VERSION(5,5,0) */
	#endif /*LINUX_VERSION_CODE < KERNEL_VERSION(5,10,188) || LINUX_VERSION_CODE >= KERNEL_VERSION(5,11,0) */
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5,15,0) */
	static inline void netif_set_gso_max_segs(struct net_device *dev,
						  unsigned int segs)
	{
		/* dev->gso_max_segs is read locklessly from sk_setup_caps() */
		WRITE_ONCE(dev->gso_max_segs, segs);
	}
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5,17,0) */
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5,19,0) */

#ifndef FALSE
	#define TRUE	1
	#define FALSE	0
#endif

enum rtl_cmd {
	RTLTOOL_PLA_OCP_READ_DWORD = 0,
	RTLTOOL_PLA_OCP_WRITE_DWORD,
	RTLTOOL_USB_OCP_READ_DWORD,
	RTLTOOL_USB_OCP_WRITE_DWORD,
	RTLTOOL_PLA_OCP_READ,
	RTLTOOL_PLA_OCP_WRITE,
	RTLTOOL_USB_OCP_READ,
	RTLTOOL_USB_OCP_WRITE,
	RTLTOOL_USB_INFO,
	RTL_ENABLE_USB_DIAG,
	RTL_DISABLE_USB_DIAG,

	RTLTOOL_INVALID
};

struct usb_device_info {
	__u16		idVendor;
	__u16		idProduct;
	__u16		bcdDevice;
	__u8		dev_addr[8];
	char		devpath[16];
};

struct rtltool_cmd {
	__u32	cmd;
	__u32	offset;
	__u32	byteen;
	__u32	data;
	void	*buf;
	struct usb_device_info nic_info;
	struct sockaddr ifru_addr;
	struct sockaddr ifru_netmask;
	struct sockaddr ifru_hwaddr;
};

#endif /* LINUX_COMPATIBILITY_H */
