fix(bt): configure static LE random address to resolve status 718 scan crash
This commit is contained in:
1 parent
2656af7975
commit
88c0dccd79
2 files changed
+144
-95
No files matched your search
@@ -165,6 +165,51 @@ bool QualcommWireless::sendHciReset(void) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QualcommWireless::sendHciLeSetRandomAddress(void) {
|
||||
// Bluetooth Core Specification 5.0+ (Vol 4, Part E, 7.8.5):
|
||||
// Commande HCI_LE_Set_Random_Address (Opcode: 0x2005 = OGF 0x08, OCF 0x0005)
|
||||
// Paramètre: 6 octets pour l'adresse aléatoire statique (les 2 bits de poids fort du MSB sont à 11b).
|
||||
// Sur macOS Monterey à Sequoia, bluetoothd initie un scan LE passif avec own_address_type = 0x01 (Random)
|
||||
// sans configurer d'adresse aléatoire. Le matériel Qualcomm WCN7850 rejette alors la commande
|
||||
// HCI_LE_Set_Scan_Enable avec le statut 0x12 (Invalid Parameters), provoquant le crash en boucle
|
||||
// de bluetoothd (OI_STATUS 718).
|
||||
// Adresse statique générée : EC:F2:3C:7F:1B:48 (0xEC = 1110 1100b -> bits 7 et 6 à 1).
|
||||
uint8_t cmd[9] = {0x05, 0x20, 0x06, 0x48, 0x1B, 0x7F, 0x3C, 0xF2, 0xEC};
|
||||
uint32_t transferred = 0;
|
||||
|
||||
StandardUSB::DeviceRequest req;
|
||||
req.bmRequestType = makeDeviceRequestbmRequestType(kRequestDirectionOut,
|
||||
kRequestTypeClass,
|
||||
kRequestRecipientInterface);
|
||||
req.bRequest = 0;
|
||||
req.wValue = 0;
|
||||
req.wIndex = 0;
|
||||
req.wLength = sizeof(cmd);
|
||||
|
||||
IOReturn kr = fDevice->deviceRequest(this, req, cmd, transferred, 2000);
|
||||
if (kr != kIOReturnSuccess) {
|
||||
IOLog("QualcommWireless: Erreur envoi HCI LE Set Random Address (0x%08x)\n", kr);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fIntrInPipe && fBulkBuffer) {
|
||||
uint32_t bytesRead = 0;
|
||||
kr = fIntrInPipe->io(fBulkBuffer, 256, bytesRead, 2000);
|
||||
if (kr == kIOReturnSuccess && bytesRead > 0) {
|
||||
uint8_t *evt = (uint8_t *)fBulkBuffer->getBytesNoCopy();
|
||||
if (evt[0] == 0x0E && bytesRead >= 6 && evt[5] == 0) {
|
||||
IOLog("QualcommWireless: HCI LE Set Random Address acquitte avec succes (statut 0x00) !\n");
|
||||
return true;
|
||||
} else {
|
||||
IOLog("QualcommWireless: HCI LE Set Random Address reponse evt=0x%02x statut=0x%02x\n",
|
||||
evt[0], (bytesRead > 5) ? evt[5] : 0xFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QualcommWireless::start(IOService *provider) {
|
||||
if (!super::start(provider)) return false;
|
||||
|
||||
@@ -203,108 +248,111 @@ bool QualcommWireless::start(IOService *provider) {
|
||||
bool needPatch = !(status & 0x80);
|
||||
bool needNvm = !(status & 0x40);
|
||||
|
||||
if (needPatch || needNvm) {
|
||||
// Recherche de l'interface 0 (avec réessais si l'énumération est en cours)
|
||||
for (int retry = 0; retry < 10 && !fInterface; retry++) {
|
||||
OSIterator *iterator = fDevice->getChildIterator(gIOServicePlane);
|
||||
if (iterator) {
|
||||
OSObject *candidate;
|
||||
while ((candidate = iterator->getNextObject())) {
|
||||
IOUSBHostInterface *intf = OSDynamicCast(IOUSBHostInterface, candidate);
|
||||
if (intf && intf->getInterfaceDescriptor() && intf->getInterfaceDescriptor()->bInterfaceNumber == 0) {
|
||||
fInterface = intf;
|
||||
fInterface->retain();
|
||||
break;
|
||||
}
|
||||
// Recherche de l'interface 0 (avec réessais si l'énumération est en cours)
|
||||
for (int retry = 0; retry < 10 && !fInterface; retry++) {
|
||||
OSIterator *iterator = fDevice->getChildIterator(gIOServicePlane);
|
||||
if (iterator) {
|
||||
OSObject *candidate;
|
||||
while ((candidate = iterator->getNextObject())) {
|
||||
IOUSBHostInterface *intf = OSDynamicCast(IOUSBHostInterface, candidate);
|
||||
if (intf && intf->getInterfaceDescriptor() && intf->getInterfaceDescriptor()->bInterfaceNumber == 0) {
|
||||
fInterface = intf;
|
||||
fInterface->retain();
|
||||
break;
|
||||
}
|
||||
OSSafeReleaseNULL(iterator);
|
||||
}
|
||||
if (!fInterface) {
|
||||
IOSleep(30);
|
||||
}
|
||||
OSSafeReleaseNULL(iterator);
|
||||
}
|
||||
|
||||
if (!fInterface) {
|
||||
IOLog("QualcommWireless: Erreur - Interface 0 non trouvee.\n");
|
||||
fDevice->close(this);
|
||||
OSSafeReleaseNULL(fDevice);
|
||||
return false;
|
||||
IOSleep(30);
|
||||
}
|
||||
|
||||
if (!fInterface->open(this)) {
|
||||
IOLog("QualcommWireless: Impossible d'ouvrir l'interface 0.\n");
|
||||
OSSafeReleaseNULL(fInterface);
|
||||
fDevice->close(this);
|
||||
OSSafeReleaseNULL(fDevice);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Recherche des pipes (Bulk OUT 0x02 et Interrupt IN 0x81)
|
||||
const StandardUSB::ConfigurationDescriptor *configDescriptor = fInterface->getConfigurationDescriptor();
|
||||
const StandardUSB::InterfaceDescriptor *interfaceDescriptor = fInterface->getInterfaceDescriptor();
|
||||
const EndpointDescriptor *endpointDescriptor = nullptr;
|
||||
|
||||
while ((endpointDescriptor = StandardUSB::getNextEndpointDescriptor(configDescriptor, interfaceDescriptor, endpointDescriptor))) {
|
||||
uint8_t epDirection = StandardUSB::getEndpointDirection(endpointDescriptor);
|
||||
uint8_t epType = StandardUSB::getEndpointType(endpointDescriptor);
|
||||
uint8_t epAddress = StandardUSB::getEndpointAddress(endpointDescriptor);
|
||||
|
||||
if (epDirection == kEndpointDirectionOut && epType == kEndpointTypeBulk) {
|
||||
fBulkOutPipe = fInterface->copyPipe(epAddress);
|
||||
} else if (epDirection == kEndpointDirectionIn && epType == kEndpointTypeInterrupt) {
|
||||
fIntrInPipe = fInterface->copyPipe(epAddress);
|
||||
}
|
||||
}
|
||||
|
||||
fBulkBuffer = fInterface->createIOBuffer(kIODirectionOut, QCA_DFU_PACKET_LEN);
|
||||
|
||||
if (fBulkOutPipe && fBulkBuffer) {
|
||||
if (needPatch) {
|
||||
IOLog("QualcommWireless: Televersement du RAMPATCH WCN7850 (%u octets)...\n", rampatch_usb_00190200_bin_len);
|
||||
if (downloadFirmware(rampatch_usb_00190200_bin, rampatch_usb_00190200_bin_len, 40)) {
|
||||
IOLog("QualcommWireless: RAMPATCH televerse avec succes !\n");
|
||||
} else {
|
||||
IOLog("QualcommWireless: Echec du televersement RAMPATCH !\n");
|
||||
}
|
||||
}
|
||||
|
||||
status = checkStatus();
|
||||
if (needNvm) {
|
||||
IOLog("QualcommWireless: Televersement du NVM WCN7850 (%u octets)...\n", nvm_usb_00190200_bin_len);
|
||||
if (downloadFirmware(nvm_usb_00190200_bin, nvm_usb_00190200_bin_len, 4)) {
|
||||
IOLog("QualcommWireless: NVM televerse avec succes !\n");
|
||||
} else {
|
||||
IOLog("QualcommWireless: Echec du televersement NVM !\n");
|
||||
}
|
||||
IOSleep(100);
|
||||
}
|
||||
|
||||
sendHciReset();
|
||||
|
||||
// Délai de stabilisation post-reset (150 ms) pour permettre au processeur Bluetooth
|
||||
// et aux tampons FIFO USB de re-calibrer leur état avant que bluetoothd n'initialise la pile.
|
||||
IOSleep(150);
|
||||
} else {
|
||||
IOLog("QualcommWireless: Erreur initialisation pipes ou buffer.\n");
|
||||
}
|
||||
|
||||
if (fIntrInPipe) {
|
||||
fIntrInPipe->clearStall(false);
|
||||
}
|
||||
if (fBulkOutPipe) {
|
||||
fBulkOutPipe->clearStall(false);
|
||||
}
|
||||
|
||||
OSSafeReleaseNULL(fBulkBuffer);
|
||||
OSSafeReleaseNULL(fBulkOutPipe);
|
||||
OSSafeReleaseNULL(fIntrInPipe);
|
||||
|
||||
if (fInterface->isOpen(this)) {
|
||||
fInterface->close(this);
|
||||
}
|
||||
OSSafeReleaseNULL(fInterface);
|
||||
}
|
||||
|
||||
if (!fInterface) {
|
||||
IOLog("QualcommWireless: Erreur - Interface 0 non trouvee.\n");
|
||||
fDevice->close(this);
|
||||
OSSafeReleaseNULL(fDevice);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!fInterface->open(this)) {
|
||||
IOLog("QualcommWireless: Impossible d'ouvrir l'interface 0.\n");
|
||||
OSSafeReleaseNULL(fInterface);
|
||||
fDevice->close(this);
|
||||
OSSafeReleaseNULL(fDevice);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Recherche des pipes (Bulk OUT 0x02 et Interrupt IN 0x81)
|
||||
const StandardUSB::ConfigurationDescriptor *configDescriptor = fInterface->getConfigurationDescriptor();
|
||||
const StandardUSB::InterfaceDescriptor *interfaceDescriptor = fInterface->getInterfaceDescriptor();
|
||||
const EndpointDescriptor *endpointDescriptor = nullptr;
|
||||
|
||||
while ((endpointDescriptor = StandardUSB::getNextEndpointDescriptor(configDescriptor, interfaceDescriptor, endpointDescriptor))) {
|
||||
uint8_t epDirection = StandardUSB::getEndpointDirection(endpointDescriptor);
|
||||
uint8_t epType = StandardUSB::getEndpointType(endpointDescriptor);
|
||||
uint8_t epAddress = StandardUSB::getEndpointAddress(endpointDescriptor);
|
||||
|
||||
if (epDirection == kEndpointDirectionOut && epType == kEndpointTypeBulk) {
|
||||
fBulkOutPipe = fInterface->copyPipe(epAddress);
|
||||
} else if (epDirection == kEndpointDirectionIn && epType == kEndpointTypeInterrupt) {
|
||||
fIntrInPipe = fInterface->copyPipe(epAddress);
|
||||
}
|
||||
}
|
||||
|
||||
fBulkBuffer = fInterface->createIOBuffer(kIODirectionOut, QCA_DFU_PACKET_LEN);
|
||||
|
||||
if (fBulkOutPipe && fBulkBuffer) {
|
||||
if (needPatch) {
|
||||
IOLog("QualcommWireless: Televersement du RAMPATCH WCN7850 (%u octets)...\n", rampatch_usb_00190200_bin_len);
|
||||
if (downloadFirmware(rampatch_usb_00190200_bin, rampatch_usb_00190200_bin_len, 40)) {
|
||||
IOLog("QualcommWireless: RAMPATCH televerse avec succes !\n");
|
||||
} else {
|
||||
IOLog("QualcommWireless: Echec du televersement RAMPATCH !\n");
|
||||
}
|
||||
}
|
||||
|
||||
status = checkStatus();
|
||||
if (needNvm) {
|
||||
IOLog("QualcommWireless: Televersement du NVM WCN7850 (%u octets)...\n", nvm_usb_00190200_bin_len);
|
||||
if (downloadFirmware(nvm_usb_00190200_bin, nvm_usb_00190200_bin_len, 4)) {
|
||||
IOLog("QualcommWireless: NVM televerse avec succes !\n");
|
||||
} else {
|
||||
IOLog("QualcommWireless: Echec du televersement NVM !\n");
|
||||
}
|
||||
IOSleep(100);
|
||||
}
|
||||
|
||||
// Réinitialisation du contrôleur Bluetooth
|
||||
sendHciReset();
|
||||
IOSleep(50);
|
||||
|
||||
// Configuration d'une adresse aléatoire statique obligatoire pour le scan LE de macOS (évite erreur 718)
|
||||
sendHciLeSetRandomAddress();
|
||||
|
||||
// Délai de stabilisation post-reset (150 ms) pour permettre au processeur Bluetooth
|
||||
// et aux tampons FIFO USB de re-calibrer leur état avant que bluetoothd n'initialise la pile.
|
||||
IOSleep(150);
|
||||
} else {
|
||||
IOLog("QualcommWireless: Erreur initialisation pipes ou buffer.\n");
|
||||
}
|
||||
|
||||
if (fIntrInPipe) {
|
||||
fIntrInPipe->clearStall(false);
|
||||
}
|
||||
if (fBulkOutPipe) {
|
||||
fBulkOutPipe->clearStall(false);
|
||||
}
|
||||
|
||||
OSSafeReleaseNULL(fBulkBuffer);
|
||||
OSSafeReleaseNULL(fBulkOutPipe);
|
||||
OSSafeReleaseNULL(fIntrInPipe);
|
||||
|
||||
if (fInterface->isOpen(this)) {
|
||||
fInterface->close(this);
|
||||
}
|
||||
OSSafeReleaseNULL(fInterface);
|
||||
|
||||
uint8_t finalStatus = checkStatus();
|
||||
IOLog("QualcommWireless: Statut FINAL: 0x%02x (Patch: %s, Syscfg: %s) -> Pret pour macOS !\n",
|
||||
finalStatus, (finalStatus & 0x80) ? "OUI" : "NON", (finalStatus & 0x40) ? "OUI" : "NON");
|
||||
|
||||
@@ -39,6 +39,7 @@ private:
|
||||
bool queryTargetVersion(struct qca_version *verOut);
|
||||
bool downloadFirmware(const uint8_t *data, size_t size, size_t hdrSize);
|
||||
bool sendHciReset(void);
|
||||
bool sendHciLeSetRandomAddress(void);
|
||||
|
||||
public:
|
||||
virtual bool init(OSDictionary *dictionary = 0) override;
|
||||
|
||||
Reference in new issue
Block a user