The discussion below is based on the assumption that we are talking about after Linux 2.6
In the model of device driver, there are three instances we have to take care of:
Bus line
Device
Driver
The bus line always bind devices with drivers. Everytime we register a device in the system, the system search a driver matching with the device; Plus, everytime we register a driver, system searches the mathcing deivce through bus line
Normally, a real linux device and a driver hung on a bus line: PCI, USB, I2C, SPI …
However, in an embedded system, SoC integrates: independent peripheral controllers …
The devices hung in the SoC memory space are not covered
Therefore, Linux comes up with a virtual bus line called platform bus line, the structure of device and driver come up correspondly.
name
: platform_match
would use name
to find a match driver.id
: the instance of the device. Platform device IDs are assumed to be encoded like this: "<name><instance>", where <name> is a short description of the type of device, like "pci" or "floppy", and <instance> is the enumerated instance of the device, like '0' or '42'. eg. pci42resource
: the resouce of the device, eg. IO space base address, regiester base address, irq number …probe
: triggered when a device is installed
remove
: triggered when a device is removed
suspend
and resume
: use to do the power management but are out of date. Now, people use struct dev_pm_ops
in the struct device_driver driver
The struct device_driver
is included not only in platform_driver
, but also i2c_driver
spi_drvier
usb_driver
pci_driver
(platform_driver has the same level to i2c_driver
spi_driver
…)
platform_match
functionWe can see that there are 4 possiblilities to find a match.
of_driver_match_device
): How devices in device tree and platform drivers were connecteddrivers/net/ethernet/davicom/dm9000.c
Firstly, let's see the platform_driver
structure
Here we can see that the name
of the driver is dm9000
and of_match_table
is specified. These are the ways that this driver can match with corresponded platform_device
through the function platform_match
.
pm
stands for power management
prob
and remove
are specified.
dm9000_probe(struct platform_device *pdev)
How do platform_get_resource
platform_get_irq
work?
Ans: by extruct struct resource *resource
from the platform_device
.
After that we can access the io space by APIs like ioremap
…
arch/arm/mach-davinci/board-dm355-evm.c
Before we start, The naming rule of a board is like: /arch/<arch>/mach<soc>/<board name>.c
So, next time if we want to add a description of a borad, that is how we do.
The first thing we can take a look is the platform_device
structure
Here we can see that the name
is dm9000
this would help system to find the match driver we regiter above.
The platform_data
is a self-defined data, for dm9000
this stores MAC address, Bus line width, is there EEPROM on the board …, which driver can get this through dev_get_platdata
(see dm9000_probe
above)
Then we can see how is resource dm355evm_dm9000_rsrc
defined.
Here we got three resouces the lastes one is arising (active high) IRQ.
And the
handle the gpio irq and assign to resource
So when dm9000_probe
calls:
The case above is not the only way to enumerated a dm9000
driver.
After Linux 3.x dm9000
driver can be enumerated through the device tree.
So, to add a dm9000
card on a board can be easily done by revising the dts file.
For example: /arch/arm/boot/dts/s3c6410-mini6410.dts
And the device tree would be parsed here: /arch/arm/kernel/setup.c
also: [PATCH 5/7] arm-dt: unflatten device tree
Case Study: keyboard gpio_keys
/drivers/input/keyboard/gpio_keys.c
static int gpio_keys_probe(struct platform_device *pdev)
struct input_dev *devm_input_allocate_device(struct device *dev)
: allocate managed input device, @dev
: device owning the input device being createdstruct input_dev *devm_input_allocate_device(struct device *dev)
: allocate managed input device, @dev
is a device owning the input device being createdstatic irqreturn_t gpio_keys_irq_isr(int irq, void *dev_id)
When we see the ISR we can find that it uses input_event
and input_sync
API to sync the data and event.
And file_operations
and IO operations are not involved in this.
In fact, the Linux VFS interface related part is in drives/input/evdev.c
void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
: report new input event.input_sync
is equal to input_event(dev, EV_SYN, SYN_REPORT, 0);
if we go deeper we can found that it call handler in the dev
/drivers/input/evdev.c
Here comes the VFS file_operations
part.
evdev_read
struct evdev *evdev = client->evdev;
gets the evdev
from file's private data.
evdev_fetch_next_event
: get the buffer from evdev_client