diff --git a/efi/OVMF_VARS.fd b/efi/OVMF_VARS.fd
index 0fad986..8a6ed7b 100644
Binary files a/efi/OVMF_VARS.fd and b/efi/OVMF_VARS.fd differ
diff --git a/kernel/src/drivers/usb/xhci/xhci_device.cpp b/kernel/src/drivers/usb/xhci/xhci_device.cpp
new file mode 100644
index 0000000..46015f1
--- /dev/null
+++ b/kernel/src/drivers/usb/xhci/xhci_device.cpp
@@ -0,0 +1,81 @@
+#include "xhci_device.h"
+
+uint16_t getInitialPacketSizeFromPortSpeed(uint8_t speed) {
+    // Calculate initial max packet size for the set device command
+    uint16_t initialMaxPacketSize = 0;
+    switch (speed) {
+    case XHCI_USB_SPEED_LOW_SPEED: initialMaxPacketSize = 8; break;
+
+    case XHCI_USB_SPEED_FULL_SPEED:
+    case XHCI_USB_SPEED_HIGH_SPEED: initialMaxPacketSize = 64; break;
+
+    case XHCI_USB_SPEED_SUPER_SPEED:
+    case XHCI_USB_SPEED_SUPER_SPEED_PLUS:
+    default: initialMaxPacketSize = 512; break;
+    }
+
+    return initialMaxPacketSize;
+}
+
+XhciDevice::XhciDevice(XhciHcContext* xhc) {
+    _allocInputContext(xhc);
+}
+
+XhciDevice::XhciDevice(XhciHcContext* xhc, uint8_t port) : port(port) {
+    _allocInputContext(xhc);
+}
+
+void XhciDevice::setupTransferRing() {
+    controlEpTransferRing = XhciTransferRing::allocate(slotId);
+}
+
+void XhciDevice::setupAddressDeviceCtx(uint8_t portSpeed) {
+    auto& inputControlCtx = inputContext32.virtualBase->controlContext;
+    auto& inputDeviceCtx = inputContext32.virtualBase->deviceContext;
+
+    // Setup the input control context
+    inputControlCtx.addFlags = (1 << 0) | (1 << 1);
+    inputControlCtx.dropFlags = 0;
+
+    // Setup the slot context
+    auto& slotContext = inputDeviceCtx.slotContext;
+    slotContext.contextEntries = 1;
+    slotContext.speed = portSpeed;
+    slotContext.rootHubPortNum = port;
+    slotContext.routeString = 0;
+    slotContext.interrupterTarget = 0;
+
+    // Setup the control endpoint context
+    auto& ctrlEpContext = inputDeviceCtx.controlEndpointContext;
+    ctrlEpContext.endpointState = XHCI_ENDPOINT_STATE_DISABLED;
+    ctrlEpContext.endpointType = XHCI_ENDPOINT_TYPE_CONTROL;
+    ctrlEpContext.interval = 0;
+    ctrlEpContext.errorCount = 3;
+    ctrlEpContext.maxPacketSize = getInitialPacketSizeFromPortSpeed(portSpeed);
+    ctrlEpContext.maxEsitPayloadLo = 0;
+    ctrlEpContext.maxEsitPayloadHi = 0;
+    ctrlEpContext.averageTrbLength = 8;
+    ctrlEpContext.transferRingDequeuePtr = controlEpTransferRing->getPhysicalBase();
+    ctrlEpContext.dcs = 1;
+}
+
+uint64_t XhciDevice::getInputContextPhysicalBase() {
+    // return inputContext64.physicalBase ? inputContext64.physicalBase : inputContext32.physicalBase;
+    return inputContext32.physicalBase;
+}
+
+void XhciDevice::_allocInputContext(XhciHcContext* xhc) {
+    if (xhc->has64ByteContextSize()) {
+        inputContext64 = xhciAllocDma<XhciInputContext64>(
+            sizeof(XhciInputContext64),
+            XHCI_INPUT_CONTROL_CONTEXT_ALIGNMENT,
+            XHCI_INPUT_CONTROL_CONTEXT_BOUNDARY
+        );
+    } else {
+        inputContext32 = xhciAllocDma<XhciInputContext32>(
+            sizeof(XhciInputContext32),
+            XHCI_INPUT_CONTROL_CONTEXT_ALIGNMENT,
+            XHCI_INPUT_CONTROL_CONTEXT_BOUNDARY
+        );
+    }
+}
diff --git a/kernel/src/drivers/usb/xhci/xhci_device.h b/kernel/src/drivers/usb/xhci/xhci_device.h
new file mode 100644
index 0000000..237ece7
--- /dev/null
+++ b/kernel/src/drivers/usb/xhci/xhci_device.h
@@ -0,0 +1,37 @@
+#ifndef XHCI_DEVICE_H
+#define XHCI_DEVICE_H
+
+#include "xhci_device_ctx.h"
+#include "xhci_ctx.h"
+
+class XhciDevice {
+public:
+    XhciDevice(XhciHcContext* xhc);
+    XhciDevice(XhciHcContext* xhc, uint8_t port);
+    ~XhciDevice() = default;
+
+    void setupTransferRing();
+    void setupAddressDeviceCtx(uint8_t portSpeed);
+
+    uint64_t getInputContextPhysicalBase();
+
+public:
+    uint8_t port;
+    uint8_t slotId;
+
+    // Pointer to the entry in DCBAA
+    XhciDma<XhciDeviceContext32>    deviceContext32;
+    XhciDma<XhciDeviceContext64>    deviceContext64;
+
+    // Input context buffer for configuring the device
+    XhciDma<XhciInputContext32> inputContext32;
+    XhciDma<XhciInputContext64> inputContext64;
+
+    // Control endpoint's transfer ring
+    kstl::SharedPtr<XhciTransferRing> controlEpTransferRing;
+
+private:
+    void _allocInputContext(XhciHcContext* xhc);
+};
+
+#endif
diff --git a/kernel/src/drivers/usb/xhci/xhci_device_ctx.cpp b/kernel/src/drivers/usb/xhci/xhci_device_ctx.cpp
index 8276d8c..d76d26d 100644
--- a/kernel/src/drivers/usb/xhci/xhci_device_ctx.cpp
+++ b/kernel/src/drivers/usb/xhci/xhci_device_ctx.cpp
@@ -1,9 +1,9 @@
 #include "xhci_device_ctx.h"
 #include <kprint.h>
 
