#include "DriverKitSerialClient.h" #include #include #include 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); }