I want to update a list of storage devices as the user inserts USB keys, adds external disks and mounts disk images. IOKit's IOServiceAddInterestNotification looks like the way to go, but the obvious use of registering general interest in kIOMediaClass only gives you notifications for unmounting of volumes and then only sometimes.
What's the right way to do this?
The following calls in DiskArbitration.h do exactly what I want:
DARegisterDiskAppearedCallback
DARegisterDiskDisappearedCallback
DARegisterDiskDescriptionChangedCallback
These cover insertion, removal (even of unmountable volumes)
metadata change events.
P.S. Don't forget to add your DASession to a runloop
or you won't get any callbacks.
I want to update a list of storage devices as the user inserts USB keys, adds external disks and mounts disk images.
I can get you two out of three with this piece of code, which I imagine wouldn't require a lot more work to give you the third.
File: USBNotificationExample.c
Description: This sample demonstrates how to use IOKitLib and IOUSBLib to set up asynchronous
callbacks when a USB device is attached to or removed from the system.
It also shows how to associate arbitrary data with each device instance.
http://opensource.apple.com/source/IOUSBFamily/IOUSBFamily-385.4.1/Examples/Another%20USB%20Notification%20Example/USBNotificationExample.c
I've personally used (a slightly modified copy of this code) for a long time, to monitor the connection of USB HDDs.
As you can see from this small sample, it may easily prove adaptable to monitor mounted drives. Or it may not. YMMV.
matchingDict = IOServiceMatching(kIOUSBDeviceClassName); // Interested in instances of class
// IOUSBDevice and its subclasses
and when it matches
void DeviceAdded(void *refCon, io_iterator_t iterator)
{
kern_return_t kr;
io_service_t usbDevice;
IOCFPlugInInterface **plugInInterface=NULL;
SInt32 score;
HRESULT res;
while ( (usbDevice = IOIteratorNext(iterator)) )
{
io_name_t deviceName;
CFStringRef deviceNameAsCFString;
MyPrivateData *privateDataRef = NULL;
UInt32 locationID;
printf("Device 0x%08x added.\n", usbDevice);
and so forth, and so on.
Would watching /Volumes for changes do what you need?
If you happen to be working at the Cocoa level, you can also register to receive the following notifications from NSWorkspace:
NSWorkspaceDidMountNotification
NSWorkspaceDidRenameVolumeNotification
NSWorkspaceWillUnmountNotification
NSWorkspaceDidUnmountNotification
Related
We have some HID devices (touch digitizers) that communicate with an internal R&D tool. This tool parses the raw feature reports from the devices to draw the touch reports along with some additional data that are present in the raw feature report but filtered out by the HID driver of Windows 7 (eg, pressure data is not present in WM_TOUCH messages).
However, we have started working with some devices that may have different firmware variants, and thus that do not share the same ordering or bytelength of the fields and I need to modify our R&D tool so that it will adapt transparently to all the devices.
The devices come from the same manufacturer (ourselves) and share the same device info, so using these fields to differentiate between the different firmwares is not an option. What I would like to do is to get the HID feature report descriptor sent by the device and update dynamically our feature report parsing method based on this information.
However, I didn't manage to find the correct method to call in order to get this descriptor when browsing the Windows API. What I have found so far is the Raw Input page on MSDN, but I'm not sure what to do next. Can I find the required information in the RID_DEVICE_HID structure ? Or do I need to call a completely different API ?
Thanks in advance for your help!
Ok, finally I've got something (almost completely) functional. As inferred by mcoill, I used the HidP_xxx() family of functions, but it needs a little bit of data preparation first.
I based my solution on this example code that targets USB joysticks and adapted it to touch digitizer devices.
If someone else also gets confused by the online doc, here are the required steps involved in the process:
registering the application for a Raw Input device at launch.
This is done by calling the function RegisterRawInputDevice(&Rid, 1, sizeof(Rid)), where Rid is a RAWINPUTDEVICE with the following properties set (in order to get a touch digitizer) :
Rid.usUsage = 0x04;
Rid.usUsagePage = 0x0d;
Rid.dwFlags = RIDEV_INPUT_SINK;
registering a callback OnInput(LPARAM lParam) for the events WM_INPUT since the Rid device will generate this type of events;
the OnInput(LPARAM lParam) method will get the data from this event in two steps:
// Parse the raw input header to read its size.
UINT bufferSize;
GetRawInputData(HRAWINPUT)lParam, RID_INPUT, NULL, &bufferSize, sizeof(RAWINPUTHEADER));
// Allocate memory for the raw input data and retrieve it
PRAWINPUT = (PRAWINPUT)HeapAlloc(GetProcessHeap(), 0, bufferSize);
GetRawInputData(HRAWINPUT)lParam, RID_INPUT, rawInput /* NOT NULL */, &bufferSize, sizeof(RAWINPUTHEADER));
it then calls a parsing method that creates the HIDP_PREPARSED_DATA structure required by the lookup functions:
// Again, read the data size, allocate then retrieve
GetRawInputDeviceInfo(rawInput->header.hDevice, RIDI_PREPARSEDDATA, NULL, &bufferSize);
PHIDP_PREPARSED_DATA preparsedData = (PHIDP_PREPARSED_DATA)HeapAlloc(heap, 0, bufferSize);
GetRawInputDeviceInfo(rawInput->header.hDevice, RIDI_PREPARSEDDATA, preparsedData, &bufferSize);
The preparsed data is split into capabilities:
// Create a structure that will hold the values
HidP_GetCaps(preparsedData, &caps);
USHORT capsLength = caps.NumberInputValueCaps;
PHIDP_VALUE_CAPS valueCaps = (PHIDP_VALUE_CAPS)HeapAlloc(heap, 0, capsLength*sizeof(HIDP_VALUE_CAPS));
HidP_GetValueCaps(HidP_Input, valueCaps, &capsLength, preparsedData);
And capabilities can be asked for their value:
// Read sample value
HidP_GetUsageValue(HidP_Input, valueCaps[i].UsagePage, 0, valueCaps[i].Range.UsageMin, &value, preparsedData, (PCHAR)rawInput->data.hid.bRawData, rawInput->data.hid.dwSizeHid);
Wouldn't HidP_GetPReparsedData(...), HidP_GetValueCaps(HidP_Feature, ...) and their ilk give you enough information without having to get the raw feature report?
HIDClass Support Routines on MSDN
I was writing some pices in winapi's raw input
It seem to working though I am not sure how reliable (unfaliable) it is
(and if it will be working on all systems machines etc, this is a bit worry)
also there appears many question, the one is
I would like to use my first (I mean normal/base mouse) in old way,
it is processint WM_MOUSEMOVE etc and moving arrow cursor, only the
secondary mouse I need processing by raw_input (primary can stay untouched by rawinput), the problem is
1) how can i be sure which mouse detected by rawinput is the
secondary?
2) the second mouse moves also my arrow -cursor, if I disable
it by RIDEV_NOLEGACY then both are not moving cursor (it bacame hourglass) and it is wrong too
think maybe i should setup it a bit differently my setrup rawinput function is like
void SetupRawInput()
{
static RAWINPUTDEVICE Rid[1];
Rid[0].usUsagePage = 0x01;
Rid[0].usUsage = 0x02;
Rid[0].dwFlags = 0; // Rid[0].dwFlags = RIDEV_NOLEGACY; /
Rid[0].hwndTarget = NULL;
int r = RegisterRawInputDevices( Rid, 1, sizeof(Rid[0]) );
if (!r) ERROR_EXIT("raw input register fail");
}
how to resolve this issueas andmake it work? tnx
I don't know if my approach is the best one, or not, but this is how I do it for the first item in your question:
When I process WM_INPUT using GetRawInputData(...), I check to see if the device handle passed back by the RAWINPUTHEADER structure (contained within the RAWINPUT structure returned from the function) is the same as the device I want to use. If it is not, then I simply don't bother sending back data, if it is, I then process the RAWINPUTMOUSE data returned in the RAWINPUT struct.
And if you're wondering how to get the list of devices, you can use GetRawInputDeviceList(...), which will return the device handles of the mice you're trying to work with.
As I said, this may not be the best way, but I have confirmed that it does work for my purposes. I also do this for my keyboard raw input data as well.
As for item #2, it seems likely that it affects both mice because Windows has exclusive access to the mice, so you can't register one specific mouse without registering them all with the same flags. But someone with more knowledge than I could probably give a better explanation.
I am interested in developing kernel module that binds two block devices into a new block device in such manner that first block device contains data at mount time, and the other is considered empty. Every write is being made to second partition, so on next mount the base filesystem remains unchanged. I know of solutions like UnionFS, but those are filesystem-based, while i want to develop it a layer lower, block-based.
Can anyone tell me how could i open ad read/write block device from kernel module? Possibly without using userspace program for reading/writing merged block devices. I found similar topic here, but the answer was rather unsatysfying because filp_* functions are rather for reading small config files, not for (large) block device I/O.
Since interface for creating block devices is standarized i was thinking of direct (or almost direct) acces to functions implementing source devices, as i will be requested to export similar functions anyway. If i could do that i would simply create some proxy-functions calling appropriate functions on source devices. Can i somehow obtain pointer to a gendisk structure that belongs to different driver?
This serves only my own purposes (satisfying quriosity being main of them) so i am not worried about messing my kernel up seriously.
Or does somebody know if module like that already exists?
The source code in the device mapper driver will suit your needs. Look at the code in the Linux source in Linux/drivers/md/dm-*.
You don't need to access the other device's gendisk structure, but rather its request queue. You can prepare I/O requests and push it down the other device's queue, and it will do the rest itself.
I have implemented a simple block device that opens another block device. Take a look in my post describing it:
stackbd: Stacking a block device over another block device
Here are some examples of functions that you need for accessing another device's gendisk.
The way to open another block device using its path ("/dev/"):
struct block_device *bdev_raw = lookup_bdev(dev_path);
printk("Opened %s\n", dev_path);
if (IS_ERR(bdev_raw))
{
printk("stackbd: error opening raw device <%lu>\n", PTR_ERR(bdev_raw));
return NULL;
}
if (!bdget(bdev_raw->bd_dev))
{
printk("stackbd: error bdget()\n");
return NULL;
}
if (blkdev_get(bdev_raw, STACKBD_BDEV_MODE, &stackbd))
{
printk("stackbd: error blkdev_get()\n");
bdput(bdev_raw);
return NULL;
}
The simplest example of passing an I/O request from one device to another is by remapping it without modifying it. Notice in the following code that the bi_bdev entry is modified with a different device. One can also modify the block address (*bi_sector) and the data itself.
static void stackbd_io_fn(struct bio *bio)
{
bio->bi_bdev = stackbd.bdev_raw;
trace_block_bio_remap(bdev_get_queue(stackbd.bdev_raw), bio,
bio->bi_bdev->bd_dev, bio->bi_sector);
/* No need to call bio_endio() */
generic_make_request(bio);
}
Consider examining the code for the dm / md block devices in drivers/md - these existing drivers create a block device that stores data on other block devices.
In fact, you could probably implement your idea as another "RAID personality" in md, and thereby make use of the existing userspace tools for setting up the devices.
You know, if you're a GPL'd kernel module you can just call open(), read(), write(), etc. from kernel mode right?
Of course this way has certain caveats including requiring forking from kernel mode to create a space for your handle to live.
I need to get the list of physical storage devices on an OS X system. IOServiceGetMatchingServices using the kIOStorageClass key gives me a list of all volumes, not all hardware storage devices. How do I do this?
The question is a little ambiguous (do you want whole drives, partitions, all of the above?), I suggest firing up the IORegistryExplorer utility (comes with XCode) and figuring out which class of device you want. I can tell you that each whole drive normally corresponds to an IOBlockStorageDriver, so maybe that's the class you want to match. It will then have an IOMedia client representing the whole device. It in turn will have a partition scheme client, which has an IOMedia client for each partition, unless it's not partitioned.
To get list of physical storage device you can match for kIOATABlockStorageDeviceClass. Following code obtains iterator for block storage devices.
IOReturn error = kIOReturnSuccess;
io_iterator_t iter = MACH_PORT_NULL;
error = IOServiceGetMatchingServices ( kIOMasterPortDefault,
IOServiceMatching ( kIOATABlockStorageDeviceClass ),
&iter );
I am developing an OS X application that is supposed to take input from two mice. I want to read the motion of each mouse independently. What would be the best way to do this?
If that is not possible, is there a way to disable/enable either of the mice programmatically?
The HID Class Device Interface is definitely what you need. There are basically two steps:
First you need to find the mouse devices. To do this you need to construct a matching dictionary and then search the IO Registry with it. There is some sample code here, you will need to add some additional elements to the dictionary so you just get the mice instead of the all HID devices on the system. Something like this should do the trick:
// Set up a matching dictionary to search the I/O Registry by class
// name for all HID class devices`
hidMatchDictionary = IOServiceMatching(kIOHIDDeviceKey);
// Add key for device usage page - 0x01 for "Generic Desktop"
UInt32 usagePage = 0x01;
CFNumberRef usagePageRef = ::CFNumberCreate( kCFAllocatorDefault, kCFNumberLongType, &usagePage );
::CFDictionarySetValue( hidMatchDictionary, CFSTR( kIOHIDPrimaryUsagePageKey ), usagePageRef );
::CFRelease( usagePageRef );
// Add key for device usage - 0x02 for "Mouse"
UInt32 usage = 0x02;
CFNumberRef usageRef = ::CFNumberCreate( kCFAllocatorDefault, kCFNumberLongType, &usage );
::CFDictionarySetValue( hidMatchDictionary, CFSTR( kIOHIDPrimaryUsageKey ), usageRef );
::CFRelease( usageRef );
You then need to listen to the X/Y/button queues from the devices you found above. This sample code should point you in the right direction. Using the callbacks is much more efficient than polling!
The HID code looks much more complex than it is - it's made rather "wordy" by the CF stuff.
It looks like the HID Manager is what you're looking for.
You're going to want to check out the I/O Kit and HID (Human Interface Device) manager stuff.
HID manager is part of I/O Kit, so looking into there might be useful. There are two APIs for HID management, the older API is a bit more painful and then you have the new 10.5 and above API which is a bit more comfortable.
Important thing to understand is this isn't going to probably be just a quick fix, it may take some significant work to get it running. If you can assume you'll have 10.5 or better installed, using the Leopard API will definitely help.
Also; depending on how you accomplish what you're doing, may be important for you to hide the mouse cursor as it may still move a lot even if you're receiving the information from both mice. If your application grabs the screen, I'd use CoreGraphics to disable the cursor and just draw my own.
You might also consider finding a wrapper for one of these APIs, an example can be found in this question.
Unless you can force one of the mice to not be dealt with as a mouse, both will continue to control the pointer. However, you can use IOKit to write a custom USB HID driver to allow your app to read from one or both of the mice (although this would probably interfere with using them as normal mice). Building Customized User Client Drivers for USB Devices would be a good place to start for how to interact directly with USB mice.
You could look at the USB/PS-2 device interrupt.
Even if you don't want to rewrite a so called driver, it could be usefull since all the mice send their data through.
You could also check this page that could give some hints http://multicursor-wm.sourceforge.net/
maybe it's a solution for you to use usb->rsr232 converter and go by reading the serial port by yourself ?