- Breakthroughs & Rétro-ingénierie :
* Analyse binaire approfondie de BootKernelExtensions.kc (__ZN17IO80211Controller5startEP9IOService @ 0xffffff8002291f30 et __ZN19IONetworkController5startEP9IOService @ 0xffffff80026f34dc).
* Découverte de la cause racine exacte du message 'IO80211Controller::start fails' :
1. Dans IO80211Controller sur macOS Tahoe / Darwin 25 (architecture Skywalk), la méthode virtuelle createWorkLoop() (slot 306) ne crée plus un IOWorkLoop classique, mais effectue un saut indirect vers le slot 395 (createWorkQueue()).
2. De même, getWorkLoop() (slot 209) effectue un saut indirect vers le slot 397 (getWorkQueue()).
3. Dans la classe de base abstraite IO80211Controller, les implémentations par défaut de createWorkQueue() (0xffffff8002295e20) et getWorkQueue() (0xffffff8002295e28) retournent simplement 0 (NULL/false).
4. Lors de l'appel super::start(provider), IONetworkController::start invoque this->createWorkLoop(), qui appelle createWorkQueue() et échoue immédiatement car celle-ci retournait false, provoquant l'avortement de start() et la libération (free) de QualcommWifi.
5. De plus, IO80211Controller::start requiert un IO80211WorkQueue non nul pour instancier IO80211CommandGate, IO80211PostOffice, IO80211TimerSource et IO80211TimerFactory via allocWithParams().
* Solution architecturale :
- Implémentation explicite de createWorkQueue() et getWorkQueue() ainsi que createWorkLoop() et getWorkLoop() dans QualcommWifi.
- Allocation dynamique de IO80211WorkQueue via sa fabrique système IO80211WorkQueue::workQueue().
- 0 conflit de padslot OpenCore : les slots 306, 209, 395 et 397 sont des symboles concrets dans le parent (__ZN17IO80211Controller15createWorkQueueEv, etc.).
- Initialisation d'une adresse MAC Qualcomm par défaut valide dans init() pour garantir le succès des vérifications d'interface.
- Modifications apportées :
* QualcommWifi/QualcommWifi.hpp : ajout du membre fWorkQueue et déclaration des méthodes virtuelles createWorkQueue, getWorkQueue, createWorkLoop, getWorkLoop.
* QualcommWifi/QualcommWifi.cpp : initialisation et libération de fWorkQueue, implémentation des créateurs WorkQueue/WorkLoop, et sécurisation des appels d'attachement d'interface réseau.
- Validation :
* Compilation sans erreur via ./build_wifi.sh.
* kmutil libraries -p QualcommWifi.kext validé à 100% contre BootKernelExtensions.kc.
* Simulation binaire OpenCore du chaînage de vtables : 0 violation de padslot (463 slots alignés).
* Déploiement direct synchronisé dans /Volumes/EFI/EFI/OC/Kexts/QualcommWifi.kext.
1009 lines
40 KiB
C++
1009 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) {}
|
|
}
|
|
|
|
#define super IO80211Controller
|
|
OSDefineMetaClassAndStructors(QualcommWifi, IO80211Controller)
|
|
|
|
bool QualcommWifi::init(OSDictionary *dictionary) {
|
|
if (!super::init(dictionary)) {
|
|
return false;
|
|
}
|
|
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) {
|
|
if (!super::probe(provider, score)) {
|
|
return nullptr;
|
|
}
|
|
|
|
IOPCIDevice *pciDev = OSDynamicCast(IOPCIDevice, provider);
|
|
if (!pciDev) {
|
|
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;
|
|
return this;
|
|
}
|
|
|
|
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 = 3000;
|
|
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(1000);
|
|
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 = 2000;
|
|
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(1000);
|
|
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 = 3000;
|
|
while (timeoutMs > 0) {
|
|
UInt32 mstat = read32(ATH12K_MHI_MHISTATUS);
|
|
if (mstat & ATH12K_MHISTATUS_READY_MASK) {
|
|
break;
|
|
}
|
|
IODelay(1000);
|
|
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 = 10000;
|
|
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(1000);
|
|
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 = 5000;
|
|
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(1000);
|
|
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) {
|
|
IOLog("QualcommWifi: Demarrage du pilote Wi-Fi natif (IO80211Controller)...\n");
|
|
|
|
if (!super::start(provider)) {
|
|
IOLog("QualcommWifi: Erreur - IO80211Controller::start(provider) a echoue !\n");
|
|
return false;
|
|
}
|
|
|
|
fPciDevice = OSDynamicCast(IOPCIDevice, provider);
|
|
if (!fPciDevice) {
|
|
return false;
|
|
}
|
|
fPciDevice->retain();
|
|
|
|
if (!fPciDevice->open(this)) {
|
|
OSSafeReleaseNULL(fPciDevice);
|
|
return false;
|
|
}
|
|
|
|
UInt16 pciCommand = fPciDevice->configRead16(kIOPCIConfigCommand);
|
|
pciCommand |= (kIOPCICommandMemorySpace | kIOPCICommandBusMaster);
|
|
fPciDevice->configWrite16(kIOPCIConfigCommand, pciCommand);
|
|
|
|
fBar0Map = fPciDevice->mapDeviceMemoryWithRegister(kIOPCIConfigBaseAddress0);
|
|
if (!fBar0Map) {
|
|
fPciDevice->close(this);
|
|
OSSafeReleaseNULL(fPciDevice);
|
|
return false;
|
|
}
|
|
fBar0Virt = (volatile void *)fBar0Map->getVirtualAddress();
|
|
|
|
UInt32 socHwVer = socRead32(TCSR_SOC_HW_VERSION);
|
|
UInt32 major = (socHwVer & TCSR_SOC_HW_VERSION_MAJOR_MASK) >> TCSR_SOC_HW_VERSION_MAJOR_SHIFT;
|
|
UInt32 minor = (socHwVer & TCSR_SOC_HW_VERSION_MINOR_MASK);
|
|
IOLog("QualcommWifi: WCN7850 HW v%u.%u detecte (0x%08x)\n", major, minor, socHwVer);
|
|
|
|
setProperty("SoC_Version", socHwVer, 32);
|
|
setProperty("SoC_Major", major, 32);
|
|
setProperty("SoC_Minor", minor, 32);
|
|
|
|
UInt32 mhiStatus = read32(ATH12K_MHI_MHISTATUS);
|
|
UInt32 mhiCtrl = read32(ATH12K_MHI_MHICTRL);
|
|
UInt32 bhiOff = read32(ATH12K_MHI_BHIOFF);
|
|
UInt32 bhieOff = read32(ATH12K_MHI_BHIEOFF);
|
|
IOLog("QualcommWifi: MHI STATUS=0x%08x, CTRL=0x%08x, BHIOFF=0x%08x, BHIEOFF=0x%08x\n",
|
|
mhiStatus, mhiCtrl, bhiOff, bhieOff);
|
|
|
|
setProperty("MHI_Status", mhiStatus, 32);
|
|
setProperty("MHI_Ctrl", mhiCtrl, 32);
|
|
setProperty("BHI_Offset", bhiOff, 32);
|
|
setProperty("BHIE_Offset", bhieOff, 32);
|
|
|
|
UInt32 bhiSerial = 0x123456;
|
|
if (bhiOff != 0xFFFFFFFF && bhiOff < 0x200000) {
|
|
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);
|
|
IOLog("QualcommWifi: BHI v%u.%u: ExecEnv=0x%x, Status=0x%x, Serial=0x%08x\n",
|
|
bhiMajor, bhiMinor, bhiEe, bhiStat, bhiSerial);
|
|
|
|
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);
|
|
}
|
|
|
|
// 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
|
|
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)
|
|
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();
|
|
}
|
|
|
|
if (!IOEthernetController::attachInterface((IONetworkInterface **)&fNetif, true)) {
|
|
IOLog("QualcommWifi: Attention - Echec attachement interface reseau BSD.\n");
|
|
} else {
|
|
IOLog("QualcommWifi: Interface reseau attachee avec succes (enX) !\n");
|
|
}
|
|
|
|
registerService();
|
|
IOLog("QualcommWifi: Pilote Wi-Fi natif 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");
|
|
|
|
if (fNetif) {
|
|
IOEthernetController::detachInterface(fNetif);
|
|
OSSafeReleaseNULL(fNetif);
|
|
}
|
|
|
|
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) {
|
|
if (fWorkQueue) {
|
|
return true;
|
|
}
|
|
fWorkQueue = IO80211WorkQueue::workQueue();
|
|
if (!fWorkQueue) {
|
|
IOLog("QualcommWifi: Erreur - Impossible d'allouer IO80211WorkQueue !\n");
|
|
return false;
|
|
}
|
|
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) {
|
|
if (!addrP) return kIOReturnBadArgument;
|
|
bcopy(&fMacAddress, addrP, sizeof(IOEthernetAddress));
|
|
return kIOReturnSuccess;
|
|
}
|
|
|
|
IOReturn QualcommWifi::enable(IONetworkInterface *netif) {
|
|
IOLog("QualcommWifi: Interface reseau activee par macOS.\n");
|
|
|
|
if (!fFirmwareLoaded) {
|
|
if (allocDmaContext(ATH12K_DMA_TEST_RING_SIZE)) {
|
|
setProperty("DMA_PhysAddr", (uint64_t)fDmaPhysAddr, 64);
|
|
|
|
int msiIndex = -1;
|
|
for (int i = 0; ; i++) {
|
|
int intrType = 0;
|
|
if (fPciDevice->getInterruptType(i, &intrType) != kIOReturnSuccess) {
|
|
break;
|
|
}
|
|
if (intrType & kIOInterruptTypePCIMessaged) {
|
|
msiIndex = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
IOWorkLoop *workLoop = getWorkLoop();
|
|
if (msiIndex >= 0 && workLoop && !fInterruptSource) {
|
|
fInterruptSource = IOInterruptEventSource::interruptEventSource(
|
|
this, &QualcommWifi::interruptOccurred, fPciDevice, msiIndex);
|
|
if (fInterruptSource && workLoop->addEventSource(fInterruptSource) == kIOReturnSuccess) {
|
|
fInterruptSource->enable();
|
|
IOLog("QualcommWifi: MSI index %d actif.\n", msiIndex);
|
|
}
|
|
}
|
|
|
|
if (loadBhiFirmware()) {
|
|
fFirmwareLoaded = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
const IONetworkMedium *medium = getSelectedMedium();
|
|
setLinkStatus(kIONetworkLinkValid | kIONetworkLinkActive, medium);
|
|
return kIOReturnSuccess;
|
|
}
|
|
|
|
IOReturn QualcommWifi::disable(IONetworkInterface *netif) {
|
|
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) {
|
|
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) {
|
|
int val = (pwr && pwr->power_state[0]) ? 1 : 0;
|
|
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) {
|
|
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: {
|
|
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;
|
|
}
|