| // 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 "usb-harriet.h" |
| |
| #include <ddk/binding.h> |
| #include <ddk/debug.h> |
| #include <ddk/device.h> |
| #include <ddk/protocol/usb.h> |
| #include <fbl/alloc_checker.h> |
| |
| namespace { |
| |
| static constexpr uint16_t GOOGLE_USB_VID = 0x18D1; |
| static constexpr uint16_t HARRIET_USB_PID = 0x9302; |
| |
| } // namespace |
| |
| namespace usb_harriet { |
| |
| zx_status_t Harriet::Bind() { |
| zx_status_t status = DdkAdd("usb-harriet"); |
| if (status != ZX_OK) { |
| return status; |
| } |
| return ZX_OK; |
| } |
| |
| // static |
| zx_status_t Harriet::Create(zx_device_t* parent) { |
| usb::UsbDevice usb(parent); |
| if (!usb.is_valid()) { |
| return ZX_ERR_PROTOCOL_NOT_SUPPORTED; |
| } |
| |
| std::optional<usb::InterfaceList> intfs; |
| zx_status_t status = usb::InterfaceList::Create(usb, true, &intfs); |
| if (status != ZX_OK) { |
| return status; |
| } |
| auto intf = intfs->begin(); |
| const usb_interface_descriptor_t* intf_desc = intf->descriptor(); |
| if (intf == intfs->end()) { |
| return ZX_ERR_NOT_SUPPORTED; |
| } |
| uint8_t intf_num = intf_desc->bInterfaceNumber; |
| zxlogf(TRACE, "found intf %u\n", intf_num); |
| |
| for (auto& intf : *intfs) { |
| auto ep_itr = intf.GetEndpointList().cbegin(); |
| do { |
| uint8_t ep_type = usb_ep_type(&ep_itr->descriptor); |
| switch (ep_type) { |
| case USB_ENDPOINT_BULK: |
| case USB_ENDPOINT_INTERRUPT: |
| zxlogf(TRACE, "%s %s EP 0x%x\n", ep_type == USB_ENDPOINT_BULK ? "BULK" : "INTERRUPT", |
| usb_ep_direction(&ep_itr->descriptor) == USB_ENDPOINT_OUT ? "OUT" : "IN", |
| ep_itr->descriptor.bEndpointAddress); |
| break; |
| default: |
| zxlogf(TRACE, "found additional unexpected EP, type: %u addr 0x%x\n", ep_type, |
| ep_itr->descriptor.bEndpointAddress); |
| } |
| } while (ep_itr++ != intf.GetEndpointList().end()); |
| } |
| |
| fbl::AllocChecker ac; |
| auto dev = fbl::make_unique_checked<Harriet>(&ac, parent, usb); |
| if (!ac.check()) { |
| return ZX_ERR_NO_MEMORY; |
| } |
| |
| status = dev->Bind(); |
| if (status == ZX_OK) { |
| // Intentionally leak as it is now held by DevMgr. |
| __UNUSED auto ptr = dev.release(); |
| } |
| return status; |
| } |
| |
| zx_status_t harriet_bind(void* ctx, zx_device_t* parent) { |
| zxlogf(TRACE, "harriet_bind\n"); |
| return usb_harriet::Harriet::Create(parent); |
| } |
| |
| static constexpr zx_driver_ops_t harriet_driver_ops = []() { |
| zx_driver_ops_t ops = {}; |
| ops.version = DRIVER_OPS_VERSION; |
| ops.bind = harriet_bind; |
| return ops; |
| }(); |
| |
| } // namespace usb_harriet |
| |
| // clang-format off |
| ZIRCON_DRIVER_BEGIN(usb_harriet, usb_harriet::harriet_driver_ops, "zircon", "0.1", 3) |
| BI_ABORT_IF(NE, BIND_PROTOCOL, ZX_PROTOCOL_USB), |
| BI_ABORT_IF(NE, BIND_USB_VID, GOOGLE_USB_VID), |
| BI_MATCH_IF(EQ, BIND_USB_PID, HARRIET_USB_PID), |
| ZIRCON_DRIVER_END(usb_harriet) |
| // clang-format on |