Artemis Milestone 2f: SET_CONFIGURATION -- 2f complete
Chains off a confirmed Mass Storage/SCSI/BOT interface match via the existing next_action deferral mechanism: device descriptor -> config descriptor -> SET_CONFIGURATION is now a single automatic sequence. bConfigurationValue is read directly out of the already-fetched config_descriptor buffer, no extra transfer needed. First write control transfer this driver has issued (every prior one was a read), so it needed its own submission helper, xhci_ep0_control_write_nodata() -- SET_CONFIGURATION has no Data Stage (wLength=0), and per USB 2.0 spec 8.5.3 a no-data control transfer's Status Stage is always IN, the reverse of an OUT-data request's status stage. XHCI_SETUP_TRT_NO_DATA already existed in xhci.h, unused until now. Verified live via QMP hotplug, all three architectures, worked first try, byte-identical: "set configuration submitted" -> "device configured", guest stays running throughout (checked via QMP query-status). Disconnect confirmed clean on every arch afterward, no wedge. FABRIC-2.md Section X Milestone 2f updated -- 2f is now fully complete, 2g (Bulk-Only Transport) can start. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QPfdtaXs9ay1nbwuMnrscu
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
b9c540a78b
commit
b4bbd043d0
@@ -130,6 +130,7 @@ int xhci_cmd_address_device(xhci_dev_t *dev, uint32_t slot_id,
|
||||
uint32_t port_id, uint32_t speed);
|
||||
int xhci_ep0_get_device_descriptor(xhci_dev_t *dev, uint32_t slot_id);
|
||||
int xhci_ep0_get_config_descriptor(xhci_dev_t *dev, uint32_t slot_id, uint16_t length);
|
||||
int xhci_ep0_set_configuration(xhci_dev_t *dev, uint32_t slot_id, uint8_t config_value);
|
||||
|
||||
int xhci_bringup(xhci_dev_t *dev)
|
||||
{
|
||||
@@ -295,6 +296,7 @@ int xhci_bringup(xhci_dev_t *dev)
|
||||
dev->next_action = XHCI_NEXT_ACTION_NONE;
|
||||
dev->next_action_slot_id = 0;
|
||||
dev->next_action_length = 0;
|
||||
dev->next_action_config_value = 0;
|
||||
|
||||
console_println("xhci: controller running");
|
||||
/* Milestone 2e prep: HCCPARAMS1.CSZ decides 32- vs 64-byte Slot/
|
||||
@@ -572,6 +574,49 @@ int xhci_ep0_get_config_descriptor(xhci_dev_t *dev, uint32_t slot_id, uint16_t l
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Shared submission for a "no Data Stage" control transfer -- Setup Stage
|
||||
* only (TRT = XHCI_SETUP_TRT_NO_DATA), then Status Stage. Per USB 2.0
|
||||
* spec section 8.5.3, a control transfer with no Data Stage always uses
|
||||
* an IN Status Stage (the reverse of a normal OUT request's OUT status),
|
||||
* so DIR_IN is set unconditionally here -- this helper isn't generic
|
||||
* across OUT-data and no-data requests, only the latter. */
|
||||
static void xhci_ep0_control_write_nodata(xhci_dev_t *dev, uint8_t bRequest,
|
||||
uint16_t wValue, uint16_t wIndex)
|
||||
{
|
||||
usb_setup_packet_t setup = {
|
||||
.bmRequestType = USB_DIR_HOST_TO_DEVICE,
|
||||
.bRequest = bRequest,
|
||||
.wValue = wValue,
|
||||
.wIndex = wIndex,
|
||||
.wLength = 0
|
||||
};
|
||||
uint64_t setup_bits;
|
||||
memcpy(&setup_bits, &setup, sizeof(setup_bits));
|
||||
|
||||
xhci_ep0_enqueue_trb(dev, setup_bits, 8u,
|
||||
(XHCI_TRB_TYPE_SETUP_STAGE << XHCI_TRB_CONTROL_TYPE_SHIFT) |
|
||||
XHCI_TRB_CONTROL_IDT |
|
||||
(XHCI_SETUP_TRT_NO_DATA << XHCI_TRB_CONTROL_TRT_SHIFT));
|
||||
|
||||
xhci_ep0_enqueue_trb(dev, 0, 0,
|
||||
(XHCI_TRB_TYPE_STATUS_STAGE << XHCI_TRB_CONTROL_TYPE_SHIFT) |
|
||||
XHCI_TRB_CONTROL_IOC |
|
||||
XHCI_TRB_CONTROL_DIR_IN);
|
||||
}
|
||||
|
||||
int xhci_ep0_set_configuration(xhci_dev_t *dev, uint32_t slot_id, uint8_t config_value)
|
||||
{
|
||||
if (!dev || !dev->ep0_ring) return -1;
|
||||
|
||||
dev->transfer_purpose = XHCI_XFER_SET_CONFIG;
|
||||
xhci_ep0_control_write_nodata(dev, USB_REQ_SET_CONFIGURATION, config_value, 0);
|
||||
|
||||
dev->pending_transfer_slot_id = slot_id;
|
||||
dev->doorbell[slot_id] = XHCI_DB_TARGET(1);
|
||||
console_println("xhci: set configuration submitted");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* Milestone 2d: Event Ring servicing, polled from sk_repl_idle().
|
||||
*
|
||||
@@ -799,6 +844,16 @@ void xhci_poll_events(void)
|
||||
iface_subclass == USB_SUBCLASS_SCSI &&
|
||||
iface_protocol == USB_PROTOCOL_BOT) {
|
||||
console_println("xhci: confirmed Mass Storage / SCSI / BOT device");
|
||||
/* Deferred (see xhci_dev_t's
|
||||
* next_action doc comment) rather
|
||||
* than called directly here --
|
||||
* same doorbell-ordering hazard
|
||||
* as the device/config descriptor
|
||||
* chaining above. */
|
||||
dev->next_action = XHCI_NEXT_ACTION_SET_CONFIG;
|
||||
dev->next_action_slot_id = xfer_slot_id;
|
||||
dev->next_action_config_value =
|
||||
dev->config_descriptor[USB_CONFIG_OFF_CONFIG_VALUE];
|
||||
} else {
|
||||
console_println("xhci: not a Mass Storage/SCSI/BOT device -- not usable as a drive");
|
||||
}
|
||||
@@ -812,6 +867,10 @@ void xhci_poll_events(void)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case XHCI_XFER_SET_CONFIG: {
|
||||
console_println("xhci: device configured");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
console_println("xhci: transfer event");
|
||||
break;
|
||||
@@ -861,5 +920,12 @@ void xhci_poll_events(void)
|
||||
if (xhci_ep0_get_config_descriptor(dev, next_slot_id, next_length) != 0) {
|
||||
console_println("xhci: deferred config descriptor request setup failed");
|
||||
}
|
||||
} else if (dev->next_action == XHCI_NEXT_ACTION_SET_CONFIG) {
|
||||
uint32_t next_slot_id = dev->next_action_slot_id;
|
||||
uint8_t next_config_value = dev->next_action_config_value;
|
||||
dev->next_action = XHCI_NEXT_ACTION_NONE;
|
||||
if (xhci_ep0_set_configuration(dev, next_slot_id, next_config_value) != 0) {
|
||||
console_println("xhci: deferred set configuration request setup failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user