Перейти к содержанию

Установка нового драйвера AIC8800 без установки старой версии (обход BSOD)

📌 Проблема

При подключении адаптера (чип AIC8800 / Broadcom BCM4378) он определяется системой только как виртуальный CD-ROM. Официальный установщик, находящийся на этом CD, устанавливает старую версию драйвера, которая вызывает синий экран смерти (BSOD) DRIVER_IRQL_NOT_LESS_OR_EQUAL (0x000000D1).

Прямое обновление драйвера невозможно, так как в Диспетчере устройств нет целевого устройства — только привод CD-ROM.

💡 Решение

Устройство необходимо перевести в режим загрузчика прошивки (или режим Wi-Fi) вручную, пропустив запуск старого установщика. Это делается отправкой специальной 16-байтовой SCSI-команды напрямую через Windows API.

1. Отправка SCSI-команды для переключения режима

Для отправки команды используется PowerShell-скрипт с вызовом IOCTL_SCSI_PASS_THROUGH_DIRECT. Скрипт автоматически находит CD-ROM (по имени или объёму), либо просит ввести букву диска вручную.

Сохраните следующий код в файл SCSI_command.ps1 и запустите его от имени администратора:

# ================= АВТООПРЕДЕЛЕНИЕ БУКВЫ ДИСКА =================
Write-Host "Поиск виртуального CD-ROM..." -ForegroundColor Cyan

$DriveLetter = $null
$cdroms = Get-CimInstance -ClassName Win32_CDROMDrive -ErrorAction SilentlyContinue

if ($cdroms) {
    # 1. Ищем по имени (Wifi, AIC, Driver)
    $targetCd = $cdroms | Where-Object { 
        ($_.Caption -match "Wifi|AIC|Driver") -or ($_.Name -match "Wifi|AIC|Driver")
    } | Select-Object -First 1

    if ($targetCd -and $targetCd.Drive) {
        $DriveLetter = $targetCd.Drive
        Write-Host "✅ Найден по имени: $($targetCd.Caption) -> $DriveLetter" -ForegroundColor Green
    } else {
        # 2. Если по имени не нашли, ищем CD-ROM с виртуальным диском (Size > 0)
        $targetCd = $cdroms | Where-Object { $_.Size -gt 0 -and $_.Drive } | Select-Object -First 1
        if ($targetCd) {
            $DriveLetter = $targetCd.Drive
            Write-Host "✅ Найден по объёму: $($targetCd.Caption) -> $DriveLetter" -ForegroundColor Green
        }
    }
}

# Если автоматически найти не удалось - предлагаем ввести вручную
if (-not $DriveLetter) {
    Write-Host "⚠️ Не удалось автоматически найти нужный CD-ROM." -ForegroundColor Yellow
    if ($cdroms) {
        Write-Host "Доступные CD-ROM в системе:" -ForegroundColor Yellow
        $cdroms | ForEach-Object { Write-Host " - $($_.Drive) : $($_.Caption) / $($_.Name)" }
    }

    $userInput = Read-Host "Пожалуйста, введите букву диска (например, E: или F:), либо нажмите Enter для выхода"
    if ([string]::IsNullOrWhiteSpace($userInput)) { Write-Host "Выход." -ForegroundColor Red; return }
    $DriveLetter = $userInput.Trim()
}

if ($DriveLetter -notmatch ":$") { $DriveLetter = $DriveLetter + ":" }

# ================= ОТПРАВКА SCSI-КОМАНДЫ =================
$Cdb = [byte[]] (0xFD,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF2)
$IOCTL_SCSI_PASS_THROUGH_DIRECT = 0x4D014

if (-not ([System.Management.Automation.PSTypeName]'SCSI_PASS_THROUGH_DIRECT').Type) {
    Add-Type -TypeDefinition @"
    using System;
    using System.Runtime.InteropServices;
    [StructLayout(LayoutKind.Sequential)]
    public struct SCSI_PASS_THROUGH_DIRECT {
        public ushort Length; public byte ScsiStatus; public byte PathId; public byte TargetId;
        public byte Lun; public byte CdbLength; public byte SenseInfoLength; public byte DataIn;
        public uint DataTransferLength; public uint TimeOutValue; public IntPtr DataBuffer;
        public uint SenseInfoOffset;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte[] Cdb;
    }
"@
}

