Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
A partir do Windows 10 versão 1903 e posterior, SerCx e SerCx2 incluem suporte para publicação de uma GUID_DEVINTERFACE_COMPORTinterface do dispositivo. Aplicativos e serviços em um sistema podem usar essa interface do dispositivo para interagir com a porta serial.
Esse recurso pode ser habilitado em plataformas baseadas em SoC que apresentam um UART integrado com um driver cliente SerCx/SerCx2, se o UART for exposto como uma porta física ou se os aplicativos regulares (UWP ou Win32) precisarem se comunicar diretamente com um dispositivo anexado ao UART. Em contraste, acessar o controlador SerCx/SerCx2 por meio de um ID de conexão permite exclusivamente o acesso ao UART por um driver periférico dedicado.
Ao usar esse recurso para portas serial gerenciadas serCx/SerCx2, um número de porta COM não é atribuído a esses dispositivos e nenhum link simbólico é criado – o que significa que os aplicativos devem usar a abordagem descrita neste documento para abrir a porta serial como uma interface do dispositivo.
Usar a interface do dispositivo (GUID_DEVINTERFACE_COMPORT) é a maneira recomendada de descobrir e acessar uma porta COM. O uso de nomes de porta COM herdados é propenso a colisões de nome e não fornece notificações de alteração de estado para um cliente. O uso dos nomes de porta COM herdados não é recomendado e não tem suporte com SerCx2 e SerCx.
Habilitando a criação da interface do dispositivo
Abaixo estão as instruções para habilitar a criação da interface do dispositivo. Observe que as portas serial são exclusivas, ou seja, se a porta serial estiver acessível como uma interface do dispositivo, um recurso de conexão no ACPI não deverá ser fornecido a nenhum outro dispositivo , por exemplo, nenhum UARTSerialBusV2 recurso deve ser fornecido a nenhum outro dispositivo no sistema; a porta deve ser tornada exclusivamente acessível por meio da interface do dispositivo.
Configuração de ACPI
Um fabricante ou integrador do sistema pode habilitar esse comportamento modificando a definição de ACPI (ASL) do dispositivo SerCx/SerCx2 existente para adicionar uma _DSD definição para propriedades de dispositivo chave-valor com UUID daffd814-6eba-4d8c-8a91-bc9bbf4aa301. Dentro dessa definição, a propriedade SerCx-FriendlyName é especificada com uma descrição específica do sistema para a porta serial; por exemplo, UART0, UART1, etc.
Exemplo de definição de dispositivo (excluindo informações específicas do fornecedor necessárias para definir o dispositivo):
Device(URT0) {
Name(_HID, ...)
Name(_CID, ...)
Name(_DSD, Package() {
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package() {
Package(2) {"SerCx-FriendlyName", "UART0"}
}
})
}
O UUID especificado (daffd814-6eba-4d8c-8a91-bc9bbf4aa301) deve ser usado e a entrada SerCx-FriendlyName deve ser definida para SerCx/SerCx2 criar a interface do dispositivo.
Chave do Registro
Para fins de desenvolvimento, o SerCxFriendlyName também pode ser configurado como uma propriedade na chave de hardware do dispositivo no registro do sistema. O CM_Open_DevNode_Key método pode ser usado para acessar a chave de hardware do dispositivo e adicionar a propriedade SerCxFriendlyName ao dispositivo, que é usado pelo SerCx/SerCx2 para recuperar o nome amigável para a interface do dispositivo.
Não é recomendável definir essa chave por meio de uma extensão INF – ela é fornecida principalmente para fins de teste e desenvolvimento. A abordagem recomendada é habilitar o recurso via ACPI, conforme documentado acima.
Interface do dispositivo
Se um FriendlyName for definido usando os métodos acima, SerCx/SerCx2 publicará uma GUID_DEVINTERFACE_COMPORTinterface de dispositivo para o controlador. Essa interface do dispositivo terá a DEVPKEY_DeviceInterface_Serial_PortName propriedade definida como o nome amigável especificado, que pode ser usado por aplicativos para localizar um controlador/porta específico.
Habilitando o acesso sem privilégios
Por padrão, o controlador/porta estará acessível somente para usuários e aplicativos privilegiados. Se o acesso de aplicativos não privilegiados for necessário, o cliente SerCx/SerCx2 deverá substituir o descritor de segurança padrão depois de chamar SerCx2InitializeDeviceInit() ou SerCxDeviceInitConfig(), mas antes de chamar SerCx2InitializeDevice() ou SerCxInitialize(), momento em que o descritor de segurança aplicado é propagado para o PDO do controlador.
Um exemplo de como habilitar o acesso desprivilegiado no SerCx2 a partir de dentro do driver de controlador do cliente SerCx2 está abaixo.
SampleControllerEvtDeviceAdd(
WDFDRIVER WdfDriver,
WDFDEVICE_INIT WdfDeviceInit
)
{
...
NTSTATUS status = SerCx2InitializeDeviceInit(WdfDeviceInit);
if (!NT_SUCCESS(status)) {
...
}
// Declare a security descriptor allowing access to all
DECLARE_CONST_UNICODE_STRING(
SDDL_DEVOBJ_SERCX_SYS_ALL_ADM_ALL_UMDF_ALL_USERS_RDWR,
L"D:P(A;;GA;;;SY)(A;;GA;;;BA)(A;;GA;;;UD)(A;;GRGW;;;BU)");
// Assign it to the device, overwriting the default SerCx2 security descriptor
status = WdfDeviceInitAssignSDDLString(
WdfDeviceInit,
&SDDL_DEVOBJ_SERCX_SYS_ALL_ADM_ALL_UMDF_ALL_USERS_RDWR);
if (!NT_SUCCESS(status)) {
...
}
...
}
Alterações de comportamento ao usar uma interface do dispositivo
Aceitar esse recurso resulta nas seguintes alterações comportamentais no SerCx/SerCx2 (em vez de acessar o controlador SerCx/SerCx2 por meio de uma ID de conexão):
Nenhuma configuração padrão é aplicada à porta (velocidade, paridade etc. Como não há nenhum recurso de conexão no ACPI para descrever isso, a porta começa em um estado não inicializado. O software que interage com a interface do dispositivo é necessário para configurar a porta usando a interface IOCTL serial definida.
As chamadas do driver cliente SerCx/SerCx2 para consultar ou aplicar a configuração padrão retornarão um status de falha. Além disso, as solicitações para a interface do dispositivo falharão,
IOCTL_SERIAL_APPLY_DEFAULT_CONFIGURATIONpois não há nenhuma configuração padrão especificada para aplicar.
Acessando a interface do dispositivo de porta serial
Para aplicativos UWP, a interface publicada pode ser acessada usando as APIs do Windows.Devices.SerialCommunication namespace, como qualquer outra porta serial em conformidade.
Para aplicativos Win32, a interface do dispositivo está localizada e acessada usando o seguinte processo:
- O aplicativo chama
CM_Get_Device_Interface_ListWpara obter uma lista de todas as interfaces de classe de dispositivoGUID_DEVINTERFACE_COMPORTno sistema. - Chamadas de
CM_Get_Device_Interface_PropertyWaplicativo para cada interface retornada para consultar cadaDEVPKEY_DeviceInterface_Serial_PortNameinterface descoberta - Quando a porta desejada é encontrada pelo nome, o aplicativo usa a string de link simbólico retornada em (1) para abrir um identificador para a porta por meio de
CreateFile()
Código de exemplo para este fluxo:
#include <windows.h>
#include <cfgmgr32.h>
#include <initguid.h>
#include <devpropdef.h>
#include <devpkey.h>
#include <ntddser.h>
...
DWORD ret;
ULONG deviceInterfaceListBufferLength;
//
// Determine the size (in characters) of buffer required for to fetch a list of
// all GUID_DEVINTERFACE_COMPORT device interfaces present on the system.
//
ret = CM_Get_Device_Interface_List_SizeW(
&deviceInterfaceListBufferLength,
(LPGUID) &GUID_DEVINTERFACE_COMPORT,
NULL,
CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
if (ret != CR_SUCCESS) {
// Handle error
...
}
//
// Allocate buffer of the determined size.
//
PWCHAR deviceInterfaceListBuffer = (PWCHAR) malloc(deviceInterfaceListBufferLength * sizeof(WCHAR));
if (deviceInterfaceListBuffer == NULL) {
// Handle error
...
}
//
// Fetch the list of all GUID_DEVINTERFACE_COMPORT device interfaces present
// on the system.
//
ret = CM_Get_Device_Interface_ListW(
(LPGUID) &GUID_DEVINTERFACE_COMPORT,
NULL,
deviceInterfaceListBuffer,
deviceInterfaceListBufferLength,
CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
if (ret != CR_SUCCESS) {
// Handle error
...
}
//
// Iterate through the list, examining one interface at a time
//
PWCHAR currentInterface = deviceInterfaceListBuffer;
while (*currentInterface) {
//
// Fetch the DEVPKEY_DeviceInterface_Serial_PortName for this interface
//
CONFIGRET configRet;
DEVPROPTYPE devPropType;
PWCHAR devPropBuffer;
ULONG devPropSize = 0;
// First, get the size of buffer required
configRet = CM_Get_Device_Interface_PropertyW(
currentInterface,
&DEVPKEY_DeviceInterface_Serial_PortName,
&devPropType,
NULL,
&devPropSize,
0);
if (configRet != CR_BUFFER_SMALL) {
// Handle error
...
}
// Allocate the buffer
devPropBuffer = malloc(devPropSize);
if (devPropBuffer == NULL) {
// Handle error
free(devPropBuffer);
...
}
configRet = CM_Get_Device_Interface_PropertyW(
currentInterface,
&DEVPKEY_DeviceInterface_Serial_PortName,
&devPropType,
(PBYTE) devPropBuffer,
&devPropSize,
0);
if (configRet != CR_SUCCESS) {
// Handle error
free(devPropBuffer);
...
}
// Verify the value is the correct type and size
if ((devPropType != DEVPROP_TYPE_STRING) ||
(devPropSize < sizeof(WCHAR))) {
// Handle error
free(devPropBuffer);
...
}
// Now, check if the interface is the one we are interested in
if (wcscmp(devPropBuffer, L"UART0") == 0) {
free(devPropBuffer);
break;
}
// Advance to the next string (past the terminating NULL)
currentInterface += wcslen(currentInterface) + 1;
free(devPropBuffer);
}
//
// currentInterface now either points to NULL (there was no match and we iterated
// over all interfaces without a match) - or, it points to the interface with
// the friendly name UART0, in which case we can open it.
//
if (*currentInterface == L'\0') {
// Handle interface not found error
...
}
//
// Now open the device interface as we would a COMx style serial port.
//
HANDLE portHandle = CreateFileW(
currentInterface,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
0,
NULL);
if (portHandle == INVALID_HANDLE_VALUE) {
// Handle error
...
}
free(deviceInterfaceListBuffer);
deviceInterfaceListBuffer = NULL;
currentInterface = NULL;
//
// We are now able to send IO requests to the device.
//
... = ReadFile(portHandle, ..., ..., ..., NULL);
Observe que um aplicativo também pode se inscrever para notificações de chegada e remoção de interfaces de dispositivos para abrir ou fechar um handle para o controlador/porta quando o dispositivo ficar disponível ou indisponível.