// Copyright 2016 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-bus.h"

#include <ddk/binding.h>
#include <ddk/debug.h>
#include <fbl/alloc_checker.h>
#include <fbl/unique_ptr.h>

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "usb-device.h"

namespace usb_bus {

zx_status_t UsbBus::Create(void* ctx, zx_device_t* parent) {
    fbl::AllocChecker ac;
    auto bus = fbl::make_unique_checked<UsbBus>(&ac, parent);
    if (!ac.check()) {
        return ZX_ERR_NO_MEMORY;
    }

    auto status = bus->Init();
    if (status != ZX_OK) {
        return status;
    }

    // devmgr is now in charge of the device.
    __UNUSED auto* dummy = bus.release();
    return ZX_OK;
}

zx_status_t UsbBus::Init() {
    // Parent must support HCI protocol.
    if (!hci_.is_valid()) {
        return ZX_ERR_NOT_SUPPORTED;
    }

    auto max_device_count = hci_.GetMaxDeviceCount();
    fbl::AllocChecker ac;
    devices_.reset(new (&ac) fbl::RefPtr<UsbDevice>[max_device_count], max_device_count);
    if (!ac.check()) {
        return ZX_ERR_NO_MEMORY;
    }

    auto status = DdkAdd("usb-bus", DEVICE_ADD_NON_BINDABLE);
    if (status != ZX_OK) {
        return status;
    }

    hci_.SetBusInterface(this, &usb_bus_interface_protocol_ops_);

    return ZX_OK;
}

zx_status_t UsbBus::UsbBusInterfaceAddDevice(uint32_t device_id, uint32_t hub_id,
                                             usb_speed_t speed) {
    if (device_id >= devices_.size()) {
        return ZX_ERR_INVALID_ARGS;
    }
    if (devices_[device_id] != nullptr) {
        return ZX_ERR_BAD_STATE;
    }

    // devices_[device_id] must be set before usb_device_add() creates the interface devices
    // so we pass pointer to it here rather than setting it after usb_device_add() returns.
    return UsbDevice::Create(zxdev(), hci_, device_id, hub_id, speed, &devices_[device_id]);
}

zx_status_t UsbBus::UsbBusInterfaceRemoveDevice(uint32_t device_id) {
    if (device_id >= devices_.size()) {
        zxlogf(ERROR, "%s: device_id out of range\n", __func__);
        return ZX_ERR_INVALID_ARGS;
    }

    auto device = devices_[device_id];
    if (device == nullptr) {
        return ZX_ERR_BAD_STATE;
    }
    device->DdkRemove();
    devices_[device_id].reset();

    return ZX_OK;
}

zx_status_t UsbBus::UsbBusInterfaceResetPort(uint32_t hub_id, uint32_t port, bool enumerating) {
    if (hub_id >= devices_.size()) {
        zxlogf(ERROR, "%s: hub_id out of range\n", __func__);
        return ZX_ERR_INVALID_ARGS;
    }
    auto device = devices_[hub_id];
    if (device == nullptr) {
        zxlogf(ERROR, "hub not found in %s\n", __func__);
        return ZX_ERR_INVALID_ARGS;
    }

    auto status = device->HubResetPort(port);

    // If we are calling reset in the middle of enumerating,
    // the XHCI would already be trying to address the device next.
    if (!enumerating) {
        status = hci_.HubDeviceReset(hub_id, port);
    }
    return status;
}

zx_status_t UsbBus::UsbBusInterfaceReinitializeDevice(uint32_t device_id) {
    if (device_id >= devices_.size()) {
        zxlogf(ERROR, "%s: device_id out of range\n", __func__);
        return ZX_ERR_INVALID_ARGS;
    }

    auto device = devices_[device_id];
    if (device == nullptr) {
        zxlogf(ERROR, "could not find device %u\n", device_id);
        return ZX_ERR_INTERNAL;
    }

    // Check if the USB device descriptor changed, in which case we need to force the device to
    // re-enumerate so we can load the uploaded device driver.
    // This can happen during a Device Firmware Upgrade.
    usb_device_descriptor_t old_desc;
    usb_device_descriptor_t updated_desc;
    size_t actual;

    device->UsbGetDeviceDescriptor(&old_desc);
    auto status = device->GetDescriptor(USB_DT_DEVICE, 0, 0, &updated_desc, sizeof(updated_desc),
                                        &actual);
    if (actual != sizeof(updated_desc)) {
        status = ZX_ERR_IO;
    }
    if (status == ZX_OK) {
        // TODO(jocelyndang): we may want to check other descriptors as well.
        bool descriptors_changed = memcmp(&old_desc, &updated_desc,
                                          sizeof(usb_device_descriptor_t)) != 0;
        if (descriptors_changed) {
            zxlogf(INFO, "device updated from VID 0x%x PID 0x%x to VID 0x%x PID 0x%x\n",
                   old_desc.idVendor, old_desc.idProduct, updated_desc.idVendor,
                   updated_desc.idProduct);

            status = UsbBusInterfaceRemoveDevice(device_id);
            if (status != ZX_OK) {
                zxlogf(ERROR, "could not remove device %u, got err %d\n", device_id, status);
                return status;
            }
            status = UsbBusInterfaceAddDevice(device_id, device->GetHubId(), device->GetSpeed());
            if (status != ZX_OK) {
                zxlogf(ERROR, "could not add device %u, got err %d\n", device_id, status);
            }
            return status;
        }
    } else {
        zxlogf(ERROR, "could not get updated descriptor: %d got len %lu\n", status, actual);
        // We should try reinitializing the device anyway.
    }

    return device->Reinitialize();
}

zx_status_t UsbBus::GetDeviceId(zx_device_t* device, uint32_t* out) {
    usb_protocol_t usb;
    if (device_get_protocol(device, ZX_PROTOCOL_USB, &usb) != ZX_OK) {
        return ZX_ERR_INTERNAL;
    }
    auto id = usb_get_device_id(&usb);
    if (id >= devices_.size()) {
        return ZX_ERR_INTERNAL;
    }
    *out = id;
    return ZX_OK;
}

zx_status_t UsbBus::UsbBusConfigureHub(zx_device_t* hub_device, usb_speed_t speed,
                                       const usb_hub_descriptor_t* desc, bool multi_tt) {
    uint32_t hub_id;
    if (GetDeviceId(hub_device, &hub_id) != ZX_OK) {
        return ZX_ERR_INTERNAL;
    }
    return hci_.ConfigureHub(hub_id, speed, desc, multi_tt);
}

zx_status_t UsbBus::UsbBusDeviceAdded(zx_device_t* hub_device, uint32_t port, usb_speed_t speed) {
    uint32_t hub_id;
    if (GetDeviceId(hub_device, &hub_id) != ZX_OK) {
        return ZX_ERR_INTERNAL;
    }
    return hci_.HubDeviceAdded(hub_id, port, speed);
}

zx_status_t UsbBus::UsbBusDeviceRemoved(zx_device_t* hub_device, uint32_t port) {
    uint32_t hub_id;
    if (GetDeviceId(hub_device, &hub_id) != ZX_OK) {
        return ZX_ERR_INTERNAL;
    }
    return hci_.HubDeviceRemoved(hub_id, port);
}

zx_status_t UsbBus::UsbBusSetHubInterface(zx_device_t* usb_device, const usb_hub_interface_protocol_t* hub) {
    uint32_t usb_device_id;
    auto status = GetDeviceId(usb_device, &usb_device_id);
    if (status != ZX_OK) {
        return status;
    }

    auto usb_dev = devices_[usb_device_id];
    if (usb_dev == nullptr) {
        zxlogf(ERROR, "%s: no device for usb_device_id %u\n", __func__, usb_device_id);
        return ZX_ERR_INTERNAL;
    }

    usb_dev->SetHubInterface(hub);
    return ZX_OK;
}

void UsbBus::DdkUnbind() {
    hci_.SetBusInterface(nullptr, nullptr);

    for (auto device : devices_) {
        if (device != nullptr) {
            device->DdkRemove();
        }
    }
    devices_.reset();

    DdkRemove();
}

void UsbBus::DdkRelease() {
    delete this;
}

static constexpr zx_driver_ops_t driver_ops = [](){
    zx_driver_ops_t ops = {};
    ops.version = DRIVER_OPS_VERSION;
    ops.bind = UsbBus::Create;
    return ops;
}();

} // namespace usb_bus

ZIRCON_DRIVER_BEGIN(usb_bus, usb_bus::driver_ops, "zircon", "0.1", 1)
    BI_MATCH_IF(EQ, BIND_PROTOCOL, ZX_PROTOCOL_USB_HCI),
ZIRCON_DRIVER_END(usb_bus)
