the-darkvoid / BrcmPatchRAM

Broadcom PatchRAM driver for OS X
GNU General Public License v2.0
88 stars 62 forks source link

Fix for Not responding - Delaying next read/device request failed/continuousRead - Failed to queue read #38

Closed lvs1974 closed 6 years ago

lvs1974 commented 6 years ago

I have managed to fix one very strange issue: after a numerous cycles of sleep/wake my bluetooth stopped working, in log I discovered: (kernel) BrcmPatchRAM2: [13d3:3404]: Not responding - Delaying next read. (kernel) BrcmPatchRAM2: [13d3:3404]: device request failed ("0xe00002ed (UNDEFINED)" 0xe00002ed). (kernel) BrcmPatchRAM2: [13d3:3404]: Not responding - Delaying next read. (kernel) BrcmPatchRAM2: [13d3:3404]: device request failed ("0xe00002d8 (UNDEFINED)" 0xe00002d8). (kernel) BrcmPatchRAM2: [13d3:3404]: continuousRead - Failed to queue read (0xe00002d8)

I had a look to the IOReg and saw two devices with the same name: BCM20702A0, but they had different sessionID. My fix is quite simple (I believe you could improve it): get the root provider for current BCM20702A0 device, iterate over all client and try to perform a firmware upgrade for all of them.

lvs1974 commented 6 years ago

This has been implemented only for NON_RESIDENT = 1 and TARGET_ELCAPITAN:

IOService* BrcmPatchRAM::probe(IOService *provider, SInt32 *probeScore)
{
    uint64_t start_time, end_time, nano_secs;

    DebugLog("probe\n");

    if (mCompletionLock)
    {
        AlwaysLog("probe is already run, exit.\n");
        return NULL;
    }

    AlwaysLog("Version %s starting on OS X Darwin %d.%d.\n", OSKextGetCurrentVersionString(), version_major, version_minor);

    // preference towards starting BrcmPatchRAM2.kext when BrcmPatchRAM.kext also exists
    *probeScore = 2000;

    clock_get_uptime(&start_time);

    mCompletionLock = IOLockAlloc();
    if (!mCompletionLock)
        return NULL;

    AlwaysLog("Provider name is %s, and his provider name is %s\n", provider->getName(), provider->getProvider()->getName());

    IOService *rootProvider = provider->getProvider();
    if (rootProvider)
    {
        OSIterator *iter = rootProvider->getClientIterator();
        if (iter)
        {
            IOService *client;
            while ((client = (IOService *) iter->getNextObject()))
            {
                uint64_t sessionID = 0;
                OSNumber *session = OSDynamicCast(OSNumber, client->getProperty("sessionID"));
                if (session != 0)
                    sessionID = session->unsigned64BitValue();
                AlwaysLog("Client name is %s, sessionID=\"0x%llx\"\n", client->getName(), sessionID);

                mDevice.setDevice(client);
                if (!mDevice.getValidatedDevice())
                {
                    AlwaysLog("Provider type is incorrect (not IOUSBDevice or IOUSBHostDevice)\n");
                    break;
                }

                // personality strings depend on version
                initBrcmStrings();

                OSString* displayName = OSDynamicCast(OSString, getProperty(kDisplayName));
                if (displayName)
                    client->setProperty(kUSBProductString, displayName);

                mVendorId = mDevice.getVendorID();
                mProductId = mDevice.getProductID();

                // get firmware here to pre-cache for eventual use on wakeup or now
                if (OSString* firmwareKey = OSDynamicCast(OSString, getProperty(kFirmwareKey)))
                {
                    if (BrcmFirmwareStore* firmwareStore = getFirmwareStore())
                        firmwareStore->getFirmware(mVendorId, mProductId, firmwareKey);
                }

                uploadFirmware();
                publishPersonality();

                clock_get_uptime(&end_time);
                absolutetime_to_nanoseconds(end_time - start_time, &nano_secs);
                uint64_t milli_secs = nano_secs / 1000000;
                AlwaysLog("Processing time %llu.%llu seconds.\n", milli_secs / 1000, milli_secs % 1000);

                // maybe residency is not required for 10.11?
                mDevice.setDevice(NULL);
            }
            iter->release();
        }
    }

    return NULL;
}
lvs1974 commented 6 years ago

And it would be nice to free mCompletionLock:

void BrcmPatchRAM::free()
{
    DebugLog("free\n");

    if (mCompletionLock)
    {
        IOLockFree(mCompletionLock);
        mCompletionLock = NULL;
    }
}
RehabMan commented 6 years ago

FYI: From what I see, the PR does not contain the suggested code changes...

Note: mCompletionLock is freed in stop.

And I don't think the suggested code is doing what that author thinks it is doing. But it is executing the uploadFirmware/etc multiple times.