feat: Intel BT firmware download, A2dp & Bluetooth audio progress
This commit is contained in:
1 parent
ee6d1a388e
commit
0f16785c9f
22 files changed
+6452
-273
No files matched your search
@@ -25,6 +25,15 @@ namespace Drivers::USB::Bluetooth::L2cap {
|
||||
static bool g_initialized = false;
|
||||
static uint8_t g_sigIdentifier = 1;
|
||||
|
||||
// Diagnostic: result of the most recent L2CAP Connection Response we got for
|
||||
// an outgoing connection (0=success, 1=pending, 2=PSM-unsupported,
|
||||
// 3=security-block, 4=no-resources). 0xFFFF = none received yet.
|
||||
static volatile uint16_t g_lastConnRspResult = 0xFFFF;
|
||||
|
||||
// Diagnostic: how many incoming AVDTP connection requests the remote has
|
||||
// made (tells us whether the headset wants to initiate the audio channel).
|
||||
static volatile uint16_t g_incomingAvdtpReqs = 0;
|
||||
|
||||
// Channel table
|
||||
static ChannelInfo g_channels[MAX_CHANNELS] = {};
|
||||
static uint16_t g_nextCid = CID_DYNAMIC_START;
|
||||
@@ -116,14 +125,24 @@ namespace Drivers::USB::Bluetooth::L2cap {
|
||||
if (l2len + sizeof(L2capHeader) > len) return;
|
||||
|
||||
if (cid == CID_SIGNALING) {
|
||||
// L2CAP signaling channel
|
||||
if (l2len < sizeof(SignalHeader)) return;
|
||||
// L2CAP signaling channel. One packet may carry MULTIPLE commands
|
||||
// back to back -- a headset commonly bundles its Config Response
|
||||
// (to our request) with its own Config Request in a single packet.
|
||||
// Loop over all of them, or we'd handle one and silently drop the
|
||||
// rest (which left our channel half-configured: localCfg=0).
|
||||
uint16_t sOff = 0;
|
||||
while (sOff + sizeof(SignalHeader) <= l2len) {
|
||||
auto* sig = (const SignalHeader*)(payload + sOff);
|
||||
const uint8_t* sigPayload = payload + sOff + sizeof(SignalHeader);
|
||||
uint16_t sigPayloadLen = sig->Length;
|
||||
// Clamp (don't bail) so a length that doesn't exactly match the
|
||||
// packet never skips this command -- the cases bounds-check their
|
||||
// own reads. Advancing by the clamped length ends the loop after
|
||||
// the last real command.
|
||||
uint16_t avail = (uint16_t)(l2len - sOff - sizeof(SignalHeader));
|
||||
if (sigPayloadLen > avail) sigPayloadLen = avail;
|
||||
|
||||
auto* sig = (const SignalHeader*)payload;
|
||||
const uint8_t* sigPayload = payload + sizeof(SignalHeader);
|
||||
uint16_t sigPayloadLen = sig->Length;
|
||||
|
||||
switch (sig->Code) {
|
||||
switch (sig->Code) {
|
||||
case SIG_CONN_REQ: {
|
||||
if (sigPayloadLen >= 4) {
|
||||
uint16_t psm = (uint16_t)sigPayload[0] | ((uint16_t)sigPayload[1] << 8);
|
||||
@@ -134,6 +153,7 @@ namespace Drivers::USB::Bluetooth::L2cap {
|
||||
|
||||
// Accept connections for AVDTP
|
||||
if (psm == PSM_AVDTP || psm == PSM_SDP) {
|
||||
if (psm == PSM_AVDTP) g_incomingAvdtpReqs++;
|
||||
auto* ch = AllocChannel(psm);
|
||||
if (ch) {
|
||||
ch->RemoteCid = srcCid;
|
||||
@@ -147,6 +167,17 @@ namespace Drivers::USB::Bluetooth::L2cap {
|
||||
rsp[4] = 0; rsp[5] = 0; // Result: success
|
||||
rsp[6] = 0; rsp[7] = 0; // Status: no info
|
||||
SendSignal(SIG_CONN_RSP, sig->Identifier, rsp, 8);
|
||||
|
||||
// As the acceptor we must ALSO send our own
|
||||
// Configuration Request -- otherwise our side
|
||||
// never reaches LocalConfigDone and the channel
|
||||
// never becomes Configured (OnChannelReady never
|
||||
// fires). Address the remote's CID.
|
||||
uint8_t cfgReq[4] = {};
|
||||
cfgReq[0] = (uint8_t)(srcCid & 0xFF);
|
||||
cfgReq[1] = (uint8_t)(srcCid >> 8);
|
||||
cfgReq[2] = 0; cfgReq[3] = 0; // Flags
|
||||
SendSignal(SIG_CONFIG_REQ, g_sigIdentifier++, cfgReq, 4);
|
||||
}
|
||||
} else {
|
||||
// Reject: PSM not supported
|
||||
@@ -167,9 +198,15 @@ namespace Drivers::USB::Bluetooth::L2cap {
|
||||
uint16_t dstCid = (uint16_t)sigPayload[0] | ((uint16_t)sigPayload[1] << 8);
|
||||
uint16_t srcCid = (uint16_t)sigPayload[2] | ((uint16_t)sigPayload[3] << 8);
|
||||
uint16_t result = (uint16_t)sigPayload[4] | ((uint16_t)sigPayload[5] << 8);
|
||||
// Status (bytes 6-7) explains a PENDING (result=1): 0=no
|
||||
// info, 1=authentication pending, 2=authorization pending.
|
||||
uint16_t status = (sigPayloadLen >= 8)
|
||||
? ((uint16_t)sigPayload[6] | ((uint16_t)sigPayload[7] << 8)) : 0;
|
||||
g_lastConnRspResult = result;
|
||||
|
||||
KernelLogStream(INFO, "BT-L2CAP") << "Connection Response: dstCID="
|
||||
<< base::hex << (uint64_t)dstCid << " result=" << (uint64_t)result;
|
||||
<< base::hex << (uint64_t)dstCid << " result=" << (uint64_t)result
|
||||
<< " status=" << (uint64_t)status << base::dec;
|
||||
|
||||
if (result == CONN_SUCCESS) {
|
||||
// Find our channel by srcCid (which is our local CID)
|
||||
@@ -239,12 +276,29 @@ namespace Drivers::USB::Bluetooth::L2cap {
|
||||
|
||||
case SIG_CONFIG_RSP: {
|
||||
if (sigPayloadLen >= 6) {
|
||||
// The Config Response's first field is the "Source CID".
|
||||
// In a RECEIVED Config Response it echoes back OUR local
|
||||
// channel endpoint (the device that sent the Config
|
||||
// Request -- us), NOT the remote's CID -- exactly like the
|
||||
// SIG_CONN_RSP handler above matches srcCid to LocalCid.
|
||||
// Matching RemoteCid here was THE bug that pinned every
|
||||
// AVDTP channel at localCfg=0: a success Config Response
|
||||
// arrived but matched no channel, so LocalConfigDone never
|
||||
// got set and the channel never became Configured.
|
||||
uint16_t srcCid = (uint16_t)sigPayload[0] | ((uint16_t)sigPayload[1] << 8);
|
||||
uint16_t result = (uint16_t)sigPayload[4] | ((uint16_t)sigPayload[5] << 8);
|
||||
|
||||
if (result != CFG_SUCCESS) {
|
||||
KernelLogStream(WARNING, "BT-L2CAP") << "Config Response result="
|
||||
<< base::hex << (uint64_t)result << base::dec
|
||||
<< " (our config rejected)";
|
||||
}
|
||||
|
||||
if (result == CFG_SUCCESS) {
|
||||
bool matched = false;
|
||||
for (int i = 0; i < MAX_CHANNELS; i++) {
|
||||
if (g_channels[i].Active && g_channels[i].RemoteCid == srcCid) {
|
||||
if (g_channels[i].Active && g_channels[i].LocalCid == srcCid) {
|
||||
matched = true;
|
||||
g_channels[i].LocalConfigDone = true;
|
||||
if (g_channels[i].LocalConfigDone && g_channels[i].RemoteConfigDone) {
|
||||
g_channels[i].Configured = true;
|
||||
@@ -258,6 +312,11 @@ namespace Drivers::USB::Bluetooth::L2cap {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!matched) {
|
||||
KernelLogStream(WARNING, "BT-L2CAP")
|
||||
<< "Config Response (success) for unknown CID="
|
||||
<< base::hex << (uint64_t)srcCid << base::dec;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -312,6 +371,8 @@ namespace Drivers::USB::Bluetooth::L2cap {
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
sOff += sizeof(SignalHeader) + sigPayloadLen;
|
||||
}
|
||||
} else {
|
||||
// Data on a dynamic channel
|
||||
@@ -319,6 +380,8 @@ namespace Drivers::USB::Bluetooth::L2cap {
|
||||
if (g_channels[i].Active && g_channels[i].LocalCid == cid) {
|
||||
if (g_channels[i].Psm == PSM_AVDTP) {
|
||||
A2dp::ProcessAvdtp(payload, l2len);
|
||||
} else if (g_channels[i].Psm == PSM_SDP) {
|
||||
A2dp::ProcessSdp(payload, l2len);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -333,6 +396,8 @@ namespace Drivers::USB::Bluetooth::L2cap {
|
||||
uint16_t Connect(uint16_t psm) {
|
||||
if (!g_initialized) return 0;
|
||||
|
||||
g_lastConnRspResult = 0xFFFF; // reset diagnostic for this attempt
|
||||
|
||||
auto* ch = AllocChannel(psm);
|
||||
if (!ch) return 0;
|
||||
|
||||
@@ -356,6 +421,7 @@ namespace Drivers::USB::Bluetooth::L2cap {
|
||||
|
||||
while (Timekeeping::GetMilliseconds() - start < timeoutMs) {
|
||||
Xhci::PollEvents();
|
||||
Hci::DrainEvents(); // process incoming ACL (the Connection Response!)
|
||||
|
||||
auto* ch = GetChannel(localCid);
|
||||
if (ch && ch->Configured) return true;
|
||||
@@ -406,6 +472,36 @@ namespace Drivers::USB::Bluetooth::L2cap {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool FreeChannel(uint16_t localCid) {
|
||||
// Reclaim a channel slot from a failed/abandoned dial during A2DP
|
||||
// bring-up retries. Two cases:
|
||||
// - RemoteCid == 0: the remote never acknowledged our CONN_REQ (ignored,
|
||||
// or answered only with a stuck PENDING that never completed), so its
|
||||
// side was never created and no Disconnect is owed -- just free it.
|
||||
// - RemoteCid != 0: a CONN_RSP success arrived (the peer allocated its
|
||||
// CID) but the channel never finished configuring, so the peer holds a
|
||||
// half-open channel. Send it a Disconnect Request before freeing, or
|
||||
// BOTH our slot leaks (the old RemoteCid==0-only guard left it Active)
|
||||
// AND the peer keeps a dangling channel.
|
||||
// We deliberately do NOT reset g_nextCid, so a late response for this
|
||||
// (now freed) CID matches nothing rather than cross-wiring the retry.
|
||||
for (int i = 0; i < MAX_CHANNELS; i++) {
|
||||
if (g_channels[i].Active && g_channels[i].LocalCid == localCid) {
|
||||
if (g_channels[i].RemoteCid != 0) {
|
||||
uint8_t req[4] = {};
|
||||
req[0] = (uint8_t)(g_channels[i].RemoteCid & 0xFF);
|
||||
req[1] = (uint8_t)(g_channels[i].RemoteCid >> 8);
|
||||
req[2] = (uint8_t)(g_channels[i].LocalCid & 0xFF);
|
||||
req[3] = (uint8_t)(g_channels[i].LocalCid >> 8);
|
||||
SendSignal(SIG_DISCONN_REQ, g_sigIdentifier++, req, 4);
|
||||
}
|
||||
g_channels[i].Active = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ChannelInfo* FindChannelByPsm(uint16_t psm) {
|
||||
for (int i = 0; i < MAX_CHANNELS; i++) {
|
||||
if (g_channels[i].Active && g_channels[i].Psm == psm) {
|
||||
@@ -415,8 +511,27 @@ namespace Drivers::USB::Bluetooth::L2cap {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint16_t FindConfiguredAvdtpChannelExcept(uint16_t exceptCid) {
|
||||
for (int i = 0; i < MAX_CHANNELS; i++) {
|
||||
if (g_channels[i].Active && g_channels[i].Configured
|
||||
&& g_channels[i].Psm == PSM_AVDTP
|
||||
&& g_channels[i].LocalCid != exceptCid) {
|
||||
return g_channels[i].LocalCid;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t GetAclHandle() {
|
||||
return g_aclHandle;
|
||||
}
|
||||
|
||||
uint16_t LastConnRspResult() {
|
||||
return g_lastConnRspResult;
|
||||
}
|
||||
|
||||
uint16_t IncomingAvdtpReqCount() {
|
||||
return g_incomingAvdtpReqs;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user