internal static MacSerialDevice TryCreate(NativeMethods.io_string_t path)
        {
            var d = new MacSerialDevice()
            {
                _path = path
            };

            var handle = NativeMethods.IORegistryEntryFromPath(0, ref path).ToIOObject();

            if (!handle.IsSet)
            {
                return(null);
            }

            using (handle)
            {
                d._fileSystemName = NativeMethods.IORegistryEntryGetCFProperty_String(handle, NativeMethods.kIOCalloutDeviceKey);
                if (d._fileSystemName == null)
                {
                    return(null);
                }
            }

            return(d);
        }
Example #2
0
        internal void Init(NativeMethods.io_string_t path)
        {
            IntPtr handle; int retryCount = 0, maxRetries = 10;

            while (true)
            {
                var newPath = path.Clone();
                using (var service = NativeMethods.IORegistryEntryFromPath(0, ref newPath).ToIOObject())
                {
                    string error;

                    if (service.IsSet)
                    {
                        handle = NativeMethods.IOHIDDeviceCreate(IntPtr.Zero, service);
                        if (handle != IntPtr.Zero)
                        {
                            var ret = NativeMethods.IOHIDDeviceOpen(handle);
                            if (ret == NativeMethods.IOReturn.Success)
                            {
                                break;
                            }

                            NativeMethods.CFRelease(handle);

                            // TODO: Only count up if IOReturn is ExclusiveAccess or Offline.
                            error = string.Format("Unable to open HID class device (error {1}): {0}", newPath.ToString(), ret);
                        }
                        else
                        {
                            error = string.Format("HID class device not found: {0}", newPath.ToString());
                        }
                    }
                    else
                    {
                        error = string.Format("HID class device path not found: {0}", newPath.ToString());
                    }

                    if (++retryCount == maxRetries)
                    {
                        throw DeviceException.CreateIOException(Device, error);
                    }

                    Debug.WriteLine(string.Format("Retrying ({0})", error));
                    Thread.Sleep(100);
                }
            }
            _handle = handle;
            HandleInitAndOpen();

            _readThread.Start();
            _writeThread.Start();
        }
        internal void Init(NativeMethods.io_string_t path, MacHidDevice device)
        {
            IntPtr handle;

            using (var service = NativeMethods.IORegistryEntryFromPath(0, ref path).ToIOObject()) {
                handle = NativeMethods.IOHIDDeviceCreate(IntPtr.Zero, service);
                if (handle == IntPtr.Zero)
                {
                    throw new IOException("HID class device not found.");
                }

                if (NativeMethods.IOReturn.Success != NativeMethods.IOHIDDeviceOpen(handle))
                {
                    NativeMethods.CFRelease(handle);
                    throw new IOException("Unable to open HID class device.");
                }
            }
            _device = device;
            _handle = handle;
            HandleInitAndOpen();

            _readThread.Start();
            _writeThread.Start();
        }
Example #4
0
        internal static MacHidDevice TryCreate(NativeMethods.io_string_t path)
        {
            var d = new MacHidDevice()
            {
                _path = path
            };

            var service = NativeMethods.IORegistryEntryFromPath(0, ref path).ToIOObject();

            if (!service.IsSet)
            {
                return(null);
            }

            using (service)
            {
                int?vid     = NativeMethods.IORegistryEntryGetCFProperty_Int(service, NativeMethods.kIOHIDVendorIDKey);
                int?pid     = NativeMethods.IORegistryEntryGetCFProperty_Int(service, NativeMethods.kIOHIDProductIDKey);
                int?version = NativeMethods.IORegistryEntryGetCFProperty_Int(service, NativeMethods.kIOHIDVersionNumberKey);
                if (vid == null || pid == null || version == null)
                {
                    return(null);
                }

                // TODO: Craft the report descriptor from IOHIDElements so we can support it below OS X 10.8...
                //       Also, our report sizes aren't correct for the no-report-ID case without this...

                d._vid              = (int)vid;
                d._pid              = (int)pid;
                d._version          = (int)version;
                d._maxInput         = NativeMethods.IORegistryEntryGetCFProperty_Int(service, NativeMethods.kIOHIDMaxInputReportSizeKey) ?? 0;
                d._maxOutput        = NativeMethods.IORegistryEntryGetCFProperty_Int(service, NativeMethods.kIOHIDMaxOutputReportSizeKey) ?? 0;
                d._maxFeature       = NativeMethods.IORegistryEntryGetCFProperty_Int(service, NativeMethods.kIOHIDMaxFeatureReportSizeKey) ?? 0;
                d._manufacturer     = NativeMethods.IORegistryEntryGetCFProperty_String(service, NativeMethods.kIOHIDManufacturerKey);
                d._productName      = NativeMethods.IORegistryEntryGetCFProperty_String(service, NativeMethods.kIOHIDProductKey);
                d._serialNumber     = NativeMethods.IORegistryEntryGetCFProperty_String(service, NativeMethods.kIOHIDSerialNumberKey);
                d._reportDescriptor = NativeMethods.IORegistryEntryGetCFProperty_Data(service, NativeMethods.kIOHIDReportDescriptorKey);
                if (d._maxInput == 0 && d._maxOutput == 0 && d._maxFeature == 0)
                {
                    return(null);
                }

                // Does this device use Report IDs? Let's find out.
                d._reportsUseID = false; bool hasInput = false, hasOutput = false, hasFeature = false;
                using (var device = NativeMethods.IOHIDDeviceCreate(IntPtr.Zero, service).ToCFType())
                {
                    if (!device.IsSet)
                    {
                        return(null);
                    }

                    using (var elementArray = NativeMethods.IOHIDDeviceCopyMatchingElements(device, IntPtr.Zero).ToCFType())
                    {
                        if (!elementArray.IsSet)
                        {
                            return(null);
                        }

                        int elementCount = checked ((int)NativeMethods.CFArrayGetCount(elementArray));
                        for (int elementIndex = 0; elementIndex < elementCount; elementIndex++)
                        {
                            var element = NativeMethods.CFArrayGetValueAtIndex(elementArray, (IntPtr)elementIndex);
                            if (element == IntPtr.Zero)
                            {
                                continue;
                            }

                            var elementType = NativeMethods.IOHIDElementGetType(element);
                            switch (elementType)
                            {
                            case NativeMethods.IOHIDElementType.InputMisc:
                            case NativeMethods.IOHIDElementType.InputButton:
                            case NativeMethods.IOHIDElementType.InputAxis:
                            case NativeMethods.IOHIDElementType.InputScanCodes:
                                hasInput = true; break;

                            case NativeMethods.IOHIDElementType.Output:
                                hasOutput = true; break;

                            case NativeMethods.IOHIDElementType.Feature:
                                hasFeature = true; break;
                            }

                            if (NativeMethods.IOHIDElementGetReportID(element) != 0)
                            {
                                d._reportsUseID = true;
                            }
                        }
                    }
                }

                if (!d._reportsUseID)
                {
                    // It does not use Report IDs. MacOS's maximums do not include said Report ID.
                    if (d._maxInput != 0)
                    {
                        d._maxInput++;
                    }
                    if (d._maxOutput != 0)
                    {
                        d._maxOutput++;
                    }
                    if (d._maxFeature != 0)
                    {
                        d._maxFeature++;
                    }
                }

                if (!hasInput)
                {
                    d._maxInput = 0;
                }
                if (!hasOutput)
                {
                    d._maxOutput = 0;
                }
                if (!hasFeature)
                {
                    d._maxFeature = 0;
                }
            }

            return(d);
        }