Download Game! Currently 97 players and visitors. Last logged in:EmboGalronioSarmaDefault

Blitzer's Blog >> 71052

Back to blogs index
Posted: 15 Jun 2026 09:28 [ permalink ]
The assignment was completely flawless.

`TD2 (STAT ) Status : 0x1C0007FF` means the Status IN stage returned exactly 0
bytes (`0x7FF` is USB-speak for a length of 0) and the Active bit cleared. The
keyboard accepted the command, updated its internal registers, and is now
exclusively listening on **Address 1**.

You have successfully detached the hardware from the shared default address.

### Phase 4: Waking the Interface (Set Configuration)

Even though the HP Keyboard has a unique address, it is currently in an
unconfigured, dormant state. Its internal scanning matrix isn't actually
looking for physical key presses yet.

To tell the keyboard to "wake up and start acting like a keyboard," we have to
send a `SET_CONFIGURATION` standard request. We will ask it to load
Configuration 1 (which enables its Human Interface Device endpoint).

This is another 2-stage DMA chain (SETUP -> STATUS IN), identical to the
Address assignment, but with two critical differences:

1. We must change the Device Address in our Transfer Descriptors from `0` to
`1`. In the UHCI Token register, the Device Address lives at bits 8-14. Our
Token changes from `0x00E0002D` to **`0x00E0012D`**.
2. We change the SETUP payload to `0x09` (Set Configuration) and ask for Value
`0x01`.

Drop this strike into your host terminal:

[GEM-TERMINAL-START]
cat << 'OUTER_EOF' > bcm_usb_setconf.sh
#!/bin/bash

```
echo "[HOST] 1. Forging SET_CONFIGURATION DMA Chain Payload..."
cat << 'JS_PAYLOAD' > usb_setconf.js
globalThis.USB.setConfig = function(base, address, configNum) {
    sys.serial("
[UHCI] Sending SET_CONFIGURATION " + configNum + " to Device " + address +
"...
");
    
    var dmaBase = sys.jit_addr();
    var flBase  = dmaBase + 0x30000;
    var qhBase  = dmaBase + 0x31000;
    var tdSetup = dmaBase + 0x32000;
    var tdStat  = dmaBase + 0x32040; 
    var bufSetup= dmaBase + 0x33000;
    
    // 1. Generate SOF Keepalives
    for (var i = 0; i < 1024; i++) globalThis.MMIO.poke32(flBase + (i*4),
0x00000001);
    sys.outw(base + 0x08, flBase & 0xFFFF);
    sys.outw(base + 0x0A, (flBase >> 16) & 0xFFFF);
    sys.outw(base + 0x00, 0x0001); // RUN
    
    for(var i=0; i<1000000; i++) {} // Stabilize
    
    // 2. Prepare SETUP Packet (SET_CONFIGURATION)
    // bmRequestType: 0x00 (Host-to-Device, Standard, Device)
    // bRequest: 0x09 (SET_CONFIGURATION)
    // wValue: configNum (0x0001)
    sys.poke(bufSetup+0, 0x00); sys.poke(bufSetup+1, 0x09); 
    sys.poke(bufSetup+2, configNum & 0xFF); sys.poke(bufSetup+3, 0x00); 
    sys.poke(bufSetup+4, 0x00); sys.poke(bufSetup+5, 0x00); 
    sys.poke(bufSetup+6, 0x00); sys.poke(bufSetup+7, 0x00); 
    
    // Shift Address into Token (Bits 8-14)
    var addrShift = (address & 0x7F) << 8;
    
    // 3. TD1 (SETUP, 8 bytes, Data0, Device X) -> Links to TD2
    globalThis.MMIO.poke32(tdSetup + 0, tdStat); 
    globalThis.MMIO.poke32(tdSetup + 4, 0x1C800000); 
    globalThis.MMIO.poke32(tdSetup + 8, 0x00E0002D | addrShift); 
    globalThis.MMIO.poke32(tdSetup + 12, bufSetup);
    
    // 4. TD2 (STATUS IN, 0 bytes, Data1, Device X) -> Links to Terminate
    globalThis.MMIO.poke32(tdStat + 0, 0x00000001); 
    globalThis.MMIO.poke32(tdStat + 4, 0x1C800000); 
    globalThis.MMIO.poke32(tdStat + 8, 0xFFE80069 | addrShift); 
    globalThis.MMIO.poke32(tdStat + 12, 0x00000000); 
    
    // 5. Link Queue Head
    globalThis.MMIO.poke32(qhBase + 0, 0x00000001);
    globalThis.MMIO.poke32(qhBase + 4, tdSetup);
    
    // 6. Hot-Plug Injection
    sys.serial(" -> Hot-Injecting SET_CONFIGURATION Chain to Address " +
address + "...
");
    var qhPtr = qhBase | 0x02;
    for (var i = 0; i < 1024; i++) globalThis.MMIO.poke32(flBase + (i*4),
qhPtr);
    
    // 7. Dynamic Polling
    var timeout = 0, st1, st2;
    while(timeout < 5000000) { 
        st1 = globalThis.MMIO.peek32(tdSetup + 4);
        st2 = globalThis.MMIO.peek32(tdStat + 4);
        
        if ((st1 & 0x00800000) === 0 && (st1 & 0x7E0000) !== 0) break;
        if ((st2 & 0x00800000) === 0) break;
        timeout++;
    }
    
    // 8. Cleanup
    for (var i = 0; i < 1024; i++) globalThis.MMIO.poke32(flBase + (i*4),
0x00000001);
    sys.outw(base + 0x00, 0x0000); // Stop controller
    
    sys.serial("
=== SET CONFIGURATION RESULTS ===
");
    sys.serial("Polls              : " + timeout + "
");
    sys.serial("TD1 (SETUP) Status : 0x" + st1.toString(16).toUpperCase() + "
");
    sys.serial("TD2 (STAT ) Status : 0x" + st2.toString(16).toUpperCase() + "
");
    
    if ((st2 & 0x00800000) === 0 && (st2 & 0x7E0000) === 0) {
        sys.serial("
[SUCCESS] HP Keyboard Endpoints are ONLINE.
");
    } else {
        sys.serial("
[ERROR] Device rejected configuration.
");
    }
    
    return "SET_CONF_COMPLETE";
};
JS_PAYLOAD

echo "[HOST] 2. Streaming Payload..."
echo "/eval EOF" | x-console elli send-stdin
cat usb_setconf.js | x-console elli send-stdin 0.05
echo "EOF" | x-console elli send-stdin

sleep 2

echo "[HOST] 3. Triggering SET_CONFIGURATION (Config 1) on Address 1..."
x-console elli send "globalThis.USB.setConfig(0x4440, 1, 1)" Enter

echo "[HOST] 4. Tailing Output:"
x-console elli tail 20
OUTER_EOF

chmod +x bcm_usb_setconf.sh