#include <unistd.h>
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/IOCFPlugIn.h>
#include <IOKit/usb/IOUSBLib.h>
#include <mach/mach.h>
#include "hex2c.h"
#define k8051_USBCS 0x7f92
#define NARRATEIO 0
static IONotificationPortRef gNotifyPort;
static io_iterator_t gRawAddedIter;
static io_iterator_t gRawRemovedIter;
static io_iterator_t gNewDeviceAddedIter;
static io_iterator_t gNewDeviceRemovedIter;
IOReturn ConfigureAnchorDevice(IOUSBDeviceInterface245 **dev)
{
UInt8 numConf;
IOReturn kr;
IOUSBConfigurationDescriptorPtr confDesc;
kr = (*dev)->GetNumberOfConfigurations(dev, &numConf);
if (!numConf)
return -1;
kr = (*dev)->GetConfigurationDescriptorPtr(dev, 0, &confDesc);
if (kr)
{
printf("\tunable to get config descriptor for index %d (err = %08x)\n", 0, kr);
return -1;
}
kr = (*dev)->SetConfiguration(dev, confDesc->bConfigurationValue);
if (kr)
{
printf("\tunable to set configuration to value %d (err=%08x)\n", 0, kr);
return -1;
}
return kIOReturnSuccess;
}
IOReturn AnchorWrite(IOUSBDeviceInterface245 **dev, UInt16 anchorAddress, UInt16 count, UInt8 writeBuffer[])
{
IOUSBDevRequest request;
request.bmRequestType = USBmakebmRequestType(kUSBOut, kUSBVendor, kUSBDevice);
request.bRequest = 0xa0;
request.wValue = anchorAddress;
request.wIndex = 0;
request.wLength = count;
request.pData = writeBuffer;
return (*dev)->DeviceRequest(dev, &request);
}
void runDeviceDriver(UInt16 vendor, UInt16 product)
{
char name[]="12341234",
vendorStr[]="65535",
prodStr[]="65535";
pid_t newPID;
sprintf(name, "%04X%04X", vendor, product);
printf("Command to exec is \"%s\"\n", name);
sprintf(vendorStr, "%d", vendor);
sprintf(prodStr, "%d", product);
printf("Args are %s/%s\n", vendorStr, prodStr);
newPID = fork();
if(newPID == 0)
{
execlp(name, name, vendorStr, prodStr, NULL);
printf("Failed to exec new driver (err = %d)\n", errno);
}
else if(newPID == -1)
{
printf("Fork failed to make new process for driver (err = %d)\n", errno);
}
}
FILE *openFile(UInt16 vendor, UInt16 product)
{
char name[]="12341234.hex";
char path[256];
char *pathp = path;
FILE *hexFile;
pathp = getenv("HEXPATH");
if(pathp != nil)
{
strncpy(path, pathp, 256);
}
else
{
pathp = getenv("PATH");
strncpy(path, pathp, 256);
}
sprintf(name, "%04X%04X.HEX", vendor, product);
printf("File to open is \"%s\"\n", name);
do{
hexFile = fopen(name, "r");
if(hexFile != nil)
{
getcwd(path, 255);
printf("From directory %s\n", path);
break;
}
if(pathp == nil)
{
break;
}
if( chdir(strsep(&pathp, ":")) != 0)
{
printf("chdir failed with errno %d\n", errno);
perror(nil);
break;
}
}while(1);
return(hexFile);
}
#if 0
Description of Intel hex records.
Position Description
1 Record Marker: The first character of the line is always a colon (ASCII 0x3A) to identify
the line as an Intel HEX file
2 - 3 Record Length: This field contains the number of data bytes in the register represented
as a 2-digit hexidecimal number. This is the total number of data bytes,
not including the checksum byte nor the first 9 characters of the line.
4 - 7 Address: This field contains the address where the data should be loaded into the chip.
This is a value from 0 to 65,535 represented as a 4-digit hexidecimal value.
8 - 9 Record Type: This field indicates the type of record for this line. The possible values
are: 00=Register contains normal data. 01=End of File. 02=Extended address.
10 - ? Data Bytes: The following bytes are the actual data that will be burned into the EPROM. The
data is represented as 2-digit hexidecimal values.
Last 2 characters Checksum: The last two characters of the line are a checksum for the line. The
checksum value is calculated by taking the twos complement of the sum of all
the preceeding data bytes, excluding the checksum byte itself and the colon
at the beginning of the line.
#endif
IOReturn hexRead(INTEL_HEX_RECORD *record, FILE *hexFile)
{
char c;
UInt16 i;
int n, c1, check, len;
c = getc(hexFile);
if(c != ':')
{
printf("Line does not start with colon (%d)\n", c);
return(kIOReturnNotAligned);
}
n = fscanf(hexFile, "%2lX%4lX%2lX", &record->Length, &record->Address, &record->Type);
if(n != 3)
{
printf("Could not read line preamble %d\n", c);
return(kIOReturnNotAligned);
}
len = record->Length;
if(len > MAX_INTEL_HEX_RECORD_LENGTH)
{
printf("length is more than can fit %d, %d\n", len, MAX_INTEL_HEX_RECORD_LENGTH);
return(kIOReturnNotAligned);
}
for(i = 0; i<len; i++)
{
n = fscanf(hexFile, "%2X", &c1);
if(n != 1)
{
if(i != record->Length)
{
printf("Line finished at wrong time %d, %ld\n", i, record->Length);
return(kIOReturnNotAligned);
}
}
record->Data[i] = c1;
}
n = fscanf(hexFile, "%2X\n", &check);
if(n != 1)
{
printf("Check not found\n");
return(kIOReturnNotAligned);
}
return(kIOReturnSuccess);
}
IOReturn DownloadToAnchorDevice(IOUSBDeviceInterface245 **dev, UInt16 vendor, UInt16 product)
{
UInt8 writeVal;
IOReturn kr;
FILE *hexFile;
INTEL_HEX_RECORD anchorCode;
hexFile = openFile(vendor, product);
if(hexFile == nil)
{
printf("File open failed\n");
return(kIOReturnNotOpen);
}
writeVal = 1;
kr = AnchorWrite(dev, k8051_USBCS, 1, &writeVal);
if (kIOReturnSuccess != kr)
{
printf("AnchorWrite reset returned err 0x%x!\n", kr);
return kr;
}
while (1)
{
kr = hexRead(&anchorCode, hexFile);
if(anchorCode.Type != 0)
{
break;
}
if(kr == kIOReturnSuccess)
{
kr = AnchorWrite(dev, anchorCode.Address, anchorCode.Length, anchorCode.Data);
}
if (kIOReturnSuccess != kr)
{
printf("AnchorWrite download %lx returned err 0x%x!\n", anchorCode.Address, kr);
return kr;
}
#if NARRATEDOWNLOAD
printf("%04lx ",anchorCode.Address);
#endif
}
#if NARRATEDOWNLOAD
printf("\n");
#endif
writeVal = 0;
kr = AnchorWrite(dev, k8051_USBCS, 1, &writeVal);
if (kIOReturnSuccess != kr)
{
printf("AnchorWrite run returned err 0x%x!\n", kr);
}
return kr;
}
void RawDeviceAdded(void *refCon, io_iterator_t iterator)
{
kern_return_t kr;
io_service_t usbDevice;
IOCFPlugInInterface **plugInInterface=NULL;
IOUSBDeviceInterface245 **dev=NULL;
HRESULT res;
SInt32 score;
UInt16 vendor;
UInt16 product;
UInt16 release;
int exclusiveErr = 0;
while ( (usbDevice = IOIteratorNext(iterator)) )
{
printf("Raw device added.\n");
kr = IOCreatePlugInInterfaceForService(usbDevice, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &plugInInterface, &score);
kr = IOObjectRelease(usbDevice); if ((kIOReturnSuccess != kr) || !plugInInterface)
{
printf("unable to create a plugin (%08x)\n", kr);
continue;
}
res = (*plugInInterface)->QueryInterface(plugInInterface, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID245), (LPVOID)&dev);
IODestroyPlugInInterface(plugInInterface);
if (res || !dev)
{
printf("couldn't create a device interface (%08x)\n", (int) res);
continue;
}
kr = (*dev)->GetDeviceVendor(dev, &vendor);
kr = (*dev)->GetDeviceProduct(dev, &product);
kr = (*dev)->GetDeviceReleaseNumber(dev, &release);
do{
kr = (*dev)->USBDeviceOpen(dev);
if(kIOReturnExclusiveAccess == kr)
{
exclusiveErr++;
printf("Exclusive access err, sleeping on it %d\n", exclusiveErr);
sleep(1);
}
}while( (kIOReturnExclusiveAccess == kr) && (exclusiveErr < 5) );
if (kIOReturnSuccess != kr)
{
printf("unable to open device: %08x\n", kr);
(void) (*dev)->Release(dev);
continue;
}
kr = ConfigureAnchorDevice(dev);
if (kIOReturnSuccess != kr)
{
printf("unable to configure device: %08x\n", kr);
(void) (*dev)->USBDeviceClose(dev);
(void) (*dev)->Release(dev);
continue;
}
kr = DownloadToAnchorDevice(dev, vendor, product);
if (kIOReturnSuccess != kr)
{
printf("unable to download to device: %08x\n", kr);
(void) (*dev)->USBDeviceClose(dev);
(void) (*dev)->Release(dev);
continue;
}
kr = (*dev)->USBDeviceClose(dev);
kr = (*dev)->Release(dev);
}
}
void RawDeviceRemoved(void *refCon, io_iterator_t iterator)
{
kern_return_t kr;
io_service_t obj;
while ( (obj = IOIteratorNext(iterator)) )
{
printf("Raw device removed.\n");
kr = IOObjectRelease(obj);
}
}
void NewDeviceAdded(void *refCon, io_iterator_t iterator)
{
kern_return_t kr;
io_service_t usbDevice;
IOCFPlugInInterface **plugInInterface=NULL;
IOUSBDeviceInterface245 **dev=NULL;
HRESULT res;
SInt32 score;
UInt16 vendor;
UInt16 product;
while ( (usbDevice = IOIteratorNext(iterator)) )
{
printf("New device added.\n");
kr = IOCreatePlugInInterfaceForService(usbDevice, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &plugInInterface, &score);
kr = IOObjectRelease(usbDevice); if ((kIOReturnSuccess != kr) || !plugInInterface)
{
printf("unable to create a plugin (%08x)\n", kr);
continue;
}
res = (*plugInInterface)->QueryInterface(plugInInterface, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID245), (LPVOID)&dev);
IODestroyPlugInInterface(plugInInterface);
if (res || !dev)
{
printf("couldn't create a device interface (%08x)\n", (int) res);
continue;
}
kr = (*dev)->GetDeviceVendor(dev, &vendor);
kr = (*dev)->GetDeviceProduct(dev, &product);
runDeviceDriver(vendor, product);
}
}
void NewDeviceRemoved(void *refCon, io_iterator_t iterator)
{
kern_return_t kr;
io_service_t obj;
while ( (obj = IOIteratorNext(iterator)) )
{
printf("New device removed.\n");
kr = IOObjectRelease(obj);
}
}
void SignalHandler(int sigraised)
{
printf("\nInterrupted\n");
IONotificationPortDestroy(gNotifyPort);
if (gRawAddedIter)
{
IOObjectRelease(gRawAddedIter);
gRawAddedIter = 0;
}
if (gRawRemovedIter)
{
IOObjectRelease(gRawRemovedIter);
gRawRemovedIter = 0;
}
if (gNewDeviceAddedIter)
{
IOObjectRelease(gNewDeviceAddedIter);
gNewDeviceAddedIter = 0;
}
if (gNewDeviceRemovedIter)
{
IOObjectRelease(gNewDeviceRemovedIter);
gNewDeviceRemovedIter = 0;
}
_exit(0);
}
int main (int argc, const char *argv[])
{
mach_port_t masterPort;
CFMutableDictionaryRef matchingDict;
CFRunLoopSourceRef runLoopSource;
kern_return_t kr;
SInt32 usbVendor = 0xdead; SInt32 usbProduct = 0xbeef; SInt32 usbVendor2;
SInt32 usbProduct2;
sig_t oldHandler;
if(argc < 3)
{
printf("Usage: loadez VID PID [PID2|VID2 PID2]\n");
return(0);
}
if (argc > 1)
usbVendor = atoi(argv[1]);
if (argc > 2)
usbProduct = atoi(argv[2]);
usbVendor2 = usbVendor;
usbProduct2 = usbProduct+1;
if (argc == 4)
{
usbVendor2 = usbVendor;
usbProduct2 = atoi(argv[3]);
}
else
{
if (argc > 3)
usbVendor2 = atoi(argv[3]);
if (argc > 4)
usbProduct2 = atoi(argv[4]);
}
oldHandler = signal(SIGINT, SignalHandler);
if (oldHandler == SIG_ERR)
printf("Could not establish new signal handler");
kr = IOMasterPort(MACH_PORT_NULL, &masterPort);
if (kr || !masterPort)
{
printf("ERR: Couldn't create a master IOKit Port(%08x)\n", kr);
return -1;
}
printf("\nLooking for devices matching vendor ID=%ld and product ID=%ld\n", usbVendor, usbProduct);
matchingDict = IOServiceMatching(kIOUSBDeviceClassName); if (!matchingDict)
{
printf("Can't create a USB matching dictionary\n");
mach_port_deallocate(mach_task_self(), masterPort);
return -1;
}
CFDictionarySetValue(
matchingDict,
CFSTR(kUSBVendorID),
CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &usbVendor));
CFDictionarySetValue(
matchingDict,
CFSTR(kUSBProductID),
CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &usbProduct));
gNotifyPort = IONotificationPortCreate(masterPort);
runLoopSource = IONotificationPortGetRunLoopSource(gNotifyPort);
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopDefaultMode);
matchingDict = (CFMutableDictionaryRef) CFRetain( matchingDict );
matchingDict = (CFMutableDictionaryRef) CFRetain( matchingDict );
matchingDict = (CFMutableDictionaryRef) CFRetain( matchingDict );
kr = IOServiceAddMatchingNotification( gNotifyPort,
kIOFirstMatchNotification,
matchingDict,
RawDeviceAdded,
NULL,
&gRawAddedIter );
RawDeviceAdded(NULL, gRawAddedIter);
kr = IOServiceAddMatchingNotification( gNotifyPort,
kIOTerminatedNotification,
matchingDict,
RawDeviceRemoved,
NULL,
&gRawRemovedIter );
RawDeviceRemoved(NULL, gRawRemovedIter);
printf("Downloaded devices should match vendor ID=%ld and product ID=%ld\n", usbVendor2, usbProduct2);
CFDictionarySetValue(
matchingDict,
CFSTR(kUSBVendorID),
CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &usbVendor2));
CFDictionarySetValue(
matchingDict,
CFSTR(kUSBProductID),
CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &usbProduct2));
kr = IOServiceAddMatchingNotification( gNotifyPort,
kIOFirstMatchNotification,
matchingDict,
NewDeviceAdded,
NULL,
&gNewDeviceAddedIter );
NewDeviceAdded(NULL, gNewDeviceAddedIter);
kr = IOServiceAddMatchingNotification( gNotifyPort,
kIOTerminatedNotification,
matchingDict,
NewDeviceRemoved,
NULL,
&gNewDeviceRemovedIter );
NewDeviceRemoved(NULL, gNewDeviceRemovedIter);
mach_port_deallocate(mach_task_self(), masterPort);
masterPort = 0;
CFRunLoopRun();
return 0;
}