if (-not ([System.Management.Automation.PSTypeName]'Kernel32').Type) {
    Add-Type -TypeDefinition @"
    using System;
    using System.Runtime.InteropServices;
    public static class Kernel32 {
        [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        public static extern IntPtr CreateFile(string lpFileName, uint dwDesiredAccess, uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition, uint dwFlagsAndAttributes, IntPtr hTemplateFile);
        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern bool DeviceIoControl(IntPtr hDevice, uint dwIoControlCode, IntPtr lpInBuffer, uint nInBufferSize, IntPtr lpOutBuffer, uint nOutBufferSize, out uint lpBytesReturned, IntPtr lpOverlapped);
        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern bool CloseHandle(IntPtr hObject);
    }
"@
}

Write-Host "Открытие устройства $DriveLetter ..." -ForegroundColor Cyan
$handle = [Kernel32]::CreateFile("\\.\$DriveLetter", 0xC0000000L, 0x00000003L, [IntPtr]::Zero, 3L, 0L, [IntPtr]::Zero)

if ($handle -eq [IntPtr]::Zero -or $handle -eq [IntPtr](-1)) {
    $err = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
    Write-Host "❌ Не удалось открыть устройство. Код ошибки: $err" -ForegroundColor Red
    return
}

$ptr = [IntPtr]::Zero
try {
    $sptd = New-Object SCSI_PASS_THROUGH_DIRECT
    $sptd.Length = [System.Runtime.InteropServices.Marshal]::SizeOf($sptd)
    $sptd.CdbLength = 16; $sptd.SenseInfoLength = 0; $sptd.DataIn = 0; $sptd.DataTransferLength = 0
    $sptd.TimeOutValue = 10; $sptd.DataBuffer = [IntPtr]::Zero; $sptd.SenseInfoOffset = 0; $sptd.Cdb = $Cdb

    $ptr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($sptd.Length)
    [System.Runtime.InteropServices.Marshal]::StructureToPtr($sptd, $ptr, $false)
    $bytesReturned = 0

    $success = [Kernel32]::DeviceIoControl($handle, $IOCTL_SCSI_PASS_THROUGH_DIRECT, $ptr, $sptd.Length, $ptr, $sptd.Length, [ref]$bytesReturned, [IntPtr]::Zero)

    if ($success) {
        Write-Host "✅ SCSI-команда отправлена. Устройство переподключится через несколько секунд." -ForegroundColor Green
    } else {
        Write-Host "❌ Ошибка отправки SCSI-команды." -ForegroundColor Red
    }
} finally {
    if ($ptr -ne [IntPtr]::Zero) { [System.Runtime.InteropServices.Marshal]::FreeHGlobal($ptr) }
    if ($handle -ne [IntPtr]::Zero -and $handle -ne [IntPtr](-1)) { [Kernel32]::CloseHandle($handle) | Out-Null }
}

После выполнения скрипта виртуальный CD-ROM исчезнет, а в Диспетчере устройств появится новое устройство AIC Load Fw Driver (или Wlan) с ID оборудования USB\VID_A69C&PID_8D80 или USB\VID_A69C&PID_8D81&MI_02.

2. Штатная установка нового драйвера

Для работы без BSOD была подтверждена стабильная версия драйвера 14.46.40.644 (более новые версии, например 668, могут не видеть сети или не иметь нужного ID в INF).

  1. Откройте Диспетчер устройств.
  2. Нажмите правой кнопкой мыши на новое устройство (AIC Load Fw Driver / Wlan с восклицательным знаком) и выберите «Обновить драйвер».
  3. Выберите «Выполнить поиск драйверов на этом компьютере».
  4. Нажмите «Указать путь к драйверу вручную» (или «Выбрать драйвер из списка доступных драйверов» -> «Установить с диска»).
  5. Укажите путь к папке с распакованными файлами aicloadfw.inf и aicusbwifi.inf версии 14.46.40.644.
  6. Нажмите «Далее». Windows установит драйвер. Устройство переподключится и определится как сетевой адаптер.

⚠️ Примечание: Если вы редактировали INF-файл вручную (например, раскомментировали строку с ID), Windows заблокирует установку из-за нарушения цифровой подписи. В этом случае загрузитесь с отключенной проверкой подписей (зажмите Shift -> «Перезагрузка» -> «Поиск и устранение неисправностей» -> «Дополнительные параметры» -> «Параметры загрузки» -> «Перезагрузить» -> клавиша 7 или F7) и повторите установку.

3. (Опционально) Очистка следов старого установщика

Если ранее запускался старый Setup.exe, он мог установить фоновую службу AicWifiService, которая больше не нужна. Удалите её в командной строке от имени администратора:

sc stop AicWifiService
sc delete AicWifiService