mirror of
https://github.com/saymrwulf/uhd.git
synced 2026-05-16 21:10:10 +00:00
148 lines
5.3 KiB
C++
148 lines
5.3 KiB
C++
//
|
|
// Copyright 2013 Ettus Research LLC
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
//
|
|
|
|
#include <uhd/transport/nirio/nirio_driver_iface.h>
|
|
#include <process.h>
|
|
|
|
#define NIRIO_IOCTL_MAP_MEMORY CTL_CODE(FILE_DEVICE_UNKNOWN, 0xF00, METHOD_BUFFERED, (FILE_READ_ACCESS | FILE_WRITE_ACCESS))
|
|
#define NIRIO_IOCTL_UNMAP_MEMORY CTL_CODE(FILE_DEVICE_UNKNOWN, 0xF01, METHOD_BUFFERED, (FILE_READ_ACCESS | FILE_WRITE_ACCESS))
|
|
|
|
namespace nirio_driver_iface {
|
|
|
|
nirio_status rio_open(
|
|
const std::string& device_path,
|
|
rio_dev_handle_t& device_handle)
|
|
{
|
|
device_handle = CreateFileA(device_path.c_str(), GENERIC_READ | GENERIC_WRITE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, /* default security */
|
|
OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL /* template file */);
|
|
|
|
return (device_handle == INVALID_HANDLE_VALUE) ? NiRio_Status_InvalidParameter : NiRio_Status_Success;
|
|
}
|
|
|
|
void rio_close(rio_dev_handle_t& device_handle)
|
|
{
|
|
::CloseHandle(device_handle);
|
|
device_handle = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
bool rio_isopen(rio_dev_handle_t device_handle)
|
|
{
|
|
return (device_handle != INVALID_HANDLE_VALUE);
|
|
}
|
|
|
|
nirio_status rio_ioctl(
|
|
rio_dev_handle_t device_handle,
|
|
uint32_t ioctl_code,
|
|
const void *write_buf,
|
|
size_t write_buf_len,
|
|
void *read_buf,
|
|
size_t read_buf_len)
|
|
{
|
|
if (!rio_isopen(device_handle)) return NiRio_Status_ResourceNotInitialized;
|
|
|
|
/* Note, if the file handle was opened with the OVERLAPPED flag, you must
|
|
* supply an OVERLAPPED structure to ReadFile, WriteFile, and
|
|
* DeviceIoControl, even when doing synchronous IO. */
|
|
OVERLAPPED zeroedOverlapped = {0};
|
|
DWORD outLen = 0;
|
|
int_fast32_t lastError = 0;
|
|
|
|
if (!(DeviceIoControl(device_handle, ioctl_code,
|
|
const_cast<void*>(write_buf), static_cast<DWORD>(write_buf_len),
|
|
read_buf, static_cast<DWORD>(read_buf_len),
|
|
&outLen, &zeroedOverlapped )))
|
|
{
|
|
lastError = GetLastError();
|
|
return NiRio_Status_SoftwareFault;
|
|
}
|
|
|
|
return NiRio_Status_Success;
|
|
}
|
|
|
|
unsigned int __stdcall memory_map_thread_routine(void *context)
|
|
{
|
|
rio_mmap_threadargs_t *args = (rio_mmap_threadargs_t*)context;
|
|
args->status = rio_ioctl(args->device_handle, NIRIO_IOCTL_MAP_MEMORY, &(args->params), sizeof(args->params), NULL, 0);
|
|
if (nirio_status_fatal(args->status))
|
|
{
|
|
SetEvent(reinterpret_cast<HANDLE>(args->params.map_ready_event_handle));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
nirio_status rio_mmap(
|
|
rio_dev_handle_t device_handle,
|
|
uint16_t memory_type,
|
|
size_t size,
|
|
bool writable,
|
|
rio_mmap_t &map)
|
|
{
|
|
if (!rio_isopen(device_handle)) return NiRio_Status_ResourceNotInitialized;
|
|
|
|
access_mode_t access_mode = writable ? ACCESS_MODE_WRITE : ACCESS_MODE_READ;
|
|
|
|
uint64_t mapped_addr = 0;
|
|
map.map_thread_args.device_handle = device_handle;
|
|
map.map_thread_args.status = NiRio_Status_Success;
|
|
map.map_thread_args.params.memoryType = memory_type;
|
|
map.map_thread_args.params.size = (uint32_t)size;
|
|
map.map_thread_args.params.mapped_va_ptr = reinterpret_cast<uintptr_t>(&mapped_addr);
|
|
map.map_thread_args.params.access_mode = (uint8_t)access_mode;
|
|
HANDLE map_ready_event_handle = CreateEventA(NULL, TRUE, FALSE, NULL);
|
|
if (map_ready_event_handle == NULL) {
|
|
map.addr = NULL;
|
|
return NiRio_Status_SoftwareFault;
|
|
}
|
|
map.map_thread_args.params.map_ready_event_handle = reinterpret_cast<uint64_t>(map_ready_event_handle);
|
|
map.map_thread_handle = (HANDLE) _beginthreadex(NULL, 0, memory_map_thread_routine, &(map.map_thread_args), 0, NULL);
|
|
|
|
nirio_status status = NiRio_Status_Success;
|
|
if (map.map_thread_handle == NULL) {
|
|
map.addr = NULL;
|
|
return NiRio_Status_SoftwareFault;
|
|
} else {
|
|
WaitForSingleObject(map_ready_event_handle, INFINITE);
|
|
map.addr = reinterpret_cast<void*>(mapped_addr);
|
|
if (map.addr == NULL) {
|
|
WaitForSingleObject(map.map_thread_handle, INFINITE);
|
|
CloseHandle(map.map_thread_handle);
|
|
nirio_status_chain(map.map_thread_args.status, status);
|
|
}
|
|
}
|
|
CloseHandle(map_ready_event_handle);
|
|
return status;
|
|
}
|
|
|
|
nirio_status rio_munmap(rio_mmap_t &map)
|
|
{
|
|
if (!rio_isopen(map.map_thread_args.device_handle)) return NiRio_Status_ResourceNotInitialized;
|
|
|
|
nirio_status status = NiRio_Status_Success;
|
|
if (map.addr != NULL) {
|
|
uint64_t mapped_addr = reinterpret_cast<uintptr_t>(map.addr);
|
|
status = rio_ioctl(map.map_thread_args.device_handle, NIRIO_IOCTL_UNMAP_MEMORY, &mapped_addr, sizeof(mapped_addr), NULL, 0);
|
|
if (nirio_status_not_fatal(status)) {
|
|
WaitForSingleObject(map.map_thread_handle, INFINITE);
|
|
}
|
|
CloseHandle(map.map_thread_handle);
|
|
map.addr = NULL;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
}
|