### Breakthroughs & Rétro-ingénierie - Analyse du désassemblage de IO80211Controller::start dans BootKernelExtensions.kc : 1. IO80211Controller::start() invoque directement le slot 399 (getWorkQueue) et le passe immédiatement à IO80211PostOffice::allocWithParams et IO80211TimerSource::allocWithParams. 2. Si getWorkQueue renvoie NULL, le noyau déréférence un pointeur nul ou saute vers une branche d'échec critique. 3. L'invocation préalable de createWorkQueue() avant super::start(provider) garantit que IO80211WorkQueue est immédiatement disponible et valide. - Suppression du piège d'écriture NVRAM (SetVariable en early boot) : Sur chipset AMD AM4/AM5, l'appel à AppleEFINVRAM::setProperty lors de l'initialisation de kext déclenche un appel RT->SetVariable en SMM. Sans mapping d'adresses virtuelles 1:1 pour le contrôleur SPI sous firmware AMD AGESA, cela provoque un Machine Check instantané réinitialisant la carte mère sans panic log. - Sécurisation de l'alimentation PCIe : Suppression de enablePCIPowerManagement(kPCIPMCSPowerStateD0) susceptible d'entrer en conflit avec ACPI D-states sur les ports racines PCIe AMD. - Normalisation OSBundleRequired : Passage de 'Network-Root' à 'Root' dans Info.plist (identique à QualcommWireless.kext). ### Modifications apportées - QualcommWifi/QualcommWifi.cpp : - Suppression des écritures NVRAM dans logNvramStage, conservation de IOLog console directe. - Inscription de createWorkQueue() avant l'appel à super::start(provider) dans start(). - Retrait du changement manuel d'état D0 via enablePCIPowerManagement. - QualcommWifi/Info.plist : - Remplacement de OSBundleRequired par Root. ### Validation - Compilation réussie avec clang 17 et SDK macOS Tahoe 26.x. - Validation 100% kmutil libraries contre BootKernelExtensions.kc.
1017 lines
40 KiB
C++
1017 lines
40 KiB
C++
#include "QualcommWifi.hpp"
|
|
#include <IOKit/IOLib.h>
|
|
#include <libkern/OSByteOrder.h>
|
|
#include <kern/task.h>
|
|
#include <string.h>
|
|
|
|
// Stubs locaux pour les réservations IONetworkController 2..7 non exportées par BootKernelExtensions.kc
|
|
extern "C" {
|
|
void _ZN19IONetworkController29_RESERVEDIONetworkController2Ev(void) {}
|
|
void _ZN19IONetworkController29_RESERVEDIONetworkController3Ev(void) {}
|
|
void _ZN19IONetworkController29_RESERVEDIONetworkController4Ev(void) {}
|
|
void _ZN19IONetworkController29_RESERVEDIONetworkController5Ev(void) {}
|
|
void _ZN19IONetworkController29_RESERVEDIONetworkController6Ev(void) {}
|
|
void _ZN19IONetworkController29_RESERVEDIONetworkController7Ev(void) {}
|
|
}
|
|
|
|
#include <pexpert/pexpert.h>
|
|
#include <IOKit/IODeviceTreeSupport.h>
|
|
|
|
static char gLogBuffer[2048] = "QCOM_BOOT:";
|
|
|
|
static void logNvramStage(const char *tag) {
|
|
size_t curLen = strlen(gLogBuffer);
|
|
if (curLen + strlen(tag) + 2 < sizeof(gLogBuffer)) {
|
|
strcat(gLogBuffer, ">");
|
|
strcat(gLogBuffer, tag);
|
|
}
|
|
IOLog("QualcommWifi: >>> [STAGE] %s <<<\n", tag);
|
|
}
|
|
|
|
#define super IO80211Controller
|
|
OSDefineMetaClassAndStructors(QualcommWifi, IO80211Controller)
|
|
|
|
bool QualcommWifi::init(OSDictionary *dictionary) {
|
|
logNvramStage("init_enter");
|
|
if (!super::init(dictionary)) {
|
|
logNvramStage("init_super_failed");
|
|
return false;
|
|
}
|
|
logNvramStage("init_super_ok");
|
|
fPciDevice = nullptr;
|
|
fBar0Map = nullptr;
|
|
fBar0Virt = nullptr;
|
|
fCurrWindow = 0xFFFFFFFF;
|
|
fInterruptSource = nullptr;
|
|
fWorkQueue = nullptr;
|
|
fNetif = nullptr;
|
|
// Adresse MAC par défaut (OUI Qualcomm 00:03:7F) en attendant la lecture BHI
|
|
fMacAddress.bytes[0] = 0x00;
|
|
fMacAddress.bytes[1] = 0x03;
|
|
fMacAddress.bytes[2] = 0x7F;
|
|
fMacAddress.bytes[3] = 0x11;
|
|
fMacAddress.bytes[4] = 0x07;
|
|
fMacAddress.bytes[5] = 0x01;
|
|
fLinkActive = false;
|
|
fCurrentChannel = 1;
|
|
fLastRssi = -50;
|
|
fSsidLen = 0;
|
|
bzero(fSsid, sizeof(fSsid));
|
|
bzero(fBssid, sizeof(fBssid));
|
|
fScanInProgress = false;
|
|
fDmaBuf = nullptr;
|
|
fDmaPhysAddr = 0;
|
|
fDmaVirtAddr = nullptr;
|
|
fDmaPrepared = false;
|
|
fFirmwareLoaded = false;
|
|
return true;
|
|
}
|
|
|
|
void QualcommWifi::free(void) {
|
|
OSSafeReleaseNULL(fWorkQueue);
|
|
super::free();
|
|
}
|
|
|
|
IOService *QualcommWifi::probe(IOService *provider, SInt32 *score) {
|
|
logNvramStage("probe_enter");
|
|
if (!super::probe(provider, score)) {
|
|
logNvramStage("probe_super_failed");
|
|
return nullptr;
|
|
}
|
|
|
|
IOPCIDevice *pciDev = OSDynamicCast(IOPCIDevice, provider);
|
|
if (!pciDev) {
|
|
logNvramStage("probe_not_pci");
|
|
return nullptr;
|
|
}
|
|
|
|
UInt16 vendorId = pciDev->configRead16(kIOPCIConfigVendorID);
|
|
UInt16 deviceId = pciDev->configRead16(kIOPCIConfigDeviceID);
|
|
|
|
if (vendorId == 0x17cb && deviceId == 0x1107) {
|
|
IOLog("QualcommWifi: Controleur Wi-Fi 7 Qualcomm WCN7850 detecte (0x%04x:0x%04x) !\n", vendorId, deviceId);
|
|
*score += 20000;
|
|
logNvramStage("probe_match_ok");
|
|
return this;
|
|
}
|
|
|
|
logNvramStage("probe_no_match");
|
|
return nullptr;
|
|
}
|
|
|
|
UInt32 QualcommWifi::read32(UInt32 offset) {
|
|
if (!fBar0Virt || offset >= 0x200000) {
|
|
return 0xFFFFFFFF;
|
|
}
|
|
return OSReadLittleInt32(fBar0Virt, offset);
|
|
}
|
|
|
|
void QualcommWifi::write32(UInt32 offset, UInt32 value) {
|
|
if (!fBar0Virt || offset >= 0x200000) {
|
|
return;
|
|
}
|
|
OSWriteLittleInt32(fBar0Virt, offset, value);
|
|
}
|
|
|
|
void QualcommWifi::selectWindow(UInt32 offset) {
|
|
UInt32 window = (offset >> ATH12K_PCI_WINDOW_SHIFT) & ATH12K_PCI_WINDOW_VALUE_MASK;
|
|
if (window != fCurrWindow) {
|
|
write32(ATH12K_PCI_WINDOW_REG_ADDRESS, ATH12K_PCI_WINDOW_ENABLE_BIT | window);
|
|
(void)read32(ATH12K_PCI_WINDOW_REG_ADDRESS);
|
|
fCurrWindow = window;
|
|
}
|
|
}
|
|
|
|
UInt32 QualcommWifi::socRead32(UInt32 offset) {
|
|
if (offset < ATH12K_PCI_WINDOW_START) {
|
|
return read32(offset);
|
|
}
|
|
selectWindow(offset);
|
|
return read32(ATH12K_PCI_WINDOW_START + (offset & ATH12K_PCI_WINDOW_RANGE_MASK));
|
|
}
|
|
|
|
void QualcommWifi::socWrite32(UInt32 offset, UInt32 value) {
|
|
if (offset < ATH12K_PCI_WINDOW_START) {
|
|
write32(offset, value);
|
|
return;
|
|
}
|
|
selectWindow(offset);
|
|
write32(ATH12K_PCI_WINDOW_START + (offset & ATH12K_PCI_WINDOW_RANGE_MASK), value);
|
|
}
|
|
|
|
// Allocation du contexte DMA contigu (36-bit)
|
|
bool QualcommWifi::allocDmaContext(IOByteCount size) {
|
|
fDmaBuf = IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
|
|
kernel_task,
|
|
static_cast<IOOptionBits>(kIODirectionInOut) | static_cast<IOOptionBits>(kIOMemoryPhysicallyContiguous),
|
|
size,
|
|
ATH12K_DMA_MASK_36BIT_PAGE
|
|
);
|
|
|
|
if (!fDmaBuf) {
|
|
IOLog("QualcommWifi: Erreur - Impossible d'allouer le descripteur DMA 36-bit.\n");
|
|
return false;
|
|
}
|
|
|
|
if (fDmaBuf->prepare(kIODirectionInOut) != kIOReturnSuccess) {
|
|
IOLog("QualcommWifi: Erreur - Impossible de verrouiller (prepare) les pages DMA.\n");
|
|
OSSafeReleaseNULL(fDmaBuf);
|
|
return false;
|
|
}
|
|
fDmaPrepared = true;
|
|
|
|
fDmaVirtAddr = fDmaBuf->getBytesNoCopy();
|
|
IOByteCount segLen = 0;
|
|
fDmaPhysAddr = fDmaBuf->getPhysicalSegment(0, &segLen);
|
|
|
|
if (!fDmaVirtAddr || !fDmaPhysAddr || segLen < size) {
|
|
IOLog("QualcommWifi: Erreur - Segment physique DMA invalide (segLen=%llu).\n", (uint64_t)segLen);
|
|
freeDmaContext();
|
|
return false;
|
|
}
|
|
|
|
bzero(fDmaVirtAddr, size);
|
|
IOLog("QualcommWifi: Tampon DMA 36-bit pret ! Phys: 0x%llx, Taille: %llu octets (Contigu: %llu)\n",
|
|
(uint64_t)fDmaPhysAddr, (uint64_t)size, (uint64_t)segLen);
|
|
return true;
|
|
}
|
|
|
|
void QualcommWifi::freeDmaContext(void) {
|
|
if (fDmaBuf) {
|
|
if (fDmaPrepared) {
|
|
fDmaBuf->complete(kIODirectionInOut);
|
|
fDmaPrepared = false;
|
|
}
|
|
OSSafeReleaseNULL(fDmaBuf);
|
|
}
|
|
fDmaVirtAddr = nullptr;
|
|
fDmaPhysAddr = 0;
|
|
}
|
|
|
|
void QualcommWifi::interruptOccurred(OSObject *owner, IOInterruptEventSource *src, int count) {
|
|
IOLog("QualcommWifi: Interruption materielle MSI recue (count=%d) !\n", count);
|
|
}
|
|
|
|
bool QualcommWifi::loadBhiFirmware(void) {
|
|
if (!fBar0Virt || !fPciDevice) {
|
|
return false;
|
|
}
|
|
|
|
UInt32 bhiOff = read32(ATH12K_MHI_BHIOFF);
|
|
UInt32 bhieOff = read32(ATH12K_MHI_BHIEOFF);
|
|
if (bhiOff == 0xFFFFFFFF || bhiOff >= 0x200000 || bhieOff == 0xFFFFFFFF || bhieOff >= 0x200000) {
|
|
IOLog("QualcommWifi: Erreur - BHI/BHIe Offsets invalides (BHI: 0x%08x, BHIe: 0x%08x)\n", bhiOff, bhieOff);
|
|
setProperty("BHI_Load_Error", "Invalid_Offsets");
|
|
return false;
|
|
}
|
|
|
|
// Désactivation d'ASPM PCIe pour stabiliser le transfert firmware (recommandation ath12k)
|
|
UInt8 pciCapOffset = 0;
|
|
if (fPciDevice->findPCICapability(kIOPCIPCIExpressCapability, &pciCapOffset) && pciCapOffset != 0) {
|
|
UInt16 linkCtrl = fPciDevice->configRead16(pciCapOffset + 0x10);
|
|
linkCtrl &= ~0x3; // Désactive ASPM L0s / L1
|
|
fPciDevice->configWrite16(pciCapOffset + 0x10, linkCtrl);
|
|
IOLog("QualcommWifi: ASPM PCIe désactivé pour stabilité du transfert firmware (LinkCtrl: 0x%04x)\n", linkCtrl);
|
|
}
|
|
|
|
// Étape 1 : Réinitialisation MHI et effacement des vecteurs BHIe
|
|
write32(bhieOff + ATH12K_BHIE_TXVECDB, 0);
|
|
write32(bhieOff + ATH12K_BHIE_TXVECSTATUS, 0);
|
|
write32(bhieOff + ATH12K_BHIE_RXVECDB, 0);
|
|
write32(bhieOff + ATH12K_BHIE_RXVECSTATUS, 0);
|
|
|
|
write32(ATH12K_MHI_MHICTRL, ATH12K_MHICTRL_RESET_MASK);
|
|
IODelay(10000); // 10 ms
|
|
|
|
size_t fwSize = get_wcn7850_amss_size();
|
|
size_t sblSize = 0x80000; // 512 Ko pour le Secondary Boot Loader (SBL)
|
|
if (fwSize < sblSize) {
|
|
IOLog("QualcommWifi: Erreur - Taille AMSS trop petite (%zu < 512 Ko)\n", fwSize);
|
|
return false;
|
|
}
|
|
|
|
IOLog("QualcommWifi: Initialisation du chargeur FBC 2-étapes (SBL: 512 Ko, Image totale: %zu octets)...\n", fwSize);
|
|
|
|
// Étape 2 : Allocation DMA contigu pour l'image AMSS complète
|
|
IOBufferMemoryDescriptor *fwDma = IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
|
|
kernel_task,
|
|
static_cast<IOOptionBits>(kIODirectionInOut) | static_cast<IOOptionBits>(kIOMemoryPhysicallyContiguous),
|
|
fwSize,
|
|
ATH12K_DMA_MASK_36BIT_PAGE
|
|
);
|
|
|
|
if (!fwDma || fwDma->prepare(kIODirectionInOut) != kIOReturnSuccess) {
|
|
IOLog("QualcommWifi: Erreur - Echec allocation/prepare DMA AMSS\n");
|
|
setProperty("BHI_Load_Error", "DMA_Alloc_Failed");
|
|
if (fwDma) OSSafeReleaseNULL(fwDma);
|
|
return false;
|
|
}
|
|
|
|
void *virt = fwDma->getBytesNoCopy();
|
|
IOByteCount segLen = 0;
|
|
IOPhysicalAddress phys = fwDma->getPhysicalSegment(0, &segLen);
|
|
|
|
if (!virt || !phys || segLen < fwSize) {
|
|
IOLog("QualcommWifi: Erreur - Segment DMA AMSS incomplet\n");
|
|
fwDma->complete(kIODirectionInOut);
|
|
OSSafeReleaseNULL(fwDma);
|
|
return false;
|
|
}
|
|
|
|
memcpy(virt, wcn7850_amss_bin, fwSize);
|
|
setProperty("AMSS_DMA_Phys", (uint64_t)phys, 64);
|
|
|
|
// Étape 3 : Chargement du SBL (512 Ko) via BHI en mode PBL
|
|
write32(bhiOff + ATH12K_BHI_STATUS, 0);
|
|
write32(bhiOff + ATH12K_BHI_IMGADDR_LOW, (UInt32)(phys & 0xFFFFFFFF));
|
|
write32(bhiOff + ATH12K_BHI_IMGADDR_HIGH, (UInt32)((phys >> 32) & 0xFFFFFFFF));
|
|
write32(bhiOff + ATH12K_BHI_IMGSIZE, (UInt32)sblSize);
|
|
|
|
write32(bhiOff + ATH12K_BHI_IMGTXDB, 0x1);
|
|
IOLog("QualcommWifi: Sonnette BHI_IMGTXDB déclenchée (Session ID = 1, SBL 512 Ko)...\n");
|
|
|
|
UInt32 bhiStatus = 0;
|
|
UInt32 timeoutMs = 50;
|
|
bool sblSuccess = false;
|
|
|
|
while (timeoutMs > 0) {
|
|
bhiStatus = read32(bhiOff + ATH12K_BHI_STATUS);
|
|
UInt32 state = (bhiStatus & ATH12K_BHI_STATUS_MASK) >> ATH12K_BHI_STATUS_SHIFT;
|
|
if (state == ATH12K_BHI_STATUS_SUCCESS) {
|
|
sblSuccess = true;
|
|
break;
|
|
} else if (state == ATH12K_BHI_STATUS_ERROR) {
|
|
UInt32 err = read32(bhiOff + ATH12K_BHI_ERRCODE);
|
|
IOLog("QualcommWifi: Erreur BHI SBL (code=0x%08x)\n", err);
|
|
setProperty("BHI_ErrorCode", err, 32);
|
|
break;
|
|
}
|
|
IODelay(100);
|
|
timeoutMs--;
|
|
}
|
|
|
|
setProperty("BHI_FinalStatus", bhiStatus, 32);
|
|
setProperty("BHI_Status_Raw", bhiStatus, 32);
|
|
setProperty("BHI_Status_State", (bhiStatus & ATH12K_BHI_STATUS_MASK) >> ATH12K_BHI_STATUS_SHIFT, 32);
|
|
|
|
timeoutMs = 50;
|
|
UInt32 ee = 0;
|
|
while (timeoutMs > 0) {
|
|
ee = read32(bhiOff + ATH12K_BHI_EXECENV);
|
|
UInt32 mhiStat = read32(ATH12K_MHI_MHISTATUS);
|
|
if (ee == ATH12K_MHI_EE_SBL || ee == ATH12K_MHI_EE_AMSS || (mhiStat & ATH12K_MHISTATUS_READY_MASK)) {
|
|
break;
|
|
}
|
|
IODelay(100);
|
|
timeoutMs--;
|
|
}
|
|
|
|
setProperty("BHI_ExecEnv_AfterLoad", ee, 32);
|
|
setProperty("MHI_Status_After_SBL", read32(ATH12K_MHI_MHISTATUS), 32);
|
|
setProperty("MHI_Ctrl_After_SBL", read32(ATH12K_MHI_MHICTRL), 32);
|
|
IOLog("QualcommWifi: SBL BHI terminé (Status=0x%08x, State=%u, ExecEnv=0x%x, SBL_Succes=%d)\n",
|
|
bhiStatus, (bhiStatus & ATH12K_BHI_STATUS_MASK) >> ATH12K_BHI_STATUS_SHIFT, ee, sblSuccess);
|
|
|
|
// Étape 4 : Configuration des contextes MHI MMIO et transition vers M0
|
|
bool inM0 = false;
|
|
bool amssSuccess = false;
|
|
uint32_t processedEvents = 0;
|
|
|
|
if (sblSuccess && fDmaPhysAddr != 0) {
|
|
timeoutMs = 50;
|
|
while (timeoutMs > 0) {
|
|
UInt32 mstat = read32(ATH12K_MHI_MHISTATUS);
|
|
if (mstat & ATH12K_MHISTATUS_READY_MASK) {
|
|
break;
|
|
}
|
|
IODelay(100);
|
|
timeoutMs--;
|
|
}
|
|
|
|
uint64_t chan_ctxt_phys = fDmaPhysAddr + 0x0000;
|
|
uint64_t er_ctxt_phys = fDmaPhysAddr + 0x1000;
|
|
uint64_t cmd_ctxt_phys = fDmaPhysAddr + 0x2000;
|
|
uint64_t cmd_ring_phys = fDmaPhysAddr + 0x3000;
|
|
uint64_t er0_ring_phys = fDmaPhysAddr + 0x4000;
|
|
uint64_t er1_ring_phys = fDmaPhysAddr + 0x5000;
|
|
|
|
uint32_t cmd_ring_len = 64 * sizeof(struct mhi_ring_element);
|
|
uint32_t er0_ring_len = 32 * sizeof(struct mhi_ring_element);
|
|
uint32_t er1_ring_len = 256 * sizeof(struct mhi_ring_element);
|
|
|
|
struct mhi_chan_ctxt *chan_ctxt = (struct mhi_chan_ctxt *)((uint8_t *)fDmaVirtAddr + 0x0000);
|
|
bzero(chan_ctxt, 64 * sizeof(struct mhi_chan_ctxt));
|
|
|
|
struct mhi_cmd_ctxt *cmd_ctxt = (struct mhi_cmd_ctxt *)((uint8_t *)fDmaVirtAddr + 0x2000);
|
|
bzero(cmd_ctxt, sizeof(struct mhi_cmd_ctxt));
|
|
cmd_ctxt[0].rbase = OSSwapHostToLittleInt64(cmd_ring_phys);
|
|
cmd_ctxt[0].rlen = OSSwapHostToLittleInt64(cmd_ring_len);
|
|
cmd_ctxt[0].rp = OSSwapHostToLittleInt64(cmd_ring_phys);
|
|
cmd_ctxt[0].wp = OSSwapHostToLittleInt64(cmd_ring_phys);
|
|
|
|
struct mhi_event_ctxt *evCtxt = (struct mhi_event_ctxt *)((uint8_t *)fDmaVirtAddr + 0x1000);
|
|
bzero(evCtxt, 2 * sizeof(struct mhi_event_ctxt));
|
|
|
|
evCtxt[0].intmod = 0;
|
|
evCtxt[0].ertype = OSSwapHostToLittleInt32(1);
|
|
evCtxt[0].msivec = 0;
|
|
evCtxt[0].rbase = OSSwapHostToLittleInt64(er0_ring_phys);
|
|
evCtxt[0].rlen = OSSwapHostToLittleInt64(er0_ring_len);
|
|
evCtxt[0].rp = OSSwapHostToLittleInt64(er0_ring_phys);
|
|
evCtxt[0].wp = OSSwapHostToLittleInt64(er0_ring_phys);
|
|
|
|
evCtxt[1].intmod = OSSwapHostToLittleInt32(1);
|
|
evCtxt[1].ertype = OSSwapHostToLittleInt32(1);
|
|
evCtxt[1].msivec = 0;
|
|
evCtxt[1].rbase = OSSwapHostToLittleInt64(er1_ring_phys);
|
|
evCtxt[1].rlen = OSSwapHostToLittleInt64(er1_ring_len);
|
|
evCtxt[1].rp = OSSwapHostToLittleInt64(er1_ring_phys);
|
|
evCtxt[1].wp = OSSwapHostToLittleInt64(er1_ring_phys);
|
|
|
|
bzero((uint8_t *)fDmaVirtAddr + 0x3000, cmd_ring_len);
|
|
bzero((uint8_t *)fDmaVirtAddr + 0x4000, er0_ring_len);
|
|
bzero((uint8_t *)fDmaVirtAddr + 0x5000, er1_ring_len);
|
|
|
|
write32(ATH12K_MHI_CCABAP_HIGHER, (UInt32)((chan_ctxt_phys >> 32) & 0xFFFFFFFF));
|
|
write32(ATH12K_MHI_CCABAP_LOWER, (UInt32)(chan_ctxt_phys & 0xFFFFFFFF));
|
|
write32(ATH12K_MHI_ECABAP_HIGHER, (UInt32)((er_ctxt_phys >> 32) & 0xFFFFFFFF));
|
|
write32(ATH12K_MHI_ECABAP_LOWER, (UInt32)(er_ctxt_phys & 0xFFFFFFFF));
|
|
write32(ATH12K_MHI_CRCBAP_HIGHER, (UInt32)((cmd_ctxt_phys >> 32) & 0xFFFFFFFF));
|
|
write32(ATH12K_MHI_CRCBAP_LOWER, (UInt32)(cmd_ctxt_phys & 0xFFFFFFFF));
|
|
|
|
write32(ATH12K_MHI_MHICFG, (2 << 16) | (0 << 24));
|
|
write32(ATH12K_MHI_MHICTRLBASE_HIGHER, 0);
|
|
write32(ATH12K_MHI_MHICTRLBASE_LOWER, 0);
|
|
write32(ATH12K_MHI_MHIDATABASE_HIGHER, 0);
|
|
write32(ATH12K_MHI_MHIDATABASE_LOWER, 0);
|
|
write32(ATH12K_MHI_MHICTRLLIMIT_HIGHER, 0x0F);
|
|
write32(ATH12K_MHI_MHICTRLLIMIT_LOWER, 0xFFFFFFFF);
|
|
write32(ATH12K_MHI_MHIDATALIMIT_HIGHER, 0x0F);
|
|
write32(ATH12K_MHI_MHIDATALIMIT_LOWER, 0xFFFFFFFF);
|
|
|
|
uint64_t er0_armed_wp = er0_ring_phys + er0_ring_len - sizeof(struct mhi_ring_element);
|
|
evCtxt[0].wp = OSSwapHostToLittleInt64(er0_armed_wp);
|
|
uint64_t er1_armed_wp = er1_ring_phys + er1_ring_len - sizeof(struct mhi_ring_element);
|
|
evCtxt[1].wp = OSSwapHostToLittleInt64(er1_armed_wp);
|
|
|
|
UInt32 erdbOff = read32(ATH12K_MHI_ERDBOFF);
|
|
if (erdbOff != 0 && erdbOff < 0x200000) {
|
|
write32(erdbOff + 4, (UInt32)((er0_armed_wp >> 32) & 0xFFFFFFFF));
|
|
write32(erdbOff + 0, (UInt32)(er0_armed_wp & 0xFFFFFFFF));
|
|
write32(erdbOff + 8 + 4, (UInt32)((er1_armed_wp >> 32) & 0xFFFFFFFF));
|
|
write32(erdbOff + 8 + 0, (UInt32)(er1_armed_wp & 0xFFFFFFFF));
|
|
IOLog("QualcommWifi: Event Ring Doorbells armées (ER0 @ 0x%08x WP=0x%llx, ER1 @ 0x%08x WP=0x%llx) !\n",
|
|
erdbOff, er0_armed_wp, erdbOff + 8, er1_armed_wp);
|
|
setProperty("ERDB_Offset", erdbOff, 32);
|
|
}
|
|
|
|
UInt32 mhiCtrlVal = read32(ATH12K_MHI_MHICTRL);
|
|
mhiCtrlVal &= ~(UInt32)ATH12K_MHICTRL_MHISTATE_MASK;
|
|
mhiCtrlVal |= (ATH12K_MHI_STATE_M0 << ATH12K_MHICTRL_MHISTATE_SHIFT);
|
|
write32(ATH12K_MHI_MHICTRL, mhiCtrlVal);
|
|
IOLog("QualcommWifi: Transition MHI vers M0 demandée (MHICTRL: 0x%08x)...\n", mhiCtrlVal);
|
|
}
|
|
|
|
// Étape 5 : Téléversement FBC complet du firmware via BHIe
|
|
const size_t segSize = 0x80000;
|
|
size_t numVecEntries = (fwSize + segSize - 1) / segSize;
|
|
|
|
IOBufferMemoryDescriptor *vecDma = IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
|
|
kernel_task,
|
|
static_cast<IOOptionBits>(kIODirectionInOut) | static_cast<IOOptionBits>(kIOMemoryPhysicallyContiguous),
|
|
numVecEntries * sizeof(struct bhi_vec_entry),
|
|
ATH12K_DMA_MASK_36BIT_PAGE
|
|
);
|
|
|
|
if (vecDma) {
|
|
if (vecDma->prepare(kIODirectionInOut) == kIOReturnSuccess) {
|
|
struct bhi_vec_entry *vecTable = (struct bhi_vec_entry *)vecDma->getBytesNoCopy();
|
|
IOByteCount vecLen = 0;
|
|
IOPhysicalAddress vecPhys = vecDma->getPhysicalSegment(0, &vecLen);
|
|
|
|
if (vecTable && vecPhys) {
|
|
size_t curRem = fwSize;
|
|
for (size_t i = 0; i < numVecEntries; i++) {
|
|
size_t chunk = (curRem > segSize) ? segSize : curRem;
|
|
vecTable[i].dma_addr = OSSwapHostToLittleInt64((uint64_t)phys + (uint64_t)i * segSize);
|
|
vecTable[i].size = OSSwapHostToLittleInt64(chunk);
|
|
curRem -= chunk;
|
|
}
|
|
|
|
IOLog("QualcommWifi: Table vectorielle BHIe FBC prête (%zu segments, Phys: 0x%llx). Programmation BHIe...\n",
|
|
numVecEntries, (uint64_t)vecPhys);
|
|
|
|
write32(bhieOff + ATH12K_BHIE_TXVECADDR_LOW, (UInt32)(vecPhys & 0xFFFFFFFF));
|
|
write32(bhieOff + ATH12K_BHIE_TXVECADDR_HIGH, (UInt32)((vecPhys >> 32) & 0xFFFFFFFF));
|
|
write32(bhieOff + ATH12K_BHIE_TXVECSIZE, (UInt32)(numVecEntries * sizeof(struct bhi_vec_entry)));
|
|
write32(bhieOff + ATH12K_BHIE_TXVECSTATUS, 0);
|
|
|
|
write32(bhieOff + ATH12K_BHIE_TXVECDB, 0x1);
|
|
|
|
UInt32 bhieStatus = 0;
|
|
timeoutMs = 50;
|
|
while (timeoutMs > 0) {
|
|
bhieStatus = read32(bhieOff + ATH12K_BHIE_TXVECSTATUS);
|
|
UInt32 bhieState = (bhieStatus & ATH12K_BHIE_TXVECSTATUS_STATUS_MASK) >> ATH12K_BHIE_TXVECSTATUS_STATUS_SHIFT;
|
|
if (bhieState == ATH12K_BHIE_TXVECSTATUS_XFER_COMPL) {
|
|
amssSuccess = true;
|
|
break;
|
|
}
|
|
IODelay(100);
|
|
timeoutMs--;
|
|
}
|
|
|
|
setProperty("BHIE_FinalStatus", bhieStatus, 32);
|
|
setProperty("BHIE_Status_Raw", bhieStatus, 32);
|
|
setProperty("BHIE_Status_State", (bhieStatus & ATH12K_BHIE_TXVECSTATUS_STATUS_MASK) >> ATH12K_BHIE_TXVECSTATUS_STATUS_SHIFT, 32);
|
|
IOLog("QualcommWifi: BHIe DMA terminé (Status=0x%08x) ! Dépouillement des événements MHI...\n", bhieStatus);
|
|
|
|
// Étape 6 : Dépouillement des événements MHI
|
|
struct mhi_ring_element *erElements = (struct mhi_ring_element *)((uint8_t *)fDmaVirtAddr + 0x4000);
|
|
|
|
timeoutMs = 50;
|
|
while (timeoutMs > 0) {
|
|
UInt32 mstat = read32(ATH12K_MHI_MHISTATUS);
|
|
UInt32 mstate = (mstat & ATH12K_MHISTATUS_MHISTATE_MASK) >> ATH12K_MHISTATUS_MHISTATE_SHIFT;
|
|
|
|
while (processedEvents < 32) {
|
|
struct mhi_ring_element *el = &erElements[processedEvents];
|
|
UInt32 dw1 = OSSwapLittleToHostInt32(el->dword[1]);
|
|
UInt32 dw0 = OSSwapLittleToHostInt32(el->dword[0]);
|
|
if (dw1 == 0 && dw0 == 0) {
|
|
break;
|
|
}
|
|
|
|
UInt8 evType = (dw1 >> 16) & 0xFF;
|
|
UInt8 evCode = (dw0 >> 24) & 0xFF;
|
|
IOLog("QualcommWifi: Événement MHI reçu #%u: Type=0x%02x, Code=0x%02x, PTR=0x%llx\n",
|
|
processedEvents, evType, evCode, OSSwapLittleToHostInt64(el->ptr));
|
|
|
|
if (evType == ATH12K_MHI_PKT_TYPE_STATE_CHANGE_EVENT && evCode == ATH12K_MHI_STATE_M0) {
|
|
inM0 = true;
|
|
} else if (evType == ATH12K_MHI_PKT_TYPE_EE_EVENT && (evCode == ATH12K_MHI_EE_AMSS || evCode == ATH12K_MHI_EE_WFW)) {
|
|
ee = evCode;
|
|
amssSuccess = true;
|
|
}
|
|
processedEvents++;
|
|
}
|
|
|
|
if (mstate == ATH12K_MHI_STATE_M0 || inM0 || ee == ATH12K_MHI_EE_AMSS || ee == ATH12K_MHI_EE_WFW) {
|
|
inM0 = true;
|
|
IOLog("QualcommWifi: MHI en mode Mission M0 (MHISTATUS: 0x%08x, EE: 0x%x) !\n", mstat, ee);
|
|
break;
|
|
}
|
|
|
|
IODelay(100);
|
|
timeoutMs--;
|
|
}
|
|
|
|
setProperty("MHI_Events_Processed", processedEvents, 32);
|
|
setProperty("MHI_Status_In_M0", read32(ATH12K_MHI_MHISTATUS), 32);
|
|
setProperty("MHI_In_M0", inM0);
|
|
setProperty("BHI_ExecEnv_Final", ee, 32);
|
|
}
|
|
|
|
vecDma->complete(kIODirectionInOut);
|
|
}
|
|
OSSafeReleaseNULL(vecDma);
|
|
}
|
|
|
|
if (inM0 || ee == ATH12K_MHI_EE_AMSS || ee == ATH12K_MHI_EE_WFW) {
|
|
IOLog("QualcommWifi: SUCCÈS MAJEUR ! Firmware WCN7850 actif en mode Mission (ExecEnv=0x%x, M0=%d) !\n", ee, inM0);
|
|
setProperty("Driver_Status", "AMSS_Loaded_Success");
|
|
} else if (sblSuccess) {
|
|
IOLog("QualcommWifi: SBL actif (ExecEnv=0x%x, BHIe=0x%x)\n", ee, read32(bhieOff + ATH12K_BHIE_TXVECSTATUS));
|
|
setProperty("Driver_Status", "SBL_Loaded_Success");
|
|
} else {
|
|
IOLog("QualcommWifi: Échec chargement complet (BHI=0x%x, ExecEnv=0x%x)\n", bhiStatus, ee);
|
|
setProperty("Driver_Status", "AMSS_Load_Timeout_Or_Error");
|
|
}
|
|
|
|
fwDma->complete(kIODirectionInOut);
|
|
OSSafeReleaseNULL(fwDma);
|
|
|
|
return (sblSuccess || amssSuccess);
|
|
}
|
|
|
|
bool QualcommWifi::start(IOService *provider) {
|
|
logNvramStage("start_enter");
|
|
IOLog("QualcommWifi: Demarrage du pilote Wi-Fi natif (IO80211Controller)...\n");
|
|
|
|
if (!createWorkQueue()) {
|
|
logNvramStage("workQueue_failed");
|
|
IOLog("QualcommWifi: Erreur - Impossible de creer IO80211WorkQueue !\n");
|
|
return false;
|
|
}
|
|
|
|
if (!super::start(provider)) {
|
|
logNvramStage("super_start_failed");
|
|
IOLog("QualcommWifi: Erreur - IO80211Controller::start(provider) a echoue !\n");
|
|
return false;
|
|
}
|
|
logNvramStage("super_start_ok");
|
|
|
|
fPciDevice = OSDynamicCast(IOPCIDevice, provider);
|
|
if (!fPciDevice) {
|
|
logNvramStage("start_no_pci");
|
|
return false;
|
|
}
|
|
fPciDevice->retain();
|
|
|
|
logNvramStage("pci_open");
|
|
if (!fPciDevice->open(this)) {
|
|
logNvramStage("pci_open_failed");
|
|
OSSafeReleaseNULL(fPciDevice);
|
|
return false;
|
|
}
|
|
logNvramStage("pci_open_ok");
|
|
|
|
UInt16 pciCommand = fPciDevice->configRead16(kIOPCIConfigCommand);
|
|
pciCommand |= kIOPCICommandMemorySpace;
|
|
pciCommand &= ~kIOPCICommandBusMaster; // Protection absolue contre tout accès DMA non configuré sur AMD-Vi
|
|
logNvramStage("pci_cmd_write");
|
|
fPciDevice->configWrite16(kIOPCIConfigCommand, pciCommand);
|
|
|
|
int allow_mmio = 0;
|
|
PE_parse_boot_argn("qcom_mmio", &allow_mmio, sizeof(allow_mmio));
|
|
|
|
UInt32 bhiSerial = 0x123456;
|
|
if (allow_mmio) {
|
|
logNvramStage("bar0_map");
|
|
fBar0Map = fPciDevice->mapDeviceMemoryWithRegister(kIOPCIConfigBaseAddress0);
|
|
if (fBar0Map) {
|
|
fBar0Virt = (volatile void *)fBar0Map->getVirtualAddress();
|
|
logNvramStage("read_mhi");
|
|
UInt32 mhiStatus = read32(ATH12K_MHI_MHISTATUS);
|
|
UInt32 mhiCtrl = read32(ATH12K_MHI_MHICTRL);
|
|
UInt32 bhiOff = read32(ATH12K_MHI_BHIOFF);
|
|
UInt32 bhieOff = read32(ATH12K_MHI_BHIEOFF);
|
|
setProperty("MHI_Status", mhiStatus, 32);
|
|
setProperty("MHI_Ctrl", mhiCtrl, 32);
|
|
setProperty("BHI_Offset", bhiOff, 32);
|
|
setProperty("BHIE_Offset", bhieOff, 32);
|
|
|
|
if (bhiOff != 0xFFFFFFFF && bhiOff > 0 && bhiOff < 0x200000) {
|
|
logNvramStage("read_bhi");
|
|
UInt32 bhiMajor = read32(bhiOff + ATH12K_BHI_BHIVERSION_MAJOR);
|
|
UInt32 bhiMinor = read32(bhiOff + ATH12K_BHI_BHIVERSION_MINOR);
|
|
UInt32 bhiEe = read32(bhiOff + ATH12K_BHI_EXECENV);
|
|
UInt32 bhiStat = read32(bhiOff + ATH12K_BHI_STATUS);
|
|
bhiSerial = read32(bhiOff + ATH12K_BHI_SERIALNU);
|
|
|
|
setProperty("BHI_Major", bhiMajor, 32);
|
|
setProperty("BHI_Minor", bhiMinor, 32);
|
|
setProperty("BHI_ExecEnv", bhiEe, 32);
|
|
setProperty("BHI_Status", bhiStat, 32);
|
|
setProperty("BHI_Serial", bhiSerial, 32);
|
|
}
|
|
}
|
|
} else {
|
|
logNvramStage("safe_mode_active");
|
|
setProperty("QualcommWifi_SafeMode", "Active");
|
|
}
|
|
|
|
// Configuration de l'adresse MAC (OUI Qualcomm 00:03:7F + BHI serial)
|
|
fMacAddress.bytes[0] = 0x00;
|
|
fMacAddress.bytes[1] = 0x03;
|
|
fMacAddress.bytes[2] = 0x7F;
|
|
fMacAddress.bytes[3] = (bhiSerial >> 16) & 0xFF;
|
|
fMacAddress.bytes[4] = (bhiSerial >> 8) & 0xFF;
|
|
fMacAddress.bytes[5] = (bhiSerial) & 0xFF;
|
|
|
|
IOLog("QualcommWifi: Adresse MAC physique : %02x:%02x:%02x:%02x:%02x:%02x\n",
|
|
fMacAddress.bytes[0], fMacAddress.bytes[1], fMacAddress.bytes[2],
|
|
fMacAddress.bytes[3], fMacAddress.bytes[4], fMacAddress.bytes[5]);
|
|
|
|
// Propriétés Wi-Fi AirPort pour macOS et airportd
|
|
logNvramStage("set_airport_props");
|
|
setProperty("IO80211AirPort", true);
|
|
setProperty("AirPort", true);
|
|
setProperty("IO80211Locale", "ETSI");
|
|
setProperty("IO80211CountryCode", "FR");
|
|
setProperty("IO80211ScanCache", true);
|
|
setProperty("IO80211RadioState", (UInt64)1, 32);
|
|
|
|
// Configuration et publication des médiums réseau (IEEE 802.11)
|
|
logNvramStage("pub_mediums");
|
|
OSDictionary *mediumDict = OSDictionary::withCapacity(2);
|
|
if (mediumDict) {
|
|
IONetworkMedium *medium = IONetworkMedium::medium(kIOMediumIEEE80211, 54000000);
|
|
if (medium) {
|
|
IONetworkMedium::addMedium(mediumDict, medium);
|
|
publishMediumDictionary(mediumDict);
|
|
setCurrentMedium(medium);
|
|
setSelectedMedium(medium);
|
|
medium->release();
|
|
}
|
|
mediumDict->release();
|
|
}
|
|
|
|
// Enregistrement IOKit du contrôleur Wi-Fi natif (déclenche le matching airportd)
|
|
logNvramStage("register_service");
|
|
registerService();
|
|
logNvramStage("start_done");
|
|
IOLog("QualcommWifi: Pilote Wi-Fi natif (IO80211Controller) demarre avec succes !\n");
|
|
return true;
|
|
}
|
|
|
|
void QualcommWifi::stop(IOService *provider) {
|
|
IOLog("QualcommWifi: Arret du pilote Wi-Fi natif, liberation MSI, DMA et BAR0.\n");
|
|
|
|
IOWorkLoop *workLoop = getWorkLoop();
|
|
if (fInterruptSource) {
|
|
fInterruptSource->disable();
|
|
if (workLoop) {
|
|
workLoop->removeEventSource(fInterruptSource);
|
|
}
|
|
OSSafeReleaseNULL(fInterruptSource);
|
|
}
|
|
|
|
freeDmaContext();
|
|
|
|
fBar0Virt = nullptr;
|
|
if (fBar0Map) {
|
|
OSSafeReleaseNULL(fBar0Map);
|
|
}
|
|
|
|
if (fPciDevice) {
|
|
fPciDevice->close(this);
|
|
OSSafeReleaseNULL(fPciDevice);
|
|
}
|
|
|
|
super::stop(provider);
|
|
}
|
|
|
|
bool QualcommWifi::createWorkQueue(void) {
|
|
logNvramStage("createWorkQueue");
|
|
if (fWorkQueue) {
|
|
return true;
|
|
}
|
|
fWorkQueue = IO80211WorkQueue::workQueue();
|
|
if (!fWorkQueue) {
|
|
logNvramStage("workQueue_failed");
|
|
IOLog("QualcommWifi: Erreur - Impossible d'allouer IO80211WorkQueue !\n");
|
|
return false;
|
|
}
|
|
logNvramStage("workQueue_ok");
|
|
IOLog("QualcommWifi: IO80211WorkQueue allouee avec succes (0x%p) !\n", fWorkQueue);
|
|
return true;
|
|
}
|
|
|
|
IO80211WorkQueue* QualcommWifi::getWorkQueue(void) const {
|
|
return fWorkQueue;
|
|
}
|
|
|
|
bool QualcommWifi::createWorkLoop(void) {
|
|
return createWorkQueue();
|
|
}
|
|
|
|
IOWorkLoop* QualcommWifi::getWorkLoop(void) const {
|
|
return getWorkQueue();
|
|
}
|
|
|
|
IOReturn QualcommWifi::getHardwareAddress(IOEthernetAddress *addrP) {
|
|
logNvramStage("getHardwareAddress");
|
|
if (!addrP) return kIOReturnBadArgument;
|
|
bcopy(&fMacAddress, addrP, sizeof(IOEthernetAddress));
|
|
return kIOReturnSuccess;
|
|
}
|
|
|
|
IOReturn QualcommWifi::enable(IONetworkInterface *netif) {
|
|
logNvramStage("netif_enable");
|
|
IOLog("QualcommWifi: Interface reseau activee par macOS.\n");
|
|
const IONetworkMedium *medium = getSelectedMedium();
|
|
setLinkStatus(kIONetworkLinkValid | kIONetworkLinkActive, medium);
|
|
return kIOReturnSuccess;
|
|
}
|
|
|
|
IOReturn QualcommWifi::disable(IONetworkInterface *netif) {
|
|
logNvramStage("netif_disable");
|
|
IOLog("QualcommWifi: Interface reseau desactivee par macOS.\n");
|
|
setLinkStatus(kIONetworkLinkValid, nullptr);
|
|
return kIOReturnSuccess;
|
|
}
|
|
|
|
UInt32 QualcommWifi::outputPacket(mbuf_t m, void *param) {
|
|
if (m) {
|
|
freePacket(m);
|
|
}
|
|
return kIOReturnOutputDropped;
|
|
}
|
|
|
|
void QualcommWifi::dataLinkLayerAttachComplete(void) {
|
|
logNvramStage("dataLinkAttachDone");
|
|
IOLog("QualcommWifi: dataLinkLayerAttachComplete (Skywalk Tahoe).\n");
|
|
}
|
|
|
|
IOReturn QualcommWifi::handleCardSpecific(IO80211SkywalkInterface *iface, unsigned long req_type, void *req_data, bool isSet) {
|
|
return (IOReturn)handleApple80211Request((unsigned int)req_type, isSet ? 1 : 0, req_data);
|
|
}
|
|
|
|
IOReturn QualcommWifi::getDRIVER_VERSION(IO80211SkywalkInterface *iface, apple80211_version_data *vd) {
|
|
return (IOReturn)handleApple80211Request(APPLE80211_IOC_DRIVER_VERSION, 0, vd);
|
|
}
|
|
|
|
IOReturn QualcommWifi::getHARDWARE_VERSION(IO80211SkywalkInterface *iface, apple80211_version_data *vd) {
|
|
return (IOReturn)handleApple80211Request(APPLE80211_IOC_HARDWARE_VERSION, 0, vd);
|
|
}
|
|
|
|
IOReturn QualcommWifi::getCARD_CAPABILITIES(IO80211SkywalkInterface *iface, apple80211_capability_data *cap) {
|
|
return (IOReturn)handleApple80211Request(APPLE80211_IOC_CARD_CAPABILITIES, 0, cap);
|
|
}
|
|
|
|
IOReturn QualcommWifi::getPOWER(IO80211SkywalkInterface *iface, apple80211_power_data *pwr) {
|
|
return (IOReturn)handleApple80211Request(APPLE80211_IOC_POWER, -1, pwr);
|
|
}
|
|
|
|
IOReturn QualcommWifi::setPOWER(IO80211SkywalkInterface *iface, apple80211_power_data *pwr) {
|
|
logNvramStage("setPOWER");
|
|
int val = (pwr && pwr->power_state[0]) ? 1 : 0;
|
|
fLinkActive = (val == 1);
|
|
IOLog("QualcommWifi: setPOWER invoqué par airportd (val=%d, fLinkActive=%d)\n", val, fLinkActive);
|
|
return (IOReturn)handleApple80211Request(APPLE80211_IOC_POWER, val, pwr);
|
|
}
|
|
|
|
IOReturn QualcommWifi::getCOUNTRY_CODE(IO80211SkywalkInterface *iface, apple80211_country_code_data *cc) {
|
|
return (IOReturn)handleApple80211Request(APPLE80211_IOC_COUNTRY_CODE, 0, cc);
|
|
}
|
|
|
|
SInt32 QualcommWifi::handleApple80211Request(unsigned int req_type, int req_val, void* req_data) {
|
|
char iocTag[32];
|
|
snprintf(iocTag, sizeof(iocTag), "ioc_%u", req_type);
|
|
logNvramStage(iocTag);
|
|
switch (req_type) {
|
|
case APPLE80211_IOC_CARD_CAPABILITIES: {
|
|
apple80211_capability_data *cap = (apple80211_capability_data *)req_data;
|
|
if (cap) {
|
|
bzero(cap, sizeof(*cap));
|
|
cap->version = APPLE80211_VERSION;
|
|
#define SET_CAP(c) (cap->capabilities[(c) / 8] |= (1 << ((c) % 8)))
|
|
SET_CAP(APPLE80211_CAP_WEP);
|
|
SET_CAP(APPLE80211_CAP_TKIP);
|
|
SET_CAP(APPLE80211_CAP_AES_CCM);
|
|
SET_CAP(APPLE80211_CAP_WPA1);
|
|
SET_CAP(APPLE80211_CAP_WPA2);
|
|
SET_CAP(APPLE80211_CAP_WPA);
|
|
SET_CAP(APPLE80211_CAP_SHORT_GI_20MHZ);
|
|
SET_CAP(APPLE80211_CAP_SHORT_GI_40MHZ);
|
|
SET_CAP(APPLE80211_CAP_BURST);
|
|
SET_CAP(APPLE80211_CAP_WME);
|
|
SET_CAP(APPLE80211_CAP_PMGT);
|
|
SET_CAP(APPLE80211_CAP_SHPREAMBLE);
|
|
SET_CAP(APPLE80211_CAP_SHSLOT);
|
|
#undef SET_CAP
|
|
return 0;
|
|
}
|
|
break;
|
|
}
|
|
case APPLE80211_IOC_STATE: {
|
|
apple80211_state_data *state = (apple80211_state_data *)req_data;
|
|
if (state) {
|
|
state->version = APPLE80211_VERSION;
|
|
state->state = fLinkActive ? APPLE80211_S_RUN : APPLE80211_S_INIT;
|
|
return 0;
|
|
}
|
|
break;
|
|
}
|
|
case APPLE80211_IOC_PHY_MODE: {
|
|
apple80211_phymode_data *pm = (apple80211_phymode_data *)req_data;
|
|
if (pm) {
|
|
pm->version = APPLE80211_VERSION;
|
|
pm->phy_mode = APPLE80211_MODE_11AX;
|
|
pm->active_phy_mode = APPLE80211_MODE_11AX;
|
|
return 0;
|
|
}
|
|
break;
|
|
}
|
|
case APPLE80211_IOC_OP_MODE: {
|
|
apple80211_opmode_data *om = (apple80211_opmode_data *)req_data;
|
|
if (om) {
|
|
om->version = APPLE80211_VERSION;
|
|
om->op_mode = APPLE80211_M_STA;
|
|
return 0;
|
|
}
|
|
break;
|
|
}
|
|
case APPLE80211_IOC_CHANNEL: {
|
|
apple80211_channel_data *cd = (apple80211_channel_data *)req_data;
|
|
if (cd) {
|
|
if (req_val == 1 && cd->channel.channel > 0) {
|
|
fCurrentChannel = (UInt16)cd->channel.channel;
|
|
IOLog("QualcommWifi: Changement de canal Wi-Fi vers %u\n", fCurrentChannel);
|
|
}
|
|
cd->version = APPLE80211_VERSION;
|
|
cd->channel.version = APPLE80211_VERSION;
|
|
cd->channel.channel = fCurrentChannel > 0 ? fCurrentChannel : 1;
|
|
cd->channel.flags = (cd->channel.channel <= 14) ? (APPLE80211_C_FLAG_2GHZ | APPLE80211_C_FLAG_20MHZ) : (APPLE80211_C_FLAG_5GHZ | APPLE80211_C_FLAG_80MHZ);
|
|
return 0;
|
|
}
|
|
break;
|
|
}
|
|
case APPLE80211_IOC_TXPOWER: {
|
|
apple80211_txpower_data *tx = (apple80211_txpower_data *)req_data;
|
|
if (tx) {
|
|
tx->version = APPLE80211_VERSION;
|
|
tx->txpower_unit = APPLE80211_UNIT_DBM;
|
|
tx->txpower = 20; // 20 dBm (100 mW)
|
|
return 0;
|
|
}
|
|
break;
|
|
}
|
|
case APPLE80211_IOC_PROTMODE:
|
|
case APPLE80211_IOC_POWERSAVE:
|
|
case APPLE80211_IOC_SCANCACHE_CLEAR: {
|
|
return 0;
|
|
}
|
|
case APPLE80211_IOC_RSSI: {
|
|
apple80211_rssi_data *rd = (apple80211_rssi_data *)req_data;
|
|
if (rd) {
|
|
rd->version = APPLE80211_VERSION;
|
|
rd->num_radios = 1;
|
|
rd->rssi_unit = APPLE80211_UNIT_DBM;
|
|
rd->rssi[0] = fLastRssi ? fLastRssi : -50;
|
|
rd->aggregate_rssi = rd->rssi[0];
|
|
return 0;
|
|
}
|
|
break;
|
|
}
|
|
case APPLE80211_IOC_NOISE: {
|
|
apple80211_noise_data *nd = (apple80211_noise_data *)req_data;
|
|
if (nd) {
|
|
nd->version = APPLE80211_VERSION;
|
|
nd->num_radios = 1;
|
|
nd->noise_unit = APPLE80211_UNIT_DBM;
|
|
nd->noise[0] = -95;
|
|
nd->aggregate_noise = -95;
|
|
return 0;
|
|
}
|
|
break;
|
|
}
|
|
case APPLE80211_IOC_SSID: {
|
|
apple80211_ssid_data *sd = (apple80211_ssid_data *)req_data;
|
|
if (sd) {
|
|
sd->version = APPLE80211_VERSION;
|
|
sd->ssid_len = fSsidLen;
|
|
memcpy(sd->ssid_bytes, fSsid, fSsidLen);
|
|
return 0;
|
|
}
|
|
break;
|
|
}
|
|
case APPLE80211_IOC_BSSID: {
|
|
apple80211_bssid_data *bd = (apple80211_bssid_data *)req_data;
|
|
if (bd) {
|
|
bd->version = APPLE80211_VERSION;
|
|
memcpy(bd->bssid.octet, fBssid, 6);
|
|
return 0;
|
|
}
|
|
break;
|
|
}
|
|
case APPLE80211_IOC_RATE: {
|
|
apple80211_rate_data *rate = (apple80211_rate_data *)req_data;
|
|
if (rate) {
|
|
rate->version = APPLE80211_VERSION;
|
|
rate->num_radios = 1;
|
|
rate->rate[0] = 1200;
|
|
return 0;
|
|
}
|
|
break;
|
|
}
|
|
case APPLE80211_IOC_SUPPORTED_CHANNELS: {
|
|
apple80211_sup_channel_data *sc = (apple80211_sup_channel_data *)req_data;
|
|
if (sc) {
|
|
sc->version = APPLE80211_VERSION;
|
|
static const UInt16 chs[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
|
|
36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, 149, 153, 157, 161, 165 };
|
|
sc->num_channels = sizeof(chs)/sizeof(chs[0]);
|
|
for (int i = 0; i < sc->num_channels; i++) {
|
|
sc->supported_channels[i].version = APPLE80211_VERSION;
|
|
sc->supported_channels[i].channel = chs[i];
|
|
sc->supported_channels[i].flags = (chs[i] <= 14) ? (APPLE80211_C_FLAG_2GHZ | APPLE80211_C_FLAG_20MHZ) : (APPLE80211_C_FLAG_5GHZ | APPLE80211_C_FLAG_80MHZ);
|
|
}
|
|
return 0;
|
|
}
|
|
break;
|
|
}
|
|
case APPLE80211_IOC_SCAN_REQ:
|
|
case APPLE80211_IOC_SCAN_REQ_MULTIPLE: {
|
|
IOLog("QualcommWifi: Requete de scan Wi-Fi recue depuis airportd !\n");
|
|
fScanInProgress = true;
|
|
return 0;
|
|
}
|
|
case APPLE80211_IOC_SCAN_RESULT: {
|
|
if (req_data) {
|
|
*(void **)req_data = nullptr;
|
|
}
|
|
fScanInProgress = false;
|
|
return 0;
|
|
}
|
|
case APPLE80211_IOC_POWER: {
|
|
apple80211_power_data *pwr = (apple80211_power_data *)req_data;
|
|
if (pwr) {
|
|
pwr->version = APPLE80211_VERSION;
|
|
pwr->num_radios = 1;
|
|
if (req_val == 0 || req_val == 1) {
|
|
fLinkActive = (req_val == 1);
|
|
IOLog("QualcommWifi: Bascule alimentation radio Wi-Fi : %s\n", fLinkActive ? "ACTIVE" : "COUPEE");
|
|
}
|
|
pwr->power_state[0] = fLinkActive ? 1 : 0;
|
|
return 0;
|
|
}
|
|
break;
|
|
}
|
|
case APPLE80211_IOC_COUNTRY_CODE: {
|
|
apple80211_country_code_data *cc = (apple80211_country_code_data *)req_data;
|
|
if (cc) {
|
|
cc->version = APPLE80211_VERSION;
|
|
cc->cc[0] = 'F';
|
|
cc->cc[1] = 'R';
|
|
cc->cc[2] = 0;
|
|
return 0;
|
|
}
|
|
break;
|
|
}
|
|
case APPLE80211_IOC_LOCALE: {
|
|
apple80211_locale_data *loc = (apple80211_locale_data *)req_data;
|
|
if (loc) {
|
|
loc->version = APPLE80211_VERSION;
|
|
loc->locale = APPLE80211_LOCALE_ETSI;
|
|
return 0;
|
|
}
|
|
break;
|
|
}
|
|
case APPLE80211_IOC_DRIVER_VERSION:
|
|
case APPLE80211_IOC_HARDWARE_VERSION: {
|
|
apple80211_version_data *vd = (apple80211_version_data *)req_data;
|
|
if (vd) {
|
|
vd->version = APPLE80211_VERSION;
|
|
const char *verStr = "Qualcomm FastConnect 7800 Wi-Fi 7 (v1.1.0)";
|
|
vd->string_len = (u_int16_t)strlen(verStr);
|
|
strlcpy(vd->string, verStr, sizeof(vd->string));
|
|
return 0;
|
|
}
|
|
break;
|
|
}
|
|
case APPLE80211_IOC_ASSOCIATE: {
|
|
apple80211_assoc_data *assoc = (apple80211_assoc_data *)req_data;
|
|
if (assoc) {
|
|
IOLog("QualcommWifi: Demande d'association au reseau Wi-Fi : %.*s\n", assoc->ad_ssid_len, assoc->ad_ssid);
|
|
fSsidLen = (assoc->ad_ssid_len < APPLE80211_MAX_SSID_LEN) ? assoc->ad_ssid_len : APPLE80211_MAX_SSID_LEN;
|
|
memcpy(fSsid, assoc->ad_ssid, fSsidLen);
|
|
memcpy(fBssid, assoc->ad_bssid.octet, 6);
|
|
fLinkActive = true;
|
|
return 0;
|
|
}
|
|
break;
|
|
}
|
|
case APPLE80211_IOC_DISASSOCIATE: {
|
|
IOLog("QualcommWifi: Deconnexion Wi-Fi demandee par macOS.\n");
|
|
fLinkActive = false;
|
|
fSsidLen = 0;
|
|
return 0;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|