A Linux-based software stack might require debugging in both application and kernel layers. A typical Linux application interacts with the kernel space driver using IOCTL calls. If an I/O read/write response is not returned from the kernel driver, you can check the specific hardware registers to see if the address, length, interrupt-related mask/enable signals are programmed correctly. If the registers are programmed properly, the next debug step is to check if any interrupts have been registered for the specific hardware device by looking at /proc/interrupts using a cat command.
If the interrupts are not registered, further debugging needs to occur from the hardware side. If the interrupts are registered, you can add specific kernel print statements in the driver to debug interrupt service routines and other function calls in the device driver. The application level debug can be done using GDB debugger. Also, ensure that the application code is free of memory leak that typically occurs when a dynamically allocated memory is not freed up once its use is over. Such issues can be debugged using the Valgrind tool that helps detect such scenarios.