-void XhciDeviceContextManager::allocateDcbaa(XhciHcContext* ctx) {
-    size_t contextEntrySize = ctx->has64ByteContextSize() ? 64 : 32;
-    size_t dcbaaSize = contextEntrySize * (ctx->getMaxDeviceSlots() + 1);
+void XhciDeviceContextManager::allocateDcbaa(XhciHcContext* xhc) {
+    size_t contextEntrySize = xhc->has64ByteContextSize() ? 64 : 32;
+    size_t dcbaaSize = contextEntrySize * (xhc->getMaxDeviceSlots() + 1);
 
     m_dcbaa = xhciAllocDma<uint64_t>(dcbaaSize, XHCI_DEVICE_CONTEXT_ALIGNMENT, XHCI_DEVICE_CONTEXT_BOUNDARY);
 
@@ -18,7 +18,7 @@ void XhciDeviceContextManager::allocateDcbaa(XhciHcContext* ctx) {
     */
 
     // Initialize scratchpad buffer array if needed
-    uint8_t scratchpadBuffers = ctx->getMaxScratchpadBuffers();
+    uint8_t scratchpadBuffers = xhc->getMaxScratchpadBuffers();
     if (scratchpadBuffers > 0) {
         // Array of uint64_t pointers
         XhciDma<uint64_t> scratchpadArray = xhciAllocDma<uint64_t>(scratchpadBuffers * sizeof(uint64_t));
@@ -34,10 +34,26 @@ void XhciDeviceContextManager::allocateDcbaa(XhciHcContext* ctx) {
     }
 
     // Update the DCBAAP entry in operational registers
-    ctx->opRegs->dcbaap = m_dcbaa.physicalBase;
+    xhc->opRegs->dcbaap = m_dcbaa.physicalBase;
 }
 
-void* XhciDeviceContextManager::allocateDeviceContext(uint8_t slot) const {
-    (void)slot;
-    return nullptr;
+void XhciDeviceContextManager::allocateDeviceContext(XhciHcContext* xhc, uint8_t slot) const {
+    // Allocate a memory block for the device context
+    if (xhc->has64ByteContextSize()) {
+        auto ctx = xhciAllocDma<XhciDeviceContext64>(
+            sizeof(XhciDeviceContext64),
+            XHCI_DEVICE_CONTEXT_ALIGNMENT,
+            XHCI_DEVICE_CONTEXT_BOUNDARY
+        );
+
+        m_dcbaa.virtualBase[slot] = ctx.physicalBase;
+    } else {
+        auto ctx = xhciAllocDma<XhciDeviceContext32>(
+            sizeof(XhciDeviceContext32),
+            XHCI_DEVICE_CONTEXT_ALIGNMENT,
+            XHCI_DEVICE_CONTEXT_BOUNDARY
+        );
+
+        m_dcbaa.virtualBase[slot] = ctx.physicalBase;
+    }
 }
diff --git a/kernel/src/drivers/usb/xhci/xhci_device_ctx.h b/kernel/src/drivers/usb/xhci/xhci_device_ctx.h
index eb81f75..f5ec8e3 100644
--- a/kernel/src/drivers/usb/xhci/xhci_device_ctx.h
+++ b/kernel/src/drivers/usb/xhci/xhci_device_ctx.h
@@ -485,14 +485,94 @@ static_assert(sizeof(XhciDeviceContext32) == 1024, "Size mismatch for 32-byte De
 using XhciDeviceContext64 = XhciDeviceContext<64>;
 static_assert(sizeof(XhciDeviceContext64) == 2048, "Size mismatch for 64-byte Device Context.");
 
+/*
+// xHci Sped Section 6.2.5.1 Figure 6-6: Input Control Context (page 461)
+
+The Input Control Context data structure defines which Device Context data
+structures are affected by a command and the operations to be performed on
+those contexts
+*/
+template <size_t Size>
+struct XhciInputControlContext {
+    /*
+        Drop Context flags (D2 - D31). These single bit fields identify which Device Context data
+        structures should be disabled by command. If set to ‘1’, the respective Endpoint Context shall
+        be disabled. If cleared to ‘0’, the Endpoint Context is ignored.
+    */
+    uint32_t dropFlags;
+
+    /*
+        Add Context flags (A0 - A31). These single bit fields identify which Device Context data
+        structures shall be evaluated and/or enabled by a command. If set to ‘1’, the respective Context
+        shall be evaluated. If cleared to ‘0’, the Context is ignored.
+    */
+    uint32_t addFlags;
+
+    uint32_t rsvd0[5];
+
+    /*
+        Configuration Value. If CIC = ‘1’, CIE = ‘1’, and this Input Context is associated with a Configure
+        Endpoint Command, then this field contains the value of the Standard Configuration Descriptor
+        bConfigurationValue field associated with the command, otherwise the this field shall be
+        cleared to ‘0’.
+    */
+    uint8_t configValue;
+
+    /*
+        Interface Number. If CIC = ‘1’, CIE = ‘1’, this Input Context is associated with a Configure
+        Endpoint Command, and the command was issued due to a SET_INTERFACE request, then this
+        field contains the value of the Standard Interface Descriptor bInterfaceNumber field associated
+        with the command, otherwise the this field shall be cleared to ‘0’.
+    */
+    uint8_t interfaceNumber;
+
+    /*
+        Alternate Setting. If CIC = ‘1’, CIE = ‘1’, this Input Context is associated with a Configure
+        Endpoint Command, and the command was issued due to a SET_INTERFACE request, then this
+        field contains the value of the Standard Interface Descriptor bAlternateSetting field associated
+        with the command, otherwise the this field shall be cleared to ‘0’
+    */
+    uint8_t alternateSetting;
+
+    // Reserved and zero'd
+    uint8_t rsvd1;
+
+    // Reserved fields depending on context size
+    uint32_t rsvd2[Size == 64 ? 8 : 0]; // 8 reserved for 64-byte context, none for 32-byte
+} __attribute__((packed));
+
+using XhciInputControlContext32 = XhciInputControlContext<32>;
+static_assert(sizeof(XhciInputControlContext32) == 32, "Size mismatch for 32-byte Input Control Context.");
+
+using XhciInputControlContext64 = XhciInputControlContext<64>;
+static_assert(sizeof(XhciInputControlContext64) == 64, "Size mismatch for 64-byte Input Control Context.");
+
+template <size_t Size>
+struct XhciInputContext {
+    XhciInputControlContext<Size> controlContext;
+    XhciDeviceContext<Size> deviceContext;
+};
+
+using XhciInputContext32 = XhciInputContext<32>;
+static_assert(sizeof(XhciInputContext32) == 1056, "Size mismatch for 32-byte Input Context.");
+
+using XhciInputContext64 = XhciInputContext<64>;
+static_assert(sizeof(XhciInputContext64) == 2112, "Size mismatch for 64-byte Input Context.");
+
 class XhciDeviceContextManager {
 public:
     XhciDeviceContextManager() = default;
     ~XhciDeviceContextManager() = default;
 
-    void allocateDcbaa(XhciHcContext* ctx);
+    void allocateDcbaa(XhciHcContext* xhc);
+
+    // Returns a physical address
+    void allocateDeviceContext(XhciHcContext* xhc, uint8_t slot) const;
 
-    void* allocateDeviceContext(uint8_t slot) const;
+    template <size_t Size>
+    inline XhciDeviceContext<Size>* getDeviceContext(uint8_t slot) {
+        return reinterpret_cast<XhciDeviceContext<Size>*>(m_dcbaa.virtualBase[slot]);
+    }
 
 private:
     XhciDma<uint64_t> m_dcbaa;
diff --git a/kernel/src/drivers/usb/xhci/xhci_hcd.cpp b/kernel/src/drivers/usb/xhci/xhci_hcd.cpp
index 68bc686..b43ec72 100644
--- a/kernel/src/drivers/usb/xhci/xhci_hcd.cpp
+++ b/kernel/src/drivers/usb/xhci/xhci_hcd.cpp
@@ -72,6 +72,102 @@ const char* trbCompletionCodeToString(uint8_t completionCode) {
     }
 }
 
+void dumpDeviceContext32(const XhciDeviceContext32* context) {
+    // Dump Slot Context
+    kprint("\nSlot Context:\n");
+    kprint("  Route String:           0x%x\n", context->slotContext.routeString);
+    kprint("  Speed:                  0x%x\n", context->slotContext.speed);
+    kprint("  Reserved:               0x%x\n", context->slotContext.rz);
+    kprint("  MTT:                    0x%x\n", context->slotContext.mtt);
+    kprint("  Hub:                    0x%x\n", context->slotContext.hub);
+    kprint("  Context Entries:        0x%x\n", context->slotContext.contextEntries);
+    kprint("  Max Exit Latency:       0x%x\n", context->slotContext.maxExitLatency);
+    kprint("  Root Hub Port Number:   0x%x\n", context->slotContext.rootHubPortNum);
+    kprint("  Port Count:             0x%x\n", context->slotContext.portCount);
+    kprint("  Parent Hub Slot ID:     0x%x\n", context->slotContext.parentHubSlotId);
+    kprint("  Parent Port Number:     0x%x\n", context->slotContext.parentPortNumber);
+    kprint("  TT Think Time:          0x%x\n", context->slotContext.ttThinkTime);
+    kprint("  Reserved0:              0x%x\n", context->slotContext.rsvd0);
+    kprint("  Interrupter Target:     0x%x\n", context->slotContext.interrupterTarget);
+    kprint("  Device Address:         0x%x\n", context->slotContext.deviceAddress);
+    kprint("  Reserved1:              0x%x\n", context->slotContext.rsvd1);
+    kprint("  Slot State:             0x%x\n", context->slotContext.slotState);
+
+    // Reserved fields
+    kprint("  Reserved Fields (Slot Context): [ ");
+    for (int i = 0; i < 4; ++i) {
+        kprint("0x%x ", context->slotContext.rsvdZ[i]);
+    }
+    kprint("]\n");
+
+    // Dump Control Endpoint Context
+    kprint("\nControl Endpoint Context:\n");
+    kprint("  Endpoint State:         0x%x\n", context->controlEndpointContext.endpointState);
+    kprint("  Mult:                   0x%x\n", context->controlEndpointContext.mult);
+    kprint("  Max Primary Streams:    0x%x\n", context->controlEndpointContext.maxPrimaryStreams);
+    kprint("  Linear Stream Array:    0x%x\n", context->controlEndpointContext.linearStreamArray);
+    kprint("  Interval:               0x%x\n", context->controlEndpointContext.interval);
+    kprint("  Max ESIT Payload Hi:    0x%x\n", context->controlEndpointContext.maxEsitPayloadHi);
+    kprint("  Error Count:            0x%x\n", context->controlEndpointContext.errorCount);
+    kprint("  Endpoint Type:          0x%x\n", context->controlEndpointContext.endpointType);
+    kprint("  Host Initiate Disable:  0x%x\n", context->controlEndpointContext.hostInitiateDisable);
+    kprint("  Max Burst Size:         0x%x\n", context->controlEndpointContext.maxBurstSize);
+    kprint("  Max Packet Size:        0x%x\n", context->controlEndpointContext.maxPacketSize);
+    kprint("  Dequeue Cycle State:    0x%llx\n", context->controlEndpointContext.dcs);
+    kprint("  TR Dequeue Ptr:         0x%llx\n", context->controlEndpointContext.trDequeuePtrAddressBits);
+    kprint("  Average TRB Length:     0x%x\n", context->controlEndpointContext.averageTrbLength);
+    kprint("  Max ESIT Payload Lo:    0x%x\n", context->controlEndpointContext.maxEsitPayloadLo);
+
+    // Reserved fields (Control Endpoint Context)
+    kprint("  Reserved Fields (Control Endpoint Context): [ ");
+    for (int i = 0; i < 0; ++i) {
+        kprint("0x%x ", context->controlEndpointContext.rsvd[i]);
+    }
+    kprint("]\n");
+
+    // Dump each Endpoint Context (ep[0] to ep[29])
+    for (int epIndex = 0; epIndex < 30; ++epIndex) {
+        if (context->ep[epIndex].endpointState == XHCI_ENDPOINT_STATE_DISABLED) {
+            continue;
+        }
+
+        kprint("\nEndpoint Context %i:\n", epIndex);
+        kprint("  Endpoint State:         0x%x\n", context->ep[epIndex].endpointState);
+        kprint("  Mult:                   0x%x\n", context->ep[epIndex].mult);
+        kprint("  Max Primary Streams:    0x%x\n", context->ep[epIndex].maxPrimaryStreams);
+        kprint("  Linear Stream Array:    0x%x\n", context->ep[epIndex].linearStreamArray);
+        kprint("  Interval:               0x%x\n", context->ep[epIndex].interval);
+        kprint("  Max ESIT Payload Hi:    0x%x\n", context->ep[epIndex].maxEsitPayloadHi);
+        kprint("  Error Count:            0x%x\n", context->ep[epIndex].errorCount);
+        kprint("  Endpoint Type:          0x%x\n", context->ep[epIndex].endpointType);
+        kprint("  Host Initiate Disable:  0x%x\n", context->ep[epIndex].hostInitiateDisable);
+        kprint("  Max Burst Size:         0x%x\n", context->ep[epIndex].maxBurstSize);
+        kprint("  Max Packet Size:        0x%x\n", context->ep[epIndex].maxPacketSize);
+        kprint("  Dequeue Cycle State:    0x%llx\n", context->ep[epIndex].dcs);
+        kprint("  TR Dequeue Ptr:         0x%llx\n", context->ep[epIndex].trDequeuePtrAddressBits);
+        kprint("  Average TRB Length:     0x%x\n", context->ep[epIndex].averageTrbLength);
+        kprint("  Max ESIT Payload Lo:    0x%x\n", context->ep[epIndex].maxEsitPayloadLo);
+    }
+}
+
+void dumpXhciInputContext32(const XhciInputContext32* context) {
+    // Dump Input Control Context
+    kprint("Input Control Context:\n");
+    kprint("  Drop Flags:             0x%x\n", context->controlContext.dropFlags);
+    kprint("  Add Flags:              0x%x\n", context->controlContext.addFlags);
+    kprint("  Reserved0:              [ ");
+    for (int i = 0; i < 5; ++i) {
+        kprint("0x%x ", context->controlContext.rsvd0[i]);
+    }
+    kprint("]\n");
+    kprint("  Config Value:           0x%x\n", context->controlContext.configValue);
+    kprint("  Interface Number:       0x%x\n", context->controlContext.interfaceNumber);
+    kprint("  Alternate Setting:      0x%x\n", context->controlContext.alternateSetting);
+    kprint("  Reserved1:              0x%x\n", context->controlContext.rsvd1);
+
+    dumpDeviceContext32(&context->deviceContext);
+}
+
 void XhciHcd::init(PciDeviceInfo* deviceInfo) {
     uint64_t xhcBase = xhciMapMmio(deviceInfo->barAddress);
 
@@ -125,7 +221,9 @@ void XhciHcd::init(PciDeviceInfo* deviceInfo) {
         portRegisterSet.readPortscReg(portsc);
 
         if (portsc.ccs) {
-            _setupDevice(port);
+            // Port number has to be 1-indexed
+            // in the device setup routine.
+            _setupDevice(port + 1);
             
             // For debugging purposes
             break;
@@ -389,7 +487,8 @@ void XhciHcd::_setupDevice(uint8_t port) {
     kprintInfo("Port State Change Event on port %i: ", port);
     kprint("%s device ATTACHED with speed ", m_ctx->isPortUsb3(port) ? "USB3" : "USB2");
 
-    switch (portsc.portSpeed) {
+    uint8_t portSpeed = portsc.portSpeed;
+    switch (portSpeed) {
     case XHCI_USB_SPEED_FULL_SPEED: kprint("Full Speed (12 MB/s - USB2.0)\n"); break;
     case XHCI_USB_SPEED_LOW_SPEED: kprint("Low Speed (1.5 Mb/s - USB 2.0)\n"); break;
     case XHCI_USB_SPEED_HIGH_SPEED: kprint("High Speed (480 Mb/s - USB 2.0)\n"); break;
@@ -397,4 +496,55 @@ void XhciHcd::_setupDevice(uint8_t port) {
     case XHCI_USB_SPEED_SUPER_SPEED_PLUS: kprint("Super Speed Plus (10 Gb/s - USB 3.1)\n"); break;
     default: kprint("Undefined\n"); break;
     }
+
+    auto device = new XhciDevice(m_ctx.get(), port);
+    device->slotId = _enableSlot();
+    if (!device->slotId) {
+        kprint("[XHCI] Failed to allocate a slot for device on port %i\n", port);
+        return;
+    }
+
+    device->setupTransferRing();
+    device->setupAddressDeviceCtx(portSpeed);
+
+    // Allocate the output device context entry in the DCBAA slot
+    m_deviceContextManager->allocateDeviceContext(m_ctx.get(), device->slotId);
+
+    // Send the Address Device command
+    if (!_addressDevice(device)) {
+        return;
+    }
+}
+
+uint8_t XhciHcd::_enableSlot() {
+    XhciTrb_t enableSlotTrb = XHCI_CONSTRUCT_CMD_TRB(XHCI_TRB_TYPE_ENABLE_SLOT_CMD);
+    auto completionTrb = sendCommand(&enableSlotTrb);
+
+    if (!completionTrb) {
+        return 0;
+    }
+
+    return completionTrb->slotId;
+}
+
+bool XhciHcd::_addressDevice(XhciDevice* device) {
+    // Construct the Address Device TRB
+    XhciAddressDeviceCommandTrb_t addressDeviceTrb;
+    zeromem(&addressDeviceTrb, sizeof(XhciAddressDeviceCommandTrb_t));
+    addressDeviceTrb.trbType = XHCI_TRB_TYPE_ADDRESS_DEVICE_CMD;
+    addressDeviceTrb.inputContextPhysicalBase = device->getInputContextPhysicalBase();
+    addressDeviceTrb.bsr = 0;
+    addressDeviceTrb.slotId = device->slotId;
+
+    // Send the AddressDevice command
+    auto completionTrb = sendCommand((XhciTrb_t*)&addressDeviceTrb);
+    if (!completionTrb || completionTrb->completionCode != XHCI_TRB_COMPLETION_CODE_SUCCESS) {
+        kprintError("[XHCI] Failed to complete the first Device Address command\n");
+        return false;
+    }
+
+    kprintInfo("[*] Successfully issued the first Device Address command!\n");
+    msleep(200);
+
+    return true;
 }
diff --git a/kernel/src/drivers/usb/xhci/xhci_hcd.h b/kernel/src/drivers/usb/xhci/xhci_hcd.h
index 58cb0b3..f4be360 100644
--- a/kernel/src/drivers/usb/xhci/xhci_hcd.h
+++ b/kernel/src/drivers/usb/xhci/xhci_hcd.h
@@ -1,7 +1,7 @@
 #ifndef XHCI_HCD_H
 #define XHCI_HCD_H
 
-#include "xhci_device_ctx.h"
+#include "xhci_device.h"
 
 // Forward declaration
 struct PciDeviceInfo;
@@ -32,6 +32,9 @@ class XhciHcd {
 
     void _setupDevice(uint8_t port);
 
+    uint8_t _enableSlot();
+    bool _addressDevice(XhciDevice* device);
+
 private:
     kstl::SharedPtr<XhciHcContext> m_ctx;
     kstl::SharedPtr<XhciDeviceContextManager> m_deviceContextManager;
diff --git a/kernel/src/drivers/usb/xhci/xhci_rings.cpp b/kernel/src/drivers/usb/xhci/xhci_rings.cpp
index d0ce0cd..8aea972 100644
--- a/kernel/src/drivers/usb/xhci/xhci_rings.cpp
+++ b/kernel/src/drivers/usb/xhci/xhci_rings.cpp
@@ -129,3 +129,45 @@ XhciTrb_t* XhciEventRing::_dequeueTrb() {
 
     return ret;
 }
+
+kstl::SharedPtr<XhciTransferRing> XhciTransferRing::allocate(uint8_t slotId) {
+    return kstl::SharedPtr<XhciTransferRing>(
+        new XhciTransferRing(XHCI_TRANSFER_RING_TRB_COUNT, slotId)
+    );
+}
+
+XhciTransferRing::XhciTransferRing(size_t maxTrbs, uint8_t doorbellId) {
+    m_maxTrbCount = maxTrbs;
+    m_rcsBit = 1;
+    m_dequeuePtr = 0;
+    m_enqueuePtr = 0;
+    m_doorbellId = doorbellId;
+
+    const uint64_t ringSize = maxTrbs * sizeof(XhciTrb_t);
+
+    // Create the transfer ring memory block
+    m_trbs = xhciAllocDma<XhciTrb_t>(
+        ringSize,
+        XHCI_TRANSFER_RING_SEGMENTS_ALIGNMENT,
+        XHCI_TRANSFER_RING_SEGMENTS_BOUNDARY
+    );
+
+    // Set the last TRB as a link TRB to point back to the first TRB
+    m_trbs.virtualBase[m_maxTrbCount - 1].parameter = m_trbs.physicalBase;
+    m_trbs.virtualBase[m_maxTrbCount - 1].control = (XHCI_TRB_TYPE_LINK << XHCI_TRB_TYPE_SHIFT) | m_rcsBit;
+}
+
+void XhciTransferRing::enqueue(XhciTrb_t* trb) {
+    // Adjust the TRB's cycle bit to the current DCS
+    trb->cycleBit = m_rcsBit;
+
+    // Insert the TRB into the ring
+    m_trbs.virtualBase[m_enqueuePtr] = *trb;
+
+    // Advance and possibly wrap the enqueue pointer if needed.
+    // maxTrbCount - 1 accounts for the LINK_TRB.
+    if (++m_enqueuePtr == m_maxTrbCount - 1) {
+        m_enqueuePtr = 0;
+        m_rcsBit = !m_rcsBit;
+    }
+}
diff --git a/kernel/src/drivers/usb/xhci/xhci_rings.h b/kernel/src/drivers/usb/xhci/xhci_rings.h
index 39be6f3..fcd7b7f 100644
--- a/kernel/src/drivers/usb/xhci/xhci_rings.h
+++ b/kernel/src/drivers/usb/xhci/xhci_rings.h
@@ -71,4 +71,27 @@ class XhciEventRing {
     XhciTrb_t* _dequeueTrb();
 };
 
+class XhciTransferRing {
+public:
+    static kstl::SharedPtr<XhciTransferRing> allocate(uint8_t slotId);
+
+    XhciTransferRing(size_t maxTrbs, uint8_t doorbellId);
+    ~XhciTransferRing() = default;
+
+    inline XhciTrb_t* getVirtualBase() const { return m_trbs.virtualBase; }
+    inline uint64_t getPhysicalBase() const { return m_trbs.physicalBase; }
+    inline uint8_t  getCycleBit() const { return m_rcsBit; }
+    inline uint8_t getDoorbellId() const { return m_doorbellId; }
+
+    void enqueue(XhciTrb_t* trb);
+
+private:
+    size_t              m_maxTrbCount;  // Number of valid TRBs in the ring including the LINK_TRB
+    size_t              m_dequeuePtr;   // Transfer ring consumer dequeue pointer
+    size_t              m_enqueuePtr;   // Transfer ring producer enqueue pointer
+    XhciDma<XhciTrb_t>  m_trbs;         // Base address of the ring buffer
+    uint8_t             m_rcsBit;       // Dequeue cycle state
+    uint8_t             m_doorbellId;   // ID of the doorbell associated with the ring
+};
+
 #endif