I am studying windows device drivers on my own and I find it's very difficult to differentiate between PDO and FDO. Let me tell you the flow that I have in my head correct me if I am wrong !!
when system boots it loads the root bus driver that will create a FDO. Now it will enumerates its child devices and i guess some hot plug method of the bus driver will be called, when a new child will be found and that method will notify the PNP manager. PNP manager will call the AddDevice() routine of the root bus driver and that will intern create PDOs for new buses like one for PCI and etc. Please explain the whole flow in detail, this is just my imagination. And then it is documented that system will load the functional driver for the PCI bus that will create the FDO ??
what is this FDO?? and why would i need that?? According to me PCI bus driver should also follow the same as done by the root bus, enumerate its child and create PDOs for them, or by this FDO they mean PDO only ?? I am so much confused :( !!
What are you actually doing, or are you just trying to learn? I am just wondering how you ended up this low down in the stack.
PDO = Physical Device Object
FDO = Functional Device Object
A PDO acts as a physical device, but it does not necessarily have to be physical. It is essentially the interface between a device on a bus, and the bus itself. This is pretty well covered on MSDN.
Here is an example that uses USB sticks and this illustrates the difference quite well.
Here is a more in depth explanation and the important quote
If your point of reference is the PCI bus, then Pci.sys is the function driver. But if your point of reference is the Proseware Gizmo device, then Pci.sys is the bus driver. This dual role is typical in the PnP device tree. A driver that serves as function driver for a bus also serves as bus driver for a child device of the bus.
You also have filter drivers which allow you to sit between PDO's and FDO's and start doing naughty stuff like hiding files, POC rootkits etc. At this stage you can add extra functionality, or completely prevent access to the PDO.
And here is all the MSDN links.
http://msdn.microsoft.com/en-us/library/windows/hardware/hh439632(v=vs.85).aspx
http://msdn.microsoft.com/en-us/library/windows/hardware/ff554721(v=vs.85).aspx
http://msdn.microsoft.com/en-us/library/windows/hardware/hh439643(v=vs.85).aspx
http://msdn.microsoft.com/en-us/library/windows/hardware/ff554731(v=vs.85).aspx
http://msdn.microsoft.com/en-us/library/windows/hardware/ff564859(v=vs.85).aspx
http://technet.microsoft.com/en-us/library/cc776371(v=ws.10).aspx
If that doesn't clear it up for you, feel free to post back.
Here is the excerpt form "Programming the Microsoft Windows Driver Model", 2nd edition, Walter One:
- PDO stands for physical device object. The bus driver uses this
object to represent the connection between the device and the bus.
- FDO stands for function device object. The function driver uses
this object to manage the functionality of the device.
- FiDO stands
for filter device object. A filter driver uses this object as a place
to store the information it needs to keep about the hardware and its
filtering activities. (The early beta releases of the Windows 2000
DDK used the term FiDO, and I adopted it then. The DDK no longer
uses this term because, I guess, it was considered too frivolous.)
Hope this helps you out.
According to me PCI bus driver should also follow the same as done by the root bus, enumerate its child and create PDOs for them --WRONG!.
If you are talking about WDM, PnP Manager creates PDOs. Earlier to that, YOU had to create it(after detection of device) in DriverEntry().
Related
I have tried extending IOUserNetworkEthernet and calling RegisterEthernetInterface(). This works perfectly for one ethernet interface, though the driver crashes when RegisterEthernetInterface is called a second time (doesn't return an error code). I have tried registering with separate queues.
Another approach was extending IOUserClient instead, and calling IOService::Create to create child IOUserNetworkEthernet instances. Everything about this approach works (the children appear within ioreg). However, once I call RegisterEthernetInterface on just one of the children, macOS crashes.
How would I go about creating a dext with multiple ethernet interfaces? Have I been approaching it the right way?
Appreciate any help.
I haven't yet implemented an ethernet dext myself, but based on my experience with using DriverKit for other types of drivers and knowing its design goals, I have an idea what the solution might be.
First off, let's clarify: you're implementing either a virtual ethernet device, or you're building a driver for hardware that unites multiple independent ports in one physical device. In the former case (I'm guessing this is what you're doing based on your IOUserClient comment), your driver will be matching IOUserResources and you create the ethernet driver instance when you receive the corresponding message from your user space component.
Now, DriverKit design: DriverKit is built around a goal of keeping the driver instance for each device in its own separate process. Sort of circling back to the microkernel idea. Specifically, this means that multiple devices that use the same driver will each create an independent instance of that driver in its own process. This very likely means that NetworkingDriverKit was never designed to support more than one instance of IOUserNetworkEthernet, because they are seen as separate devices. Hence the crashes.
OK, what do we do about it? Use DriverKit the way it was intended. Put each virtual ethernet adapter in its own driver instance. This gets a bit tricky. I think this should work:
Your dext has a "control" instance. This is the thing that matches IOUserResources. It's a simple IOService class which listens for the signal (presumably IOUserClient) to create or destroy a virtual ethernet device. When creating a virtual ethernet device, you need that to run in its own driver instance though. (For an actual device with multiple ports, this would match the USB/PCI device nub, manage bus communication with the device, and enumerate the ports.)
Instead of creating an instance of a IOUserNetworkEthernet subclass, create an instance of a "nub" class and attach it to your central control class instance. Call RegisterService() in its startup code, so it's considered for IOKit matching.
Set up a second IOKit matching dictionary in your Info.plist, which matches your new "nub" object. Here, use your IOUserNetworkEthernet-derived class to "drive" the nub. Once the virtual ethernet device is ready to use, call RegisterEthernetInterface().
2 extra things to note:
The virtual device will run in a separate process from the control object, so they can only communicate via DriverKit inter-process calls, i.e. user clients. Hopefully, they don't really need to communicate much though, and the control client can pass all the information required via properties on the nub. If you're implementing support for multi-port hardware, you probably won't be able to avoid this part though.
Your user space component (app, daemon) will need to open a new communication channel with the virtual device, so you'll probably need to implement user client support there too.
I'm not sure how you'd go about shutting down an individual virtual ethernet device, you could try calling Terminate() on either it or the nub it's matched on and see what happens.
From a general standpoint, I am trying to figure out how to access a platform device from userspace. To be more specific, I have a EMIF controller on and SoC of which I have added to my device tree and I believe it is correctly bound to a pre-written EMIF platform device driver. Now I am trying to figure out how I can access this EMIF device from a userspace application. I have come accross a couple different topics that seem to have some connection to this issue but I cannot quite find out how they relate.
1) As I read it seems like most I/O is done through the use of device nodes which are created by mknod(), do I need to create a device node in order to access this device?
2) I have read a couple threads that talk about writting a Kernel module (Character?, Block?) that can interface with both userspace and the platform device driver, and use it as an intermediary.
3) I have read about the possibility of using mmap() to map the memory of my platform device into my virtual memory space. Is this possible?
4) It seems that when the EMIF driver is instantiated, it calls the probe() fucntion. What functions would a userpace application call in the driver?
It's not completely clear what you're needing to do (and I should caveat that I have no experience with EMIF or with "platform devices" specifically), but here's some overview to help you get started:
Yes, the usual way of providing access to a device is via a device node. Usually this access is provided by a character device driver unless there's some more specific way of providing it. Most of the time if an application is talking "directly" to your driver, it's a character device. Most other types of devices are used in interfacing with other kernel subsystems: for example, a block device is typically used to provide access from a file system driver (say) to an underlying disk drive; a network driver provides access to the network from the in-kernel TCP/IP stack, etc.
There are several char device methods or entry points that can be supported by your driver, but the most common are "read" (i.e. if a user-space program opens your device and does a read(2) from it), "write" (analogous for write(2)) and "ioctl" (often used for configuration/administrative tasks that don't fall naturally into either a read or write). Note that mknod(2) only creates the user-space side of the device. There needs to be a corresponding device driver in the kernel (the "major device number" given in the mknod call links the user-space node with the driver).
For actually creating the device node in the file system, this can be automated (i.e. the node will automatically show up in /dev) if you call the right kernel functions while setting up your device. There's a special daemon that gets notifications from the kernel and responds by executing the mknod(2) system call.
A kernel module is merely a dynamically loadable way of creating a driver or other kernel extension. It can create a character, block or network device (et al.), but then so can a statically linked module. There are some differences in capability mostly because not all kernel functions you might want to use are "exported" to (i.e. visible to) dynamically loaded modules.
It's possible to support mapping of the device memory into user virtual memory space. This would be implemented by yet another driver entry point (mmap). See struct file_operations for all the entry points a char driver can support.
This is pretty much up to you: it depends on what the application needs to be able to do. There are many drivers in the kernel that provide no direct function to user-space, only to other kernel code. As to "probe", there are many probe functions defined in various interfaces. In most cases, these are called by the kernel (or perhaps by a 'higher level "class" driver') to allow the specific driver to discover, identify and "claim" individual devices. They (probe functions) don't usually have anything directly to do with providing access from user-space but I might well be missing something in a particular interface.
You need to create a device node in order to access the device.
The probe function is called when the driver finds a matching device.
For information on platform device API, the following articles could be useful.
The platform device API
Platform devices and device trees
I am writing a serial driver for UART in windows just for learning purpose. More specifically in WDM.
I will write both the bus driver and function driver.
Currently i am writing the bus driver. So my question is from where i can come to know in my driver that how many serial ports i have in my system, so that i can expose that number of PDO's from my bus driver?? And resources allocated to each port. Do i have to check some kind of registry or windows will provide some kind of structure.
Please help me!! Thanks in advance
Assuming your UARTs are part of the PC, there's already a bus driver which will enumerate them. ACPI.SYS gets information from the platform BIOS, which includes the number and resource assignments for built-in components like UARTs.
If you're writing your driver for an add-in multi-port serial board, then you would need to look at the documentation for the board to determine how you find the number of UARTs. It might be as simple as looking at the PCI Product ID and having a hard-coded count for the type of board you have.
When ACPI enumerates the device, your driver's AddDevice routine will be called to load on it, and you'll receive the assigned resources when handling the PNP START message.
If a USB device driver is loaded, and at some time the device plugs in, then which part of the kernel will create struct device and register it?
When the driver is loaded, the system calls the function, which you assigned in module_init. You will want to call there usb_register(struct usb_driver skel_driver), where skel_driver is a struct with pointers to methods servicing the device, like the probe method.
The probe method is the one which is called, when a new usb device is introduced in to the system. In this place you can fill your struct (usb_skel) with what you will need in the future, initiate a char device or whatever you do, when the device is introduced.
The system mostly won't create anything by itself, it has to have most of the structs prepared and filled with device specific data.
Please see usb-skeleton in lxr for reference and learn to use it, besides read writing usb drivers from LDD.
Cheers
I am currenlty trying to monitor my battery status through SMBus.
I have a battery along with a control board that constantly outputs the battery status.
This control board is then connected to my mother board through a I2C-USB module.
I need to write a program to recognize the SMBus connection and transmit the battery status to the user.
I'm a beginner when it comes to dealing with smart batteries and I2C/SMBus, and I'm somewhat lost with how to approach this problem.
Any help of suggestions would be appreciated. Thanks.
Your question is a bit lacking. What kind of I2C-USB module? Or rather does it come with a Linux driver? If it does you probably won't need to write one. An application will do. You can read more about I2C and SMBus here.
Basically what you need is the I2C address of the control board (a single byte). When you have the address you (as the master) issue read commands over the I2C bus to the control board using its address and reads the response. If there's a driver for the I2C-USB module this should be straightforward enough. Plug in the device and open() the device (/dev/[i2c-usb-name] where [i2c-usb-name] is the name of the device). Then follow the driver implementer's guide how to setup and send data over that device (typically using read()/write() or ioctl()). Here are some additional information on working with I2C from user space: http://www.mjmwired.net/kernel/Documentation/i2c (select topics in the menu on the left hand side).
If you must write the driver yourself, the first stop for a Linux device driver beginner is the LDD3. Read it, it's quite a pleasant read.