macOS: detect when storage device is attached or detached - objective-c

It's fairly easy on macOS to detect mount and unmount operations with an NSNotificationCenter listener, as explained here.
But I'm actually looking for a way to detect whether a (physical or virtual) storage device was attached (without mount) or detached (e.g. after unmount).
(It must be possible because there are a couple of applications like Jettison or Mountain that have this functionality, e.g. they will notice when the external storage device is detached, or whether it's still present for re-mounting.)

Related

How to programmatically find mount/eject usb device on macOS?

I am trying to unmount/eject usb device programmatically on macOS.
Using IOkit I tried to register to IOServiceMatching(kIOUSBInterfaceClassName) and iterate over all devices and for each device i tried getting the BSD name and go from there:
IORegistryEntrySearchCFProperty(usbDevice,kIOServicePlane,CFSTR(kIOBSDNameKey),kCFAllocatorDefault,kIORegistryIterateRecursively);
But i found that on Intel based devices that regestry search dosnt work.
I do have Vendor id, product id etc..
So my quistion:
Is there diffrent alternative?
Is there a syscall i can use?
Maybe diffrent approch and not use IoKit?
Thanks
I tried to register using Iokit to:
IOServiceMatching(kIOUSBHostDeviceClassName)
and
IOServiceMatching(kIOUSBInterfaceClassName);
and
IOServiceMatching(kIOUSBDeviceClassName);
First of all, there's no concept of "ejecting" in USB itself. Mounting, unmounting, ejecting, etc. are all storage device/volume concepts, and USB mass storage devices are just one type of storage device on which you can perform these operations.
You therefore need to look at the Disk Arbitration framework, specifically the DADiskEject function for ejecting. There is a certain mapping between I/O Kit and Disk Arbitration objects, but not all DADisk objects will necessarily have corresponding I/O Kit objects, as they also exist for APFS snapshot volumes, network mounts, etc. If looking for the device via I/O Kit is natural (for example because you're interested in a specific vendor+product ID pair) then you can easily find an IOMedia object's corresponding DADisk using DADiskCreateFromIOMedia.
For searching the I/O Kit registry for USB devices, use one of the documented matching dictionary formats.
For example, something like:
#{
#kIOProviderClassKey: #kIOUSBHostDeviceClassName,
#kUSBVendorID : #1234,
#kUSBProductID: #5678,
}

Get macOS Output Device Audio Buffers in Realtime

I'm trying to tap the currently selected output audio device on macOS, so I basically have a pass through listener that can monitor the audio stream currently being output without affecting it.
I want to copy this data to a ring buffer in real time so I can operate on it separately.
The combination of Apple docs and (outdated?) SO answers are confusing as to whether I need to write a hacky kernel extension, can utilise CoreAudio for this, or need to interface with the HAL?
I would like to work in Swift if possible.
Many thanks
(ps. I had been looking at this and this)
I don't know about kernel extensions - their use of special "call us" signing certificates or the necessity of turning off SIP discourages casual exploration.
However you can use a combination of CoreAudio and HAL AudioServer plugins to do what you want, and you don't even need to write the plugin yourself, there are several open source versions to choose from.
CoreAudio doesn't give you a way to record from (or "tap") output devices - you can only record from input devices, so the way to get around this is to create a virtual "pass through" device (AudioServerPlugin), not associated with any hardware, that copies output through to input and then set this pass through device as default output and record from its input. I've done this using open source AudioServer Plugins like BackgroundMusic and BlackHole [TODO: add more].
To tap/record from the resulting device you can simply add an AudioDeviceIOProc callback to it or set the device as the kAudioOutputUnitProperty_CurrentDevice of an kAudioUnitSubType_HALOutput AudioUnit
There are two problems with the above virtual pass through device approach:
you can't your hear output anymore, because it's being consumed by the pass through device
changing default output device will switch away from your device and the tap will fall silent.
If 1. is a problem, then a simple is to create a Multi-Output device containing the pass through device and a real output device (see screenshot) & set this as the default output device. Volume controls stop working, but you can still change the real output device's volume in Audio MIDI Setup.app.
For 2. you can add a listener to the default output device and update the multi-output device above when it changes.
You can do most of the above in swift, although for ringbuffer-stowing from the buffer delivery callbacks you'll have to use C or some other language that can respect the realtime audio rules (no locks, no memory allocation, etc). You could maybe try AVAudioEngine to do the tap, but IIRC changing input device is a vale of tears.

How do you access secret area of any USB device?

We know interfaces based on "vtable" principle. Once you have a pointer to an object, you can narrow-cast it to an interface and the new object is the same object but is very limited to the interface. I always thought hardware firmware is somewhat similar. For example, for block devices (HDDs or SSDs), this interface is like read, write, status and similar. So driver is a user of such a device interface.
As it turns out, any storage device has firmware and a special area of its storage marked internal where firmware is saved. Manufacturers release programs that allow to "flash" their specific devices, e.g. by writing new program to its internal space, hidden from the OS.
My question is: on a software level, how do they perform this read-write operations to the "hidden" area of a drive? How dead "COM ports" are related?
If HDDs work across all OSes, why do firmware upgrade software is only released for Windows? In open source world of linux, what do i need to read to understand "debugging firmware" better?
We know interfaces based on "vtable" principle. Once you have a pointer to an object, you can narrow-cast it to an interface and the new object is the same object but is very limited to the interface. I always thought hardware firmware is somewhat similar. For example, for block devices (HDDs or SSDs), this interface is like read, write, status and similar. So driver is a user of such a device interface.
No, not really. Object-orientated programming is unrelated to personal computer hardware and your impression that virtual calls are relatable to device drivers is misguided. They're completely unrelated.
As it turns out, any storage device has firmware and a special area of its storage marked internal where firmware is saved. Manufacturers release programs that allow to "flash" their specific devices, e.g. by writing new program to its internal space, hidden from the OS.
This is not true. Not all storage devices have firmware - and whatever firmware they have (if any) is not necessarily stored on rewritable flash-storage. ROM chips exist, for example, which are not rewritable.
My question is: on a software level, how do they perform this read-write operations to the "hidden" area of a drive? How dead "COM ports" are related?
If you're referring to firmware updates of modern (post-2004) SATA and NVMe storage devices, then those devices' firmware can be updated using SATA and NVMe's built-in commands.
This is documented in places like and t13.org ATA/ATAPI Command Set - 4
If HDDs work across all OSes, why do firmware upgrade software is only released for Windows? In open source world of linux, what do i need to read to understand "debugging firmware" better?
why do firmware upgrade software is only released for Window
Because Windows is the predominant operating-system used by users of those kinds of hardware. While the firmware can be updated using raw SATA/NVMe commands, you still need a host operating system to run the program that will issue those SATA/NVMe commands. Supposing it costs $100k to build a firmware update for an SSD for Windows and another $100k for Linux (for $200k for both Linux and Windows) - but 90% of all Linux users also run Windows - so why spend $200k for 100% coverage when you can spend $100k on 90% coverage, then spend the extra $100k buying a Ferrari or Tesla Model X P100D on yourself, and blame the users for not booting from a Windows USB stick to upgrade their firmware? (Side note: I chose the latter, and yes, I really do love my Tesla Model X)
You cannot have a program that just magically runs on any computer platform (Windows, BSD, Linux, macOS, QNX, etc) and updates periphial device firmware: it always needs to be a program that can be executed by a host OS (you can argue that UEFI/EFI is a platform-agnostic approach, but in reality UEFI/EFI is still its own platform)
In open source world of linux, what do i need to read to understand "debugging firmware" better?
200mg of Adderall and a pirated copy of IDA Pro.
...or 500mg of Dexedrine and NSA Ghidra.
It depends on the exact type of block device and how it is interfaced to the PC. A very common interface is SATA, when can be used directly with a SATA controller in a home PC - or it can be reached through a USB-SATA bridge.
If we take SATA as an example, there exists a special command in the SATA protocol known as "Download Microcode" (command ID 0x92) - which exists solely for the purpose of transferring new firmware to the drive controller.
The firmware is typically not stored on a "hidden area of the drive" itself, as your indicate - it is typically stored in flash memory or similar on the drive controller PCB or within the drive controller IC.
There are no "dead COM ports" involved in this.
The reason why harddrive vendors some times release firmware update tools only for Windows is probably the simple reason that most of their customers use Windows, and it is cheaper for them to simply support that one platform.

Is it possible to write a program on flash drive (pen drive) to perform a task on inserting flash drive into USB port?

I have a music playlist folder in my Flash drive (pen drive), music names are sorted in a fixed manner, I want to shuffle my music playlist by renaming the files. Generally I use Flash drive to play music in my car.
Is it practically possible to write a program for a flash drive? On inserting a flash drive into PC/car firmware; music files in the playlist folder must be shuffled every time.
Thank you.
I searched on web, I didn't find useful resources to accomplish the task.
It's only possible if either of the following are true:
The "computer" you're inserting it into supports running code. (Like an autoexec.bat on Windows). Obviously this depends entirely on what CPU/"OS" your car's audio player runs. Unlikely that there's any intentional support for executing code, but you might find an exploit that would let you run code on your car's audio-player microcontroller. The audio player probably doesn't really have an OS, it's probably just a lightweight custom system.
Your flash drive can run custom firmware that has a driver for FAT32 and modifies its own contents on powerup, before making itself visible to the host.
Flash drives do have a microcontroller internally to run the flash remapping / wear-leveling firmware. But usually there's no documented interface for uploading programs to it. And normally it doesn't know anything about filesystems, only block-level stuff, so anything you wanted to stuff into it would have to include a driver for FAT32.
I assume some people have reverse-engineered the programming / firmware-update interface on some flash drives.
You can probably also get USB devices that are designed to run custom programs like this as well as act as USB storage. If you really really want this (and your car doesn't have a "randomize" mode you can use instead), buying a USB-storage device that was designed to be programmable would probably be the easiest way to go. I assume such things exist but IDK.

Most common firmware update protocol

I am supposed to pick (and may be implement) the firmware update protocol/software/procedure for the embedded device without USB and with limited program memory size. That device will work autonomously most of the time but once in a while a technician will be coming and updating the firmware.
What would be the most common choice for the update protocol if I wanted to use RS232 or CAN?
The requirements for the update are: complete after interrupted update (boot loader will be needed, I assume), small memory footprint, merge user settings with the newly introduced user data fields (in EEPROM), backup the previous version of the firmware with the possibility to roll the update back, safely update the boot loader itself.
It would be nice if the implementation of the boot loader and update client software existed already too (at least for Windows).
And just out of curiosity - are there any good alternatives to DFU for devices with USB?
Thanks in advance
I am not sure about "most common"; I am not sure anyone could answer that authoritatively or whether the answer is even useful. However I can tell you that I have implemented XMODEM-CRC/XMODEM-1K on a number of devices (ARM 7, ARM Cortem-M, PIC24, TI C55xx for example) in less than 4Kbytes. The bootloader sends an XMODEM start request on each port that is to support update, then for each port if a response is received within a short timeout (a few tens of milliseconds), then transfer continues. If no response is received the application is started normally.
complete after interrupted update (boot loader will be needed, I assume)
The approach I have taken is to not program the start address immediatly to flash on receipt but to copy it sideways and then program it last. The bootloader checks the start address on start-up and if it is 0xFFFFFFFF (i.e. not programmed) the transfer did not complete, and the bootloader restarts continuously polling for XMODEM start.
merge user settings with the newly introduced user data fields (in EEPROM),
In my case I have used Intel HEX files, but EEPROM memory is not commonly memory mapped. You could solve that by using a proprietary data format or set the address of the HEX data to an area that is invalid on the processor which the bootloader code will recognise as data to be sent to the EEPROM instead.
backup the previous version of the firmware with the possibility to
roll the update back,
That is a function of the bootloader implementation rather than the protocol. It of course requires that you have space to store two copies of the application. The unused copy could possibly be zipped, but incorporating decompression in the bootloader will increase its size. A perhaps simpler and least costly approach would be to have the bootloader support output of the current application image via XMODEM allowing the back-up to be stored on the host. However by doing that you are potentially enabling a third party to access your code.
safely update the boot loader itself.
Again that is a function of your bootloader rather then the protocol. If the code runs from RAM (i.e. the bootloader is copied from ROM to RAM and executed, then it is straightforward. In this case it is safest if possible to load the entire bootloader data into RAM before programming flash memory in order to minimise the time the target has no bootloader and so that sucessful programming does not rely on the host connection being maintained throughout.
If however the bootloader runs from flash, replacing it from the bootloader itself is not possible. Instead you might load an application that the bootloader runs and which replaces the bootloader before loading (or reloading) the final application.
It would be nice if the implementation of the boot loader and update
client software existed already too (at least for Windows).
Any terminal emulator software such as TeraTerm, Hyperterminal, PuTTY etc. will support XMODEM transfer. Implementing your own custom XMODEM sender is relatively straightforward with XMODEM source code widely available.
And just out of curiosity - are there any good alternatives to DFU for
devices with USB?
What I have done is implement a CDC/ACM device class USB stack in the bootloader so that it appears to the host as a serial port, and then used the same XMODEM code as before to do the data transfer. This increases the size of the bootloader; in my case to about 12kbytes. It was implemented using a stack and CDC/ACM (virtual COM port) app-note provided by the chip vendor. Strictly speaking for this you will need a USB vendor-id (VID) registered to your company; you should not use just any old ID.