diff --git a/src/driver/bus/usb/driver.bus.usb.core.pas b/src/driver/bus/usb/driver.bus.usb.core.pas index 1ce08a85..2e1437d7 100644 --- a/src/driver/bus/usb/driver.bus.usb.core.pas +++ b/src/driver/bus/usb/driver.bus.usb.core.pas @@ -247,8 +247,7 @@ begin if (status AND $01) <> 0 then begin io.syslog.log('driver.bus.usb Core', 'Device detected on port '); io.syslog.writeintln(port); - { Determine speed from status bits - HC specific, - default to full-speed for now } + { Root-port speed is resolved by enumerate_device after reset. } speed := USB_SPEED_FULL; enumerate_device(hc, port, speed, nil, port); end; @@ -656,6 +655,10 @@ begin end; end; + { Speed is valid after reset. Hub children retain the hub-reported speed. } + if (parentHub = nil) and (hc^.fnPortSpeed <> nil) then + speed := hc^.fnPortSpeed(hc, port); + { Step 2: Create device at address 0 } dev := PUSBDevice(kalloc(sizeof(TUSBDevice))); dev^.Address := 0; diff --git a/src/driver/bus/usb/driver.bus.usb.ehci.pas b/src/driver/bus/usb/driver.bus.usb.ehci.pas index b78652a8..ee036e1e 100644 --- a/src/driver/bus/usb/driver.bus.usb.ehci.pas +++ b/src/driver/bus/usb/driver.bus.usb.ehci.pas @@ -783,6 +783,13 @@ end; { ========================= Port Reset ========================= } +function ehci_port_speed(hc : PUSBHCDriver; port : uint8) : uint8; +begin + { Successful EHCI root resets retain only high-speed devices; + full/low-speed devices are handed to a companion controller. } + ehci_port_speed := USB_SPEED_HIGH; +end; + function ehci_port_reset(hc : PUSBHCDriver; port : uint8) : boolean; var priv : PEHCI_PrivData; @@ -1558,6 +1565,7 @@ begin hc.fnPoll := TUSBHCPoll(@ehci_poll); hc.fnPortReset := TUSBHCPortReset(@ehci_port_reset); hc.fnPortStatus := TUSBHCPortStatus(@ehci_port_status); + hc.fnPortSpeed := TUSBHCPortSpeed(@ehci_port_speed); { Reset the controller } if not ehci_reset(@hc) then begin diff --git a/src/driver/bus/usb/driver.bus.usb.ohci.pas b/src/driver/bus/usb/driver.bus.usb.ohci.pas index b40e30b3..448b8ac3 100644 --- a/src/driver/bus/usb/driver.bus.usb.ohci.pas +++ b/src/driver/bus/usb/driver.bus.usb.ohci.pas @@ -602,6 +602,14 @@ end; { ========================= Port Reset ========================= } +function ohci_port_speed(hc : PUSBHCDriver; port : uint8) : uint8; +begin + if (ohci_port_status(hc, port) AND OHCI_PORT_LSDA) <> 0 then + ohci_port_speed := USB_SPEED_LOW + else + ohci_port_speed := USB_SPEED_FULL; +end; + function ohci_port_reset(hc : PUSBHCDriver; port : uint8) : boolean; var priv : POHCI_PrivData; @@ -1257,6 +1265,7 @@ begin hc.fnPoll := TUSBHCPoll(@ohci_poll); hc.fnPortReset := TUSBHCPortReset(@ohci_port_reset); hc.fnPortStatus := TUSBHCPortStatus(@ohci_port_status); + hc.fnPortSpeed := TUSBHCPortSpeed(@ohci_port_speed); { Reset the controller } if not ohci_reset(@hc) then begin diff --git a/src/driver/bus/usb/driver.bus.usb.types.pas b/src/driver/bus/usb/driver.bus.usb.types.pas index 3d6a8441..1bb0eb4f 100644 --- a/src/driver/bus/usb/driver.bus.usb.types.pas +++ b/src/driver/bus/usb/driver.bus.usb.types.pas @@ -261,6 +261,8 @@ type TUSBHCPoll = procedure(hc : PUSBHCDriver); TUSBHCPortReset = function(hc : PUSBHCDriver; port : uint8) : boolean; TUSBHCPortStatus = function(hc : PUSBHCDriver; port : uint8) : uint32; + { Return USB_SPEED_* after root-port reset has completed. } + TUSBHCPortSpeed = function(hc : PUSBHCDriver; port : uint8) : uint8; { ---- HC Driver Record ---- } @@ -283,6 +285,7 @@ type fnPoll : TUSBHCPoll; fnPortReset : TUSBHCPortReset; fnPortStatus : TUSBHCPortStatus; + fnPortSpeed : TUSBHCPortSpeed; end; { ========================= Utility Functions ========================= } @@ -429,6 +432,7 @@ begin hc^.fnPoll := nil; hc^.fnPortReset := nil; hc^.fnPortStatus := nil; + hc^.fnPortSpeed := nil; end; pop_trace; end; diff --git a/src/driver/bus/usb/driver.bus.usb.uhci.pas b/src/driver/bus/usb/driver.bus.usb.uhci.pas index 0096f0ff..45372cfd 100644 --- a/src/driver/bus/usb/driver.bus.usb.uhci.pas +++ b/src/driver/bus/usb/driver.bus.usb.uhci.pas @@ -453,6 +453,14 @@ end; { ========================= Port Reset ========================= } +function uhci_port_speed(hc : PUSBHCDriver; port : uint8) : uint8; +begin + if (uhci_port_status(hc, port) AND UHCI_PORT_LSDA) <> 0 then + uhci_port_speed := USB_SPEED_LOW + else + uhci_port_speed := USB_SPEED_FULL; +end; + function uhci_port_reset(hc : PUSBHCDriver; port : uint8) : boolean; var priv : PUHCI_PrivData; @@ -976,6 +984,7 @@ begin hc.fnPoll := TUSBHCPoll(@uhci_poll); hc.fnPortReset := TUSBHCPortReset(@uhci_port_reset); hc.fnPortStatus := TUSBHCPortStatus(@uhci_port_status); + hc.fnPortSpeed := TUSBHCPortSpeed(@uhci_port_speed); { Reset the controller } if not uhci_reset(@hc) then begin diff --git a/src/driver/bus/usb/driver.bus.usb.xhci.pas b/src/driver/bus/usb/driver.bus.usb.xhci.pas index af9cdf2e..d1fd063d 100644 --- a/src/driver/bus/usb/driver.bus.usb.xhci.pas +++ b/src/driver/bus/usb/driver.bus.usb.xhci.pas @@ -1142,6 +1142,12 @@ begin pop_trace; end; +function xhci_port_speed(hc : PUSBHCDriver; port : uint8) : uint8; +begin + xhci_port_speed := xhci_map_speed( + (xhci_port_status(hc, port) AND XHCI_PORTSC_SPEED_MASK) SHR XHCI_PORTSC_SPEED_SHIFT); +end; + function xhci_port_reset(hc : PUSBHCDriver; port : uint8) : boolean; var priv : PXHCI_PrivData; @@ -2095,6 +2101,7 @@ begin hc.fnPoll := TUSBHCPoll(@xhci_poll); hc.fnPortReset := TUSBHCPortReset(@xhci_port_reset); hc.fnPortStatus := TUSBHCPortStatus(@xhci_port_status); + hc.fnPortSpeed := TUSBHCPortSpeed(@xhci_port_speed); { Reset the controller } if not xhci_reset(@hc) then begin