├── LICENSE ├── Makefile └── devreset.c /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 David Helkowski 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | TARGET = devreset 2 | 3 | all: $(TARGET) 4 | 5 | $(TARGET): devreset.c 6 | gcc devreset.c -framework IOKit -framework CoreFoundation -o devreset 7 | 8 | clean: 9 | $(RM) $(TARGET) -------------------------------------------------------------------------------- /devreset.c: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2020 Jesús A. Álvarez 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define kExcAccMaxWait 5 10 | 11 | static IONotificationPortRef gNotificationPort; 12 | static io_iterator_t gDevIter; 13 | static mach_port_t gMachPort; 14 | 15 | void DeviceConnected (void *refCon, io_iterator_t iterator); 16 | 17 | int main (int argc, char const *argv[]) 18 | { 19 | if (argc < 3) { 20 | fprintf(stderr, "usage: %s productID vendorID\n", argv[0]); 21 | exit(1); 22 | } 23 | 24 | SInt32 productID, vendorID; 25 | productID = strtol(argv[1], NULL, 0); 26 | vendorID = strtol(argv[2], NULL, 0); 27 | 28 | if (productID <= 0 || productID > 0xffff || vendorID <= 0 || vendorID > 0xffff) { 29 | fprintf(stderr, "Invalid productID or vendorID\n"); 30 | exit(1); 31 | } 32 | 33 | printf("Looking for productID=0x%04x vendorID=0x%04x\n", productID, vendorID); 34 | 35 | kern_return_t kerr; 36 | kerr = IOMasterPort(MACH_PORT_NULL, &gMachPort); 37 | if (kerr || !gMachPort) return 1; 38 | 39 | CFMutableDictionaryRef dict = IOServiceMatching(kIOUSBDeviceClassName); 40 | if (!dict) { 41 | fprintf(stderr, "could not create matching dictionary for device vendor=0x%04X,product=0x%04X\n", vendorID, productID); 42 | exit(1); 43 | } 44 | CFDictionarySetValue(dict, CFSTR(kUSBVendorID), CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vendorID)); 45 | CFDictionarySetValue(dict, CFSTR(kUSBProductID), CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &productID)); 46 | gNotificationPort = IONotificationPortCreate(gMachPort); 47 | kerr = IOServiceAddMatchingNotification(gNotificationPort, kIOFirstMatchNotification, dict, DeviceConnected, NULL, &gDevIter); 48 | if (kerr != kIOReturnSuccess) { 49 | fprintf(stderr, "IOServiceAddMatchingNotification\n"); 50 | exit(1); 51 | } 52 | DeviceConnected(NULL, gDevIter); 53 | mach_port_deallocate(mach_task_self(), gMachPort); 54 | 55 | return 0; 56 | } 57 | 58 | IOReturn ConfigureDevice (IOUSBDeviceInterface245 **dev) { 59 | UInt8 nConf; 60 | IOUSBConfigurationDescriptorPtr confDescPtr; 61 | 62 | (*dev)->GetNumberOfConfigurations(dev, &nConf); 63 | if (nConf == 0) return kIOReturnError; 64 | 65 | if ((*dev)->GetConfigurationDescriptorPtr(dev, 0, &confDescPtr)) return kIOReturnError; 66 | if ((*dev)->SetConfiguration(dev, confDescPtr->bConfigurationValue)) return kIOReturnError; 67 | 68 | return kIOReturnSuccess; 69 | } 70 | 71 | void DeviceConnected (void *refCon, io_iterator_t iterator) { 72 | kern_return_t kerr; 73 | io_service_t device; 74 | IOCFPlugInInterface **iodev; 75 | IOUSBDeviceInterface245 **dev = NULL; 76 | UInt16 vendor, product, version; 77 | HRESULT result; 78 | int u; 79 | 80 | while ((device = IOIteratorNext(iterator))) { 81 | // get device plugin 82 | kerr = IOCreatePlugInInterfaceForService(device, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &iodev, (SInt32*)&u); 83 | IOObjectRelease(device); 84 | if (kerr != kIOReturnSuccess) { 85 | fprintf(stderr, "could not create plug-in interface: %08x\n", kerr); 86 | continue; 87 | } 88 | 89 | // get device interface 90 | result = (*iodev)->QueryInterface(iodev, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID245), (LPVOID)&dev); 91 | IODestroyPlugInInterface(iodev); 92 | if (result || !dev) { 93 | fprintf(stderr, "could not get device interface: %08x\n", (int)result); 94 | continue; 95 | } 96 | 97 | // get device data 98 | (*dev)->GetDeviceVendor(dev, &vendor); 99 | (*dev)->GetDeviceProduct(dev, &product); 100 | (*dev)->GetDeviceReleaseNumber(dev, &version); 101 | fprintf(stdout, "Found device vendor=0x%04X, product=0x%04X, version=0x%04X\n", vendor, product, version); 102 | 103 | // open device 104 | u = 0; 105 | do { 106 | kerr = (*dev)->USBDeviceOpen(dev); 107 | if (kerr == kIOReturnExclusiveAccess) { 108 | fprintf(stdout, "waiting for access (%d)\n", kExcAccMaxWait-u); 109 | u++; 110 | sleep(1); 111 | } 112 | } while ((kerr == kIOReturnExclusiveAccess) && (u < kExcAccMaxWait)); 113 | 114 | if (kerr != kIOReturnSuccess) { 115 | fprintf(stderr, "could not open device: %08x\n", kerr); 116 | (void) (*dev)->Release(dev); 117 | continue; 118 | } 119 | 120 | // configure device 121 | if (ConfigureDevice(dev) != kIOReturnSuccess) { 122 | fprintf(stderr, "could not configure device\n"); 123 | (*dev)->USBDeviceClose(dev); 124 | (*dev)->Release(dev); 125 | continue; 126 | } 127 | 128 | // reenumerate to device 129 | kerr = (*dev)->USBDeviceReEnumerate(dev, 0); 130 | if (kerr != kIOReturnSuccess) { 131 | fprintf(stdout, "USBDeviceReEnumerate: error %d\n", kerr); 132 | } 133 | 134 | // close device 135 | (*dev)->USBDeviceClose(dev); 136 | (*dev)->Release(dev); 137 | } 138 | } 139 | --------------------------------------------------------------------------------