| // Copyright 2019 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "lib/usb-virtual-bus-launcher/usb-virtual-bus-launcher.h" |
| |
| #include <fcntl.h> |
| #include <lib/async-loop/cpp/loop.h> |
| #include <lib/ddk/platform-defs.h> |
| #include <lib/fdio/fd.h> |
| #include <lib/fdio/fdio.h> |
| #include <lib/fdio/namespace.h> |
| #include <lib/fdio/spawn.h> |
| #include <lib/fdio/unsafe.h> |
| #include <lib/fdio/watcher.h> |
| #include <lib/fidl-async/cpp/bind.h> |
| #include <lib/usb-peripheral-utils/event-watcher.h> |
| #include <sys/stat.h> |
| #include <unistd.h> |
| #include <zircon/hw/usb.h> |
| #include <zircon/processargs.h> |
| #include <zircon/syscalls.h> |
| |
| #include <zxtest/zxtest.h> |
| |
| namespace usb_virtual_bus_base { |
| |
| using driver_integration_test::IsolatedDevmgr; |
| using usb_virtual_bus::ValidateResult; |
| |
| USBVirtualBusBase::USBVirtualBusBase() { |
| args_.disable_block_watcher = true; |
| |
| board_test::DeviceEntry dev = {}; |
| dev.did = 0; |
| dev.vid = PDEV_VID_TEST; |
| dev.pid = PDEV_PID_USB_VBUS_TEST; |
| args_.device_list.push_back(dev); |
| |
| ASSERT_OK(IsolatedDevmgr::Create(&args_, &devmgr_)); |
| |
| fbl::unique_fd fd; |
| device_watcher::RecursiveWaitForFile(devmgr_.devfs_root(), "sys/platform/11:03:0/usb-virtual-bus", |
| &fd); |
| ASSERT_TRUE(fd.is_valid()); |
| |
| zx::channel virtual_bus; |
| ASSERT_OK(fdio_get_service_handle(fd.release(), virtual_bus.reset_and_get_address())); |
| virtual_bus_ = |
| fidl::BindSyncClient<fuchsia_hardware_usb_virtual_bus::Bus>(std::move(virtual_bus)); |
| |
| auto enable_result = virtual_bus_->Enable(); |
| ASSERT_NO_FATAL_FAILURE(ValidateResult(enable_result)); |
| |
| fd.reset(openat(devmgr_.devfs_root().get(), "class/usb-peripheral", O_RDONLY)); |
| fbl::String devpath; |
| while (fdio_watch_directory(fd.get(), usb_virtual_bus::WaitForAnyFile, ZX_TIME_INFINITE, |
| &devpath) != ZX_ERR_STOP) |
| continue; |
| |
| devpath = fbl::String::Concat({fbl::String("class/usb-peripheral/"), fbl::String(devpath)}); |
| fd.reset(openat(devmgr_.devfs_root().get(), devpath.c_str(), O_RDWR)); |
| |
| zx::channel peripheral; |
| ASSERT_OK(fdio_get_service_handle(fd.release(), peripheral.reset_and_get_address())); |
| peripheral_ = |
| fidl::BindSyncClient<fuchsia_hardware_usb_peripheral::Device>(std::move(peripheral)); |
| |
| ASSERT_NO_FATAL_FAILURE(ClearPeripheralDeviceFunctions()); |
| } |
| |
| int USBVirtualBusBase::GetRootFd() { return devmgr_.devfs_root().get(); } |
| |
| void USBVirtualBusBase::SetupPeripheralDevice(DeviceDescriptor&& device_desc, |
| std::vector<ConfigurationDescriptor> config_descs) { |
| zx::channel handles[2]; |
| ASSERT_OK(zx::channel::create(0, handles, handles + 1)); |
| auto set_result = peripheral_->SetStateChangeListener(std::move(handles[1])); |
| ASSERT_OK(set_result.status()); |
| |
| auto set_config = peripheral_->SetConfiguration( |
| std::move(device_desc), |
| fidl::VectorView<ConfigurationDescriptor>::FromExternal(config_descs)); |
| ASSERT_OK(set_config.status()); |
| ASSERT_FALSE(set_config->is_error()); |
| |
| async::Loop loop(&kAsyncLoopConfigNeverAttachToThread); |
| usb_peripheral_utils::EventWatcher watcher(&loop, std::move(handles[0]), 1); |
| loop.Run(); |
| ASSERT_TRUE(watcher.all_functions_registered()); |
| |
| auto connect_result = virtual_bus_->Connect(); |
| ASSERT_NO_FATAL_FAILURE(ValidateResult(connect_result)); |
| } |
| |
| void USBVirtualBusBase::ClearPeripheralDeviceFunctions() { |
| zx::channel handles[2]; |
| ASSERT_OK(zx::channel::create(0, handles, handles + 1)); |
| auto set_result = peripheral_->SetStateChangeListener(std::move(handles[1])); |
| ASSERT_OK(set_result.status()); |
| |
| auto clear_functions = peripheral_->ClearFunctions(); |
| ASSERT_OK(clear_functions.status()); |
| |
| async::Loop loop(&kAsyncLoopConfigNeverAttachToThread); |
| usb_peripheral_utils::EventWatcher watcher(&loop, std::move(handles[0]), 1); |
| loop.Run(); |
| ASSERT_TRUE(watcher.all_functions_cleared()); |
| } |
| |
| } // namespace usb_virtual_bus_base |