blob: 08ab0ca72389db71140fef968988b31772babab5 [file] [log] [blame]
// 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.
#ifndef SRC_DEVICES_USB_DRIVERS_XHCI_XHCI_DEVICE_STATE_H_
#define SRC_DEVICES_USB_DRIVERS_XHCI_XHCI_DEVICE_STATE_H_
#include <lib/inspect/cpp/vmo/types.h>
#include <lib/sync/completion.h>
#include <optional>
#include "src/devices/usb/drivers/xhci/xhci-endpoint.h"
#include "src/devices/usb/drivers/xhci/xhci-hub.h"
#include "zircon/compiler.h"
namespace usb_xhci {
// The maximum number of endpoints a USB device can support
constexpr uint8_t kMaxEndpoints = 32;
// DeviceState is RefCounted. The device itself holds a reference to DeviceState and all its direct
// descendents (if the device is a hub) hold references to DeviceState. DeviceState calls its
// destructor when all references to it is released (see comment in destructor).
// In further detail:
// DeviceState is created when a slot is assigned. A reference is added when a slot is assigned or
// there are any direct descendents that will reference it (In other words, this device is a hub.
// One reference is added per device connected to the hub). A reference is removed when one of its
// descendents is removed or when the hub itself is removed.
class DeviceState : public fbl::RefCounted<DeviceState> {
public:
DeviceState(uint32_t device_id, UsbXhci* hci)
: device_id_(device_id), hci_(hci), tr_(hci, device_id, 0) {}
~DeviceState();
void Disconnect() __TA_REQUIRES(transaction_lock_) { disconnecting_ = true; }
void SetDeviceInformation(uint8_t slot, uint8_t port, const std::optional<HubInfo>& hub)
__TA_REQUIRES(transaction_lock_) {
slot_ = slot;
port_ = port;
hub_ = hub;
disconnecting_ = false;
}
// True if the device state has been initialized, false otherwise.
bool IsValid() const { return slot_; }
uint8_t GetPort() const { return port_; }
uint8_t GetSlot() const { return slot_; }
uint16_t GetInterrupterTarget() const { return interrupter_target_; }
std::optional<HubInfo>& GetHubLocked() __TA_REQUIRES(transaction_lock_) { return hub_; }
std::optional<HubInfo>& GetHub() {
fbl::AutoLock l(&transaction_lock_);
return hub_;
}
bool IsDisconnecting() const __TA_REQUIRES(transaction_lock_) { return disconnecting_; }
Endpoint& GetEndpoint() __TA_REQUIRES(transaction_lock_) { return tr_; }
zx_status_t InitEndpoint(uint8_t ep_addr, EventRing* event_ring, fdf::MmioBuffer* mmio)
__TA_REQUIRES(transaction_lock_);
// idx should correspond to XhciEndpointIndex
Endpoint& GetEndpoint(uint8_t idx) __TA_REQUIRES(transaction_lock_) {
if (!rings_[idx]) {
rings_[idx].emplace(hci_, device_id_, XhciEndpointIndexInverse(idx + 1));
}
return *rings_[idx];
}
std::unique_ptr<dma_buffer::PagedBuffer>& GetInputContext() __TA_REQUIRES(transaction_lock_) {
return input_context_;
}
std::unique_ptr<dma_buffer::PagedBuffer>& GetDeviceContext() __TA_REQUIRES(transaction_lock_) {
return device_context_;
}
TRBPromise AddressDeviceCommand(UsbXhci* hci, uint8_t slot_id, uint8_t port_id,
std::optional<HubInfo> hub_info, uint64_t* dcbaa,
uint16_t interrupter_target, CommandRing* command_ring,
fdf::MmioBuffer* mmio, bool bsr);
fbl::Mutex& transaction_lock() __TA_RETURN_CAPABILITY(transaction_lock_) {
return transaction_lock_;
}
// Used by xhci to break cyclic dependency during dtor.
void ResetHci() { hci_ = nullptr; }
void CreateInspectNode(inspect::Node node, uint16_t vendor_id, uint16_t product_id);
uint32_t device_id() const { return device_id_; }
private:
zx_status_t InitializeSlotBuffer(const UsbXhci& hci, uint8_t slot_id, uint8_t port_id,
const std::optional<HubInfo>& hub_info,
std::unique_ptr<dma_buffer::PagedBuffer>* out);
zx_status_t InitializeEndpointContext(const UsbXhci& hci, uint8_t slot_id, uint8_t port_id,
std::optional<HubInfo>& hub_info,
dma_buffer::PagedBuffer* slot_context_buffer)
__TA_REQUIRES(transaction_lock_);
zx_status_t InitializeOutputContextBuffer(const UsbXhci& hci, uint8_t slot_id, uint8_t port_id,
const std::optional<HubInfo>& hub_info, uint64_t* dcbaa,
std::unique_ptr<dma_buffer::PagedBuffer>* out)
__TA_REQUIRES(transaction_lock_);
uint32_t device_id_;
UsbXhci* hci_;
uint8_t slot_ = 0;
uint8_t port_ = 0;
uint16_t interrupter_target_;
fbl::Mutex transaction_lock_;
std::optional<HubInfo> hub_ __TA_GUARDED(transaction_lock_);
bool disconnecting_ __TA_GUARDED(transaction_lock_) = false;
Endpoint tr_ __TA_GUARDED(transaction_lock_);
std::optional<Endpoint> rings_[kMaxEndpoints] __TA_GUARDED(transaction_lock_);
std::unique_ptr<dma_buffer::PagedBuffer> input_context_ __TA_GUARDED(transaction_lock_);
std::unique_ptr<dma_buffer::PagedBuffer> device_context_ __TA_GUARDED(transaction_lock_);
// Published inspect data
inspect::Node inspect_node_;
inspect::StringProperty vendor_id_;
inspect::StringProperty product_id_;
};
} // namespace usb_xhci
#endif // SRC_DEVICES_USB_DRIVERS_XHCI_XHCI_DEVICE_STATE_H_