Files
usb_serial/ios/flutter_usb_serial/Sources/DriverKitSerialClient/DriverKitSerialClient.c
T
Tony 17414656a9 Enhance USB serial plugin for Android and iPadOS with DriverKit support
- 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>
2026-08-01 20:40:46 +08:00

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, &registryEntryId) ==
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);
}