// // Copyright 2013,2015-2016 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 . // #include #include #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; if (!(DeviceIoControl(device_handle, ioctl_code, const_cast(write_buf), static_cast(write_buf_len), read_buf, static_cast(read_buf_len), &outLen, &zeroedOverlapped ))) { UHD_UNUSED(int_fast32_t 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(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(&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(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(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(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; } }