There is a lot within this topic due to how many different methods there really are, some are however naturally unsupported. It is best to stick to supported, documented techniques though (for stability and maintenance purposes).
Functions like DeviceIoControl require a handle. You can acquire this handle through using CreateFile(A/W). You can use this combination to send IOCTL (Input & Output Control) codes to the device driver which will handle the requests through IRP_MJ_XXXXXX callback routines.
You can also use Shared Events (trigger an event to cause a routine elsewhere execute an operation), Inverted Calls, or even shared named pipes (although named pipes is not supported in kernel-mode by default - using this technique would be "hacky" and not recommended unless you are certain you know what you are doing and have a good reason for doing so). One of the most preferred methods for kernel-mode to user-mode communication transitioning is through Ports (an example for this is demonstrated by Microsoft in the file-system mini-filter device driver samples).
Regarding named pipes in kernel-mode... You can re-create your own wrapper for Win32 API pipe functions yourself. NtCreateNamedPipeFile (NTDLL) is called when
CreateNamedPipe (KERNEL32) is called however it is not exported by NTOSKRNL but since NTDLL performs a system call, this means there is an address to the routine within the System Service Dispatch Table (SSDT). NtCreateNamedPipeFile will call
IoCreateFile (a function which is exported and accessible) therefore it would be much easier to just rely on
IoCreateFile to create a kernel-mode equivalent of NtCreateNamedPipeFile. Regarding some of the other functions, they will internally call functions like
NtFsControlFile so you could use
FltFsControlFile, and the alike.
Alternatively, you can go old-school and store data within protected files or protected registry keys (e.g. under the values for specific entries) (which only your device driver or user-mode program can access).
OSR have a great article surrounding Inverted Calls, you can find it here:
The Inverted Call Model in KMDF - OSR
OSR also have a great article surrounding Shared Events, although it was posted back in 2002, it is still extremely beneficial IMO. You can find it here:
The NT Insider:Sharing Is Caring - Sharing Events Between Kernel-User Mode
I wish you great luck with accomplishing your goals, I am sure you will manage to achieve them!