mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 08:47:35 +00:00
Kernel/USB: Add Hubs and the UHCI Root Hub
This commit is contained in:
parent
9dcd146ab4
commit
da0a1068e9
11 changed files with 1009 additions and 100 deletions
|
@ -26,7 +26,7 @@ KResultOr<NonnullRefPtr<Device>> Device::try_create(USBController const& control
|
|||
if (!device)
|
||||
return ENOMEM;
|
||||
|
||||
auto enumerate_result = device->enumerate();
|
||||
auto enumerate_result = device->enumerate_device();
|
||||
if (enumerate_result.is_error())
|
||||
return enumerate_result;
|
||||
|
||||
|
@ -42,20 +42,58 @@ Device::Device(USBController const& controller, PortNumber port, DeviceSpeed spe
|
|||
{
|
||||
}
|
||||
|
||||
KResult Device::enumerate()
|
||||
Device::Device(NonnullRefPtr<USBController> controller, u8 address, PortNumber port, DeviceSpeed speed, NonnullOwnPtr<Pipe> default_pipe)
|
||||
: m_device_port(port)
|
||||
, m_device_speed(speed)
|
||||
, m_address(address)
|
||||
, m_controller(controller)
|
||||
, m_default_pipe(move(default_pipe))
|
||||
{
|
||||
}
|
||||
|
||||
Device::Device(Device const& device, NonnullOwnPtr<Pipe> default_pipe)
|
||||
: m_device_port(device.port())
|
||||
, m_device_speed(device.speed())
|
||||
, m_address(device.address())
|
||||
, m_device_descriptor(device.device_descriptor())
|
||||
, m_controller(device.controller())
|
||||
, m_default_pipe(move(default_pipe))
|
||||
{
|
||||
}
|
||||
|
||||
Device::~Device()
|
||||
{
|
||||
}
|
||||
|
||||
KResult Device::enumerate_device()
|
||||
{
|
||||
USBDeviceDescriptor dev_descriptor {};
|
||||
|
||||
// Send 8-bytes to get at least the `max_packet_size` from the device
|
||||
auto transfer_length_or_error = m_default_pipe->control_transfer(USB_REQUEST_TRANSFER_DIRECTION_DEVICE_TO_HOST, USB_REQUEST_GET_DESCRIPTOR, (DESCRIPTOR_TYPE_DEVICE << 8), 0, 8, &dev_descriptor);
|
||||
constexpr u8 short_device_descriptor_length = 8;
|
||||
auto transfer_length_or_error = m_default_pipe->control_transfer(USB_REQUEST_TRANSFER_DIRECTION_DEVICE_TO_HOST, USB_REQUEST_GET_DESCRIPTOR, (DESCRIPTOR_TYPE_DEVICE << 8), 0, short_device_descriptor_length, &dev_descriptor);
|
||||
|
||||
if (transfer_length_or_error.is_error())
|
||||
return transfer_length_or_error.error();
|
||||
|
||||
auto transfer_length = transfer_length_or_error.release_value();
|
||||
|
||||
// FIXME: This shouldn't crash! Do some correct error handling on me please!
|
||||
VERIFY(transfer_length > 0);
|
||||
// FIXME: This be "not equal to" instead of "less than", but control transfers report a higher transfer length than expected.
|
||||
if (transfer_length < short_device_descriptor_length) {
|
||||
dbgln("USB Device: Not enough bytes for short device descriptor. Expected {}, got {}.", short_device_descriptor_length, transfer_length);
|
||||
return EIO;
|
||||
}
|
||||
|
||||
if constexpr (USB_DEBUG) {
|
||||
dbgln("USB Short Device Descriptor:");
|
||||
dbgln("Descriptor length: {}", dev_descriptor.descriptor_header.length);
|
||||
dbgln("Descriptor type: {}", dev_descriptor.descriptor_header.descriptor_type);
|
||||
|
||||
dbgln("Device Class: {:02x}", dev_descriptor.device_class);
|
||||
dbgln("Device Sub-Class: {:02x}", dev_descriptor.device_sub_class);
|
||||
dbgln("Device Protocol: {:02x}", dev_descriptor.device_protocol);
|
||||
dbgln("Max Packet Size: {:02x} bytes", dev_descriptor.max_packet_size);
|
||||
}
|
||||
|
||||
// Ensure that this is actually a valid device descriptor...
|
||||
VERIFY(dev_descriptor.descriptor_header.descriptor_type == DESCRIPTOR_TYPE_DEVICE);
|
||||
|
@ -68,8 +106,11 @@ KResult Device::enumerate()
|
|||
|
||||
transfer_length = transfer_length_or_error.release_value();
|
||||
|
||||
// FIXME: This shouldn't crash! Do some correct error handling on me please!
|
||||
VERIFY(transfer_length > 0);
|
||||
// FIXME: This be "not equal to" instead of "less than", but control transfers report a higher transfer length than expected.
|
||||
if (transfer_length < sizeof(USBDeviceDescriptor)) {
|
||||
dbgln("USB Device: Unexpected device descriptor length. Expected {}, got {}.", sizeof(USBDeviceDescriptor), transfer_length);
|
||||
return EIO;
|
||||
}
|
||||
|
||||
// Ensure that this is actually a valid device descriptor...
|
||||
VERIFY(dev_descriptor.descriptor_header.descriptor_type == DESCRIPTOR_TYPE_DEVICE);
|
||||
|
@ -83,24 +124,23 @@ KResult Device::enumerate()
|
|||
dbgln("Number of configurations: {:02x}", dev_descriptor.num_configurations);
|
||||
}
|
||||
|
||||
m_address = m_controller->allocate_address();
|
||||
auto new_address = m_controller->allocate_address();
|
||||
|
||||
// Attempt to set devices address on the bus
|
||||
transfer_length_or_error = m_default_pipe->control_transfer(USB_REQUEST_TRANSFER_DIRECTION_HOST_TO_DEVICE, USB_REQUEST_SET_ADDRESS, m_address, 0, 0, nullptr);
|
||||
transfer_length_or_error = m_default_pipe->control_transfer(USB_REQUEST_TRANSFER_DIRECTION_HOST_TO_DEVICE, USB_REQUEST_SET_ADDRESS, new_address, 0, 0, nullptr);
|
||||
|
||||
if (transfer_length_or_error.is_error())
|
||||
return transfer_length_or_error.error();
|
||||
|
||||
transfer_length = transfer_length_or_error.release_value();
|
||||
// This has to be set after we send out the "Set Address" request because it might be sent to the root hub.
|
||||
// The root hub uses the address to intercept requests to itself.
|
||||
m_address = new_address;
|
||||
m_default_pipe->set_device_address(new_address);
|
||||
|
||||
VERIFY(transfer_length > 0);
|
||||
dbgln_if(USB_DEBUG, "USB Device: Set address to {}", m_address);
|
||||
|
||||
memcpy(&m_device_descriptor, &dev_descriptor, sizeof(USBDeviceDescriptor));
|
||||
return KSuccess;
|
||||
}
|
||||
|
||||
Device::~Device()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue