# Test passing $(1) to $(CC). If $(CC) succeeds, then echo $(1).
# Copy from https://github.com/NVIDIA/open-gpu-kernel-modules/blob/main/utils.mk
TEST_CC_ARG = \
 $(shell $(CC) -c -x c /dev/null -Werror $(1) -o /dev/null > /dev/null 2>&1 && \
   echo $(1))

ifeq ($(ARCH),ARM64)
	ARCH:=arm64
endif

ifneq ($(RDMA_ENABLED),)
	ifeq ($(RDMA_ENABLED),1)
		NVIDIA_VERSION := $(shell modinfo nvidia | grep '^version:' | awk '{print $$2}')
		ifeq ($(NVIDIA_VERSION),)
$(error RDMA_ENABLED=1 but NVIDIA driver not detected! Please install NVIDIA driver or set RDMA_ENABLED=0)
		endif
$(info >> NVIDIA driver version detected : $(NVIDIA_VERSION))
		NVIDIA_SRC := $(shell ls -d /usr/src/nvidia-$(NVIDIA_VERSION) 2>/dev/null || echo "")
$(info >> NVIDIA driver version detected: $(NVIDIA_VERSION)	at $(NVIDIA_SRC))

		# Find nv-p2p.h header
		NVIDIA_P2P_HEADER := $(shell find $(NVIDIA_SRC) -type f -name nv-p2p.h 2>/dev/null | head -n1)
		NVIDIA_P2P_DIR := $(dir $(NVIDIA_P2P_HEADER))

		ifeq ($(NVIDIA_P2P_HEADER),)
$(error RDMA_ENABLED=1 but nv-p2p.h not found in $(NVIDIA_SRC)!)
		endif

		EXTRA_CFLAGS += -DRDMA_ENABLED=1

		# Optional: Disable GPL_ONLY_SYMBOLS for some platforms
		# Set NO_GPL_ONLY_SYMBOLS=1 if you get "Unknown symbol nvidia_p2p_* (err -22)" errors
		ifdef NO_GPL_ONLY_SYMBOLS
			ifeq ($(NO_GPL_ONLY_SYMBOLS),1)
$(info >> NO_GPL_ONLY_SYMBOLS flag enabled)
				EXTRA_CFLAGS += -DNO_GPL_ONLY_SYMBOLS
			endif
		endif

		# Find Module.symvers in multiple locations (DKMS may clean build dir)
		NVIDIA_MODULE_SYMVERS := $(shell \
			find $(NVIDIA_SRC) -type f -name Module.symvers 2>/dev/null | head -n1 || \
			find /var/lib/dkms/nvidia/$(NVIDIA_VERSION)/build -name Module.symvers 2>/dev/null | head -n1 || \
			find /var/lib/dkms/nvidia/$(NVIDIA_VERSION)/$(shell uname -r) -name Module.symvers 2>/dev/null | head -n1 || \
			echo "")

		# If Module.symvers not found, try to build it automatically (optional)
		ifeq ($(NVIDIA_MODULE_SYMVERS),)
			ifneq ($(NVIDIA_SRC),)
$(warning >> Module.symvers not found - attempting to build NVIDIA modules...)
				NVIDIA_BUILD_RESULT := $(shell cd $(NVIDIA_SRC) && $(MAKE) modules > /tmp/nvidia-build.log 2>&1 && echo "success" || echo "failed")
				ifeq ($(NVIDIA_BUILD_RESULT),success)
					NVIDIA_MODULE_SYMVERS := $(shell find $(NVIDIA_SRC) -type f -name Module.symvers 2>/dev/null | head -n1)
$(warning >> Module.symvers successfully created at: $(NVIDIA_MODULE_SYMVERS))
				else
$(error >> Failed to build NVIDIA modules. Check /tmp/nvidia-build.log)
				endif
			endif
		endif

		EXTRA_CFLAGS += -DRDMA_ENABLED=1

		ifneq ($(NVIDIA_P2P_HEADER),)
$(info >> nv-p2p.h found at: $(NVIDIA_P2P_HEADER))
			EXTRA_CFLAGS += -I$(NVIDIA_P2P_DIR)
		endif

$(info >> Module.symvers found at: $(NVIDIA_MODULE_SYMVERS))
		KBUILD_EXTRA_SYMBOLS := $(NVIDIA_MODULE_SYMVERS)
	else
$(info >> RDMA_ENABLED is set to 0)
	endif
else
$(info >> RDMA_ENABLED not defined, defaulting to 0)
endif

SHELL := /bin/bash

DRIVERNAME = delta-x300

BINARY-OBJS := X3XXDrvBoard.o XDrvBoard.o BufMngr.o DMABufMngr.o DMAMngr.o PropertiesMngr.o ShadowRegisters.o SkelDrv.o CommonBufMngr.o KernelObjectCommon.o SkelProperties.o Stream.o StreamProperties.o PCIeBridge_ADVLP.o FPGA_DMAController_ADVLP.o USBufMngr.o ArmUart.o DrvDbg.o EventMngr.o NorFlash.o X300DrvBoard.o X320DrvBoard.o X330DrvBoard.o X34XDrvBoard.o X340DrvBoard.o X341DrvBoard.o X350DrvBoard.o X370DrvBoard.o  X370HmiDrvBoard.o X370SdiAsiDrvBoard.o X380DrvBoard.o MailboxMngr.o LowLatencyMngr.o UltimateLowLatencyMngr.o Scp.o X330Drv_NorFlash2Functions.o X34XDrv_NorFlash2Functions.o X3XXDrv_NorFlash2Functions.o NorFlash2.o NorFlash2_Manager.o NorFlash2_ComplexOperations.o NorFlash2_BasicOperations.o NorFlash2_Helper.o RegisterWaiter.o ConfigurationSpaceMngr.o ClockReconstructionMngr.o DelayedStreamStarterMngr.o SdiDrvBoard.o LtcMngr.o DvDrvBoard.o HpdMngr.o BramStatusMngr.o HDMIInfoFrames.o ScpDv.o XDvDrv_Properties.o XDv_Helper.o XSdi_Helper.o

