Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować się zalogować lub zmienić katalog.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Sterownik USB Type-C Connector System Software Interface (UCSI) działa jako sterownik kontrolera dla systemu USB Type-C z osadzonym kontrolerem (EC).
Jeśli system, który implementuje Platform Policy Manager (PPM), zgodnie z opisem w specyfikacji UCSI, w EC połączonym z systemem poprzez:
Nie musisz pisać sterownika dla transportu ACPI. Załaduj sterownik wbudowany firmy Microsoft (UcmUcsiCx.sys i UcmUcsiAcpiClient.sys). (Zobacz sterownik UCSI).
W przypadku transportu innego niż ACPI, na przykład USB, PCI, I2C lub UART, należy napisać sterownik klienta dla kontrolera.
Uwaga
Jeśli sprzęt USB Type-C nie ma możliwości obsługi stanu maszyny dostarczania zasilania (PD), rozważ napisanie sterownika kontrolera portu USB Type-C. Aby uzyskać więcej informacji, zobacz Napisanie sterownika kontrolera portu USB Type-C.
Począwszy od Windows 10, wersja 1809, dodano nowe rozszerzenie klasy dla UCSI (UcmUcsiCx.sys), które implementuje specyfikację UCSI w sposób niezależny od transportu. Przy użyciu minimalnej ilości kodu, sterownik, który jest klientem UcmUcsiCx, może komunikować się ze sprzętem USB Type-C poprzez transport inny niż ACPI. W tym temacie opisano usługi udostępniane przez rozszerzenie klasy UCSI i oczekiwane zachowanie sterownika klienta.
Oficjalne specyfikacje
Dotyczy:
- Windows 10, wersja 1809
Wersja usługi WDF
- KMDF w wersji 1.27
Ważne interfejsy API
Odniesienie do rozszerzeń klas UcmUcsiCx
Przykład
Przykład sterownika klienta UcmUcsiCx
Zamień fragmenty ACPI na swoją implementację dla wymaganej magistrali.
Architektura rozszerzenia klasy UCSI
Rozszerzenie klasy UCSI, UcmUcsiCx, umożliwia napisanie sterownika komunikującego się z jego osadzonym kontrolerem przy użyciu transportu innego niż ACPI. Sterownik kontrolera jest sterownikiem klienta do UcmUcsiCx. UcmUcsiCx jest z kolei klientem dla menedżera łącznika USB (UCM). W związku z tym UcmUcsiCx nie podejmuje własnych decyzji politycznych. Zamiast tego implementuje zasady udostępniane przez użytkownika. UcmUcsiCx implementuje maszyny stanów do obsługi powiadomień programu Platform Policy Manager (PPM) ze sterownika klienta i wysyła polecenia w celu zaimplementowania decyzji dotyczących zasad UCM, co pozwala na bardziej niezawodne wykrywanie problemów i obsługę błędów.
Menedżer zasad systemu operacyjnego (OPM)
Program OS Policy Manager (OPM) implementuje logikę interakcji z PPM zgodnie ze specyfikacją UCSI. OpM jest odpowiedzialny za:
- Konwertowanie zasad UCM na polecenia UCSI i powiadomienia UCSI na powiadomienia UCM.
- Wysyłanie poleceń UCSI wymaganych do inicjowania PPM, wykrywania błędów i mechanizmów odzyskiwania.
Obsługa poleceń UCSI
Typowa operacja obejmuje kilka poleceń, które mają zostać wykonane przez sprzęt zgodny ze standardem UCSI. Rozważmy na przykład polecenie GET_CONNECTOR_STATUS.
- Oprogramowanie układowe PPM wysyła powiadomienie o zmianie połączenia do sterownika UcmUcsiCx/klienta.
- W odpowiedzi sterownik UcmUcsiCx/klient wysyła polecenie GET_CONNECTOR_STATUS z powrotem do oprogramowania układowego PPM.
- Oprogramowanie układowe PPM wykonuje GET_CONNECTOR_STATUS i asynchronicznie wysyła powiadomienie o zakończeniu polecenia do sterownika klienta UcmUcsiCx. To powiadomienie zawiera dane dotyczące rzeczywistego stanu połączenia.
- Sterownik kliencki UcmUcsiCx przetwarza informacje o stanie i wysyła ACK_CC_CI do oprogramowania układowego PPM.
- Oprogramowanie układowe PPM wykonuje ACK_CC_CI i asynchronicznie wysyła powiadomienie o zakończeniu polecenia do sterownika UcmUcsiCx/client.
- Sterownik UcmUcsiCx/klienta uważa, że polecenie GET_CONNECTOR_STATUS zostało ukończone.
Komunikacja z programem Platform Policy Manager (PPM)
UcmUcsiCx abstrahuje szczegóły wysyłania poleceń UCSI z OPM do oprogramowania układowego PPM i odbierania powiadomień z oprogramowania układowego PPM. Konwertuje polecenia PPM na obiekty WDFREQUEST i przekazuje je do sterownika klienta.
Powiadomienia PPM
Sterownik klienta powiadamia użytkownika UcmUcsiCx o powiadomieniach PPM z oprogramowania układowego. Sterownik udostępnia blok danych interfejsu użytkownika zawierający CCI. UcmUcsiCx przekazuje powiadomienia do OPM i innych komponentów, które podejmują odpowiednie działania na podstawie danych.
Polecenia IOCTL do sterownika klienta
UcmUcsiCx wysyła polecenia UCSI (za pośrednictwem żądań IOCTL) do sterownika klienta, aby przekazać je do oprogramowania układowego PPM. Sterownik oprogramowania jest odpowiedzialny za ukończenie żądania po wysłaniu polecenia UCSI do oprogramowania układowego.
Obsługa przejść zasilania
Sterownik klienta jest właścicielem zasad zasilania.
Jeśli sterownik klienta wchodzi w stan Dx z powodu S0-Idle, WDF przywraca sterownik do stanu D0, gdy UcmUcsiCx wysyła IOCTL zawierające polecenie UCSI do kolejki zarządzanej przez sterownik klienta. Sterownik klienta w S0-Idle powinien powrócić do stanu zasilania, gdy pojawi się powiadomienie PPM z firmware'u, ponieważ w stanie S0-Idle powiadomienia PPM są nadal włączone.
Zanim rozpoczniesz
Określ, który typ sterownika należy napisać, w zależności od tego, czy twój sprzęt lub oprogramowanie układowe implementuje maszynę stanu PD oraz sposób transportu.
Aby uzyskać więcej informacji, zobacz Tworzenie sterowników systemu Windows dla łączników Type-C USB.Zainstaluj system Windows 10 dla wersji klasycznych (Home, Pro, Enterprise i Education).
Zainstaluj najnowszy zestaw sterowników systemu Windows (WDK) na komputerze dewelopera. Zestaw zawiera wymagane pliki nagłówka i biblioteki do pisania sterownika klienta, w szczególności potrzebne są następujące elementy:
- Biblioteka szkieletowa (UcmUcsiCxStub.lib). Biblioteka tłumaczy wywołania wykonywane przez sterownik klienta i przekazuje je do rozszerzenia klasy.
- Plik nagłówkowy Ucmucsicx.h.
- Sterownik klienta działa w trybie jądra i wiąże się z biblioteką KMDF 1.27.
Zapoznaj się z programem Windows Driver Foundation (WDF). Zalecane czytanie: Opracowywanie sterowników z Windows Driver Foundation napisane przez Penny Orwick i Guy Smith.
1. Rejestrowanie sterownika klienta za pomocą interfejsu UcmUcsiCx
W implementacji EVT_WDF_DRIVER_DEVICE_ADD .
Po ustawieniu funkcji wywołania zwrotnego zdarzeń Plug and Play i zarządzania energią (WdfDeviceInitSetPnpPowerEventCallbacks), wywołaj UcmUcsiDeviceInitInitialize, aby zainicjować WDFDEVICE_INIT nieprzezroczystą strukturę. Wywołanie kojarzy sterownik klienta z platformą.
Po utworzeniu obiektu urządzenia platformy (WDFDEVICE) wywołaj metodę UcmUcsiDeviceInitialize, aby zarejestrować sterownik klienta w UcmUcsiCx.
2. Tworzenie obiektu PPM za pomocą interfejsu UcmUcsiCx
W swojej implementacji EVT_WDF_DEVICE_PREPARE_HARDWARE, po otrzymaniu listy zasobów surowych i przetłumaczonych, użyj tych zasobów do przygotowania sprzętu. Jeśli na przykład twój transport to I2C, odczytaj zasoby sprzętowe, aby otworzyć kanał komunikacyjny. Następnie utwórz obiekt PPM. Aby utworzyć obiekt, należy ustawić pewne opcje konfiguracji.
Podaj dojście do kolekcji łączników na urządzeniu.
Utwórz kolekcję łączników, wywołując element UcmUcsiConnectorCollectionCreate.
Wylicz łączniki na urządzeniu i dodaj je do kolekcji poprzez wywołanie UcmUcsiConnectorCollectionAddConnector
// Create the connector collection. UCMUCSI_CONNECTOR_COLLECTION* ConnectorCollectionHandle; status = UcmUcsiConnectorCollectionCreate(Device, //WDFDevice WDF_NO_OBJECT_ATTRIBUTES, ConnectorCollectionHandle); // Enumerate the connectors on the device. // ConnectorId of 0 is reserved for the parent device. // In this example, we assume the parent has no children connectors. UCMUCSI_CONNECTOR_INFO_INIT(&connectorInfo); connectorInfo.ConnectorId = 0; status = UcmUcsiConnectorCollectionAddConnector ( &ConnectorCollectionHandle, &connectorInfo);
Zdecyduj, czy chcesz włączyć kontroler urządzenia.
Skonfiguruj i utwórz obiekt PPM.
Zainicjuj strukturę UCMUCSI_PPM_CONFIG przez podanie dojścia łącznika, które utworzyłeś w kroku 1.
Ustaw element członkowski UsbDeviceControllerEnabled na wartość logiczną określoną w kroku 2.
Ustaw wywołania zwrotne zdarzeń w WDF_OBJECT_ATTRIBUTES.
Wywołaj metodę UcmUcsiPpmCreate , przekazując wszystkie skonfigurowane struktury.
UCMUCSIPPM ppmObject = WDF_NO_HANDLE; PUCMUCSI_PPM_CONFIG UcsiPpmConfig; WDF_OBJECT_ATTRIBUTES attrib; UCMUCSI_PPM_CONFIG_INIT(UcsiPpmConfig, ConnectorCollectionHandle); UcsiPpmConfig->UsbDeviceControllerEnabled = TRUE; WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attrib, Ppm); attrib->EvtDestroyCallback = &EvtObjectContextDestroy; status = UcmUcsiPpmCreate(wdfDevice, UcsiPpmConfig, &attrib, &ppmObject);
3. Konfigurowanie kolejek we/wy
UcmUcsiCx wysyła polecenia interfejsu użytkownika do sterownika klienta w celu wysłania do oprogramowania układowego PPM. Polecenia są wysyłane w postaci tych żądań IOCTL w kolejce WDF.
Sterownik klienta jest odpowiedzialny za tworzenie i rejestrowanie tej kolejki w UcmUcsiCx przez wywołanie UcmUcsiPpmSetUcsiCommandRequestQueue. Kolejka musi być zarządzana pod względem zasilania.
UcmUcsiCx gwarantuje, że w kolejce WDF może istnieć co najwyżej jedno zaległe żądanie. Sterownik klienta jest również odpowiedzialny za ukończenie żądania WDF po wysłaniu polecenia interfejsu użytkownika do oprogramowania układowego.
Zazwyczaj sterownik konfiguruje kolejki w implementacji EVT_WDF_DEVICE_PREPARE_HARDWARE.
WDFQUEUE UcsiCommandRequestQueue = WDF_NO_HANDLE;
WDF_OBJECT_ATTRIBUTES attrib;
WDF_IO_QUEUE_CONFIG queueConfig;
WDF_OBJECT_ATTRIBUTES_INIT(&attrib);
attrib.ParentObject = GetObjectHandle();
// In this example, even though the driver creates a sequential queue,
// UcmUcsiCx guarantees that will not send another request
// until the previous one has been completed.
WDF_IO_QUEUE_CONFIG_INIT(&queueConfig, WdfIoQueueDispatchSequential);
// The queue must be power-managed.
queueConfig.PowerManaged = WdfTrue;
queueConfig.EvtIoDeviceControl = EvtIoDeviceControl;
status = WdfIoQueueCreate(device, &queueConfig, &attrib, &UcsiCommandRequestQueue);
UcmUcsiPpmSetUcsiCommandRequestQueue(ppmObject, UcsiCommandRequestQueue);
Ponadto sterownik klienta musi również wywołać polecenie UcmUcsiPpmStart , aby powiadomić UcmUcsiCx, że sterownik jest gotowy do odbierania żądań IOCTL. Zalecamy wykonanie tego wywołania w EVT_WDF_DEVICE_PREPARE_HARDWARE po utworzeniu dojścia WDFQUEUE do odbierania poleceń UCSI poprzez UcmUcsiPpmSetUcsiCommandRequestQueue. Z drugiej strony, gdy sterownik nie chce przetwarzać więcej żądań, musi wywołać UcmUcsiPpmStop. Wykonaj to w swojej implementacji EVT_WDF_DEVICE_RELEASE_HARDWARE.
4. Obsługa żądań IOCTL
Rozważmy tę przykładową sekwencję zdarzeń, które występują, gdy partner Type-C USB jest dołączony do łącznika.
- Oprogramowanie układowe PPM określa zdarzenie dołączania i wysyła powiadomienie do sterownika klienta.
- Sterownik klienta wywołuje funkcję UcmUcsiPpmNotification, aby wysłać to powiadomienie do interfejsu UcmUcsiCx.
- UcmUcsiCx powiadamia maszynę stanu OPM i wysyła polecenie Get Connector Status do UcmUcsiCx.
- UcmUcsiCx tworzy żądanie i wysyła IOCTL_UCMUCSI_PPM_SEND_UCSI_DATA_BLOCK do sterownika klienta.
- Sterownik klienta przetwarza to żądanie i wysyła polecenie do oprogramowania układowego PPM. Sterownik realizuje to żądanie asynchronicznie i wysyła kolejne powiadomienie do UcmUcsiCx.
- Po pomyślnym powiadomieniu o zakończeniu polecenia, maszyna stanów OPM odczytuje ładunek (zawierający informacje o statusie łącznika) i powiadamia UCM o zdarzeniu podłączenia Type-C.
W tym przykładzie informacje zawarte w ładunku wskazały również, że zmiana statusu negocjacji dostarczania zasilania między oprogramowaniem układowym a partnerem portu zakończyła się pomyślnie. Maszyna stanów OPM wysyła kolejne polecenie UCSI: Pobierz PDO. Podobnie jak w przypadku polecenia Pobierz stan łącznika, kiedy pobieranie PDO zakończy się pomyślnie, automat stanowy OPM powiadamia UCM o tym fakcie.
Procedura obsługi sterownika klienta dla EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL jest podobna do tego przykładowego kodu. Aby uzyskać informacje na temat obsługi żądań, zobacz Procedury obsługi żądań
void EvtIoDeviceControl(
_In_ WDFREQUEST Request,
_In_ ULONG IoControlCode
)
{
...
switch (IoControlCode)
{
case IOCTL_UCMUCSI_PPM_SEND_UCSI_DATA_BLOCK:
EvtSendData(Request);
break;
case IOCTL_UCMUCSI_PPM_GET_UCSI_DATA_BLOCK:
EvtReceiveData(Request);
break;
default:
status = STATUS_NOT_SUPPORTED;
goto Exit;
}
status = STATUS_SUCCESS;
Exit:
if (!NT_SUCCESS(status))
{
WdfRequestComplete(Request, status);
}
}
VOID EvtSendData(
WDFREQUEST Request
)
{
NTSTATUS status;
PUCMUCSI_PPM_SEND_UCSI_DATA_BLOCK_IN_PARAMS inParams;
status = WdfRequestRetrieveInputBuffer(Request, sizeof(*inParams),
reinterpret_cast<PVOID*>(&inParams), nullptr);
if (!NT_SUCCESS(status))
{
goto Exit;
}
// Build a UCSI command request and send to the PPM firmware.
Exit:
WdfRequestComplete(Request, status);
}
VOID EvtReceiveData(
WDFREQUEST Request
)
{
NTSTATUS status;
PUCMUCSI_PPM_GET_UCSI_DATA_BLOCK_IN_PARAMS inParams;
PUCMUCSI_PPM_GET_UCSI_DATA_BLOCK_OUT_PARAMS outParams;
status = WdfRequestRetrieveInputBuffer(Request, sizeof(*inParams),
reinterpret_cast<PVOID*>(&inParams), nullptr);
if (!NT_SUCCESS(status))
{
goto Exit;
}
status = WdfRequestRetrieveOutputBuffer(Request, sizeof(*outParams),
reinterpret_cast<PVOID*>(&outParams), nullptr);
if (!NT_SUCCESS(status))
{
goto Exit;
}
// Receive data from the PPM firmware.
if (!NT_SUCCESS(status))
{
goto Exit;
}
WdfRequestSetInformation(Request, sizeof(*outParams));
Exit:
WdfRequestComplete(Request, status);
}