17414656a9
- Updated README.md to reflect platform support for iPadOS. - Implemented isDriverAvailable method in FlutterUsbSerialPlugin for DriverKit readiness check. - Added DriverKitSerialClient C source and header files for iPadOS integration. - Created Swift Package for iPadOS support. - Updated pubspec.yaml and flutter_usb_serial.dart to clarify platform compatibility. - Enhanced tests to verify isDriverAvailable functionality. Signed-off-by: Tony <tonylu@tony-cloud.com>
196 lines
6.5 KiB
C
196 lines
6.5 KiB
C
#include "DriverKitSerialClient.h"
|
|
|
|
#include <IOKit/IOKitLib.h>
|
|
#include <mach/mach.h>
|
|
#include <string.h>
|
|
|
|
static const char *const kFlutterUsbDriverService =
|
|
"DaliMasterEspressifUsbDriver";
|
|
|
|
enum {
|
|
kFlutterUsbDriverGetInfo = 0,
|
|
kFlutterUsbDriverWrite = 1,
|
|
kFlutterUsbDriverRead = 2,
|
|
kFlutterUsbDriverControl = 3,
|
|
kFlutterUsbDriverConfigure = 4,
|
|
kFlutterUsbDriverSetLineState = 5,
|
|
kFlutterUsbDriverPurge = 6,
|
|
};
|
|
|
|
static bool FlutterUsbSerialDriverGetInfo(
|
|
io_connect_t connection,
|
|
FlutterUsbDriverDeviceInfo *info) {
|
|
size_t outputSize = sizeof(*info);
|
|
memset(info, 0, sizeof(*info));
|
|
kern_return_t result = IOConnectCallStructMethod(
|
|
connection, kFlutterUsbDriverGetInfo, NULL, 0, info, &outputSize);
|
|
return result == KERN_SUCCESS && outputSize == sizeof(*info) &&
|
|
info->protocolVersion == 1 &&
|
|
info->kind == FlutterUsbDriverKindSerial;
|
|
}
|
|
|
|
size_t FlutterUsbSerialDriverCopyDevices(
|
|
FlutterUsbDriverDeviceInfo *devices,
|
|
size_t capacity) {
|
|
CFMutableDictionaryRef matching =
|
|
IOServiceNameMatching(kFlutterUsbDriverService);
|
|
if (matching == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
io_iterator_t iterator = IO_OBJECT_NULL;
|
|
kern_return_t result = IOServiceGetMatchingServices(
|
|
kIOMainPortDefault, matching, &iterator);
|
|
if (result != KERN_SUCCESS) {
|
|
return 0;
|
|
}
|
|
|
|
size_t count = 0;
|
|
io_service_t service = IO_OBJECT_NULL;
|
|
while ((service = IOIteratorNext(iterator)) != IO_OBJECT_NULL) {
|
|
io_connect_t connection = IO_OBJECT_NULL;
|
|
FlutterUsbDriverDeviceInfo info;
|
|
if (IOServiceOpen(service, mach_task_self_, 0, &connection) ==
|
|
KERN_SUCCESS &&
|
|
FlutterUsbSerialDriverGetInfo(connection, &info)) {
|
|
uint64_t registryEntryId = 0;
|
|
if (IORegistryEntryGetRegistryEntryID(service, ®istryEntryId) ==
|
|
KERN_SUCCESS) {
|
|
info.registryEntryId = registryEntryId;
|
|
if (devices != NULL && count < capacity) {
|
|
devices[count] = info;
|
|
}
|
|
count++;
|
|
}
|
|
}
|
|
if (connection != IO_OBJECT_NULL) {
|
|
IOServiceClose(connection);
|
|
}
|
|
IOObjectRelease(service);
|
|
}
|
|
IOObjectRelease(iterator);
|
|
return count;
|
|
}
|
|
|
|
bool FlutterUsbSerialDriverIsAvailable(void) {
|
|
return FlutterUsbSerialDriverCopyDevices(NULL, 0) > 0;
|
|
}
|
|
|
|
int32_t FlutterUsbSerialDriverOpen(uint64_t registryEntryId,
|
|
uint32_t *connection) {
|
|
if (connection == NULL) {
|
|
return kIOReturnBadArgument;
|
|
}
|
|
*connection = IO_OBJECT_NULL;
|
|
|
|
CFMutableDictionaryRef matching =
|
|
IOServiceNameMatching(kFlutterUsbDriverService);
|
|
if (matching == NULL) {
|
|
return kIOReturnNoMemory;
|
|
}
|
|
io_iterator_t iterator = IO_OBJECT_NULL;
|
|
kern_return_t result = IOServiceGetMatchingServices(
|
|
kIOMainPortDefault, matching, &iterator);
|
|
if (result != KERN_SUCCESS) {
|
|
return result;
|
|
}
|
|
|
|
io_service_t service = IO_OBJECT_NULL;
|
|
result = kIOReturnNotFound;
|
|
while ((service = IOIteratorNext(iterator)) != IO_OBJECT_NULL) {
|
|
uint64_t candidateId = 0;
|
|
if (IORegistryEntryGetRegistryEntryID(service, &candidateId) ==
|
|
KERN_SUCCESS &&
|
|
candidateId == registryEntryId) {
|
|
io_connect_t opened = IO_OBJECT_NULL;
|
|
result = IOServiceOpen(service, mach_task_self_, 0, &opened);
|
|
if (result == KERN_SUCCESS) {
|
|
FlutterUsbDriverDeviceInfo info;
|
|
if (FlutterUsbSerialDriverGetInfo(opened, &info)) {
|
|
*connection = opened;
|
|
} else {
|
|
IOServiceClose(opened);
|
|
result = kIOReturnUnsupported;
|
|
}
|
|
}
|
|
IOObjectRelease(service);
|
|
break;
|
|
}
|
|
IOObjectRelease(service);
|
|
}
|
|
IOObjectRelease(iterator);
|
|
return result;
|
|
}
|
|
|
|
void FlutterUsbSerialDriverClose(uint32_t connection) {
|
|
if (connection != IO_OBJECT_NULL) {
|
|
IOServiceClose((io_connect_t)connection);
|
|
}
|
|
}
|
|
|
|
int32_t FlutterUsbSerialDriverWrite(uint32_t connection,
|
|
const uint8_t *bytes,
|
|
uint32_t length,
|
|
uint32_t *bytesWritten) {
|
|
if (connection == IO_OBJECT_NULL || bytes == NULL || bytesWritten == NULL) {
|
|
return kIOReturnBadArgument;
|
|
}
|
|
uint64_t output = 0;
|
|
uint32_t outputCount = 1;
|
|
kern_return_t result = IOConnectCallMethod(
|
|
(io_connect_t)connection, kFlutterUsbDriverWrite, NULL, 0, bytes, length,
|
|
&output, &outputCount, NULL, NULL);
|
|
*bytesWritten = result == KERN_SUCCESS ? (uint32_t)output : 0;
|
|
return result;
|
|
}
|
|
|
|
int32_t FlutterUsbSerialDriverRead(uint32_t connection,
|
|
uint8_t *bytes,
|
|
uint32_t capacity,
|
|
uint32_t timeoutMilliseconds,
|
|
uint32_t *bytesRead) {
|
|
if (connection == IO_OBJECT_NULL || bytes == NULL || bytesRead == NULL) {
|
|
return kIOReturnBadArgument;
|
|
}
|
|
const uint64_t inputs[] = {capacity, timeoutMilliseconds};
|
|
size_t outputSize = capacity;
|
|
kern_return_t result = IOConnectCallMethod(
|
|
(io_connect_t)connection, kFlutterUsbDriverRead, inputs, 2, NULL, 0,
|
|
NULL, NULL, bytes, &outputSize);
|
|
if (result == kIOReturnTimeout) {
|
|
*bytesRead = 0;
|
|
return KERN_SUCCESS;
|
|
}
|
|
*bytesRead = result == KERN_SUCCESS ? (uint32_t)outputSize : 0;
|
|
return result;
|
|
}
|
|
|
|
int32_t FlutterUsbSerialDriverConfigure(uint32_t connection,
|
|
uint32_t baudRate,
|
|
uint8_t dataBits,
|
|
uint8_t parity,
|
|
uint8_t stopBits) {
|
|
const uint64_t inputs[] = {baudRate, dataBits, parity, stopBits};
|
|
return IOConnectCallScalarMethod((io_connect_t)connection,
|
|
kFlutterUsbDriverConfigure, inputs, 4,
|
|
NULL, NULL);
|
|
}
|
|
|
|
int32_t FlutterUsbSerialDriverSetLineState(uint32_t connection,
|
|
bool dtr,
|
|
bool rts) {
|
|
const uint64_t inputs[] = {dtr ? 1U : 0U, rts ? 1U : 0U};
|
|
return IOConnectCallScalarMethod((io_connect_t)connection,
|
|
kFlutterUsbDriverSetLineState, inputs, 2,
|
|
NULL, NULL);
|
|
}
|
|
|
|
int32_t FlutterUsbSerialDriverPurge(uint32_t connection,
|
|
bool purgeWrite,
|
|
bool purgeRead) {
|
|
const uint64_t inputs[] = {purgeWrite ? 1U : 0U, purgeRead ? 1U : 0U};
|
|
return IOConnectCallScalarMethod((io_connect_t)connection,
|
|
kFlutterUsbDriverPurge, inputs, 2,
|
|
NULL, NULL);
|
|
}
|