SRC-OBJS :=  CommonBufMngr_Linux.o DriverAccess.o DriverEntry.o DrvParam.o EventMngr_Linux.o KernelObjects.o KernelSysCall.o LinuxDrvHlp.o USBufMngr_Linux.o KThreadMngr.o InterlockedOp.o DMAMngr_Linux.o KernelTime.o NvidiaP2PWrapper.o

# default to currently running kernel if KVER not specified
ifeq ($(KVER),)
	KVER := $(shell uname -r)
endif

KERNEL_MAJOR := $(shell echo $(KVER) | cut -d. -f1)

ifeq ($(shell [ $(KERNEL_MAJOR) -le 5 ] && echo true),true)
	USE_SHIPPED := 0
else
	USE_SHIPPED := 1
endif

KDIR ?= /lib/modules/$(KVER)/build
INSTALLDIR ?= /lib/modules/$(KVER)
PWD := $(shell pwd)

# Conditionally add -mno-outline-atomics to CFLAGS if it is supported
CONDITIONAL_CFLAGS := $(call TEST_CC_ARG, -mno-outline-atomics)

EXTRA_CFLAGS += -DMEM_ALLOC_METHOD=Dynamic
EXTRA_CFLAGS += -w -DDBG=0 -DDRIVER -DNO_C_LIB
EXTRA_CFLAGS += $(CFLAGS)
EXTRA_CFLAGS += -fno-stack-protector
EXTRA_CFLAGS += -Wno-error=incompatible-pointer-types
EXTRA_CFLAGS += $(CONDITIONAL_CFLAGS)

ifneq ($(KERNELRELEASE),)

obj-m := $(DRIVERNAME).o

ifeq ($(USE_SHIPPED),1)
	$(DRIVERNAME)-objs := $(SRC-OBJS) $(BINARY-OBJS:.o=.o_shipped)
else
	$(DRIVERNAME)-objs := $(SRC-OBJS) $(BINARY-OBJS)
endif

else

ifndef VERBOSE
.SILENT: all
endif

all: gencmd default

default:
		
	for file in *.o_shipped; do if ! file "$$file" | grep -q 'ELF'; then xxd -p -r "$$file" > "$${file/.o_shipped/}.c"; fi; done

		@trap '$(MAKE) shipped_cleanup' EXIT ; $(MAKE) -C $(KDIR) M=$(PWD) modules

gencmd:
ifeq ($(USE_SHIPPED),1)
		for file in $(BINARY-OBJS:.o=.o_shipped); do touch .$${file}.cmd; done
else
		for file in $(BINARY-OBJS); do touch .$${file}.cmd; done
endif

genbin:
		for file in $(BINARY-OBJS); do echo "X" > $${file/.o/}.o_shipped; done

install:
		# Driver installation
		cp $(DRIVERNAME).ko $(INSTALLDIR)/$(DRIVERNAME).ko
		cp $(DRIVERNAME).rules /etc/udev/$(DRIVERNAME).rules
		if [ ! -f /etc/udev/rules.d/010-$(DRIVERNAME).rules ]; then ln -sf /etc/udev/$(DRIVERNAME).rules /etc/udev/rules.d/010-$(DRIVERNAME).rules; fi
		depmod -a
		modprobe -rq $(DRIVERNAME)
		modprobe $(DRIVERNAME)
		@for files in /dev/$(DRIVERNAME)*; do if [ ! -r files ]; then ( dmesg | grep -i $(DRIVERNAME) ) | grep -i "System needs a restart" -o --colour=always; echo "">NULL; fi; done

		# Creating character devices if necessary
		-START_LINE=$$(dmesg | grep -n '=====' | tail -n 1 | sed -E 's/^(.+):.*/\1/') &&\
		dmesg | tail -n +$$START_LINE | grep -i '==MKNOD==' &&\
		rm -rf /dev/delta-x3* &&\
		eval $$(dmesg | tail -n +$$START_LINE | grep -i '==MKNOD==' | sed -E 's/^.*driver name: (.+), board index: (.+), major: (.+), minor: (.+)/mknod -m 666 \/dev\/\1\2 c \3 \4 ; /i') ||:

uninstall:
		# Driver uninstallation
		modprobe -r $(DRIVERNAME)
		rm $(INSTALLDIR)/$(DRIVERNAME).ko
		rm /etc/udev/$(DRIVERNAME).rules
		rm /etc/udev/rules.d/010-$(DRIVERNAME).rules

	
shipped_cleanup:
	for file in *.o_shipped; do if ! file "$$file" | grep -q 'ELF'; then rm -f "$${file/.o_shipped/}.c"; fi; done

clean:
		rm -f *.o
		rm -f Module.symvers
		rm -f modules.order
		rm -f *.ko
		rm -f .*.cmd

endif
