Linux Device Driver

tags: Linux Kernel

Learning Source

Linux 2020 link note book

Tutorial

CSE 438/598 Embedded Systems Programming

Linux Kernel Device Model Recap

Driver is between bus infrastructure and framework.

Device Model Key Data Structures

​​​​1. `struct bus_type` 
​​​​2. `struct device_driver`
​​​​3. `struct device`

Device Model

  • Adapter driver: USB controllers, PCI controllers
    • The USB adapter driver that corresponds to the USB controller registers itself to the USB core.
    • usb_add_hcd
    • e.g.: linux/drivers/pci/controller/dwc/pcie-designware-plat.c
      • builtin_platform_driver(dw_plat_pcie_driver);
  • Device Driver: USB device driver
    • The rtl8150 USB device driver registers itself to the USB core
    • usb_register(): register the driver structure
    • struct usb_driver: hooking function device_driver
    • struct usb_device_id: register supported devices
  • Bus infrastructure: Bus core (USB core, PCI core)
    • The USB core now knows the association between the vendor/product IDs of rtl8150 and the struct usb_driver structure of this driver.

Register the Device Driver flow

  • driver_register: register driver with bus
  • driver_find: locate driver on a bus by its name.
  • bus_add_driver: Add a driver to the bus
    driver_attach => bus_for_each_dev => __driver_attach
    => async_schedule_dev => __driver_attach_async_helper
    => driver_probe_device => really_probe => drv->probe
  • driver_add_groups: Add sysfs file for driver

When a device detected

The adpater Driver is device driver,too

Platform Device and Drivers

Describing non-detectable devices

  • Use Device Tree
  • All Device Tree bindings in kernel: Documentation/devicetree/bindings
  • Dump the DTB file:
sudo apt-get install dtc
dtc -I dtb -o dts user-bbb.dtb>user-bbb.dts

e.g. I2C driver (Adapter Driver)

  • Matching by name (mandatory for I2C)
  • Matching by compatible property (for DT)
  • Matching by ACPI ID (for ACPI systems - x86)
static const struct i2c_device_id mma7660_i2c_id[] = { {"mma7660", 0}, {} }; MODULE_DEVICE_TABLE(i2c, mma7660_i2c_id); static const struct of_device_id mma7660_of_match[] = { { .compatible = "fsl,mma7660" }, { } }; MODULE_DEVICE_TABLE(of, mma7660_of_match); static const struct acpi_device_id mma7660_acpi_id[] = { {"MMA7660", 0}, {} };
  • mma7660_probe: Register to bus framework.
  • mma7660_remove: Unregister from bus framework
static struct i2c_driver mma7660_driver = {
	.driver = {
		.name = "mma7660",
		.pm = MMA7660_PM_OPS,
		.of_match_table = mma7660_of_match,
		.acpi_match_table = ACPI_PTR(mma7660_acpi_id),
	},
	.probe		= mma7660_probe,
	.remove		= mma7660_remove,
	.id_table	= mma7660_i2c_id,
};

module_i2c_driver(mma7660_driver);

其它單元傳送門

Building External Modules

  • How to write the kernel module makefile:
    Documentation/kbuild/modules.rst
  • Further documentation describing the syntax used by kbuild is
    located in Documentation/kbuild/makefiles.rst.
  • Building External Modules
obj-m := <module_name>.o

Result in the kernel module <module_name>.ko
When the module is built from multiple sources, an additional line is
needed listing the files:

<module_name>-y := <src1>.o <src2>.o ...

or

<module_name>-objs := ./<src1>.o \
                      ./<src1>.o

Linux GPIO Driver

  • GPIO driver (user-level interface) : ./driver/gpio/gpiolib.c

MMAP Access kernel Space

PFN Method: Github

My Code Example

LDD3 MMAP and DMA

Select a repo