How to make the connection from device to driver and vice ve
How to make the connection from device to driver and vice ve
I'm asking about theory, not practice(ie I have no code and expect no code). What are the methods used to identify devices and their drivers? For example, does the kernel need to detect that a device exists, then inform the driver, or should the driver detect the device and register it with the kernel?
-
- Member
- Posts: 255
- Joined: Tue Jun 15, 2010 9:27 am
- Location: Flyover State, United States
- Contact:
Re: How to make the connection from device to driver and vic
I think the kernel should look and see what hardware is available, and then load the drivers for what it found. That would save the trouble of having to load each driver, have it look for the hardware, and then have to unload it if the hardware is not present.
Do not quote me on this as I am but a lowly mortal.
Do not quote me on this as I am but a lowly mortal.
Re: How to make the connection from device to driver and vic
How does a kernel know what driver controls what device? This was my only problem with the method in which the kernel detects.
- gravaera
- Member
- Posts: 737
- Joined: Tue Jun 02, 2009 4:35 pm
- Location: Supporting the cause: Use \tabs to indent code. NOT \x20 spaces.
Re: How to make the connection from device to driver and vic
Hi:
The kernel does not enumerate drivers. What you see being done by the horde of tutorial followers here is not good practice. Drivers enumerate drivers. The kernel manages device classes, and loads drivers as requested. A kernel should not be aware of the hardware details of any chipset, and thus should not be able to enumerate devices on that chipset.
The kernel sets up a set of classes to generically represent and manage classes of devices. You have for example, co-ordinate input devices, character input devices, graphical output devices, disk devices, buses, timers, etc. Your driver framework (whether self-designed, or taken stock from an already well-designed and documented API) specifies APIs for communicating with each type of device, and what inputs and outputs should be given to and received from each API call to each device class.
For enumeration, you load a base chipset class driver. The chipset driver enumerates all buses present. The kernel does not. Next, the chipset driver returns all of the enumerated buses to the kernel, and the kernel does something like:
As each bus driver is loaded (assuming one is found) that bus will enumerate the devices which pertain to it. So an ISA bus driver will enumerate a VGA function, the PIT, etc. EISA will enumerate EISA devices. PCI will enumerate PCI devices, and possible more buses, whose drivers will be loaded. Each non-bus node in the tree of devices is enumerated by its device class.
So a VGA function enumerated by the ISA bus driver will present a graphics device to the kernel, with some information on which driver would be optimal for controlling that particular graphical device. A CMOS timer enumerated by the ISA bus driver would be presented to the kernel as two different types of devices: a one shot timer device and a continuous timer with interdependencies.
So:
--All the best,
gravaera.
The kernel does not enumerate drivers. What you see being done by the horde of tutorial followers here is not good practice. Drivers enumerate drivers. The kernel manages device classes, and loads drivers as requested. A kernel should not be aware of the hardware details of any chipset, and thus should not be able to enumerate devices on that chipset.
The kernel sets up a set of classes to generically represent and manage classes of devices. You have for example, co-ordinate input devices, character input devices, graphical output devices, disk devices, buses, timers, etc. Your driver framework (whether self-designed, or taken stock from an already well-designed and documented API) specifies APIs for communicating with each type of device, and what inputs and outputs should be given to and received from each API call to each device class.
For enumeration, you load a base chipset class driver. The chipset driver enumerates all buses present. The kernel does not. Next, the chipset driver returns all of the enumerated buses to the kernel, and the kernel does something like:
Code: Select all
bus_t **chipsetBuses;
for (; nBusesEnumerated > 0; nBusesEnumerated--)
{
chipsetBuses[nBusesEnumerated] = (bus_t *)malloc(sizeof(bus_t));
driverMgr::initializeBusMetadata(chipsetBuses[nBusesEnumerated], dataReturnedFromDriver[nBusesEnumerated]);
};
search_for_bus_drivers(chipsetBuses);
So a VGA function enumerated by the ISA bus driver will present a graphics device to the kernel, with some information on which driver would be optimal for controlling that particular graphical device. A CMOS timer enumerated by the ISA bus driver would be presented to the kernel as two different types of devices: a one shot timer device and a continuous timer with interdependencies.
So:
The answer would be the latter. Designing a proper driver API by yourself is going to be cumbersome, and very difficult. The experienced developers of the Linux kernel haven't got it right, and MS has more than one driver framework to date, with another one due to be released. You may find it expedient to adopt a portable and relatively reliable API that has already been designed.For example, does the kernel need to detect that a device exists, then inform the driver, or should the driver detect the device and register it with the kernel?
--All the best,
gravaera.
17:56 < sortie> Paging is called paging because you need to draw it on pages in your notebook to succeed at it.
Re: How to make the connection from device to driver and vic
The above approach attempts to force 3 or 4 different kinds of programs into a "driver" class. This may or may not be what you want. The "perfect" API design for devices has not been created yet. You need to decide how your taste in programming/APIs should deal with the following:
There must be:
1) Programs that enumerate busses one time and then exit. Let's call these "enumerators". These programs fork/recurse multiple times into either: other enumerators, or device driver loaders. They need to contain a table and/or algorithm to go from the detected bus ID info (eg. PCI vendor/class/subclass ID info) to a file on the disk that contains the device driver loader. These programs do not necessarily need to communicate with the kernel at all. They do not need an IO interface. (For PCI, Brendan suggests having a hardcoded directory structure on your disk, that can be traversed using vendor/class/subclass info to find drivers, for example.)
2) Programs that wait for hot connect/disconnect events on a bus, and remain resident. These programs may need a very simple interface with the kernel -- especially if you want to tell the kernel to UNload a running device driver. Otherwise, these programs act like enumerators.
3) Device drivers that interface between a specific piece of hardware and the kernel. They remain resident, and must interact heavily with the kernel during loadtime, to set up the kernel IO interface to the device. They require special "blocking" functionality -- since they can only serve one IO request at a time.
4) "Virtual" device drivers. These drivers have a double-ended IO interface, but no hardware at all. They are not started by an enumerator -- they are started by the user/system. These types of drivers can be pipelined into a "stack", such as your TCP/IP stack, or your USB stack -- because their purpose is to transform and/or merge datastreams before they are sent to a final piece of destination hardware.
Note that it may be better suited for your system to run enumerators in kernelspace, and drivers in userspace.
There must be:
1) Programs that enumerate busses one time and then exit. Let's call these "enumerators". These programs fork/recurse multiple times into either: other enumerators, or device driver loaders. They need to contain a table and/or algorithm to go from the detected bus ID info (eg. PCI vendor/class/subclass ID info) to a file on the disk that contains the device driver loader. These programs do not necessarily need to communicate with the kernel at all. They do not need an IO interface. (For PCI, Brendan suggests having a hardcoded directory structure on your disk, that can be traversed using vendor/class/subclass info to find drivers, for example.)
2) Programs that wait for hot connect/disconnect events on a bus, and remain resident. These programs may need a very simple interface with the kernel -- especially if you want to tell the kernel to UNload a running device driver. Otherwise, these programs act like enumerators.
3) Device drivers that interface between a specific piece of hardware and the kernel. They remain resident, and must interact heavily with the kernel during loadtime, to set up the kernel IO interface to the device. They require special "blocking" functionality -- since they can only serve one IO request at a time.
4) "Virtual" device drivers. These drivers have a double-ended IO interface, but no hardware at all. They are not started by an enumerator -- they are started by the user/system. These types of drivers can be pipelined into a "stack", such as your TCP/IP stack, or your USB stack -- because their purpose is to transform and/or merge datastreams before they are sent to a final piece of destination hardware.
Note that it may be better suited for your system to run enumerators in kernelspace, and drivers in userspace.
Re: How to make the connection from device to driver and vic
Thanks for your responses, I'm still considering how I will do my API. I'm considering a design in which enumorators will make a kernel call passing a pointer to a device info structure of the form.
The kernel will take the above, give it a meaningless uid, and adding a few other yet undetermined fields(ie maybe a field to store a pointer to a list of resources(memory, irqs, etc.) used by the device)
The kernel will in turn run every driver available, each will init by calling the kernel for a list of device info structures, each driver will then register itself with the kernel on a structure by structure basis, reporting it's fitness, on a scale of 0-3, for use for that device. Once receiving a 3, an entry is immediately removed from the list by the kernel upon the driver making a call asking for control of the device. A 2 will only be given control after all drivers have reported in, same for 1s but 2s are given preference. A 0 is ignored. The device structure is still keep by the kernel in the background, it just isn't passed as part of the list anymore. As part of asking for control of a device the driver will pass it's name(which is where the "*driver_name" field gets filled in) and will be added to a list of drivers, and given a uid. I'm working on a way for drivers to interface with the kernel, one idea is that the driver could register a file with the kernel, any accesses to that file must be offset based, the offset and length of the read or write would be passed to the driver which would respond appropriately.
Code: Select all
struct device_info{
int device_num;
char* dev_name; /* optional */
void* extra_info;
}
Code: Select all
struct kernel_dev_info{
int uid;
int device_num;
char* dev_name; /* optional */
char* driver_name; /* optional */
void* driver;
void* extra_info;
void* resources;
}