From e4b65cd548d889c96b85b56acdf2b6798882691e Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Thu, 18 Jun 2026 15:41:42 +0530 Subject: [PATCH 01/55] Update README.md --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index de8ecfe..2138d7c 100644 --- a/README.md +++ b/README.md @@ -1 +1,6 @@ -# Tutorials \ No newline at end of file +# Tutorials +1. Linux Device Drivers +2. microcontrollers +3. RTOS/FreeRTOS +4. Unit Testing + From 382c92cab458f77b205bd17b54266c8bd3b1b0a6 Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Thu, 18 Jun 2026 15:55:23 +0530 Subject: [PATCH 02/55] Update ReadMe.md --- Linux/Device_Driver/Hello_World/ReadMe.md | 37 ++++++++++++++--------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/Linux/Device_Driver/Hello_World/ReadMe.md b/Linux/Device_Driver/Hello_World/ReadMe.md index 9e2f6a2..36c1c8d 100644 --- a/Linux/Device_Driver/Hello_World/ReadMe.md +++ b/Linux/Device_Driver/Hello_World/ReadMe.md @@ -1,20 +1,27 @@ -This is just a basic linux device driver. This kernel module will print some debug messages at the init and exit time. +# Hello World LDD +- This is just a basic linux device driver. This kernel module will print some debug messages at the init and exit time. +- Please update your Beaglebone board's kernel directory in the Makefile. -Please update your Beaglebone board's kernel directory in the Makefile. - -Build for Beaglebone: +## Build for Beaglebone: + ``` sudo make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- - -Build for Raspberry Pi or Virtualbox Ubuntu: + ``` + +## Build for Raspberry Pi or Virtualbox Ubuntu: + ``` sudo make - -Please refer this URL for the complete tutorial of this source code. + ``` +- Please refer this URL for the complete tutorial of this source code. +``` https://embetronicx.com/tutorials/linux/device-drivers/linux-device-driver-tutorial-part-2-first-device-driver/ - -You can check the video tutorial of this project. +``` +- You can check the video tutorial of this project. +``` https://youtu.be/hMsA1bA1Upk and https://youtu.be/xqsro29xQPo - -The Linux Device Driver Video Playlist - https://www.youtube.com/watch?v=BRVGchs9UUQ&list=PLArwqFvBIlwHq8WMKgsXSQdqIvymrEz9k - -How to Setup Ubuntu and Raspberry PI - https://www.youtube.com/watch?v=e6gNeje3ljA -How to Setup BeagleBone and Cross compile the kernel - https://www.youtube.com/watch?v=am-dgmrMgYY&t +``` +- The Linux Device Driver Video Playlist - + ``` + https://www.youtube.com/watch?v=BRVGchs9UUQ&list=PLArwqFvBIlwHq8WMKgsXSQdqIvymrEz9k + ``` +- How to Setup Ubuntu and Raspberry PI - ``` https://www.youtube.com/watch?v=e6gNeje3ljA ``` +- How to Setup BeagleBone and Cross compile the kernel - ``` https://www.youtube.com/watch?v=am-dgmrMgYY&t ``` From 7a1b6e1cbf5f2c156eb8790b40b8ae7b4f0ae64f Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Thu, 18 Jun 2026 15:55:55 +0530 Subject: [PATCH 03/55] Update ReadMe.md --- Linux/Device_Driver/Hello_World/ReadMe.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Linux/Device_Driver/Hello_World/ReadMe.md b/Linux/Device_Driver/Hello_World/ReadMe.md index 36c1c8d..581468a 100644 --- a/Linux/Device_Driver/Hello_World/ReadMe.md +++ b/Linux/Device_Driver/Hello_World/ReadMe.md @@ -3,14 +3,14 @@ - Please update your Beaglebone board's kernel directory in the Makefile. ## Build for Beaglebone: - ``` +``` sudo make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- - ``` +``` ## Build for Raspberry Pi or Virtualbox Ubuntu: - ``` +``` sudo make - ``` +``` - Please refer this URL for the complete tutorial of this source code. ``` https://embetronicx.com/tutorials/linux/device-drivers/linux-device-driver-tutorial-part-2-first-device-driver/ From 284dd77399283d9670bafaa16bd5f671807fe409 Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Fri, 19 Jun 2026 17:01:26 +0530 Subject: [PATCH 04/55] Create README.md --- .../1 LDD Introduction/README.md | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 Linux/Device_Driver/1 LDD Introduction/README.md diff --git a/Linux/Device_Driver/1 LDD Introduction/README.md b/Linux/Device_Driver/1 LDD Introduction/README.md new file mode 100644 index 0000000..9a043fb --- /dev/null +++ b/Linux/Device_Driver/1 LDD Introduction/README.md @@ -0,0 +1,61 @@ +# Linux Device Driver – Part 1: Introduction +- This repository contains notes and example code for learning the basics of Linux device drivers, focusing on how drivers integrate with the Linux kernel and user space. + +## What is a Device Driver? +- A device driver is a piece of software that lets the operating system communicate with hardware devices. +- In Linux, many drivers are built into the kernel or loaded as kernel modules, allowing hardware to be + controlled via standard interfaces. + +## Types of Linux Device Drivers + +Common categories of Linux device drivers include: + +- **Character drivers** – Accessed as streams of bytes (for example `/dev/ttyS0` for serial ports) +- **Block drivers** – Handle data in blocks and are used for storage devices +- **Network drivers** – Interface network hardware with the kernel’s networking stack + +This introduction usually starts with character drivers because they are simpler conceptually. + +## Kernel Space vs User Space + +Linux clearly separates: + +- **User space** – Where normal applications run, with restricted access +- **Kernel space** – Where the kernel and drivers run, with full access to hardware and system resources + +A device driver typically runs in kernel space and exposes an interface (often via `/dev` files or sysfs) that user-space programs can use. + +## Loadable Kernel Modules (LKM) + +Instead of compiling every driver into the kernel, Linux supports **loadable kernel modules**: + +- Drivers can be compiled as modules +- Modules can be inserted (`insmod`/`modprobe`) and removed (`rmmod`) at runtime +- `dmesg` and `/var/log` can be used to inspect kernel messages from drivers + +This introduction often walks through how to build a simple module, load it, and see messages using `dmesg`. + +## Basic Steps to Write a Simple Driver Module + +Typical steps you will follow in this series: + +1. Write a minimal C file that defines `init` and `exit` functions for the module +2. Use `module_init()` and `module_exit()` macros to register these functions +3. Add a `Makefile` that uses the kernel build system to compile the module +4. Build the module against your current kernel headers +5. Load the module and verify its messages in the kernel log +6. Unload the module cleanly + +## Prerequisites + +Before following along: + +- Basic knowledge of C programming +- A Linux environment (for example, Ubuntu) with kernel headers installed +- Ability to use the terminal and run basic compilation commands + +## Disclaimer and Credits + +This README is a high-level summary intended for learning and personal use. +Please read the original tutorial at embetronicx.com and respect its author’s intellectual property +when using or sharing material. From 4c8a0c8aa626ca2483a43ccd65ff1cb2905687ec Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Fri, 19 Jun 2026 17:02:41 +0530 Subject: [PATCH 05/55] Update README.md --- Linux/Device_Driver/1 LDD Introduction/README.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Linux/Device_Driver/1 LDD Introduction/README.md b/Linux/Device_Driver/1 LDD Introduction/README.md index 9a043fb..1744cf4 100644 --- a/Linux/Device_Driver/1 LDD Introduction/README.md +++ b/Linux/Device_Driver/1 LDD Introduction/README.md @@ -54,8 +54,6 @@ Before following along: - A Linux environment (for example, Ubuntu) with kernel headers installed - Ability to use the terminal and run basic compilation commands -## Disclaimer and Credits - -This README is a high-level summary intended for learning and personal use. -Please read the original tutorial at embetronicx.com and respect its author’s intellectual property -when using or sharing material. +REFER: +- https://github.com/darshankharbikar/raspberry-pi-4b +- https://embetronicx.com/tutorials/linux/device-drivers/setup-ubuntu-and-raspberry-pi-linux-device-driver-tutorial/ From d2bc027ef03724508dc713da55fc9c1352c8e6c5 Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Fri, 19 Jun 2026 17:10:08 +0530 Subject: [PATCH 06/55] Update ReadMe.md --- Linux/Device_Driver/Hello_World/ReadMe.md | 95 +++++++++++++++++++++++ 1 file changed, 95 insertions(+) diff --git a/Linux/Device_Driver/Hello_World/ReadMe.md b/Linux/Device_Driver/Hello_World/ReadMe.md index 581468a..232fc00 100644 --- a/Linux/Device_Driver/Hello_World/ReadMe.md +++ b/Linux/Device_Driver/Hello_World/ReadMe.md @@ -1,3 +1,98 @@ +# Linux Device Driver – Part 2: First Device Driver + +This repository contains a simple Linux character device driver, based on an introductory device-driver tutorial. It shows how to create, build, load, and test a basic driver implemented as a loadable kernel module. + +## Goal + +The main goals of this example are: + +- To register a simple character device with the kernel +- To expose a device file under `/dev` +- To implement minimal `open`, `close`, `read`, and `write` callbacks +- To learn how to build and insert a kernel module + +## Files in this Repository + +- `first_driver.c` – The main driver source file implementing a character device +- `Makefile` – Uses the kernel build system to build the module +- `README.md` – This documentation + +You can rename these to match your actual filenames. + +## How the Driver Works + +This driver: + +- Registers a character device with the kernel using a major/minor number +- Creates a device class and device node so that a file appears under `/dev` +- Defines a `file_operations` structure with callbacks for: + - `open` + - `release` (close) + - `read` + - `write` +- Prints kernel log messages for each operation so you can see when user space accesses the driver + +You can view these messages using `dmesg` or `journalctl`, depending on your distribution. + +## Building the Module + +Make sure you have the kernel headers and build tools installed on your system. + +To build: + +```bash +make +``` + +If successful, this produces a `.ko` file (for example `first_driver.ko`). + +To clean: + +```bash +make clean +``` + +## Loading and Unloading the Module + +Insert the module: + +```bash +sudo insmod first_driver.ko +dmesg | tail +``` + +Check that: + +- The module is listed in `lsmod` +- A corresponding device node is created under `/dev` (possibly via `udev`) + +Remove the module: + +```bash +sudo rmmod first_driver +dmesg | tail +``` + +Always verify that resources (device number, class, device) are cleaned up in the module’s exit function. + +## Testing from User Space + +After loading the driver and confirming the `/dev` node exists: + +```bash +echo "test" | sudo tee /dev/your_device_name +sudo cat /dev/your_device_name +``` + +These commands exercise the `write` and `read` callbacks. Replace `/dev/your_device_name` with the actual node created by your driver. + +## Prerequisites + +- Linux system with kernel headers installed +- Basic C programming knowledge +- Familiarity with `make`, `insmod`, `rmmod`, and `dmesg` + +------------------------------------------------------------------------------------------------------------ # Hello World LDD - This is just a basic linux device driver. This kernel module will print some debug messages at the init and exit time. - Please update your Beaglebone board's kernel directory in the Makefile. From 8424a5f357d195d29f7f0239c1a40f1108fe19ff Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Fri, 19 Jun 2026 17:11:43 +0530 Subject: [PATCH 07/55] Update ReadMe.md --- .../ReadMe.md | 105 ++++++++++++++++++ 1 file changed, 105 insertions(+) diff --git a/Linux/Device_Driver/Passing_arguments_to_Linux_device_driver/ReadMe.md b/Linux/Device_Driver/Passing_arguments_to_Linux_device_driver/ReadMe.md index d2723c5..3e6686d 100644 --- a/Linux/Device_Driver/Passing_arguments_to_Linux_device_driver/ReadMe.md +++ b/Linux/Device_Driver/Passing_arguments_to_Linux_device_driver/ReadMe.md @@ -1,3 +1,108 @@ +# Linux Device Driver – Part 3: Passing Arguments to Device Driver + +This repository demonstrates how to pass parameters (arguments) from user space to a Linux kernel module (device driver) when it is loaded. + +## Goal + +The goals of this example are: + +- To define module parameters that can be set at load time +- To understand how different data types (for example `int`, `charp`, arrays) are handled as parameters +- To see how these values are used inside the driver code +- To practice loading a module with different argument values + +## Concepts Covered + +This example focuses on: + +- Declaring module parameters using kernel macros +- Specifying default values and permissions for these parameters +- Accessing the parameter values inside `init` and other driver functions +- Observing the values via kernel logs + +These concepts apply to both simple “hello world” style modules and more complex device drivers. + +## How Module Parameters Work + +In the Linux kernel, module parameters: + +- Are declared in the driver source using macros (for example for integers, strings, or arrays) +- Can be set from user space when inserting the module using `insmod` or `modprobe` +- Appear in `/sys/module//parameters/` (subject to permissions), allowing runtime inspection and sometimes modification + +This allows flexible configuration of driver behavior without recompiling. + +## Files in this Repository + +- `param_driver.c` – Example driver showing how to declare and use module parameters +- `Makefile` – Builds the kernel module using the kernel build system +- `README.md` – Documentation for this part + +Rename files as needed to match your actual source. + +## Building the Module + +Ensure kernel headers and build tools are installed. + +To build: + +```bash +make +``` + +This should produce a `.ko` file (for example `param_driver.ko`). + +To clean: + +```bash +make clean +``` + +## Loading the Module with Arguments + +Load the module with default parameters: + +```bash +sudo insmod param_driver.ko +dmesg | tail +``` + +Load the module with custom parameters (example): + +```bash +sudo insmod param_driver.ko myint=10 mystring="hello" myarray=1,2,3 +dmesg | tail +``` + +Check `dmesg` (or `journalctl`) to verify that the driver prints the values of the parameters when it initializes. + +If supported by your code, you can also inspect parameters via: + +```bash +ls /sys/module/param_driver/parameters +cat /sys/module/param_driver/parameters/myint +``` + +Replace names with those used in your actual module. + +## Unloading the Module + +To remove the module: + +```bash +sudo rmmod param_driver +dmesg | tail +``` + +Ensure your exit function runs cleanly and that no state depends on the module parameters after unload. + +## Prerequisites + +- Linux system with development tools and kernel headers +- Basic understanding of kernel modules from previous parts +- Familiarity with `insmod`, `rmmod`, `dmesg`, and possibly `modprobe` + +------------------------------------------------------------------------------------------------------------- This is just a basic linux device driver. This will explain how to pass the arguments to the linux device driver. Please update your Beaglebone board's kernel directory in the Makefile. From dc2b2bea36b88d36b88971cfef99a3e3eb15ec06 Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Fri, 19 Jun 2026 17:12:07 +0530 Subject: [PATCH 08/55] Rename ReadMe.md to README.md --- .../{ReadMe.md => README.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Linux/Device_Driver/Passing_arguments_to_Linux_device_driver/{ReadMe.md => README.md} (100%) diff --git a/Linux/Device_Driver/Passing_arguments_to_Linux_device_driver/ReadMe.md b/Linux/Device_Driver/Passing_arguments_to_Linux_device_driver/README.md similarity index 100% rename from Linux/Device_Driver/Passing_arguments_to_Linux_device_driver/ReadMe.md rename to Linux/Device_Driver/Passing_arguments_to_Linux_device_driver/README.md From 24c4ec6fe3afc14c5572eeacc0def940b695e60f Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Fri, 19 Jun 2026 17:19:01 +0530 Subject: [PATCH 09/55] Update and rename ReadMe.md to README.md --- .../Major_and_Minor_number/README.md | 151 ++++++++++++++++++ .../Major_and_Minor_number/ReadMe.md | 19 --- 2 files changed, 151 insertions(+), 19 deletions(-) create mode 100644 Linux/Device_Driver/Major_and_Minor_number/README.md delete mode 100644 Linux/Device_Driver/Major_and_Minor_number/ReadMe.md diff --git a/Linux/Device_Driver/Major_and_Minor_number/README.md b/Linux/Device_Driver/Major_and_Minor_number/README.md new file mode 100644 index 0000000..6e94c8b --- /dev/null +++ b/Linux/Device_Driver/Major_and_Minor_number/README.md @@ -0,0 +1,151 @@ +# Character Device Driver: Major and Minor Numbers + +This repository demonstrates how to create a Linux character device driver that explicitly uses and manages major and minor numbers. It covers static and dynamic major number allocation and how these numbers relate to device files under `/dev`. + +## Goal + +The main goals of this example are: + +- To understand the role of major and minor numbers in character devices +- To register a character device with a specific major number (static allocation) +- To demonstrate dynamic major number allocation using the kernel API +- To show how major/minor numbers are associated with device files in `/dev` + +## What Are Major and Minor Numbers? + +In Linux: + +- The **major number** identifies the driver that controls a device. +- The **minor number** is used by the driver to distinguish between multiple devices or instances controlled by the same driver. + +Example: + +```text +/dev/mydev0 → major=, minor=0 +/dev/mydev1 → major=, minor=1 +``` + +Multiple minor numbers can share the same major number, allowing one driver to manage several devices. + +Character devices historically had fixed major numbers in `/proc/devices` or header files, but modern kernels typically use dynamically allocated major numbers. + +## Key Kernel APIs Used + +This driver typically uses: + +- `register_chrdev()` or `register_chrdev_region()` to register a character device region +- `alloc_chrdev_region()` to allocate a range of device numbers dynamically +- `cdev_init()` and `cdev_add()` to create and add a kernel `cdev` structure +- `device_create()` (often via a device class) to create a device node under `/dev` +- Cleanup functions: `cdev_del()`, `put_device()`, and `unregister_chrdev_region()` or `free_chrdev_region()` + +Your exact code may use a simpler old-style `register_chrdev()`/`unregister_chrdev()` depending on the tutorial. + +## Files in this Repository + +- `char_dev_major_minor.c` – Driver source implementing a character device with major/minor handling +- `Makefile` – Build script using the kernel build system +- `README.md` – This documentation + +Rename files to match your actual source. + +## Building the Module + +Ensure kernel headers and tools are installed. + +To build: + +```bash +make +``` + +This should produce a `.ko` file (for example `char_dev_major_minor.ko`). + +To clean: + +```bash +make clean +``` + +## Viewing Registered Devices + +After building, you can inspect current devices: + +```bash +cat /proc/devices +``` + +Look for your driver’s name and its major number. + +## Loading the Module + +Insert the module: + +```bash +sudo insmod char_dev_major_minor.ko +dmesg | tail +``` + +Check: + +- The major number printed in kernel logs +- The device file created under `/dev` (e.g., `/dev/mydev`) +- The entry in `/proc/devices` + +You can also inspect dynamic device info: + +```bash +ls /sys/class// +ls /dev/ +``` + +## Unloading the Module + +To remove the module: + +```bash +sudo rmmod char_dev_major_minor +dmesg | tail +``` + +Ensure that all resources (device numbers, `cdev`, device nodes) are properly freed. + +## Testing from User Space + +Once the device node exists: + +```bash +echo "test" | sudo tee /dev/your_device_name +sudo cat /dev/your_device_name +``` + +This exercises the driver’s `read` and `write` callbacks if they are implemented. + +Replace `/dev/your_device_name` with the actual device name created by your driver. + +## Prerequisites + +- Linux system with kernel headers and build tools +- Basic understanding of character devices and kernel modules +- Familiarity with `make`, `insmod`, `rmmod`, `dmesg`, and `/proc/devices` + +----------------------------------------------------------------------------------------------------------- +This is just a basic linux device driver. This will explain major and minor number in the linux device driver. + +Please update your Beaglebone board's kernel directory in the Makefile. + +Build for Beaglebone: + sudo make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- + +Build for Raspberry Pi or Virtualbox Ubuntu: + sudo make + +You can check the video tutorial of this example here (https://www.youtube.com/watch?v=TfUTkCMCyig) and (https://youtu.be/aTwBCUjtTnw). + +Please refer this URL for the complete tutorial of this source code. +https://embetronicx.com/tutorials/linux/device-drivers/character-device-driver-major-number-and-minor-number/ + +The Linux Device Driver Video Playlist - https://www.youtube.com/watch?v=BRVGchs9UUQ&list=PLArwqFvBIlwHq8WMKgsXSQdqIvymrEz9k + +How to Setup Ubuntu and Raspberry PI - https://www.youtube.com/watch?v=e6gNeje3ljA +How to Setup BeagleBone and Cross compile the kernel - https://www.youtube.com/watch?v=am-dgmrMgYY&t diff --git a/Linux/Device_Driver/Major_and_Minor_number/ReadMe.md b/Linux/Device_Driver/Major_and_Minor_number/ReadMe.md deleted file mode 100644 index e4a31d9..0000000 --- a/Linux/Device_Driver/Major_and_Minor_number/ReadMe.md +++ /dev/null @@ -1,19 +0,0 @@ -This is just a basic linux device driver. This will explain major and minor number in the linux device driver. - -Please update your Beaglebone board's kernel directory in the Makefile. - -Build for Beaglebone: - sudo make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- - -Build for Raspberry Pi or Virtualbox Ubuntu: - sudo make - -You can check the video tutorial of this example here (https://www.youtube.com/watch?v=TfUTkCMCyig) and (https://youtu.be/aTwBCUjtTnw). - -Please refer this URL for the complete tutorial of this source code. -https://embetronicx.com/tutorials/linux/device-drivers/character-device-driver-major-number-and-minor-number/ - -The Linux Device Driver Video Playlist - https://www.youtube.com/watch?v=BRVGchs9UUQ&list=PLArwqFvBIlwHq8WMKgsXSQdqIvymrEz9k - -How to Setup Ubuntu and Raspberry PI - https://www.youtube.com/watch?v=e6gNeje3ljA -How to Setup BeagleBone and Cross compile the kernel - https://www.youtube.com/watch?v=am-dgmrMgYY&t From bbb528584b5c7b5f445ec660bf4fce9f7db4e3da Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Fri, 19 Jun 2026 17:21:38 +0530 Subject: [PATCH 10/55] Create README.md --- Linux/Device_Driver/README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 Linux/Device_Driver/README.md diff --git a/Linux/Device_Driver/README.md b/Linux/Device_Driver/README.md new file mode 100644 index 0000000..48cbb44 --- /dev/null +++ b/Linux/Device_Driver/README.md @@ -0,0 +1 @@ +refer: https://embetronicx.com/linux-device-driver-tutorials/ From fcce26b15c320e18770c0ef0cfa2aed71eb837f9 Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Fri, 19 Jun 2026 17:23:49 +0530 Subject: [PATCH 11/55] Update ReadMe.md --- .../Device_File_Creation/ReadMe.md | 161 ++++++++++++++++++ 1 file changed, 161 insertions(+) diff --git a/Linux/Device_Driver/Device_File_Creation/ReadMe.md b/Linux/Device_Driver/Device_File_Creation/ReadMe.md index ba490dc..fc5956e 100644 --- a/Linux/Device_Driver/Device_File_Creation/ReadMe.md +++ b/Linux/Device_Driver/Device_File_Creation/ReadMe.md @@ -1,3 +1,164 @@ +# Device File Creation for Character Drivers + +This repository demonstrates how to create device files (device nodes) under `/dev` for a Linux character device driver. It covers both manual creation and automatic creation using kernel APIs and udev. + +## Goal + +The main goals of this example are: + +- To understand why device files are needed for character drivers +- To manually create a device file (for example with `mknod`) +- To automatically create a device file using kernel classes and device APIs +- To see how `udev` rules can control device node names and permissions + +## Why Device Files? + +In Linux: + +- User-space programs interact with devices via device files like `/dev/mydev` +- The kernel uses these files to route I/O to the correct driver +- The device file encodes the major and minor number of the device + +Without a device file, a character driver is registered but not easily usable from user space. + +## Manual Device File Creation + +A traditional approach is: + +1. Register the character device with a known major number +2. Use `mknod` to create the device file manually: + +```bash +sudo mknod /dev/mydev c 0 +``` + +where: + +- `c` indicates a character device +- `` is the major number assigned to your driver +- `0` is the minor number + +This method is simple but not ideal for modern systems because: + +- The device file won’t be recreated automatically on reboot +- It doesn’t integrate well with dynamic device management + +## Automatic Device File Creation + +Modern kernels use `udev` to manage device nodes automatically. Common approaches in the driver: + +- Create a device class with `class_create()` (or the newer `device_class` API) +- Create a device with `device_create()` (or `dev_device_create()` variants) +- The kernel then asks `udev` to create a device node under `/dev` automatically + +This approach: + +- Recreates device nodes automatically on boot/reload +- Supports permissions and naming via udev rules +- Is the recommended method for modern drivers + +Key APIs often used: + +- `class_create()` / `device_create()` (older style) +- `device_class` and related helpers (newer style) +- Cleanup with `class_destroy()` / `device_destroy()` + +Your exact code may vary depending on the kernel version and tutorial style. + +## Files in this Repository + +- `dev_file_creation.c` – Driver source that creates a character device and device file +- `Makefile` – Builds the kernel module using the kernel build system +- `README.md` – This documentation +- (Optional) `udev.rules` – Example udev rule file for custom naming/permissions + +Rename files to match your actual source. + +## Building the Module + +Ensure kernel headers and tools are installed. + +To build: + +```bash +make +``` + +This should produce a `.ko` file (for example `dev_file_creation.ko`). + +To clean: + +```bash +make clean +``` + +## Loading the Module + +Insert the module: + +```bash +sudo insmod dev_file_creation.ko +dmesg | tail +``` + +Check: + +- The driver prints the major number and confirms device creation +- A device node appears under `/dev` (e.g., `/dev/mydev`) +- The device is listed in `/proc/devices` and/or under `/sys/class/` + +## Unloading the Module + +To remove the module: + +```bash +sudo rmmod dev_file_creation +dmesg | tail +``` + +Ensure the driver: + +- Removes the device node (`device_destroy()` or equivalent) +- Destroys the device class (`class_destroy()` or equivalent) +- Unregisters the character device region + +## Testing from User Space + +Once the device node exists: + +```bash +echo "hello" | sudo tee /dev/your_device_name +sudo cat /dev/your_device_name +``` + +This exercises `write` and `read` callbacks if they are implemented. Replace `/dev/your_device_name` with the actual device name. + +## Customizing Device Name and Permissions with udev + +You can: + +- Create a udev rule file (for example `/etc/udev/rules.d/99-mydev.rules`) +- Control the device node name and permissions (e.g. `MODE="0666"`) + +Example rule: + +```text +KERNEL=="mydev", NAME="mydev", MODE="0666" +``` + +Then reload udev rules: + +```bash +sudo udevadm control --reload-rules +``` + +## Prerequisites + +- Linux system with kernel headers and build tools +- Basic understanding of character devices and kernel modules +- Familiarity with `insmod`, `rmmod`, `dmesg`, `mknod`, and `udev` + +## Conclusion This is just a basic linux device driver. This will explain about the device file and how to create that in the linux device driver. Please update your Beaglebone board's kernel directory in the Makefile. From ea583caa2276b4899992e2833c405ef6b01ca0c6 Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Fri, 19 Jun 2026 17:25:37 +0530 Subject: [PATCH 12/55] Update ReadMe.md --- Linux/Device_Driver/File_Operations/ReadMe.md | 149 ++++++++++++++++++ 1 file changed, 149 insertions(+) diff --git a/Linux/Device_Driver/File_Operations/ReadMe.md b/Linux/Device_Driver/File_Operations/ReadMe.md index e24442d..338baa4 100644 --- a/Linux/Device_Driver/File_Operations/ReadMe.md +++ b/Linux/Device_Driver/File_Operations/ReadMe.md @@ -1,3 +1,152 @@ +# cdev Structure and File Operations of Character Drivers + +This repository demonstrates how to use the Linux kernel `cdev` structure and `file_operations` to implement a character device driver. It follows modern kernel practices for character drivers instead of the older `register_chrdev()` approach. + +## Goal + +The main goals of this example are: + +- To understand the role of the `cdev` structure in character drivers +- To define and register `file_operations` callbacks (`open`, `read`, `write`, `release`, etc.) +- To use the modern kernel API (`alloc_chrdev_region`, `cdev_init`, `cdev_add`, etc.) to register a character device +- To create a device file under `/dev` automatically using a device class + +## What Is `cdev`? + +In modern Linux kernels: + +- `cdev` represents a character device in the kernel +- Each `cdev` is associated with: + - A device number range (major/minor) + - A `file_operations` structure that defines how to handle I/O + +Instead of using the old `register_chrdev()` directly, you: + +1. Allocate a device number range with `alloc_chrdev_region()` +2. Initialize a `cdev` with `cdev_init()` +3. Set its `file_operations` +4. Add it to the system with `cdev_add()` +5. Clean up with `cdev_del()` and `free_chrdev_region()` + +This approach is more flexible and aligns with the kernel’s internal device model. + +## File Operations (`file_operations`) + +The `file_operations` structure defines callbacks that the kernel invokes when user space performs operations on the device file: + +Common callbacks include: + +| Callback | Purpose | +|----------------|----------------------------------------------| +| `open` | Called when the device file is opened | +| `read` | Called when data is read from the device | +| `write` | Called when data is written to the device | +| `release` | Called when the device file is closed | +| `unlocked_ioctl` | Optional: for ioctl commands (if needed) | + +Your driver defines these functions and assigns them to a `struct file_operations`: + +```c +static const struct file_operations fops = { + .open = my_open, + .read = my_read, + .write = my_write, + .release = my_release, +}; +``` + +Then this is linked to the `cdev` via `cdev_init()`. + +## Key Kernel APIs Used + +Typical APIs for a modern character driver: + +- `alloc_chrdev_region(&dev, 0, 1, MY_CLASS_NAME)` – Allocate device numbers +- `cdev_init(&cd, &fops)` – Initialize `cdev` with file operations +- `cdev_add(&cd, dev, 1)` – Register the character device +- `cdev_del(&cd)` – Remove the character device +- `free_chrdev_region(dev, 1)` – Free the allocated device numbers +- `class_create()` / `device_create()` – Create device class and node under `/dev` +- `class_destroy()` / `device_destroy()` – Cleanup + +Your exact code may use slightly different names depending on kernel version and the tutorial. + +## Files in this Repository + +- `cdev_fileops.c` – Driver source implementing a character device using `cdev` and `file_operations` +- `Makefile` – Builds the kernel module using the kernel build system +- `README.md` – This documentation + +Rename files to match your actual source. + +## Building the Module + +Ensure kernel headers and tools are installed. + +To build: + +```bash +make +``` + +This should produce a `.ko` file (for example `cdev_fileops.ko`). + +To clean: + +```bash +make clean +``` + +## Loading the Module + +Insert the module: + +```bash +sudo insmod cdev_fileops.ko +dmesg | tail +``` + +Check: + +- The driver prints the major number and confirms device registration +- A device node appears under `/dev` (e.g., `/dev/mydev`) +- The device is listed in `/proc/devices` and under `/sys/class/` + +## Unloading the Module + +To remove the module: + +```bash +sudo rmmod cdev_fileops +dmesg | tail +``` + +Ensure the driver: + +- Removes the device node (`device_destroy()`) +- Destroys the device class (`class_destroy()`) +- Deletes the `cdev` (`cdev_del()`) +- Frees the device number range (`free_chrdev_region()`) + +## Testing from User Space + +Once the device node exists: + +```bash +echo "hello" | sudo tee /dev/your_device_name +sudo cat /dev/your_device_name +``` + +This exercises `write` and `read` callbacks if they are implemented. Replace `/dev/your_device_name` with the actual device name. + +## Prerequisites + +- Linux system with kernel headers and build tools +- Basic understanding of character devices and kernel modules +- Familiarity with `make`, `insmod`, `rmmod`, `dmesg`, and `/proc/devices` +- Comfort reading and writing C code for the kernel + +## Conclusion This is just a basic linux device driver which explains about the file operations. Please update your Beaglebone board's kernel directory in the Makefile. From 81d4b0a619f0dac99d1143ed71206920ba8101d2 Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Fri, 19 Jun 2026 17:26:21 +0530 Subject: [PATCH 13/55] Rename ReadMe.md to README.md --- Linux/Device_Driver/File_Operations/{ReadMe.md => README.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Linux/Device_Driver/File_Operations/{ReadMe.md => README.md} (100%) diff --git a/Linux/Device_Driver/File_Operations/ReadMe.md b/Linux/Device_Driver/File_Operations/README.md similarity index 100% rename from Linux/Device_Driver/File_Operations/ReadMe.md rename to Linux/Device_Driver/File_Operations/README.md From 19ee56e33da60d8aaa5a15361e00448268add75f Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Fri, 19 Jun 2026 17:34:38 +0530 Subject: [PATCH 14/55] Update ReadMe.md --- .../Real_device_driver/ReadMe.md | 138 ++++++++++++++++++ 1 file changed, 138 insertions(+) diff --git a/Linux/Device_Driver/Real_device_driver/ReadMe.md b/Linux/Device_Driver/Real_device_driver/ReadMe.md index 4a2a518..d8aba04 100644 --- a/Linux/Device_Driver/Real_device_driver/ReadMe.md +++ b/Linux/Device_Driver/Real_device_driver/ReadMe.md @@ -1,3 +1,141 @@ +# Linux Device Driver Tutorial – Programming + +This repository is a collection of example Linux kernel modules and character device drivers from an introductory device driver tutorial series. It focuses on practical programming: building, loading, and testing real drivers on Linux. + +## Overview + +This tutorial series covers: + +- Basics of Linux device drivers and kernel modules +- Character device drivers (read/write/open/release) +- Major and minor numbers for character devices +- Dynamic device file creation under `/dev` +- Using the `cdev` structure and `file_operations` +- Passing arguments (parameters) to kernel modules +- Build systems and module development workflow + +Each part in the series has its own directory or file with example code and a small README explaining its goals. + +## Goals of This Repository + +The goals are: + +- To provide working example code for learning Linux device driver programming +- To keep all examples in a single place for easy reference and experimentation +- To demonstrate modern kernel APIs for character drivers (`cdev`, `alloc_chrdev_region`, etc.) +- To show how to build modules with a `Makefile`, load them with `insmod`/`modprobe`, and test them from user space + +## Repository Structure + +Example structure (adapt to your actual layout): + +```text +linux-device-driver-programming/ + part1-introduction/ + README.md + hello_module.c + Makefile + part2-first-device-driver/ + README.md + first_driver.c + Makefile + part3-passing-arguments/ + README.md + param_driver.c + Makefile + major-minor-numbers/ + README.md + char_dev_major_minor.c + Makefile + device-file-creation/ + README.md + dev_file_creation.c + Makefile + cdev-file-operations/ + README.md + cdev_fileops.c + Makefile + README.md # This file +``` + +You can reorganize or rename directories/files to match your actual source. + +## Common Build and Test Commands + +For each part: + +Build: + +```bash +cd partX-... +make +``` + +Load: + +```bash +sudo insmod .ko +dmesg | tail +``` + +Check devices: + +```bash +cat /proc/devices +ls /dev/your_device_name +``` + +Test: + +```bash +echo "test" | sudo tee /dev/your_device_name +sudo cat /dev/your_device_name +``` + +Unload: + +```bash +sudo rmmod +dmesg | tail +``` + +Clean: + +```bash +make clean +``` + +## Prerequisites + +- Linux system (e.g., Ubuntu) with kernel headers and build tools installed +- Basic C programming knowledge +- Familiarity with: + - `make`, `gcc` + - `insmod`, `rmmod`, `modprobe` + - `dmesg`, `/proc/devices`, `/sys` +- Root access (or `sudo`) for loading modules and creating device nodes + +## Minimal Build Environment Setup (Ubuntu Example) + +```bash +sudo apt update +sudo apt install -y build-essential linux-headers-$(uname -r) +``` + +Then clone or copy your source files and run `make` in each part directory. + +## How to Use This Repository + +1. Pick a part that matches what you want to learn (e.g., “first device driver” or “cdev + file_operations”). +2. Read that part’s `README.md`. +3. Build the module with `make`. +4. Load it with `insmod` and inspect kernel logs with `dmesg`. +5. Test using shell commands (`echo`, `cat`) on the device file. +6. Unload with `rmmod` and observe cleanup messages. + +Repeat for each part, gradually building your understanding. + +## Conclusion This is just a basic linux device driver which explains about the real read and write of the device file. Please update your Beaglebone board's kernel directory in the Makefile. From 3901d6eca8feb709999af8b4250d07e0e45f531a Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Fri, 19 Jun 2026 17:35:21 +0530 Subject: [PATCH 15/55] Update ReadMe.md --- Linux/Device_Driver/Real_device_driver/ReadMe.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Linux/Device_Driver/Real_device_driver/ReadMe.md b/Linux/Device_Driver/Real_device_driver/ReadMe.md index d8aba04..a25468a 100644 --- a/Linux/Device_Driver/Real_device_driver/ReadMe.md +++ b/Linux/Device_Driver/Real_device_driver/ReadMe.md @@ -1,6 +1,7 @@ # Linux Device Driver Tutorial – Programming -This repository is a collection of example Linux kernel modules and character device drivers from an introductory device driver tutorial series. It focuses on practical programming: building, loading, and testing real drivers on Linux. +- This repository is a collection of example Linux kernel modules and character device drivers from an introductory device driver tutorial series. +- It focuses on practical programming: building, loading, and testing real drivers on Linux. ## Overview From a610eec0901746788b779b5113f9696c821b6e31 Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Fri, 19 Jun 2026 17:39:52 +0530 Subject: [PATCH 16/55] Update ReadMe.md --- .../Real_device_driver/ReadMe.md | 322 +++++++++++++----- 1 file changed, 235 insertions(+), 87 deletions(-) diff --git a/Linux/Device_Driver/Real_device_driver/ReadMe.md b/Linux/Device_Driver/Real_device_driver/ReadMe.md index a25468a..fa14285 100644 --- a/Linux/Device_Driver/Real_device_driver/ReadMe.md +++ b/Linux/Device_Driver/Real_device_driver/ReadMe.md @@ -1,141 +1,289 @@ -# Linux Device Driver Tutorial – Programming +# Linux Device Driver Tutorial – Programming (Real Device Driver) -- This repository is a collection of example Linux kernel modules and character device drivers from an introductory device driver tutorial series. -- It focuses on practical programming: building, loading, and testing real drivers on Linux. +This repository contains a complete “real” Linux character device driver and a matching user-space test application, based on the EmbetronicX Linux Device Driver tutorial series. It demonstrates how to: -## Overview +- Implement kernel-space driver functions: `open`, `write`, `read`, and `close` (release) +- Allocate and free kernel memory with `kmalloc()` and `kfree()` +- Safely copy data between user space and kernel space using `copy_from_user()` and `copy_to_user()` +- Use `cdev`, major/minor numbers, and automatic device file creation under `/dev` +- Build a kernel module and a user-space application, and test them together -This tutorial series covers: +Source code for the original examples is available at: +https://github.com/Embetronicx/Tutorials/tree/master/Linux/Device_Driver/Real_device_driver -- Basics of Linux device drivers and kernel modules -- Character device drivers (read/write/open/release) -- Major and minor numbers for character devices -- Dynamic device file creation under `/dev` -- Using the `cdev` structure and `file_operations` -- Passing arguments (parameters) to kernel modules -- Build systems and module development workflow +The full tutorial series is at: +https://www.youtube.com/playlist?list=PLArwqFvBIlwHq8WMKgsXSQdqIvymrEz9k +Website: https://embetronicx.com/linux-device-driver-tutorials/ -Each part in the series has its own directory or file with example code and a small README explaining its goals. +## Concept -## Goals of This Repository +- A **user-space application** communicates with a **kernel-space driver** via a device file (e.g. `/dev/etx_device`). +- When the user writes data to the device file, the driver: + - Copies the data from user space to kernel space using `copy_from_user()` + - Stores it in a kernel-allocated buffer (via `kmalloc()`) +- When the user reads the device file, the driver: + - Copies the stored data from kernel space back to user space using `copy_to_user()` + - Returns it to the user-space application -The goals are: +This implements a simple “write once, read later” buffer in kernel memory. -- To provide working example code for learning Linux device driver programming -- To keep all examples in a single place for easy reference and experimentation -- To demonstrate modern kernel APIs for character drivers (`cdev`, `alloc_chrdev_region`, etc.) -- To show how to build modules with a `Makefile`, load them with `insmod`/`modprobe`, and test them from user space +## Files in This Repository -## Repository Structure +- `driver.c` – Kernel-space character device driver source +- `test_app.c` – User-space application to test the driver +- `Makefile` – Builds the kernel module (`driver.ko`) +- `README.md` – This documentation -Example structure (adapt to your actual layout): +You can download the original code from: +https://github.com/Embetronicx/Tutorials/tree/master/Linux/Device_Driver/Real_device_driver -```text -linux-device-driver-programming/ - part1-introduction/ - README.md - hello_module.c - Makefile - part2-first-device-driver/ - README.md - first_driver.c - Makefile - part3-passing-arguments/ - README.md - param_driver.c - Makefile - major-minor-numbers/ - README.md - char_dev_major_minor.c - Makefile - device-file-creation/ - README.md - dev_file_creation.c - Makefile - cdev-file-operations/ - README.md - cdev_fileops.c - Makefile - README.md # This file -``` - -You can reorganize or rename directories/files to match your actual source. - -## Common Build and Test Commands - -For each part: - -Build: +## Key Kernel Functions Used + +### `kmalloc()` + +Allocates memory in kernel space (like `malloc()` in user space). + +```c +#include +void *kmalloc(size_t size, gfp_t flags); +``` + +- `size`: number of bytes to allocate +- `flags`: memory type, e.g.: + - `GFP_KERNEL` – normal kernel memory (may sleep) + - `GFP_USER` – for user behalf (may sleep) + - `GFP_ATOMIC` – no sleep (e.g. interrupt handlers) + +The memory is physically contiguous and not cleared. + +### `kfree()` + +Frees previously allocated kernel memory: + +```c +void kfree(const void *objp); +``` + +- `objp`: pointer returned by `kmalloc()` + +### `copy_from_user()` + +Copies data from user space to kernel space: + +```c +#include +unsigned long copy_from_user(void *to, const void __user *from, unsigned long n); +``` + +- `to`: destination in kernel space +- `from`: source in user space +- `n`: number of bytes to copy + +Returns number of bytes that could not be copied (0 on success). + +### `copy_to_user()` + +Copies data from kernel space to user space: + +```c +unsigned long copy_to_user(const void __user *to, const void *from, unsigned long n); +``` + +- `to`: destination in user space +- `from`: source in kernel space +- `n`: number of bytes to copy + +Returns number of bytes that could not be copied (0 on success). + +## File Operations in the Driver + +The driver implements four main operations: + +1. **`open`** – Called when the device file is opened. + - In this tutorial’s sample, it logs a message; the original full driver also allocates memory in `init`. +2. **`write`** – Called when data is written to the device file. + - Uses `copy_from_user()` to copy data from user space into `kernel_buffer`. +3. **`read`** – Called when data is read from the device file. + - Uses `copy_to_user()` to copy data from `kernel_buffer` back to user space. +4. **`release` (close)** – Called when the device file is closed. + - Frees the kernel buffer with `kfree()`. + +## Driver Overview + +Key points from `driver.c`: + +- Uses modern kernel APIs: + - `alloc_chrdev_region()`, `cdev_init()`, `cdev_add()` + - `class_create()`, `device_create()` for automatic `/dev/etx_device` +- Allocates a kernel buffer of size `mem_size` (1024 bytes) with `kmalloc()`. +- Initializes the buffer with `"Hello_World"` in the init function. +- Implements: + - `etx_open()` + - `etx_release()` + - `etx_read()` using `copy_to_user()` + - `etx_write()` using `copy_from_user()` + +## Building the Device Driver + +### Native Build (Ubuntu / Raspberry Pi) ```bash -cd partX-... -make +sudo make ``` -Load: +This produces `driver.ko`. + +### Cross-Compile for BeagleBone (ARM) ```bash -sudo insmod .ko -dmesg | tail +sudo make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- +``` + +Make sure your `Makefile` has the correct BeagleBone kernel build path set in `KDIR`. + +Download the original Makefile from: +https://github.com/Embetronicx/Tutorials/tree/master/Linux/Device_Driver/Real_device_driver + +Clean: + +```bash +sudo make clean ``` -Check devices: +## Compiling the User-Space Application + +### Native (x86) ```bash -cat /proc/devices -ls /dev/your_device_name +gcc -o test_app test_app.c ``` -Test: +### For BeagleBone (ARM) ```bash -echo "test" | sudo tee /dev/your_device_name -sudo cat /dev/your_device_name +arm-linux-gnueabihf-gcc -o test_app test_app.c ``` -Unload: +## Execution (Output) + +1. Load the driver: ```bash -sudo rmmod +sudo insmod driver.ko dmesg | tail ``` -Clean: +You should see: + +- Major/minor number printed +- “Device Driver Insert...Done!!!” + +2. Run the application: ```bash -make clean +sudo ./test_app ``` +Example interaction: + +```text +** +**WWW.EmbeTronicX.com** +**Please Enter the Option** + 1. Write + 2. Read + 3. Exit +** +Select option 1 to write data to the driver and write the string (e.g. "embetronicx"). + +1 +Your Option = 1 +Enter the string to write into driver :embetronicx +Data Writing ...Done! +``` + +The string is passed to the driver and stored in kernel memory. + +Now select option 2 to read: + +```text +2 +Your Option = 2 +Data Reading ...Done! + +Data = embetronicx +``` + +You now see the same string read back from kernel space. + +3. Exit: + +```text +3 +``` + +The device file is closed and the application exits. + +Check `dmesg` to see: + +- “Device File Opened...!!!” +- “Data Write : Done!” +- “Data Read : Done!” +- “Device File Closed...!!!” + +To remove the driver: + +```bash +sudo rmmod driver +dmesg | tail +``` + +You should see “Device Driver Remove...Done!!!”. + +## Using `echo` and `cat` Instead of the Application + +Instead of `test_app`, you can use shell commands: + +Write: + +```bash +echo "embetronicx" | sudo tee /dev/etx_device +``` + +Read: + +```bash +sudo cat /dev/etx_device +``` + +This exercises the same `write` and `read` callbacks. + ## Prerequisites -- Linux system (e.g., Ubuntu) with kernel headers and build tools installed +- Linux system (Ubuntu, Raspberry Pi, or BeagleBone) with kernel headers - Basic C programming knowledge - Familiarity with: - `make`, `gcc` - - `insmod`, `rmmod`, `modprobe` - - `dmesg`, `/proc/devices`, `/sys` -- Root access (or `sudo`) for loading modules and creating device nodes + - `insmod`, `rmmod`, `dmesg` + - Device files under `/dev` -## Minimal Build Environment Setup (Ubuntu Example) +## Minimal Build Environment (Ubuntu) ```bash sudo apt update sudo apt install -y build-essential linux-headers-$(uname -r) ``` -Then clone or copy your source files and run `make` in each part directory. - -## How to Use This Repository +## Credits and Note on Copyright -1. Pick a part that matches what you want to learn (e.g., “first device driver” or “cdev + file_operations”). -2. Read that part’s `README.md`. -3. Build the module with `make`. -4. Load it with `insmod` and inspect kernel logs with `dmesg`. -5. Test using shell commands (`echo`, `cat`) on the device file. -6. Unload with `rmmod` and observe cleanup messages. +This repository contains example code inspired by the EmbetronicX Linux Device Driver tutorial series. +Refer to the original tutorial for detailed explanations, diagrams, and exact source code: -Repeat for each part, gradually building your understanding. +- Tutorial page: https://embetronicx.com/tutorials/linux/device-drivers/linux-device-driver-tutorial-programming/ +- YouTube playlist: https://www.youtube.com/playlist?list=PLArwqFvBIlwHq8WMKgsXSQdqIvymrEz9k +- GitHub source: https://github.com/Embetronicx/Tutorials/tree/master/Linux/Device_Driver/Real_device_driver +Please respect the author’s intellectual property. Do not copy the tutorial’s code verbatim unless you have permission. Use these examples as learning aids and adapt them in your own words and style. ## Conclusion This is just a basic linux device driver which explains about the real read and write of the device file. From f0800041eea35417e807235efb26271dd361b963 Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Fri, 19 Jun 2026 17:43:51 +0530 Subject: [PATCH 17/55] Update ReadMe.md --- Linux/Device_Driver/IOCTL/ReadMe.md | 254 +++++++++++++++++++++++++++- 1 file changed, 253 insertions(+), 1 deletion(-) diff --git a/Linux/Device_Driver/IOCTL/ReadMe.md b/Linux/Device_Driver/IOCTL/ReadMe.md index 2d768b6..d25b22c 100644 --- a/Linux/Device_Driver/IOCTL/ReadMe.md +++ b/Linux/Device_Driver/IOCTL/ReadMe.md @@ -1,4 +1,256 @@ +# ioctl Tutorial in Linux Device Drivers + +This repository demonstrates how to implement and use `ioctl` (Input/Output Control) in a Linux character device driver. It shows how to add custom commands beyond basic `read`/`write` and how user-space applications can invoke them via the `ioctl()` system call. + +`ioctl` is commonly used for: + +- Device configuration (e.g., setting modes, speeds, parameters) +- Control operations (e.g., start/stop, reset, enable/disable) +- Querying device status or capabilities + +Reference: Linux kernel documentation on ioctl-based interfaces [web:15]. + +## Goal + +The main goals of this example are: + +- To define custom `ioctl` commands using the kernel’s `_IO*` macros +- To implement an `unlocked_ioctl` (or `ioctl`) function in the driver +- To safely pass arguments between user space and kernel space +- To show how a user-space application calls `ioctl()` on a device file + +## What Is `ioctl`? + +`ioctl` is a system call for device-specific control operations that don’t fit naturally into `read`/`write`. + +In user space: + +```c +#include +int ioctl(int fd, unsigned long request, ...); +``` + +- `fd`: file descriptor of the device (from `open()`) +- `request`: ioctl command code +- Optional argument: pointer to data or an integer value + +In the kernel driver: + +```c +#include +#include + +static long unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + // handle cmd and arg +} +``` + +Reference: O’Reilly’s “The ioctl Method” in Linux Device Drivers [web:12]. + +## Defining ioctl Commands + +Custom ioctl commands are defined using macros from ``: + +```c +#define MY_IOC_MAGIC 'k' + +#define MY_IOC_HELLO _IO(MY_IOC_MAGIC, 0) // no argument +#define MY_IOC_SETVAL _IOW(MY_IOC_MAGIC, 1, int) // write (user -> kernel) +#define MY_IOC_GETVAL _IOR(MY_IOC_MAGIC, 2, int) // read (kernel -> user) +#define MY_IOC_BOTH _IOWR(MY_IOC_MAGIC, 3, int) // read-write +``` + +Key macros: + +- `_IO(magic, nr)` – no argument +- `_IOW(magic, nr, type)` – write (user → kernel) +- `_IOR(magic, nr, type)` – read (kernel → user) +- `_IOWR(magic, nr, type)` – read-write + +- `magic`: a unique character (e.g., `'k'`) to distinguish your driver +- `nr`: command number +- `type`: C type of the argument (e.g., `int`, `struct my_config`) + +Reference: Example ioctl command definitions in a Linux driver repo [web:11]. + +## File Operations with ioctl + +In the driver, you define a `file_operations` structure that includes `unlocked_ioctl`: + +```c +static const struct file_operations fops = { + .owner = THIS_MODULE, + .open = my_open, + .release = my_release, + .read = my_read, + .write = my_write, + .unlocked_ioctl = my_ioctl, +}; +``` + +The `unlocked_ioctl` prototype: + +```c +static long my_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + switch (cmd) { + case MY_IOC_HELLO: + // no arg + break; + case MY_IOC_SETVAL: + { + int val; + if (copy_from_user(&val, (int __user *)arg, sizeof(int))) + return -EFAULT; + // use val in kernel + break; + } + case MY_IOC_GETVAL: + { + int val = /* some kernel value */; + if (copy_to_user((int __user *)arg, &val, sizeof(int))) + return -EFAULT; + break; + } + default: + return -EINVAL; + } + return 0; +} +``` + +Key points: + +- Use `copy_from_user()` to get data from user space. +- Use `copy_to_user()` to send data to user space. +- Return `-EINVAL` for unknown commands. +- Return `-EFAULT` if copy fails. + +Reference: Example `unlocked_ioctl` implementation in a Linux driver [web:11]. + +## Files in This Repository + +- `ioctl_driver.c` – Kernel driver with custom ioctl commands +- `ioctl_test.c` – User-space application that calls `ioctl()` +- `Makefile` – Builds both the kernel module and user app +- `README.md` – This documentation + +Rename files to match your actual source. + +## Building the Kernel Module + +Ensure kernel headers and tools are installed. + +To build the module: + +```bash +make module +``` + +This produces `ioctl_driver.ko`. + +To build the user-space app: + +```bash +make app +``` + +This produces `ioctl_test`. + +To clean: + +```bash +make clean +``` + +## Loading the Module + +Insert the module: + +```bash +sudo insmod ioctl_driver.ko +dmesg | tail +``` + +Check: + +- The driver prints major/minor numbers and confirms device creation +- A device node appears under `/dev` (e.g., `/dev/ioctl_dev`) + +## Running the User-Space Application + +```bash +sudo ./ioctl_test +``` + +Typical interactions: + +```text +1. Hello (no arg) +2. Set value +3. Get value +4. Exit +``` + +Examples: + +- **Hello**: calls `ioctl(fd, MY_IOC_HELLO, 0)` +- **Set value**: calls `ioctl(fd, MY_IOC_SETVAL, &val)` +- **Get value**: calls `ioctl(fd, MY_IOC_GETVAL, &val)` and prints the returned value + +The driver logs each ioctl command in `pr_info()`/`pr_err()`. Check with: + +```bash +dmesg | tail +``` + +## Unloading the Module + +```bash +sudo rmmod ioctl_driver +dmesg | tail +``` + +Ensure the driver: + +- Removes the device node +- Destroys the device class +- Deletes the `cdev` +- Unregisters the chrdev region + +## Example ioctl Commands + +Common patterns: + +| Command | Direction | Example Use | +|------------------|----------------|--------------------------------| +| `MY_IOC_HELLO` | none | Simple “hello” control | +| `MY_IOC_SETVAL` | user → kernel | Set a parameter (e.g., mode) | +| `MY_IOC_GETVAL` | kernel → user | Get current parameter value | +| `MY_IOC_BOTH` | both | Configure and query together | + +Reference: Example ioctl commands like `_IO`, `_IOW`, `_IOR` in a Linux driver [web:11]. + +## Prerequisites + +- Linux system with kernel headers and build tools +- Basic C programming knowledge +- Familiarity with: + - `make`, `gcc` + - `insmod`, `rmmod`, `dmesg` + - Device files under `/dev` + - `ioctl()` system call in user space + +## Minimal Build Environment (Ubuntu) + +```bash +sudo apt update +sudo apt install -y build-essential linux-headers-$(uname -r) +``` + +## Conclusion This is just a basic linux device driver which explains about the IOCTL. Please refer this URL for the complete tutorial of this example source code. -https://embetronicx.com/tutorials/linux/device-drivers/ioctl-tutorial-in-linux/ \ No newline at end of file +https://embetronicx.com/tutorials/linux/device-drivers/ioctl-tutorial-in-linux/ From 8f610833113fc3065865779593496c4852af7deb Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Fri, 19 Jun 2026 17:56:25 +0530 Subject: [PATCH 18/55] Update ReadMe.md --- Linux/Device_Driver/procfs/ReadMe.md | 342 ++++++++++++++++++++++++++- 1 file changed, 341 insertions(+), 1 deletion(-) diff --git a/Linux/Device_Driver/procfs/ReadMe.md b/Linux/Device_Driver/procfs/ReadMe.md index a07b618..2e2884c 100644 --- a/Linux/Device_Driver/procfs/ReadMe.md +++ b/Linux/Device_Driver/procfs/ReadMe.md @@ -1,4 +1,344 @@ +# procfs in Linux – Kernel Module Example + +- This repository demonstrates how to create and use entries in the **proc filesystem (procfs)** from a Linux kernel module. +- It shows how to expose kernel data to user space via `/proc` files and how to implement read/write operations for proc entries. + +> **Note:** For modern device drivers, `sysfs` is preferred over `procfs` for configuration and status. `procfs` is mainly intended for process-related and global kernel information, and its use by drivers is discouraged for new production code [web:22][web:23]. This example is primarily for learning and debugging. + +## What Is procfs? + +`procfs` is a virtual filesystem mounted at `/proc`. It: + +- Exists in RAM (not on disk) +- Provides kernel and system runtime information +- Acts as a bridge between kernel space and user space +- Allows user-space programs to read (and sometimes write) kernel data + +Common examples: + +- `/proc/cpuinfo` – CPU information +- `/proc/meminfo` – Memory statistics +- `/proc/[pid]` – Process-specific information [web:22] + +For kernel modules, you can create your own entries under `/proc` to: + +- Export driver variables or status +- Receive configuration from user space (by writing to the file) +- Debug kernel module behavior [web:22][web:26] + +## Types of proc Entries + +You can create: + +1. **Read-only entries** – Expose kernel data to user space +2. **Read-write entries** – Allow user space to both read and configure kernel data + +Reference: procfs as a kernel-to-user-space interface [web:27]. + +## Key procfs APIs + +### Creating a proc Directory + +```c +#include +#include + +struct proc_dir_entry *proc_mkdir(const char *name, struct proc_dir_entry *parent); +``` + +- `name`: directory name under `/proc` +- `parent`: parent directory (or `NULL` for root `/proc`) + +Example: + +```c +struct proc_dir_entry *my_dir = proc_mkdir("mydriver", NULL); +// Creates /proc/mydriver +``` + +### Creating a proc File (Modern API, kernel ≥ 3.10) + +```c +struct proc_dir_entry *proc_create( + const char *name, + umode_t mode, + struct proc_dir_entry *parent, + const struct proc_ops *ops // or file_operations in older kernels +); +``` + +- `name`: file name (e.g., `"status"`) +- `mode`: file permissions (e.g., `0444` for read-only, `0644` for read-write) +- `parent`: parent directory (or `NULL`) +- `ops`: pointer to `proc_ops` (or `file_operations` in older kernels) + +Example: + +```c +static struct proc_ops my_proc_ops = { + .proc_read = my_proc_read, + .proc_write = my_proc_write, +}; + +struct proc_dir_entry *entry = proc_create( + "mydriver_status", + 0644, + NULL, + &my_proc_ops +); +// Creates /proc/mydriver_status +``` + +For kernel ≥ 5.6, use `struct proc_ops` instead of `struct file_operations` [web:26]. + +### Older API (kernel < 3.10) + +Older kernels used: + +```c +static struct file_operations proc_fops = { + .open = open_proc, + .read = read_proc, + .write = write_proc, + .release = release_proc, +}; + +struct proc_dir_entry *entry = create_proc_read_entry( + "mydriver_status", + 0644, + NULL, + read_proc, + NULL +); +``` + +This is deprecated in modern kernels. + +### Removing proc Entries + +```c +void remove_proc_entry(const char *name, struct proc_dir_entry *parent); +void proc_remove(struct proc_dir_entry *entry); +``` + +- `remove_proc_entry()` removes a file or directory +- `proc_remove()` removes a directory and its contents + +Example in module exit: + +```c +remove_proc_entry("mydriver_status", NULL); +remove_proc_entry("mydriver", NULL); +``` + +Reference: Removing proc entries in module exit [web:21]. + +## Implementing proc Read and Write + +### `proc_ops` (Modern) + +```c +#include +#include + +static ssize_t my_proc_read(struct file *file, char __user *buf, + size_t count, loff_t *offset) +{ + static const char *data = "Hello from procfs\n"; + size len = strlen(data); + + if (*offset >= len) + return 0; + if (count > len - *offset) + count = len - *offset; + + if (copy_to_user(buf, data + *offset, count)) + return -EFAULT; + + *offset += count; + return count; +} + +static ssize_t my_proc_write(struct file *file, const char __user *buf, + size_t count, loff_t *offset) +{ + char kernel_buf; + int len = min(count, 63); + + if (copy_from_user(kernel_buf, buf, len)) + return -EFAULT; + + kernel_buf[len] = '\0'; + pr_info("procfs write: %s\n", kernel_buf); + + return count; +} + +static struct proc_ops my_proc_ops = { + .proc_read = my_proc_read, + .proc_write = my_proc_write, +}; +``` + +Key points: + +- Use `copy_to_user()` and `copy_from_user()` for safety +- Return number of bytes handled +- Return `-EFAULT` on copy failure + +Reference: Creating procfs entries with read/write and removing them [web:26]. + +## Files in This Repository + +- `procfs_driver.c` – Kernel module that creates proc entries +- `Makefile` – Builds the kernel module +- `README.md` – This documentation + +Rename files to match your actual source. + +## Building the Module + +Ensure kernel headers and tools are installed. + +```bash +make +``` + +This produces `procfs_driver.ko`. + +Clean: + +```bash +make clean +``` + +## Loading the Module + +```bash +sudo insmod procfs_driver.ko +dmesg | tail +``` + +Check: + +- The module prints success messages +- A file appears under `/proc`, e.g. `/proc/mydriver_status` + +List proc entries: + +```bash +ls /proc/mydriver* +``` + +## Using the proc Entry + +### Read + +```bash +cat /proc/mydriver_status +``` + +This calls your `proc_read` function and returns the kernel data. + +### Write + +```bash +echo "test message" | sudo tee /proc/mydriver_status +``` + +This calls your `proc_write` function and logs the message via `pr_info()`. + +Check kernel logs: + +```bash +dmesg | tail +``` + +## Unloading the Module + +```bash +sudo rmmod procfs_driver +dmesg | tail +``` + +Ensure the module: + +- Removes all proc entries with `remove_proc_entry()` or `proc_remove()` +- Cleans up any allocated resources + +## Example: Read-Only proc Entry + +For a simple read-only entry: + +```c +static struct proc_ops my_proc_ops = { + .proc_read = my_proc_read, +}; + +struct proc_dir_entry *entry = proc_create( + "mydriver_info", + 0444, // read-only + NULL, + &my_proc_ops +); +``` + +User space can only read: + +```bash +cat /proc/mydriver_info +``` + +## Prerequisites + +- Linux system with kernel headers and build tools +- Basic C programming knowledge +- Familiarity with: + - `make`, `gcc` + - `insmod`, `rmmod`, `dmesg` + - `/proc` filesystem + +## Minimal Build Environment (Ubuntu) + +```bash +sudo apt update +sudo apt install -y build-essential linux-headers-$(uname -r) +``` + +## Best Practices and Modern Alternatives + +- For **device configuration and status**, prefer `sysfs` (`/sys`) over `procfs` +- Use `procfs` mainly for: + - Debug output + - Global kernel/runtime information + - Learning and experimentation + +Key differences: + +| Aspect | procfs (`/proc`) | sysfs (`/sys`) | +|-----------------|-----------------------------------|-------------------------------------| +| Purpose | Kernel/process internals | Device & driver attributes | +| Structure | Flat, unstructured | Hierarchical, object-based | +| Recommended for drivers | Legacy / debug only | Production interfaces | +| Example paths | `/proc/cpuinfo`, `/proc/meminfo` | `/sys/class/`, `/sys/devices/` | + +Reference: procfs vs sysfs for device drivers [web:22]. + +## Credits and Note on Copyright + +This example is inspired by tutorials explaining procfs in Linux kernel modules. +Refer to additional resources for deeper understanding: + +- procfs vs sysfs for device drivers [web:22] +- Linux kernel documentation on procfs usage [web:23] +- proc pseudo file system and SCSI subsystem [web:25] +- Tutorial on creating and reading `/proc` files from kernel modules [web:27] + +Please respect original authors’ intellectual property. Use these examples as learning aids and adapt them in your own words and style. + + +## Conslusion This is just a basic linux device driver which explains about the procfs. Please refer this URL for the complete tutorial of this example source code. -https://embetronicx.com/tutorials/linux/device-drivers/procfs-in-linux/ \ No newline at end of file +https://embetronicx.com/tutorials/linux/device-drivers/procfs-in-linux/ From 3081ef8c08790e76c9f446a4182b159a00f22081 Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Fri, 19 Jun 2026 17:57:35 +0530 Subject: [PATCH 19/55] Update ReadMe.md --- Linux/Device_Driver/procfs/ReadMe.md | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/Linux/Device_Driver/procfs/ReadMe.md b/Linux/Device_Driver/procfs/ReadMe.md index 2e2884c..224b380 100644 --- a/Linux/Device_Driver/procfs/ReadMe.md +++ b/Linux/Device_Driver/procfs/ReadMe.md @@ -324,17 +324,6 @@ Key differences: Reference: procfs vs sysfs for device drivers [web:22]. -## Credits and Note on Copyright - -This example is inspired by tutorials explaining procfs in Linux kernel modules. -Refer to additional resources for deeper understanding: - -- procfs vs sysfs for device drivers [web:22] -- Linux kernel documentation on procfs usage [web:23] -- proc pseudo file system and SCSI subsystem [web:25] -- Tutorial on creating and reading `/proc` files from kernel modules [web:27] - -Please respect original authors’ intellectual property. Use these examples as learning aids and adapt them in your own words and style. ## Conslusion From 3e415cb46acc3f05cb75f627fe430ccbcc43d431 Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Fri, 19 Jun 2026 18:02:16 +0530 Subject: [PATCH 20/55] Update ReadMe.md --- .../Waitqueue-Tutorial/ReadMe.md | 460 +++++++++++++++++- 1 file changed, 459 insertions(+), 1 deletion(-) diff --git a/Linux/Device_Driver/Waitqueue-Tutorial/ReadMe.md b/Linux/Device_Driver/Waitqueue-Tutorial/ReadMe.md index f708acc..aedb297 100644 --- a/Linux/Device_Driver/Waitqueue-Tutorial/ReadMe.md +++ b/Linux/Device_Driver/Waitqueue-Tutorial/ReadMe.md @@ -1,4 +1,462 @@ +# Linux Device Driver - Wait Queue + +## Overview + +A Wait Queue is a Linux kernel synchronization mechanism used when a process or kernel thread needs to sleep until a specific event occurs. + +Instead of continuously polling for an event, the task can: + +1. Sleep (block) +2. Release CPU resources +3. Wake up when the event occurs + +This improves CPU utilization and system efficiency. + +--- + +## Why Wait Queue? + +In Linux device drivers, a process may need to wait for: + +- Data arrival +- Hardware interrupt +- Completion of an operation +- Event notification from another thread + +Wait Queues provide a safe mechanism to: + +- Put tasks into sleep state +- Wake them when the required condition becomes true + +--- + +## Wait Queue Workflow + +```text +Initialize Wait Queue + | + v +Put Task To Sleep +(wait_event...) + | + v +Event Occurs + | + v +Wake Up Task +(wake_up...) + | + v +Task Continues Execution +``` + +--- + +## Header File + +```c +#include +``` + +--- + +# Step 1: Initialize Wait Queue + +There are two methods. + +## Static Initialization + +```c +DECLARE_WAIT_QUEUE_HEAD(wq); +``` + +### Example + +```c +DECLARE_WAIT_QUEUE_HEAD(my_waitqueue); +``` + +--- + +## Dynamic Initialization + +```c +wait_queue_head_t wq; + +init_waitqueue_head(&wq); +``` + +### Example + +```c +wait_queue_head_t my_waitqueue; + +init_waitqueue_head(&my_waitqueue); +``` + +--- + +# Step 2: Put Task To Sleep + +Linux provides several macros. + +--- + +## wait_event() + +Sleep until condition becomes true. + +```c +wait_event(wq, condition); +``` + +### State + +```text +TASK_UNINTERRUPTIBLE +``` + +### Example + +```c +wait_event(my_waitqueue, data_ready); +``` + +--- + +## wait_event_timeout() + +Sleep until: + +- Condition becomes true +OR +- Timeout expires + +```c +wait_event_timeout(wq, condition, timeout); +``` + +### Example + +```c +wait_event_timeout(my_waitqueue, + data_ready, + msecs_to_jiffies(5000)); +``` + +### Returns + +| Return Value | Meaning | +|-------------|----------| +| 0 | Timeout occurred | +| >0 | Remaining jiffies | +| 1 | Condition became true after timeout | + +--- + +## wait_event_cmd() + +Execute commands before and after sleep. + +```c +wait_event_cmd(wq, + condition, + cmd1, + cmd2); +``` + +### Example + +```c +wait_event_cmd(my_waitqueue, + data_ready, + printk("Before Sleep\n"), + printk("After Wakeup\n")); +``` + +--- + +## wait_event_interruptible() + +Sleep until: + +- Condition becomes true +OR +- Signal arrives + +```c +wait_event_interruptible(wq, condition); +``` + +### State + +```text +TASK_INTERRUPTIBLE +``` + +### Returns + +| Return Value | Meaning | +|-------------|----------| +| 0 | Condition became true | +| -ERESTARTSYS | Interrupted by signal | + +--- + +## wait_event_interruptible_timeout() + +Combination of: + +- Interruptible sleep +- Timeout + +```c +wait_event_interruptible_timeout( + wq, + condition, + timeout); +``` + +### Returns + +| Return Value | Meaning | +|-------------|----------| +| 0 | Timeout | +| >0 | Remaining jiffies | +| -ERESTARTSYS | Interrupted by signal | + +--- + +## wait_event_killable() + +Sleep until: + +- Condition becomes true +OR +- Fatal signal received + +```c +wait_event_killable(wq, condition); +``` + +### State + +```text +TASK_KILLABLE +``` + +--- + +# Step 3: Wake Up Sleeping Tasks + +When the event occurs, sleeping tasks must be awakened. + +--- + +## wake_up() + +Wake one task sleeping in uninterruptible state. + +```c +wake_up(&wq); +``` + +### Example + +```c +wake_up(&my_waitqueue); +``` + +--- + +## wake_up_all() + +Wake all tasks in the wait queue. + +```c +wake_up_all(&wq); +``` + +--- + +## wake_up_interruptible() + +Wake one task sleeping in interruptible state. + +```c +wake_up_interruptible(&wq); +``` + +--- + +## wake_up_sync() + +Wake task without immediately rescheduling CPU. + +```c +wake_up_sync(&wq); +``` + +--- + +## wake_up_interruptible_sync() + +Interruptible version of wake_up_sync(). + +```c +wake_up_interruptible_sync(&wq); +``` + +--- + +# Common Driver Usage + +## Waiting Thread + +```c +while (1) +{ + wait_event_interruptible( + my_waitqueue, + event_flag != 0); + + if(event_flag == EXIT_EVENT) + break; + + printk("Event Received\n"); + + event_flag = 0; +} +``` + +--- + +## Event Producer + +```c +event_flag = 1; + +wake_up_interruptible(&my_waitqueue); +``` + +--- + +# Driver Flow Example + +```text +Kernel Thread Started + | + v +Waiting For Event + | + v +User Reads Device + | + v +Driver Sets Flag + | + v +wake_up_interruptible() + | + v +Thread Wakes Up + | + v +Processes Event + | + v +Wait Again +``` + +--- + +# Important Sleep States + +| State | Description | +|---------|-------------| +| TASK_RUNNING | Executing | +| TASK_INTERRUPTIBLE | Can be interrupted by signals | +| TASK_UNINTERRUPTIBLE | Cannot be interrupted | +| TASK_KILLABLE | Interrupted only by fatal signals | + +--- + +# Advantages + +- Efficient CPU usage +- No busy waiting +- Event-driven synchronization +- Commonly used in device drivers +- Works well with kernel threads + +--- + +# Typical Driver Use Cases + +- Blocking read() +- Interrupt handling +- Data arrival notification +- Producer-consumer synchronization +- Driver event notification +- Hardware completion events + +--- + +# Wait Queue vs Busy Waiting + +| Wait Queue | Busy Waiting | +|------------|-------------| +| Sleeps task | Continuously polls | +| CPU efficient | CPU wastage | +| Event driven | Polling driven | +| Preferred in kernel | Generally avoided | + +--- + +# Important APIs Summary + +## Initialization + +```c +DECLARE_WAIT_QUEUE_HEAD(wq); + +wait_queue_head_t wq; +init_waitqueue_head(&wq); +``` + +## Sleep + +```c +wait_event() +wait_event_timeout() +wait_event_cmd() +wait_event_interruptible() +wait_event_interruptible_timeout() +wait_event_killable() +``` + +## Wake Up + +```c +wake_up() +wake_up_all() +wake_up_interruptible() +wake_up_sync() +wake_up_interruptible_sync() +``` + +--- + +# Key Takeaways + +- Wait Queue is a kernel mechanism for sleeping and waking tasks. +- A task sleeps until a condition becomes true. +- Sleeping tasks consume no CPU. +- Another task, ISR, or driver function wakes the waiting task. +- Frequently used in Linux device drivers for blocking operations and event synchronization. + +## Conclusion This is just a basic linux device driver. This will explain waitqueue in the linux device driver. Please refer this URL for the complete tutorial of this source code. -https://embetronicx.com/tutorials/linux/device-drivers/waitqueue-in-linux-device-driver-tutorial/ \ No newline at end of file +https://embetronicx.com/tutorials/linux/device-drivers/waitqueue-in-linux-device-driver-tutorial/ From b9d8e3315a09cf879655badc72de9e3b2e5f3b97 Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Fri, 19 Jun 2026 18:04:37 +0530 Subject: [PATCH 21/55] Update ReadMe.md --- Linux/Device_Driver/sysfs/ReadMe.md | 657 +++++++++++++++++++++++++++- 1 file changed, 656 insertions(+), 1 deletion(-) diff --git a/Linux/Device_Driver/sysfs/ReadMe.md b/Linux/Device_Driver/sysfs/ReadMe.md index 4dab190..ca47700 100644 --- a/Linux/Device_Driver/sysfs/ReadMe.md +++ b/Linux/Device_Driver/sysfs/ReadMe.md @@ -1,4 +1,659 @@ +# Linux Device Driver - Sysfs + +## Overview + +Sysfs is a virtual filesystem provided by the Linux kernel that exposes kernel objects, devices, drivers, and configuration parameters to user space. + +It is mounted at: + +```bash +/sys +``` + +Sysfs allows communication between: + +```text +User Space <----> Sysfs <----> Kernel Space +``` + +Unlike regular filesystems, sysfs files do not store data on disk. Their contents are generated dynamically by the kernel when accessed. + +--- + +# Why Sysfs? + +Linux provides several mechanisms for communication between user space and kernel space: + +* IOCTL +* Procfs +* Sysfs +* Debugfs +* Configfs +* Sysctl +* Netlink Sockets +* UDP Sockets + +Among these: + +| Interface | Purpose | +| --------- | ---------------------------------- | +| Procfs | Process and system information | +| Sysfs | Device and driver information | +| Debugfs | Debugging information | +| IOCTL | Device-specific control operations | + +Sysfs is the preferred mechanism for exposing device attributes and configuration parameters. + +--- + +# Sysfs Filesystem Layout + +```text +/sys +├── block +├── bus +├── class +├── devices +├── firmware +├── kernel +└── module +``` + +Example: + +```bash +/sys/kernel/ +``` + +--- + +# What is a Kobject? + +The foundation of Sysfs is the Kernel Object (kobject). + +A kobject: + +* Represents a kernel object +* Creates directories in sysfs +* Maintains parent-child relationships +* Supports reference counting +* Connects kernel structures to sysfs + +Defined in: + +```c +#include +``` + +Simplified structure: + +```c +struct kobject +{ + char *name; + struct kobject *parent; + struct kset *kset; + struct kobj_type *ktype; + struct kref kref; +}; +``` + +Important fields: + +| Field | Purpose | +| ------ | ----------------- | +| name | Name of object | +| parent | Parent directory | +| kset | Group of kobjects | +| ktype | Object type | +| kref | Reference counter | + +--- + +# Sysfs Driver Workflow + +```text +Driver Loaded + | + v +Create Kobject + | + v +Create Sysfs File + | + v +User Reads/Writes + | + v +Show/Store Functions Called + | + v +Kernel Variable Updated +``` + +--- + +# Step 1 - Create Sysfs Directory + +Function: + +```c +struct kobject * +kobject_create_and_add( + const char *name, + struct kobject *parent); +``` + +Parameters: + +| Parameter | Description | +| --------- | -------------- | +| name | Directory name | +| parent | Parent kobject | + +--- + +## Common Parents + +### Under /sys + +```c +kobject_create_and_add("mydir", NULL); +``` + +Creates: + +```text +/sys/mydir +``` + +--- + +### Under /sys/kernel + +```c +kobject_create_and_add( + "mydir", + kernel_kobj); +``` + +Creates: + +```text +/sys/kernel/mydir +``` + +--- + +### Under /sys/firmware + +```c +kobject_create_and_add( + "mydir", + firmware_kobj); +``` + +Creates: + +```text +/sys/firmware/mydir +``` + +--- + +### Under /sys/fs + +```c +kobject_create_and_add( + "mydir", + fs_kobj); +``` + +Creates: + +```text +/sys/fs/mydir +``` + +--- + +## Example + +```c +struct kobject *kobj_ref; + +kobj_ref = +kobject_create_and_add( + "etx_sysfs", + kernel_kobj); +``` + +Result: + +```text +/sys/kernel/etx_sysfs +``` + +--- + +# Releasing Kobject + +Always release the kobject: + +```c +kobject_put(kobj_ref); +``` + +--- + +# Step 2 - Create Sysfs File + +After creating a directory, create files inside it. + +Sysfs files are called Attributes. + +Example: + +```text +/sys/kernel/etx_sysfs/etx_value +``` + +--- + +# Attribute Functions + +Every sysfs attribute requires: + +1. Show function (Read) +2. Store function (Write) + +--- + +## Show Function + +Called when: + +```bash +cat attribute_file +``` + +Prototype: + +```c +static ssize_t sysfs_show( + struct kobject *kobj, + struct kobj_attribute *attr, + char *buf); +``` + +Example: + +```c +static ssize_t sysfs_show( + struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + return sprintf(buf,"%d",etx_value); +} +``` + +--- + +## Store Function + +Called when: + +```bash +echo value > attribute_file +``` + +Prototype: + +```c +static ssize_t sysfs_store( + struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, + size_t count); +``` + +Example: + +```c +static ssize_t sysfs_store( + struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, + size_t count) +{ + sscanf(buf,"%d",&etx_value); + return count; +} +``` + +--- + +# Create Attribute + +Macro: + +```c +__ATTR( + name, + permission, + show, + store +); +``` + +Example: + +```c +struct kobj_attribute etx_attr = + __ATTR( + etx_value, + 0660, + sysfs_show, + sysfs_store + ); +``` + +--- + +# File Permissions + +| Permission | Meaning | +| ---------- | --------------------- | +| 0444 | Read only | +| 0664 | Read/Write | +| 0660 | Owner & Group RW | +| 0644 | Owner RW, Others Read | + +Example: + +```c +0660 +``` + +Equivalent: + +```bash +-rw-rw---- +``` + +--- + +# Create Sysfs File + +Function: + +```c +sysfs_create_file( + kobj_ref, + &etx_attr.attr); +``` + +Example: + +```c +if(sysfs_create_file( + kobj_ref, + &etx_attr.attr)) +{ + pr_err("Sysfs creation failed\n"); +} +``` + +Result: + +```text +/sys/kernel/etx_sysfs/etx_value +``` + +--- + +# Remove Sysfs File + +```c +sysfs_remove_file( + kobj_ref, + &etx_attr.attr); +``` + +--- + +# Complete Example + +Kernel variable: + +```c +volatile int etx_value = 0; +``` + +Create directory: + +```c +kobj_ref = +kobject_create_and_add( + "etx_sysfs", + kernel_kobj); +``` + +Create file: + +```c +sysfs_create_file( + kobj_ref, + &etx_attr.attr); +``` + +--- + +# User Space Access + +## Read + +```bash +cat /sys/kernel/etx_sysfs/etx_value +``` + +Output: + +```text +0 +``` + +--- + +## Write + +```bash +echo 123 > \ +/sys/kernel/etx_sysfs/etx_value +``` + +--- + +## Verify + +```bash +cat /sys/kernel/etx_sysfs/etx_value +``` + +Output: + +```text +123 +``` + +--- + +# Build Driver + +Makefile: + +```make +obj-m += driver.o + +KDIR = /lib/modules/$(shell uname -r)/build + +all: + make -C $(KDIR) \ + M=$(shell pwd) modules + +clean: + make -C $(KDIR) \ + M=$(shell pwd) clean +``` + +--- + +# Load Driver + +```bash +sudo insmod driver.ko +``` + +Verify: + +```bash +ls /sys/kernel +``` + +Output: + +```text +etx_sysfs +``` + +--- + +# Unload Driver + +```bash +sudo rmmod driver +``` + +--- + +# Sysfs vs Procfs + +| Feature | Sysfs | Procfs | +| ------------------------ | ----------------- | ----------------------- | +| Purpose | Devices & Drivers | Processes & System Info | +| Location | /sys | /proc | +| Device Model Integration | Yes | No | +| Attribute Based | Yes | No | +| Driver Configuration | Yes | Limited | + +--- + +# Sysfs vs IOCTL + +| Sysfs | IOCTL | +| -------------------- | ------------------ | +| File-based | System call based | +| Human readable | Binary interface | +| Easy debugging | More flexible | +| Simple configuration | Complex operations | + +--- + +# Real Driver Use Cases + +Common sysfs attributes: + +```text +brightness +power +enable +frequency +temperature +fan_speed +voltage +gpio_value +``` + +Examples: + +```text +/sys/class/leds/ +/sys/class/gpio/ +/sys/class/pwm/ +/sys/class/thermal/ +``` + +--- + +# Advantages + +* Simple user-space interface +* Human-readable files +* Easy debugging +* Device model integration +* No custom application required +* Standard Linux mechanism + +--- + +# Limitations + +* One value per file +* Not suitable for large data transfer +* Not suitable for streaming data +* Not suitable for complex commands + +--- + +# Key APIs Summary + +## Kobject APIs + +```c +kobject_create_and_add() +kobject_put() +``` + +## Attribute APIs + +```c +__ATTR() +``` + +## Sysfs APIs + +```c +sysfs_create_file() +sysfs_remove_file() +``` + +## Callback Functions + +```c +show() +store() +``` + +--- + +# Key Takeaways + +* Sysfs is mounted under `/sys`. +* Sysfs exports kernel and device information to user space. +* Every sysfs file maps to a kernel attribute. +* Reading a file invokes the `show()` callback. +* Writing a file invokes the `store()` callback. +* Kobjects create directories in sysfs. +* Sysfs is the preferred interface for driver configuration and status reporting. +* Commonly used in Linux device driver development for exposing device parameters. + +``` +``` + + +## Conclusion This is just a basic linux device driver which explains about the sysfs in linux device driver. Please refer this URL for the complete tutorial of this example source code. -https://embetronicx.com/tutorials/linux/device-drivers/sysfs-in-linux-kernel/ \ No newline at end of file +https://embetronicx.com/tutorials/linux/device-drivers/sysfs-in-linux-kernel/ From 915741a03dec85045bb0f687c6d7442643478e10 Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Fri, 19 Jun 2026 18:04:55 +0530 Subject: [PATCH 22/55] Rename ReadMe.md to README.md --- Linux/Device_Driver/sysfs/{ReadMe.md => README.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Linux/Device_Driver/sysfs/{ReadMe.md => README.md} (100%) diff --git a/Linux/Device_Driver/sysfs/ReadMe.md b/Linux/Device_Driver/sysfs/README.md similarity index 100% rename from Linux/Device_Driver/sysfs/ReadMe.md rename to Linux/Device_Driver/sysfs/README.md From 03ee1b86784b2529a3f7375696f261e4ca6ab3cf Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Fri, 19 Jun 2026 18:07:26 +0530 Subject: [PATCH 23/55] Update and rename ReadMe.md to README.md --- .../Interrupt-in-Linux-Kernel/README.md | 685 ++++++++++++++++++ .../Interrupt-in-Linux-Kernel/ReadMe.md | 4 - 2 files changed, 685 insertions(+), 4 deletions(-) create mode 100644 Linux/Device_Driver/Interrupt-in-Linux-Kernel/README.md delete mode 100644 Linux/Device_Driver/Interrupt-in-Linux-Kernel/ReadMe.md diff --git a/Linux/Device_Driver/Interrupt-in-Linux-Kernel/README.md b/Linux/Device_Driver/Interrupt-in-Linux-Kernel/README.md new file mode 100644 index 0000000..d967e95 --- /dev/null +++ b/Linux/Device_Driver/Interrupt-in-Linux-Kernel/README.md @@ -0,0 +1,685 @@ +# Linux Device Driver - Interrupts + +## Overview + +Interrupts are signals generated by hardware or software that temporarily stop the current CPU execution and force the processor to execute a special function called an: + +* Interrupt Service Routine (ISR) +* Interrupt Handler + +After servicing the interrupt, the CPU resumes its previous execution. + +--- + +# Why Interrupts? + +Without interrupts, the CPU would continuously check devices for events. + +This method is called: + +```text +Polling +``` + +Interrupts allow devices to notify the CPU only when attention is required. + +--- + +# Polling vs Interrupts + +| Polling | Interrupts | +| ------------------------------------- | ----------------------------- | +| CPU continuously checks device status | Device notifies CPU | +| CPU intensive | CPU efficient | +| Wastes processor cycles | Better utilization | +| Higher latency | Faster response | +| Simpler implementation | More efficient implementation | + +Example: + +```text +Polling +-------- +CPU -> Keyboard? +CPU -> Keyboard? +CPU -> Keyboard? + +Interrupt +---------- +Keyboard -> CPU +"Key Pressed!" +``` + +--- + +# What Happens During an Interrupt? + +```text +Hardware Event + | + v +Interrupt Controller + | + v +CPU Receives Interrupt + | + v +Current Execution Paused + | + v +ISR Executes + | + v +Interrupt Serviced + | + v +Resume Previous Task +``` + +### Detailed Flow + +1. Hardware generates interrupt. +2. Interrupt controller receives request. +3. Controller signals CPU. +4. CPU saves current execution context. +5. CPU jumps to ISR. +6. ISR handles the event. +7. CPU restores previous context. +8. Execution resumes. + +--- + +# Interrupt Sources + +Common interrupt-generating devices: + +* Keyboard +* Mouse +* UART +* SPI Controller +* I2C Controller +* Network Interface Card +* USB Controller +* DMA Controller +* GPIO Events +* Timers + +--- + +# Interrupt Terminology + +## IRQ + +IRQ stands for: + +```text +Interrupt Request +``` + +Each interrupt source is assigned an IRQ number. + +Example: + +```text +IRQ 1 -> Keyboard +IRQ 14 -> SATA Controller +IRQ 16 -> Network Card +``` + +--- + +# Interrupts vs Exceptions + +## Interrupts + +Generated externally by hardware. + +Examples: + +* Keyboard press +* UART RX data +* Timer expiry + +## Exceptions + +Generated internally by CPU. + +Examples: + +* Divide by zero +* Page fault +* Segmentation fault +* Invalid instruction + +```text +Interrupt -> External Event +Exception -> Internal CPU Event +``` + +--- + +# Types of Interrupts + +## Maskable Interrupt + +Can be enabled or disabled. + +Examples: + +```text +UART +Keyboard +Network +GPIO +``` + +--- + +## Non-Maskable Interrupt (NMI) + +Cannot be disabled. + +Used for: + +```text +Hardware failure +Critical system errors +``` + +--- + +# Types of Exceptions + +## Fault + +Correctable exception. + +Examples: + +```text +Page Fault +Divide By Zero +Segmentation Fault +``` + +--- + +## Trap + +Generated after instruction execution. + +Examples: + +```text +Breakpoint +Debug Exception +``` + +--- + +## Abort + +Serious hardware failure. + +Examples: + +```text +Machine Check Error +Memory Failure +``` + +--- + +# Interrupt Handler (ISR) + +Interrupt Service Routine is a function executed when an interrupt occurs. + +Characteristics: + +* Executes immediately +* Must be fast +* Cannot sleep +* Runs in interrupt context + +Example: + +```c +static irqreturn_t irq_handler( + int irq, + void *dev_id) +{ + printk("Interrupt Occurred\n"); + + return IRQ_HANDLED; +} +``` + +--- + +# Process Context vs Interrupt Context + +## Process Context + +Normal process execution. + +Examples: + +```text +read() +write() +open() +system calls +``` + +Properties: + +* Can sleep +* Can schedule +* Can use mutexes + +--- + +## Interrupt Context + +ISR execution. + +Properties: + +* Cannot sleep +* Cannot block +* Cannot acquire mutex +* Must finish quickly + +```text +Process Context + | + +--> Sleep Allowed + +Interrupt Context + | + +--> Sleep Not Allowed +``` + +--- + +# Restrictions Inside ISR + +The following operations are NOT allowed: + +```text +sleep() +msleep() +mutex_lock() +copy_to_user() +copy_from_user() +long processing loops +``` + +Reason: + +```text +Interrupts must complete quickly. +``` + +--- + +# Top Half and Bottom Half + +Large interrupt processing is split into two parts. + +```text +Interrupt + | + +----> Top Half + | + +----> Bottom Half +``` + +--- + +# Top Half + +Runs immediately after interrupt. + +Responsibilities: + +* Acknowledge interrupt +* Read hardware status +* Clear interrupt source +* Schedule bottom half + +Characteristics: + +```text +Very Fast +Time Critical +Interrupt Context +``` + +--- + +# Bottom Half + +Performs deferred processing. + +Responsibilities: + +* Data processing +* Packet handling +* Lengthy computations + +Characteristics: + +```text +Runs Later +Less Time Critical +Interrupts Enabled +``` + +--- + +# Bottom Half Mechanisms + +Linux provides several mechanisms: + +## Workqueue + +Runs in process context. + +Can sleep. + +```text +ISR -> Queue Work -> Worker Thread +``` + +--- + +## SoftIRQ + +High-performance deferred processing. + +Commonly used by: + +```text +Networking +Block Layer +``` + +--- + +## Tasklet + +Built on SoftIRQ. + +Lightweight deferred execution. + +--- + +## Threaded IRQ + +Interrupt handled by kernel thread. + +Can sleep. + +```text +ISR + | + +--> Kernel Thread +``` + +--- + +# Requesting an Interrupt + +Kernel API: + +```c +int request_irq( + unsigned int irq, + irq_handler_t handler, + unsigned long flags, + const char *name, + void *dev); +``` + +Parameters: + +| Parameter | Description | +| --------- | ----------------- | +| irq | IRQ number | +| handler | ISR function | +| flags | Interrupt flags | +| name | Device name | +| dev | Device identifier | + +--- + +# Example Request IRQ + +```c +ret = request_irq( + irq_number, + irq_handler, + IRQF_SHARED, + "my_device", + &device); +``` + +--- + +# Interrupt Handler Return Values + +## IRQ_HANDLED + +Interrupt successfully processed. + +```c +return IRQ_HANDLED; +``` + +--- + +## IRQ_NONE + +Interrupt not handled. + +```c +return IRQ_NONE; +``` + +--- + +# Freeing an Interrupt + +Always release IRQ during driver removal. + +```c +free_irq( + irq_number, + &device); +``` + +--- + +# Interrupt Processing Example + +```text +UART Receives Data + | + v +UART Generates IRQ + | + v +CPU Stops Current Task + | + v +UART ISR Executes + | + v +Data Copied To Buffer + | + v +Wake Waiting Process + | + v +Resume Previous Task +``` + +--- + +# Viewing Interrupts + +Linux provides interrupt statistics. + +```bash +cat /proc/interrupts +``` + +Example: + +```text +CPU0 + +16: 1024 IO-APIC eth0 +17: 512 IO-APIC uart0 +18: 250 IO-APIC usb1 +``` + +--- + +# Interrupt Flow in Device Driver + +```text +Hardware + | + v +IRQ Generated + | + v +Interrupt Controller + | + v +CPU + | + v +ISR (Top Half) + | + v +Bottom Half + | + v +Wake User Process +``` + +--- + +# Real Embedded Examples + +## UART Driver + +Interrupt on: + +```text +RX Complete +TX Complete +Error Detection +``` + +--- + +## SPI Driver + +Interrupt on: + +```text +Transfer Complete +FIFO Threshold +Error Event +``` + +--- + +## GPIO Driver + +Interrupt on: + +```text +Rising Edge +Falling Edge +Both Edges +``` + +--- + +## Network Driver + +Interrupt on: + +```text +Packet Arrival +Transmission Complete +Link Status Change +``` + +--- + +# Best Practices + +* Keep ISR extremely short. +* Avoid loops inside ISR. +* Never sleep inside ISR. +* Use Workqueues for long processing. +* Acknowledge hardware quickly. +* Protect shared data using spinlocks when required. + +--- + +# Key APIs Summary + +## Interrupt Registration + +```c +request_irq() +free_irq() +``` + +--- + +## Interrupt Return Values + +```c +IRQ_HANDLED +IRQ_NONE +``` + +--- + +## Deferred Processing + +```c +Workqueue +SoftIRQ +Tasklet +Threaded IRQ +``` + +--- + +# Key Takeaways + +* Interrupts are asynchronous events generated by hardware. +* Interrupts are more efficient than polling. +* ISR executes in interrupt context. +* ISR must be short and fast. +* ISR cannot sleep or block. +* Linux splits interrupt handling into Top Half and Bottom Half. +* Deferred work is typically handled using Workqueues, SoftIRQs, Tasklets, or Threaded IRQs. +* Device drivers register ISRs using `request_irq()`. +* Interrupt statistics can be viewed using `/proc/interrupts`. + + +## Conclusion +This is just a basic linux device driver. This will explain about the Interrupts in the linux device driver. + +Please refer this URL for the complete tutorial of this source code. +https://embetronicx.com/tutorials/linux/device-drivers/linux-device-driver-tutorial-part-13-interrupt-example-program-in-linux-kernel/ diff --git a/Linux/Device_Driver/Interrupt-in-Linux-Kernel/ReadMe.md b/Linux/Device_Driver/Interrupt-in-Linux-Kernel/ReadMe.md deleted file mode 100644 index 79b72ba..0000000 --- a/Linux/Device_Driver/Interrupt-in-Linux-Kernel/ReadMe.md +++ /dev/null @@ -1,4 +0,0 @@ -This is just a basic linux device driver. This will explain about the Interrupts in the linux device driver. - -Please refer this URL for the complete tutorial of this source code. -https://embetronicx.com/tutorials/linux/device-drivers/linux-device-driver-tutorial-part-13-interrupt-example-program-in-linux-kernel/ \ No newline at end of file From a1092c9f2c1ee6f6ac7eef877e4cd744324dddc3 Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Fri, 19 Jun 2026 18:14:28 +0530 Subject: [PATCH 24/55] Update README.md --- .../Interrupt-in-Linux-Kernel/README.md | 578 ++++++++++++++++++ 1 file changed, 578 insertions(+) diff --git a/Linux/Device_Driver/Interrupt-in-Linux-Kernel/README.md b/Linux/Device_Driver/Interrupt-in-Linux-Kernel/README.md index d967e95..b86535f 100644 --- a/Linux/Device_Driver/Interrupt-in-Linux-Kernel/README.md +++ b/Linux/Device_Driver/Interrupt-in-Linux-Kernel/README.md @@ -677,6 +677,584 @@ Threaded IRQ * Device drivers register ISRs using `request_irq()`. * Interrupt statistics can be viewed using `/proc/interrupts`. +# Linux Device Driver - Interrupt Example Program + +## Overview + +This example demonstrates how to: + +* Register an Interrupt Service Routine (ISR) +* Handle interrupts in a Linux device driver +* Use `request_irq()` +* Use `free_irq()` +* Trigger a software-generated interrupt for testing +* Observe interrupt execution through kernel logs + +The example uses **IRQ 11** and a character device driver. Instead of real hardware, the interrupt is generated through software for learning purposes. + +--- + +# Learning Objectives + +After completing this example, you should understand: + +* IRQ registration +* IRQ release +* Interrupt handler implementation +* Shared interrupts +* Software-triggered interrupts +* Interrupt debugging using `dmesg` + +--- + +# Interrupt Handler + +An Interrupt Service Routine (ISR) executes whenever the registered IRQ occurs. + +```c +#define IRQ_NO 11 + +static irqreturn_t irq_handler( + int irq, + void *dev_id) +{ + printk(KERN_INFO + "Shared IRQ: Interrupt Occurred\n"); + + return IRQ_HANDLED; +} +``` + +### Parameters + +| Parameter | Description | +| --------- | ------------------------- | +| irq | IRQ number that triggered | +| dev_id | Device-specific pointer | + +### Return Values + +```c +IRQ_HANDLED +``` + +Interrupt processed successfully. + +```c +IRQ_NONE +``` + +Interrupt not for this device. + +--- + +# Important Interrupt APIs + +## request_irq() + +Registers an interrupt handler. + +```c +int request_irq( + unsigned int irq, + irq_handler_t handler, + unsigned long flags, + const char *name, + void *dev_id +); +``` + +### Parameters + +| Parameter | Description | +| --------- | --------------------- | +| irq | IRQ number | +| handler | ISR function | +| flags | IRQ flags | +| name | Device name | +| dev_id | Unique device pointer | + +### Example + +```c +if (request_irq( + IRQ_NO, + irq_handler, + IRQF_SHARED, + "etx_device", + (void *)irq_handler)) +{ + printk(KERN_INFO + "Cannot register IRQ\n"); +} +``` + +`request_irq()` may sleep and therefore cannot be called from interrupt context. + +--- + +## free_irq() + +Releases a previously registered interrupt. + +```c +free_irq( + IRQ_NO, + (void *)irq_handler +); +``` + +Always call this during module removal. + +--- + +# Common IRQ Flags + +## IRQF_SHARED + +Allows multiple devices to share the same interrupt line. + +```c +IRQF_SHARED +``` + +When shared IRQs are used: + +* Every handler gets called +* Each handler determines if interrupt belongs to it +* Unique `dev_id` is required + +```c +request_irq( + IRQ_NO, + irq_handler, + IRQF_SHARED, + "etx_device", + dev_id); +``` + +--- + +# Driver Initialization Flow + +```text +Module Load + | + v +Register Character Device + | + v +Create Device Class + | + v +Create Device Node + | + v +Create Sysfs Entry + | + v +Register IRQ + | + v +Ready To Receive Interrupts +``` + +--- + +# Registering the Interrupt + +Inside driver initialization: + +```c +if (request_irq( + IRQ_NO, + irq_handler, + IRQF_SHARED, + "etx_device", + (void *)irq_handler)) +{ + printk(KERN_INFO + "Cannot register IRQ\n"); + + goto irq_error; +} +``` + +If successful: + +```text +IRQ 11 Registered +``` + +--- + +# Triggering Interrupt Without Hardware + +Normally: + +```text +Hardware + | + v +Interrupt Controller + | + v +CPU + | + v +ISR +``` + +For learning purposes, the tutorial uses a software interrupt. + +--- + +## x86 Interrupt Vector Mapping + +Linux maps IRQs to interrupt vectors. + +Example: + +```text +FIRST_EXTERNAL_VECTOR = 0x20 + +IRQ0 -> Vector 0x30 +IRQ11 -> Vector 0x3B +``` + +Therefore: + +```asm +int $0x3B +``` + +raises IRQ11 in the example. + +--- + +# Trigger Location + +Interrupt is generated when user reads: + +```bash +cat /dev/etx_device +``` + +Inside the driver's read function: + +```c +asm("int $0x3B"); +``` + +This invokes the ISR and demonstrates interrupt handling without external hardware. + +--- + +# Interrupt Execution Flow + +```text +User Executes: + +cat /dev/etx_device + + | + v + +Driver Read Function + + | + v + +Software Interrupt + + | + v + +IRQ 11 Triggered + + | + v + +irq_handler() + + | + v + +"Shared IRQ: Interrupt Occurred" + + | + v + +Return IRQ_HANDLED +``` + +--- + +# Driver Cleanup + +During module removal: + +```c +free_irq( + IRQ_NO, + (void *)irq_handler +); +``` + +Complete cleanup: + +```c +static void __exit etx_driver_exit(void) +{ + free_irq( + IRQ_NO, + (void *)irq_handler); + + kobject_put(kobj_ref); + + device_destroy( + dev_class, + dev); + + class_destroy(dev_class); + + cdev_del(&etx_cdev); + + unregister_chrdev_region( + dev, + 1); +} +``` + +--- + +# Build Driver + +## Makefile + +```make +obj-m += driver.o + +KDIR = /lib/modules/$(shell uname -r)/build + +all: + make -C $(KDIR) M=$(PWD) modules + +clean: + make -C $(KDIR) M=$(PWD) clean +``` + +--- + +## Compile + +```bash +make +``` + +--- + +# Load Driver + +```bash +sudo insmod driver.ko +``` + +Verify: + +```bash +dmesg +``` + +Expected: + +```text +Device Driver Insert...Done!!! +``` + +--- + +# Trigger Interrupt + +Read the device file: + +```bash +sudo cat /dev/etx_device +``` + +This executes: + +```text +Read Function + | + v +Software Interrupt + | + v +ISR +``` + +--- + +# Verify Using dmesg + +```bash +dmesg +``` + +Example Output: + +```text +Major = 246 Minor = 0 + +Device Driver Insert...Done!!! + +Device File Opened...!!! + +Read function + +Shared IRQ: Interrupt Occurred + +Device File Closed...!!! +``` + +This confirms: + +* Device opened +* Read executed +* Interrupt generated +* ISR executed +* Device closed + +--- + +# View System Interrupt Statistics + +```bash +cat /proc/interrupts +``` + +Example: + +```text +CPU0 + +11: 25 IO-APIC etx_device +``` + +Shows: + +* IRQ number +* Number of occurrences +* Device using IRQ + +--- + +# Important Rules for ISR + +### Allowed + +* Read hardware status +* Clear interrupt flag +* Wake wait queue +* Schedule workqueue +* Update counters + +### Avoid + +```c +msleep() +schedule() +mutex_lock() +copy_to_user() +copy_from_user() +``` + +Reason: + +```text +ISR executes in interrupt context. +Sleeping is not allowed. +``` + +--- + +# Real Hardware Equivalent + +Instead of: + +```asm +int $0x3B +``` + +a real driver receives interrupts from: + +```text +GPIO Edge + +UART RX Complete + +SPI Transfer Complete + +I2C Event + +DMA Completion + +Timer Expiry + +Network Packet Arrival + +USB Events +``` + +The same ISR registration process is used. + +--- + +# Key APIs Summary + +## Interrupt Registration + +```c +request_irq() +free_irq() +``` + +## Interrupt Status + +```c +IRQ_HANDLED +IRQ_NONE +``` + +## Common Flags + +```c +IRQF_SHARED +IRQF_TIMER +IRQF_DISABLED +``` + +## Debugging + +```bash +dmesg +cat /proc/interrupts +``` + +--- + +# Key Takeaways + +* `request_irq()` registers an ISR with the kernel. +* `free_irq()` releases the interrupt during cleanup. +* ISR must return `IRQ_HANDLED` or `IRQ_NONE`. +* ISR runs in interrupt context and must not sleep. +* The tutorial demonstrates interrupts without hardware using a software-generated interrupt. +* Reading `/dev/etx_device` triggers IRQ11. +* Interrupt activity can be verified using `dmesg`. +* Real device drivers use the same mechanism with GPIO, UART, SPI, I2C, DMA, and other hardware interrupts. + ## Conclusion This is just a basic linux device driver. This will explain about the Interrupts in the linux device driver. From a3d3ad4f40639b920c07c6053fdbb857cf8035ba Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Fri, 19 Jun 2026 18:18:35 +0530 Subject: [PATCH 25/55] Create README.md --- .../Static_Method/README.md | 661 ++++++++++++++++++ 1 file changed, 661 insertions(+) create mode 100644 Linux/Device_Driver/Waitqueue-Tutorial/Static_Method/README.md diff --git a/Linux/Device_Driver/Waitqueue-Tutorial/Static_Method/README.md b/Linux/Device_Driver/Waitqueue-Tutorial/Static_Method/README.md new file mode 100644 index 0000000..2dc2951 --- /dev/null +++ b/Linux/Device_Driver/Waitqueue-Tutorial/Static_Method/README.md @@ -0,0 +1,661 @@ +# Linux Device Driver - Workqueue in Linux Kernel + +## Overview + +A Workqueue is a Linux kernel mechanism used to defer work from interrupt context to process context. + +It is one of the Linux **Bottom Half** mechanisms. + +When an interrupt occurs, the Interrupt Service Routine (ISR) should execute quickly. Any time-consuming work should be postponed to a Workqueue. Workqueues execute the deferred work in kernel worker threads (`kworker`) running in process context. + +--- + +# Why Workqueue? + +Interrupt handlers have strict limitations: + +* Must execute quickly +* Cannot sleep +* Cannot perform lengthy processing + +Workqueues solve this by moving heavy work out of the ISR. The deferred work executes later in process context where sleeping is allowed. + +--- + +# Top Half vs Bottom Half + +```text +Interrupt Occurs + | + v ++------------------+ +| Top Half (ISR) | ++------------------+ + | + v +Schedule Work + | + v ++------------------+ +| Bottom Half | +| Workqueue | ++------------------+ + | + v +Deferred Processing +``` + +Workqueue is a Bottom Half mechanism. + +--- + +# Linux Bottom Half Mechanisms + +Linux provides: + +1. Workqueue +2. Threaded IRQ +3. SoftIRQ +4. Tasklet + +| Mechanism | Context | Can Sleep | +| ------------ | --------------- | --------- | +| Workqueue | Process Context | Yes | +| Threaded IRQ | Process Context | Yes | +| SoftIRQ | Atomic Context | No | +| Tasklet | Atomic Context | No | + +Workqueues are preferred when deferred work must sleep or block. + +--- + +# Workqueue Architecture + +```text +Hardware Interrupt + | + v +Interrupt Handler + | + v +schedule_work() + | + v +Global Workqueue + | + v +kworker Thread + | + v +Workqueue Function +``` + +--- + +# Key Structures + +Header File: + +```c +#include +``` + +--- + +## work_struct + +Represents a work item. + +```c +struct work_struct +``` + +Each work item contains: + +* Work information +* Callback function +* Scheduling information + +--- + +## workqueue_struct + +Represents the actual workqueue. + +```c +struct workqueue_struct +``` + +Used when creating dedicated workqueues. + +--- + +# Methods of Using Workqueue + +Two approaches: + +## 1. Global Workqueue + +Uses kernel-provided worker threads. + +```text +Driver + | + v +Kernel Global Workqueue + | + v +kworker Thread +``` + +No custom workqueue creation required. + +--- + +## 2. Custom Workqueue + +Driver creates its own workqueue. + +```text +Driver + | + v +Own Workqueue + | + v +Dedicated Worker Thread +``` + +Provides better isolation and control. + +--- + +# Static Work Initialization + +## DECLARE_WORK() + +Creates and initializes work statically. + +```c +DECLARE_WORK(name, function); +``` + +Example: + +```c +void workqueue_fn(struct work_struct *work); + +DECLARE_WORK(my_work, workqueue_fn); +``` + +--- + +# Dynamic Work Initialization + +## INIT_WORK() + +Initialize work dynamically. + +```c +INIT_WORK( + &my_work, + workqueue_fn); +``` + +Example: + +```c +struct work_struct my_work; + +INIT_WORK( + &my_work, + workqueue_fn); +``` + +--- + +# Workqueue Callback Function + +Executed by the worker thread. + +```c +void workqueue_fn( + struct work_struct *work) +{ + printk(KERN_INFO + "Workqueue Executed\n"); +} +``` + +This function performs deferred processing. + +--- + +# Scheduling Work + +## schedule_work() + +Queue work to the kernel global workqueue. + +```c +schedule_work(&my_work); +``` + +Returns: + +```text +0 -> Already queued +1 -> Successfully queued +``` + +--- + +## schedule_delayed_work() + +Schedule work after a delay. + +```c +schedule_delayed_work( + &my_dwork, + delay); +``` + +Example: + +```c +schedule_delayed_work( + &my_dwork, + msecs_to_jiffies(5000)); +``` + +--- + +## schedule_work_on() + +Queue work on a specific CPU. + +```c +schedule_work_on( + cpu, + &my_work); +``` + +--- + +# Delayed Work + +Used when execution should occur later. + +Structure: + +```c +struct delayed_work +``` + +Example: + +```c +struct delayed_work my_dwork; +``` + +Initialization: + +```c +INIT_DELAYED_WORK( + &my_dwork, + workqueue_fn); +``` + +--- + +# Workqueue Example with Interrupt + +ISR: + +```c +static irqreturn_t irq_handler( + int irq, + void *dev_id) +{ + schedule_work(&my_work); + + return IRQ_HANDLED; +} +``` + +Workqueue Function: + +```c +void workqueue_fn( + struct work_struct *work) +{ + printk("Deferred Work\n"); +} +``` + +Execution Flow: + +```text +Interrupt + | + v +ISR + | + v +schedule_work() + | + v +kworker Thread + | + v +workqueue_fn() +``` + +--- + +# Flushing Workqueue + +Wait until work completes. + +## flush_work() + +```c +flush_work(&my_work); +``` + +Blocks until the work finishes. + +--- + +## flush_scheduled_work() + +Flush all global workqueue items. + +```c +flush_scheduled_work(); +``` + +--- + +# Cancel Work + +## cancel_work_sync() + +Cancel pending work. + +```c +cancel_work_sync( + &my_work); +``` + +If already running, waits for completion. + +--- + +## cancel_delayed_work_sync() + +Cancel delayed work. + +```c +cancel_delayed_work_sync( + &my_dwork); +``` + +--- + +# Check Pending Work + +## work_pending() + +```c +work_pending( + &my_work); +``` + +Returns whether work is pending. + +--- + +## delayed_work_pending() + +```c +delayed_work_pending( + &my_dwork); +``` + +--- + +# Creating Own Workqueue + +## create_workqueue() + +Create dedicated workqueue. + +```c +struct workqueue_struct *wq; + +wq = create_workqueue( + "my_wq"); +``` + +Internally implemented using `alloc_workqueue()`. + +--- + +## create_singlethread_workqueue() + +Single worker thread. + +```c +wq = +create_singlethread_workqueue( + "my_wq"); +``` + +--- + +# Queue Work to Custom Workqueue + +## queue_work() + +```c +queue_work( + wq, + &my_work); +``` + +Queues work into a custom workqueue. + +--- + +## queue_delayed_work() + +```c +queue_delayed_work( + wq, + &my_dwork, + delay); +``` + +--- + +# Destroy Workqueue + +```c +destroy_workqueue(wq); +``` + +Always destroy custom workqueues during driver removal. + +--- + +# schedule_work() vs queue_work() + +| schedule_work() | queue_work() | +| --------------------- | --------------------------- | +| Uses global workqueue | Uses custom workqueue | +| No creation required | Requires workqueue creation | +| Shared worker thread | Dedicated worker thread | +| Simple | More control | + +--- + +# Process Context Advantages + +Since workqueue runs in process context: + +Allowed: + +```c +msleep(); +mutex_lock(); +schedule(); +wait_event(); +``` + +Not possible inside ISR. + +Workqueues are suitable for: + +* File operations +* Memory allocation +* Waiting for events +* Blocking I/O +* Long computations + +--- + +# Common Driver Use Cases + +## Network Driver + +```text +ISR + | + +--> Schedule packet processing +``` + +--- + +## GPIO Driver + +```text +Button Interrupt + | + +--> Debounce in Workqueue +``` + +--- + +## SPI Driver + +```text +Transfer Complete + | + +--> Post-processing +``` + +--- + +## USB Driver + +```text +USB Event + | + +--> Heavy Processing +``` + +--- + +# Debugging + +View worker threads: + +```bash +ps -ef | grep kworker +``` + +Kernel logs: + +```bash +dmesg +``` + +Trace workqueue activity: + +```bash +cat /sys/kernel/debug/tracing/trace_pipe +``` + +Workqueue processing is executed by kernel worker threads (`kworker`). + +--- + +# Best Practices + +* Keep ISR extremely short. +* Use workqueue for lengthy operations. +* Use dedicated workqueue for heavy workloads. +* Flush or cancel work before unloading driver. +* Avoid blocking the shared global workqueue for long periods. +* Use delayed work when timing control is needed. + +--- + +# Important APIs Summary + +## Work Initialization + +```c +DECLARE_WORK() +INIT_WORK() +INIT_DELAYED_WORK() +``` + +--- + +## Global Workqueue + +```c +schedule_work() +schedule_delayed_work() +schedule_work_on() +``` + +--- + +## Custom Workqueue + +```c +create_workqueue() +create_singlethread_workqueue() +queue_work() +queue_delayed_work() +destroy_workqueue() +``` + +--- + +## Management + +```c +flush_work() +flush_scheduled_work() +cancel_work_sync() +cancel_delayed_work_sync() +work_pending() +delayed_work_pending() +``` + +--- + +# Key Takeaways + +* Workqueue is a Linux Bottom Half mechanism. +* Workqueue executes deferred work in process context. +* Workqueue can sleep, unlike ISR, SoftIRQ, and Tasklets. +* `schedule_work()` uses the global kernel workqueue. +* `queue_work()` uses a custom workqueue. +* Workqueues are executed by `kworker` kernel threads. +* Workqueue is the preferred mechanism when deferred work requires sleeping or blocking operations. +* Frequently used with interrupts to move heavy processing out of the ISR. From 15067622d75fa8b68f70c0b7ca30f20b56553609 Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Fri, 19 Jun 2026 18:23:06 +0530 Subject: [PATCH 26/55] Update README.md --- .../Static_Method/README.md | 700 +++++++++--------- 1 file changed, 336 insertions(+), 364 deletions(-) diff --git a/Linux/Device_Driver/Waitqueue-Tutorial/Static_Method/README.md b/Linux/Device_Driver/Waitqueue-Tutorial/Static_Method/README.md index 2dc2951..0208905 100644 --- a/Linux/Device_Driver/Waitqueue-Tutorial/Static_Method/README.md +++ b/Linux/Device_Driver/Waitqueue-Tutorial/Static_Method/README.md @@ -1,24 +1,28 @@ -# Linux Device Driver - Workqueue in Linux Kernel +# Linux Device Driver - Tasklet (Static Method) ## Overview -A Workqueue is a Linux kernel mechanism used to defer work from interrupt context to process context. +A Tasklet is a Linux kernel **Bottom Half** mechanism used to defer work from an Interrupt Service Routine (ISR). -It is one of the Linux **Bottom Half** mechanisms. +When an interrupt occurs: -When an interrupt occurs, the Interrupt Service Routine (ISR) should execute quickly. Any time-consuming work should be postponed to a Workqueue. Workqueues execute the deferred work in kernel worker threads (`kworker`) running in process context. +* ISR (Top Half) executes immediately. +* Time-consuming work is deferred to a Tasklet (Bottom Half). +* Tasklets run later with interrupts enabled. + +Tasklets execute in **atomic context**, not process context. Therefore they cannot sleep or block. --- -# Why Workqueue? +# Why Tasklets? -Interrupt handlers have strict limitations: +Interrupt handlers should: -* Must execute quickly -* Cannot sleep -* Cannot perform lengthy processing +* Execute quickly +* Avoid lengthy processing +* Return control to the kernel as soon as possible -Workqueues solve this by moving heavy work out of the ISR. The deferred work executes later in process context where sleeping is allowed. +Tasklets allow deferred execution of non-critical interrupt-related work. --- @@ -26,523 +30,521 @@ Workqueues solve this by moving heavy work out of the ISR. The deferred work exe ```text Interrupt Occurs - | - v -+------------------+ -| Top Half (ISR) | -+------------------+ - | - v -Schedule Work - | - v -+------------------+ -| Bottom Half | -| Workqueue | -+------------------+ - | - v -Deferred Processing -``` - -Workqueue is a Bottom Half mechanism. - ---- - -# Linux Bottom Half Mechanisms - -Linux provides: - -1. Workqueue -2. Threaded IRQ -3. SoftIRQ -4. Tasklet - -| Mechanism | Context | Can Sleep | -| ------------ | --------------- | --------- | -| Workqueue | Process Context | Yes | -| Threaded IRQ | Process Context | Yes | -| SoftIRQ | Atomic Context | No | -| Tasklet | Atomic Context | No | - -Workqueues are preferred when deferred work must sleep or block. - ---- - -# Workqueue Architecture - -```text -Hardware Interrupt - | - v -Interrupt Handler | v -schedule_work() ++----------------+ +| ISR (Top Half) | ++----------------+ | v -Global Workqueue +Schedule Tasklet | v -kworker Thread ++-------------------+ +| Tasklet | +| (Bottom Half) | ++-------------------+ | v -Workqueue Function +Deferred Processing ``` --- -# Key Structures +# Linux Bottom Half Mechanisms -Header File: +Linux provides multiple Bottom Half mechanisms: -```c -#include -``` +| Mechanism | Context | Sleep Allowed | +| ------------ | --------------- | ------------- | +| Workqueue | Process Context | Yes | +| Threaded IRQ | Process Context | Yes | +| SoftIRQ | Atomic Context | No | +| Tasklet | Atomic Context | No | + +Tasklets are built on top of SoftIRQs. --- -## work_struct +# Important Characteristics -Represents a work item. +## Tasklets are Atomic + +Not allowed: ```c -struct work_struct +sleep(); +msleep(); +mutex_lock(); +down(); +wait_event(); ``` -Each work item contains: +Allowed: -* Work information -* Callback function -* Scheduling information +```c +spin_lock(); +spin_unlock(); +``` --- -## workqueue_struct +## CPU Affinity -Represents the actual workqueue. +A tasklet executes only on the CPU that scheduled it. -```c -struct workqueue_struct +```text +CPU0 Schedules Tasklet + | + v +Tasklet Runs On CPU0 ``` -Used when creating dedicated workqueues. - --- -# Methods of Using Workqueue +## No Self-Concurrency -Two approaches: - -## 1. Global Workqueue - -Uses kernel-provided worker threads. +A tasklet cannot execute simultaneously on multiple CPUs. ```text -Driver - | - v -Kernel Global Workqueue - | - v -kworker Thread -``` +Same Tasklet + | + +--> CPU0 (Running) -No custom workqueue creation required. +CPU1 Cannot Run Same Tasklet +Until CPU0 Completes +``` --- -## 2. Custom Workqueue - -Driver creates its own workqueue. +## Different Tasklets Can Run Concurrently ```text -Driver - | - v -Own Workqueue - | - v -Dedicated Worker Thread +Tasklet A --> CPU0 + +Tasklet B --> CPU1 ``` -Provides better isolation and control. +Possible and supported. --- -# Static Work Initialization - -## DECLARE_WORK() +# Tasklet Structure -Creates and initializes work statically. +Defined in: ```c -DECLARE_WORK(name, function); +#include ``` -Example: +Structure: ```c -void workqueue_fn(struct work_struct *work); - -DECLARE_WORK(my_work, workqueue_fn); +struct tasklet_struct +{ + struct tasklet_struct *next; + unsigned long state; + atomic_t count; + void (*func)(unsigned long); + unsigned long data; +}; ``` ---- +Field Description: -# Dynamic Work Initialization +| Field | Purpose | +| ----- | ----------------------- | +| next | Next tasklet | +| state | Running/Scheduled state | +| count | Disable counter | +| func | Callback function | +| data | Data passed to callback | -## INIT_WORK() +--- -Initialize work dynamically. +# Static Tasklet Creation -```c -INIT_WORK( - &my_work, - workqueue_fn); -``` +## DECLARE_TASKLET() -Example: +Creates and initializes a tasklet. -```c -struct work_struct my_work; +Syntax: -INIT_WORK( - &my_work, - workqueue_fn); +```c +DECLARE_TASKLET( + name, + function, + data); ``` ---- +Parameters: -# Workqueue Callback Function +| Parameter | Description | +| --------- | --------------------------- | +| name | Tasklet object | +| function | Callback function | +| data | Argument passed to callback | -Executed by the worker thread. +Example: ```c -void workqueue_fn( - struct work_struct *work) -{ - printk(KERN_INFO - "Workqueue Executed\n"); -} +void tasklet_fn(unsigned long); + +DECLARE_TASKLET( + tasklet, + tasklet_fn, + 1); ``` -This function performs deferred processing. +This tasklet is created in the enabled state. --- -# Scheduling Work +# Disabled Tasklet Creation -## schedule_work() +## DECLARE_TASKLET_DISABLED() -Queue work to the kernel global workqueue. +Creates a disabled tasklet. ```c -schedule_work(&my_work); +DECLARE_TASKLET_DISABLED( + tasklet, + tasklet_fn, + 1); ``` -Returns: +Tasklet will not run until enabled. -```text -0 -> Already queued -1 -> Successfully queued +```c +tasklet_enable(&tasklet); ``` --- -## schedule_delayed_work() +# Tasklet Callback Function -Schedule work after a delay. +This function performs deferred processing. ```c -schedule_delayed_work( - &my_dwork, - delay); +void tasklet_fn( + unsigned long arg) +{ + printk( + "Executing Tasklet : %ld\n", + arg); +} ``` -Example: +Parameter: ```c -schedule_delayed_work( - &my_dwork, - msecs_to_jiffies(5000)); +unsigned long arg ``` ---- +Receives the value passed during creation. -## schedule_work_on() +--- -Queue work on a specific CPU. +# Enable Tasklet ```c -schedule_work_on( - cpu, - &my_work); +tasklet_enable( + &tasklet); ``` +Enables execution of the tasklet. + --- -# Delayed Work +# Disable Tasklet -Used when execution should occur later. +## tasklet_disable() -Structure: +Waits for running tasklet to finish. ```c -struct delayed_work +tasklet_disable( + &tasklet); ``` -Example: +--- -```c -struct delayed_work my_dwork; -``` +## tasklet_disable_nosync() -Initialization: +Disables immediately. ```c -INIT_DELAYED_WORK( - &my_dwork, - workqueue_fn); +tasklet_disable_nosync( + &tasklet); ``` +Does not wait for completion. + --- -# Workqueue Example with Interrupt +# Schedule Tasklet -ISR: +## tasklet_schedule() -```c -static irqreturn_t irq_handler( - int irq, - void *dev_id) -{ - schedule_work(&my_work); +Schedules tasklet with normal priority. - return IRQ_HANDLED; -} +```c +tasklet_schedule( + &tasklet); ``` -Workqueue Function: +Example: ```c -void workqueue_fn( - struct work_struct *work) -{ - printk("Deferred Work\n"); -} +tasklet_schedule( + &tasklet); ``` -Execution Flow: +If already scheduled but not executed: ```text -Interrupt - | - v -ISR - | - v -schedule_work() - | - v -kworker Thread - | - v -workqueue_fn() +New schedule request ignored ``` --- -# Flushing Workqueue +# High Priority Scheduling -Wait until work completes. +## tasklet_hi_schedule() -## flush_work() +Schedules tasklet with high priority. ```c -flush_work(&my_work); +tasklet_hi_schedule( + &tasklet); ``` -Blocks until the work finishes. - --- -## flush_scheduled_work() +## tasklet_hi_schedule_first() -Flush all global workqueue items. +Special version used in specific kernel scenarios. ```c -flush_scheduled_work(); +tasklet_hi_schedule_first( + &tasklet); ``` --- -# Cancel Work +# Tasklet Priorities -## cancel_work_sync() +Linux supports: -Cancel pending work. - -```c -cancel_work_sync( - &my_work); +```text +Normal Priority +High Priority ``` -If already running, waits for completion. +Each CPU maintains its own tasklet queues. + +```text +CPU0 + | + +--> Normal Queue + | + +--> High Priority Queue + +CPU1 + | + +--> Normal Queue + | + +--> High Priority Queue +``` --- -## cancel_delayed_work_sync() +# Kill Tasklet -Cancel delayed work. +## tasklet_kill() + +Waits for completion and removes tasklet. ```c -cancel_delayed_work_sync( - &my_dwork); +tasklet_kill( + &tasklet); ``` ---- - -# Check Pending Work +Always call during module removal. -## work_pending() +Example: ```c -work_pending( - &my_work); +tasklet_kill( + &tasklet); ``` -Returns whether work is pending. - --- -## delayed_work_pending() +## tasklet_kill_immediate() + +Used when CPU is dead/offline. ```c -delayed_work_pending( - &my_dwork); +tasklet_kill_immediate( + &tasklet, + cpu); ``` --- -# Creating Own Workqueue - -## create_workqueue() +# Interrupt + Tasklet Example -Create dedicated workqueue. +## Tasklet Definition ```c -struct workqueue_struct *wq; +void tasklet_fn( + unsigned long arg); -wq = create_workqueue( - "my_wq"); +DECLARE_TASKLET( + tasklet, + tasklet_fn, + 1); ``` -Internally implemented using `alloc_workqueue()`. - --- -## create_singlethread_workqueue() - -Single worker thread. +## Tasklet Function ```c -wq = -create_singlethread_workqueue( - "my_wq"); +void tasklet_fn( + unsigned long arg) +{ + printk( + "Executing Tasklet Function : arg=%ld\n", + arg); +} ``` --- -# Queue Work to Custom Workqueue - -## queue_work() +## Interrupt Handler ```c -queue_work( - wq, - &my_work); +static irqreturn_t irq_handler( + int irq, + void *dev_id) +{ + printk( + "Interrupt Occurred\n"); + + tasklet_schedule( + &tasklet); + + return IRQ_HANDLED; +} ``` -Queues work into a custom workqueue. +ISR schedules the tasklet instead of performing lengthy processing. --- -## queue_delayed_work() +# Execution Flow -```c -queue_delayed_work( - wq, - &my_dwork, - delay); +```text +User Reads Device + | + v +Software Interrupt + | + v +IRQ Handler + | + v +tasklet_schedule() + | + v +Tasklet Queue + | + v +Tasklet Function Executes ``` --- -# Destroy Workqueue +# Driver Cleanup + +During module unload: ```c -destroy_workqueue(wq); +tasklet_kill( + &tasklet); + +free_irq( + IRQ_NO, + dev_id); ``` -Always destroy custom workqueues during driver removal. +Tasklet must be killed before driver removal. --- -# schedule_work() vs queue_work() +# Sample dmesg Output -| schedule_work() | queue_work() | -| --------------------- | --------------------------- | -| Uses global workqueue | Uses custom workqueue | -| No creation required | Requires workqueue creation | -| Shared worker thread | Dedicated worker thread | -| Simple | More control | +```text +Major = 246 Minor = 0 ---- +Device Driver Insert...Done!!! -# Process Context Advantages +Device File Opened...!!! -Since workqueue runs in process context: +Read function -Allowed: +Shared IRQ: Interrupt Occurred -```c -msleep(); -mutex_lock(); -schedule(); -wait_event(); +Executing Tasklet Function : arg = 1 + +Device File Closed...!!! + +Device Driver Remove...Done!!! ``` -Not possible inside ISR. +This confirms: + +1. Interrupt occurred +2. ISR executed +3. Tasklet scheduled +4. Tasklet function executed -Workqueues are suitable for: +--- -* File operations -* Memory allocation -* Waiting for events -* Blocking I/O -* Long computations +# Tasklet vs Workqueue + +| Feature | Tasklet | Workqueue | +| ----------------- | ------- | --------- | +| Context | Atomic | Process | +| Sleep Allowed | No | Yes | +| Uses kworker | No | Yes | +| Can Block | No | Yes | +| ISR Deferred Work | Yes | Yes | +| Mutex Allowed | No | Yes | +| Spinlock Allowed | Yes | Yes | --- -# Common Driver Use Cases +# Common Use Cases ## Network Driver ```text -ISR - | - +--> Schedule packet processing +Packet Arrival + | + +--> Tasklet Processing ``` --- -## GPIO Driver +## UART Driver ```text -Button Interrupt - | - +--> Debounce in Workqueue +RX Interrupt + | + +--> Buffer Processing ``` --- @@ -552,110 +554,80 @@ Button Interrupt ```text Transfer Complete | - +--> Post-processing + +--> Deferred Processing ``` --- -## USB Driver +## GPIO Driver ```text -USB Event - | - +--> Heavy Processing -``` - ---- - -# Debugging - -View worker threads: - -```bash -ps -ef | grep kworker -``` - -Kernel logs: - -```bash -dmesg -``` - -Trace workqueue activity: - -```bash -cat /sys/kernel/debug/tracing/trace_pipe +Button Interrupt + | + +--> Event Handling ``` -Workqueue processing is executed by kernel worker threads (`kworker`). - --- # Best Practices * Keep ISR extremely short. -* Use workqueue for lengthy operations. -* Use dedicated workqueue for heavy workloads. -* Flush or cancel work before unloading driver. -* Avoid blocking the shared global workqueue for long periods. -* Use delayed work when timing control is needed. +* Schedule tasklets for deferred work. +* Never sleep inside tasklet. +* Use spinlocks instead of mutexes. +* Kill tasklets during driver cleanup. +* Use workqueues if sleeping is required. --- # Important APIs Summary -## Work Initialization +## Creation ```c -DECLARE_WORK() -INIT_WORK() -INIT_DELAYED_WORK() +DECLARE_TASKLET() +DECLARE_TASKLET_DISABLED() ``` --- -## Global Workqueue +## Control ```c -schedule_work() -schedule_delayed_work() -schedule_work_on() +tasklet_enable() +tasklet_disable() +tasklet_disable_nosync() ``` --- -## Custom Workqueue +## Scheduling ```c -create_workqueue() -create_singlethread_workqueue() -queue_work() -queue_delayed_work() -destroy_workqueue() +tasklet_schedule() +tasklet_hi_schedule() +tasklet_hi_schedule_first() ``` --- -## Management +## Removal ```c -flush_work() -flush_scheduled_work() -cancel_work_sync() -cancel_delayed_work_sync() -work_pending() -delayed_work_pending() +tasklet_kill() +tasklet_kill_immediate() ``` --- # Key Takeaways -* Workqueue is a Linux Bottom Half mechanism. -* Workqueue executes deferred work in process context. -* Workqueue can sleep, unlike ISR, SoftIRQ, and Tasklets. -* `schedule_work()` uses the global kernel workqueue. -* `queue_work()` uses a custom workqueue. -* Workqueues are executed by `kworker` kernel threads. -* Workqueue is the preferred mechanism when deferred work requires sleeping or blocking operations. -* Frequently used with interrupts to move heavy processing out of the ISR. +* Tasklets are Linux Bottom Half mechanisms. +* Tasklets execute in atomic context. +* Tasklets cannot sleep or block. +* Same tasklet cannot run concurrently on multiple CPUs. +* Different tasklets can execute in parallel. +* ISR commonly schedules a tasklet for deferred processing. +* Tasklets are lighter than workqueues but more restricted. +* Use workqueues when deferred work requires sleeping. + From 9c1341be7c8b1d0b32a5f75742e08d09618861ec Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Fri, 19 Jun 2026 18:25:32 +0530 Subject: [PATCH 27/55] Create README.md --- .../Dynamic_Method/README.md | 483 ++++++++++++++++++ 1 file changed, 483 insertions(+) create mode 100644 Linux/Device_Driver/Waitqueue-Tutorial/Dynamic_Method/README.md diff --git a/Linux/Device_Driver/Waitqueue-Tutorial/Dynamic_Method/README.md b/Linux/Device_Driver/Waitqueue-Tutorial/Dynamic_Method/README.md new file mode 100644 index 0000000..f4b1bf3 --- /dev/null +++ b/Linux/Device_Driver/Waitqueue-Tutorial/Dynamic_Method/README.md @@ -0,0 +1,483 @@ +# Linux Device Driver - Workqueue (Dynamic Creation Method) + +## Overview + +This tutorial demonstrates **dynamic initialization of a Workqueue work item** using `INIT_WORK()`. + +Unlike the static method: + +```c +DECLARE_WORK(work, work_fn); +``` + +the dynamic method creates a `work_struct` object first and initializes it later using `INIT_WORK()`. + +--- + +# Why Dynamic Workqueue? + +Dynamic initialization is useful when: + +* Work item is part of a structure +* Work item needs runtime initialization +* Driver requires flexible work creation +* Work object cannot be statically declared + +Example: + +```c +struct work_struct workqueue; + +INIT_WORK(&workqueue, workqueue_fn); +``` + +--- + +# Workqueue Architecture + +```text +Hardware Interrupt + | + v +Interrupt Handler (ISR) + | + v +schedule_work() + | + v +Kernel Global Workqueue + | + v +kworker Thread + | + v +workqueue_fn() +``` + +The ISR schedules work and returns immediately. + +The actual processing happens later inside a kernel worker thread. + +--- + +# Header File + +```c +#include +``` + +Required for: + +* work_struct +* INIT_WORK() +* schedule_work() + +--- + +# Workqueue Structure + +```c +struct work_struct workqueue; +``` + +Represents a deferred work item. + +Example: + +```c +static struct work_struct workqueue; +``` + +--- + +# Dynamic Work Initialization + +## INIT_WORK() + +Used to initialize a work item. + +Syntax: + +```c +INIT_WORK(work, function); +``` + +Parameters: + +| Parameter | Description | +| --------- | ------------------ | +| work | work_struct object | +| function | Callback function | + +Example: + +```c +INIT_WORK( + &workqueue, + workqueue_fn); +``` + +--- + +# Workqueue Callback Function + +The callback executes inside a kernel worker thread. + +```c +void workqueue_fn( + struct work_struct *work) +{ + printk(KERN_INFO + "Executing Workqueue Function\n"); +} +``` + +This function performs the deferred processing. + +--- + +# Scheduling Work + +## schedule_work() + +Queues work into the kernel global workqueue. + +Syntax: + +```c +int schedule_work( + struct work_struct *work); +``` + +Example: + +```c +schedule_work(&workqueue); +``` + +Return Value: + +| Value | Meaning | +| -------- | ------------------- | +| 0 | Already queued | +| Non-zero | Successfully queued | + +--- + +# Delayed Scheduling + +## schedule_delayed_work() + +Execute after a delay. + +Syntax: + +```c +schedule_delayed_work( + &dwork, + delay); +``` + +Example: + +```c +schedule_delayed_work( + &dwork, + msecs_to_jiffies(5000)); +``` + +Executes after 5 seconds. + +--- + +# CPU Specific Scheduling + +## schedule_work_on() + +Queues work on a specific CPU. + +Syntax: + +```c +schedule_work_on( + cpu, + &work); +``` + +Example: + +```c +schedule_work_on( + 0, + &workqueue); +``` + +Runs on CPU0. + +--- + +# Interrupt + Workqueue Example + +## Workqueue Function + +```c +void workqueue_fn( + struct work_struct *work) +{ + printk( + KERN_INFO + "Executing Workqueue Function\n"); +} +``` + +--- + +## Interrupt Handler + +```c +static irqreturn_t irq_handler( + int irq, + void *dev_id) +{ + printk( + KERN_INFO + "Shared IRQ: Interrupt Occurred\n"); + + schedule_work( + &workqueue); + + return IRQ_HANDLED; +} +``` + +ISR schedules work and exits immediately. + +--- + +# Driver Initialization + +## Register Interrupt + +```c +request_irq( + IRQ_NO, + irq_handler, + IRQF_SHARED, + "etx_device", + (void *)irq_handler); +``` + +--- + +## Create Work Dynamically + +```c +INIT_WORK( + &workqueue, + workqueue_fn); +``` + +The work item is now ready for scheduling. + +--- + +# Driver Execution Flow + +```text +Driver Loaded + | + v +INIT_WORK() + | + v +Interrupt Occurs + | + v +IRQ Handler + | + v +schedule_work() + | + v +kworker Thread + | + v +workqueue_fn() +``` + +--- + +# Sample dmesg Output + +After: + +```bash +cat /dev/etx_device +``` + +Output: + +```text +Device File Opened...!!! + +Read function + +Shared IRQ: Interrupt Occurred + +Executing Workqueue Function + +Device File Closed...!!! +``` + +This confirms: + +1. Interrupt occurred +2. ISR executed +3. Work scheduled +4. Workqueue function executed + +--- + +# Build Driver + +## Makefile + +```make +obj-m += driver.o + +KDIR = /lib/modules/$(shell uname -r)/build + +all: + make -C $(KDIR) \ + M=$(shell pwd) modules + +clean: + make -C $(KDIR) \ + M=$(shell pwd) clean +``` + +--- + +# Build and Test + +Compile: + +```bash +make +``` + +Load: + +```bash +sudo insmod driver.ko +``` + +Trigger interrupt: + +```bash +sudo cat /dev/etx_device +``` + +View logs: + +```bash +dmesg +``` + +Unload: + +```bash +sudo rmmod driver +``` + +--- + +# Dynamic vs Static Workqueue Initialization + +| Static Method | Dynamic Method | +| --------------------------- | ----------------------------- | +| DECLARE_WORK() | INIT_WORK() | +| Compile-time initialization | Runtime initialization | +| Simpler | More flexible | +| Fixed declaration | Can be embedded in structures | +| Less configurable | More configurable | + +--- + +# Dynamic Workqueue vs Own Workqueue + +| Dynamic Method | Own Workqueue | +| --------------------- | ------------------------- | +| Uses global workqueue | Uses dedicated workqueue | +| Uses schedule_work() | Uses queue_work() | +| No worker creation | Must create worker thread | +| Simpler | Greater control | +| Shared kworker thread | Dedicated worker thread | + +--- + +# Advantages + +* Runtime initialization +* Flexible design +* Easy ISR integration +* No custom worker thread needed +* Uses kernel-managed kworker threads + +--- + +# Limitations + +* Uses shared global workqueue +* Heavy tasks may affect other queued work +* Less control than custom workqueues + +--- + +# Important APIs Summary + +## Initialization + +```c +INIT_WORK() +``` + +--- + +## Scheduling + +```c +schedule_work() +schedule_delayed_work() +schedule_work_on() +schedule_delayed_work_on() +``` + +--- + +## Work Structure + +```c +struct work_struct +``` + +--- + +## Interrupt Related + +```c +request_irq() +free_irq() +``` + +--- + +# Key Takeaways + +* `INIT_WORK()` dynamically initializes a work item. +* `schedule_work()` places work on the kernel global workqueue. +* Work executes in a `kworker` thread, not in interrupt context. +* Workqueue functions can perform longer operations than ISRs. +* The ISR should only schedule work and return quickly. +* Dynamic initialization provides more flexibility than `DECLARE_WORK()`. +* This method still uses the kernel global workqueue; it does not create a dedicated workqueue. From f747123eed01154a116f0f62e902c15898882d52 Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Fri, 19 Jun 2026 18:28:05 +0530 Subject: [PATCH 28/55] Update ReadMe.md --- .../Own_Workqueue/ReadMe.md | 655 +++++++++++++++++- 1 file changed, 654 insertions(+), 1 deletion(-) diff --git a/Linux/Device_Driver/Workqueue-in-Linux-kernel/Own_Workqueue/ReadMe.md b/Linux/Device_Driver/Workqueue-in-Linux-kernel/Own_Workqueue/ReadMe.md index fa8ef0b..fa397c7 100644 --- a/Linux/Device_Driver/Workqueue-in-Linux-kernel/Own_Workqueue/ReadMe.md +++ b/Linux/Device_Driver/Workqueue-in-Linux-kernel/Own_Workqueue/ReadMe.md @@ -1,4 +1,657 @@ +# Linux Device Driver - Own Workqueue (Dedicated Workqueue) + +## Overview + +In previous Workqueue examples, work items were queued to the **kernel global workqueue** using: + +```c +schedule_work(&work); +``` + +In this tutorial, we create a **dedicated workqueue** for the driver and queue work to it using: + +```c +queue_work(own_workqueue, &work); +``` + +This provides better isolation and control over deferred processing. + +--- + +# Global Workqueue vs Own Workqueue + +## Global Workqueue + +```text +Driver + | + v +schedule_work() + | + v +Kernel Global Workqueue + | + v +kworker Thread +``` + +Characteristics: + +* Shared by many kernel subsystems +* No creation required +* Easy to use +* Less control + +--- + +## Own Workqueue + +```text +Driver + | + v +queue_work() + | + v +Own Workqueue + | + v +Dedicated Worker Thread +``` + +Characteristics: + +* Driver-specific workqueue +* Better isolation +* More control +* Suitable for heavy workloads + +--- + +# Workqueue Components + +## Workqueue Structure + +Represents the workqueue itself. + +```c +struct workqueue_struct *own_workqueue; +``` + +--- + +## Work Structure + +Represents a deferred work item. + +```c +struct work_struct work; +``` + +Usually initialized as: + +```c +DECLARE_WORK(work, workqueue_fn); +``` + +--- + +# Header File + +```c +#include +``` + +Required for: + +* work_struct +* workqueue_struct +* queue_work() +* create_workqueue() + +--- + +# Creating a Workqueue + +## create_workqueue() + +Creates a dedicated workqueue. + +```c +struct workqueue_struct * +create_workqueue(const char *name); +``` + +Example: + +```c +own_workqueue = + create_workqueue("own_wq"); +``` + +Creates: + +```text +own_wq +``` + +workqueue for this driver. + +--- + +# Single Thread Workqueue + +## create_singlethread_workqueue() + +Creates a workqueue with only one worker thread. + +```c +own_workqueue = +create_singlethread_workqueue( + "own_wq"); +``` + +Useful when: + +* Work items must execute sequentially +* Parallel execution is not desired + +--- + +# Internal Implementation + +Both macros use: + +```c +alloc_workqueue() +``` + +internally. + +```c +create_workqueue() + | + v +alloc_workqueue() +``` + +--- + +# alloc_workqueue() + +Low-level API. + +```c +alloc_workqueue( + fmt, + flags, + max_active); +``` + +Parameters: + +| Parameter | Description | +| ---------- | ------------------------- | +| fmt | Name format | +| flags | Workqueue flags | +| max_active | Maximum active work items | + +--- + +# Common Workqueue Flags + +## WQ_UNBOUND + +Workers are not tied to specific CPUs. + +```c +WQ_UNBOUND +``` + +Benefits: + +* Better scheduling flexibility +* Less CPU locality + +--- + +## WQ_MEM_RECLAIM + +Ensures forward progress during memory pressure. + +```c +WQ_MEM_RECLAIM +``` + +Used by many kernel workqueues. + +--- + +# Creating Work + +Work item: + +```c +static void workqueue_fn( + struct work_struct *work); + +static DECLARE_WORK( + work, + workqueue_fn); +``` + +--- + +# Workqueue Callback + +Executed by worker thread. + +```c +static void workqueue_fn( + struct work_struct *work) +{ + printk( + KERN_INFO + "Executing Workqueue Function\n"); +} +``` + +This function performs deferred processing. + +--- + +# Queueing Work + +## queue_work() + +Queues work into the dedicated workqueue. + +Syntax: + +```c +bool queue_work( + struct workqueue_struct *wq, + struct work_struct *work); +``` + +Example: + +```c +queue_work( + own_workqueue, + &work); +``` + +Returns: + +| Value | Meaning | +| ----- | ------------------- | +| false | Already queued | +| true | Successfully queued | + +--- + +# Queue Work On Specific CPU + +## queue_work_on() + +```c +queue_work_on( + cpu, + own_workqueue, + &work); +``` + +Example: + +```c +queue_work_on( + 0, + own_workqueue, + &work); +``` + +Queues work on CPU0. + +--- + +# Delayed Work + +## queue_delayed_work() + +Schedule after delay. + +```c +queue_delayed_work( + own_workqueue, + &dwork, + delay); +``` + +Example: + +```c +queue_delayed_work( + own_workqueue, + &dwork, + msecs_to_jiffies(5000)); +``` + +Runs after 5 seconds. + +--- + +# Delayed Work On Specific CPU + +## queue_delayed_work_on() + +```c +queue_delayed_work_on( + cpu, + own_workqueue, + &dwork, + delay); +``` + +Example: + +```c +queue_delayed_work_on( + 0, + own_workqueue, + &dwork, + delay); +``` + +--- + +# Interrupt + Own Workqueue Example + +## Interrupt Handler + +```c +static irqreturn_t irq_handler( + int irq, + void *dev_id) +{ + printk( + KERN_INFO + "Shared IRQ: Interrupt Occurred\n"); + + queue_work( + own_workqueue, + &work); + + return IRQ_HANDLED; +} +``` + +ISR only schedules work and returns immediately. + +--- + +# Driver Initialization + +## Create Workqueue + +```c +own_workqueue = + create_workqueue( + "own_wq"); +``` + +--- + +## Register IRQ + +```c +request_irq( + IRQ_NO, + irq_handler, + IRQF_SHARED, + "etx_device", + (void *)irq_handler); +``` + +--- + +## Work Initialization + +```c +DECLARE_WORK( + work, + workqueue_fn); +``` + +--- + +# Execution Flow + +```text +Driver Loaded + | + v +Create own_wq + | + v +Interrupt Occurs + | + v +ISR Executes + | + v +queue_work() + | + v +own_wq + | + v +Worker Thread + | + v +workqueue_fn() +``` + +--- + +# Driver Cleanup + +Always destroy the workqueue. + +```c +destroy_workqueue( + own_workqueue); +``` + +Complete cleanup: + +```c +destroy_workqueue( + own_workqueue); + +free_irq( + IRQ_NO, + dev_id); +``` + +--- + +# Sample dmesg Output + +```text +Device Driver Insert...Done!!! + +Read function + +Shared IRQ: Interrupt Occurred + +Executing Workqueue Function + +Device Driver Remove...Done!!! +``` + +This confirms: + +1. Interrupt occurred +2. ISR executed +3. Work queued +4. Worker thread executed callback + +--- + +# schedule_work() vs queue_work() + +| Feature | schedule_work() | queue_work() | +| ------------------ | --------------- | ------------ | +| Workqueue Used | Global | Custom | +| Workqueue Creation | Not Required | Required | +| Control | Limited | More Control | +| Isolation | Shared | Dedicated | +| API | schedule_work() | queue_work() | + +--- + +# Global Workqueue vs Own Workqueue + +| Feature | Global Workqueue | Own Workqueue | +| ---------------- | ---------------- | --------------------------------- | +| Setup Complexity | Simple | Moderate | +| Dedicated Thread | No | Yes | +| Isolation | Shared | Dedicated | +| Scalability | Good | Better for heavy driver workloads | +| Control | Limited | High | + +--- + +# Real Driver Use Cases + +## Network Driver + +```text +Packet Arrival + | + v +ISR + | + v +Dedicated Packet Processing Workqueue +``` + +--- + +## SPI Driver + +```text +Transfer Complete + | + v +Own Workqueue + | + v +Post Processing +``` + +--- + +## USB Driver + +```text +USB Event + | + v +Own Workqueue + | + v +Protocol Handling +``` + +--- + +## Storage Driver + +```text +DMA Completion + | + v +Dedicated Workqueue + | + v +Data Processing +``` + +--- + +# Advantages + +* Driver-specific execution context +* Better workload isolation +* Prevents blocking global workqueue +* Greater scheduling control +* Suitable for heavy deferred processing + +--- + +# Limitations + +* Additional worker threads +* More memory usage +* More management overhead + +--- + +# Important APIs Summary + +## Workqueue Creation + +```c +create_workqueue() +create_singlethread_workqueue() +alloc_workqueue() +``` + +--- + +## Queue Operations + +```c +queue_work() +queue_work_on() +queue_delayed_work() +queue_delayed_work_on() +``` + +--- + +## Cleanup + +```c +destroy_workqueue() +``` + +--- + +## Work Initialization + +```c +DECLARE_WORK() +INIT_WORK() +``` + +--- + +# Key Takeaways + +* Own Workqueue provides a dedicated execution context for a driver. +* `queue_work()` is used with custom workqueues. +* `schedule_work()` uses the kernel global workqueue. +* Workqueues execute in process context and can sleep. +* Dedicated workqueues are preferred for heavy or isolated deferred processing. +* Always destroy custom workqueues during module removal. +* Workqueues are commonly used with interrupts to move lengthy processing out of the ISR. + + +## Conclusion This is just a basic linux device driver. This will explain about the Own workqueue in the linux device driver. Please refer this URL for the complete tutorial of this source code. -https://embetronicx.com/tutorials/linux/device-drivers/work-queue-in-linux-own-workqueue/ \ No newline at end of file +https://embetronicx.com/tutorials/linux/device-drivers/work-queue-in-linux-own-workqueue/ From f6e8e1938818eaa5bae39e8045e1314ae8873341 Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Fri, 19 Jun 2026 18:30:22 +0530 Subject: [PATCH 29/55] Update README.md --- Linux/Device_Driver/Linked_List/ReadMe.md | 697 +++++++++++++++++++++- 1 file changed, 696 insertions(+), 1 deletion(-) diff --git a/Linux/Device_Driver/Linked_List/ReadMe.md b/Linux/Device_Driver/Linked_List/ReadMe.md index b72049e..4790ba6 100644 --- a/Linux/Device_Driver/Linked_List/ReadMe.md +++ b/Linux/Device_Driver/Linked_List/ReadMe.md @@ -1,4 +1,699 @@ +# Linux Device Driver - Linked List in Linux Kernel + +## Overview + +The Linux kernel provides a built-in implementation of a **circular doubly linked list**. + +Instead of implementing custom linked list structures, kernel developers use: + +```c +#include +``` + +Benefits: + +* Reusable kernel implementation +* Efficient insertion and deletion +* Widely used throughout kernel subsystems +* Supports dynamic data structures + +--- + +# What is a Linked List? + +A linked list consists of nodes connected using pointers. + +Traditional implementation: + +```c +struct my_node +{ + int data; + + struct my_node *prev; + struct my_node *next; +}; +``` + +Kernel implementation embeds a `list_head` structure. + +```c +struct my_node +{ + struct list_head list; + + int data; +}; +``` + +--- + +# Linux Kernel Linked List + +Linux uses a **Circular Doubly Linked List**. + +```text ++------+ +------+ +------+ +|Node1 |<--->|Node2 |<--->|Node3 | ++------+ +------+ +------+ + ^ | + |___________________________| +``` + +Characteristics: + +* Circular +* Doubly linked +* No NULL termination +* Head node always exists + +--- + +# Header File + +```c +#include +``` + +Kernel implementation: + +```c +struct list_head +{ + struct list_head *next; + struct list_head *prev; +}; +``` + +--- + +# Creating a Linked List Node + +User-defined structure: + +```c +struct my_list +{ + struct list_head list; + int data; +}; +``` + +The `list_head` member links the node into the kernel linked list. + +--- + +# Creating the List Head + +Before creating nodes, create a list head. + +## LIST_HEAD() + +```c +LIST_HEAD(my_linked_list); +``` + +Example: + +```c +LIST_HEAD(etx_linked_list); +``` + +Internally: + +```c +struct list_head etx_linked_list = +{ + &etx_linked_list, + &etx_linked_list +}; +``` + +When: + +```text +head->next == head +head->prev == head +``` + +The list is empty. + +--- + +# Initializing a Node + +For dynamically or statically allocated nodes: + +```c +INIT_LIST_HEAD(&node.list); +``` + +Example: + +```c +struct my_list node; + +INIT_LIST_HEAD(&node.list); + +node.data = 10; +``` + +This initializes: + +```text +node.list.next = node.list +node.list.prev = node.list +``` + +--- + +# Adding Nodes + +## Add After Head + +Function: + +```c +list_add( + &node.list, + &etx_linked_list +); +``` + +Effect: + +```text +HEAD + | + v +NODE + | + v +OLD_FIRST_NODE +``` + +Used for: + +```text +Stack (LIFO) +``` + +--- + +## Add Before Head + +Function: + +```c +list_add_tail( + &node.list, + &etx_linked_list +); +``` + +Effect: + +```text +HEAD + | + v +... + | + v +NEW_NODE + | + v +HEAD +``` + +Used for: + +```text +Queue (FIFO) +``` + +--- + +# Deleting Nodes + +## list_del() + +Removes node from list. + +```c +list_del(&node.list); +``` + +Important: + +```text +Removes linkage only +Memory is NOT freed +``` + +--- + +## list_del_init() + +Deletes and reinitializes node. + +```c +list_del_init(&node.list); +``` + +Node becomes standalone again. + +--- + +# Replacing Nodes + +## list_replace() + +Replace old node with new node. + +```c +list_replace( + &old.list, + &new.list +); +``` + +--- + +## list_replace_init() + +Replace and reinitialize old node. + +```c +list_replace_init( + &old.list, + &new.list +); +``` + +--- + +# Moving Nodes + +## list_move() + +Move node after head. + +```c +list_move( + &node.list, + &etx_linked_list +); +``` + +--- + +## list_move_tail() + +Move node before head. + +```c +list_move_tail( + &node.list, + &etx_linked_list +); +``` + +--- + +# Rotating List + +## list_rotate_left() + +Rotate list left. + +```c +list_rotate_left( + &etx_linked_list +); +``` + +Example: + +Before: + +```text +HEAD -> A -> B -> C +``` + +After: + +```text +HEAD -> B -> C -> A +``` + +--- + +# Testing List State + +## list_empty() + +Check whether list is empty. + +```c +if(list_empty(&etx_linked_list)) +{ + printk("Empty\n"); +} +``` + +Returns: + +```text +1 -> Empty +0 -> Not Empty +``` + +--- + +## list_is_last() + +Check whether node is last. + +```c +list_is_last( + &node.list, + &etx_linked_list +); +``` + +--- + +## list_is_singular() + +Check whether list contains only one entry. + +```c +list_is_singular( + &etx_linked_list +); +``` + +--- + +# Splitting a List + +## list_cut_position() + +Split one list into two. + +```c +list_cut_position( + &new_list, + &old_list, + &entry->list +); +``` + +Example: + +Before: + +```text +HEAD + | + A -> B -> C -> D +``` + +After: + +```text +LIST1: +A -> B + +LIST2: +C -> D +``` + +--- + +# Joining Lists + +## list_splice() + +Join two linked lists. + +```c +list_splice( + &list2, + &list1 +); +``` + +Result: + +```text +LIST1 + LIST2 +``` + +Used commonly for: + +* Stack implementation +* Queue implementation +* Batch insertion + +--- + +# Traversing Linked Lists + +## list_entry() + +Convert list_head pointer to container structure. + +```c +list_entry( + ptr, + struct my_list, + list +); +``` + +Parameters: + +| Parameter | Description | +| --------- | ----------------- | +| ptr | list_head pointer | +| type | structure type | +| member | list_head member | + +--- + +# Forward Traversal + +## list_for_each() + +```c +struct list_head *pos; + +list_for_each( + pos, + &etx_linked_list) +{ +} +``` + +--- + +## list_for_each_entry() + +Preferred method. + +```c +struct my_list *node; + +list_for_each_entry( + node, + &etx_linked_list, + list) +{ + printk("%d\n", + node->data); +} +``` + +--- + +# Safe Traversal + +## list_for_each_entry_safe() + +Safe while deleting nodes. + +```c +struct my_list *node; +struct my_list *tmp; + +list_for_each_entry_safe( + node, + tmp, + &etx_linked_list, + list) +{ + list_del(&node->list); +} +``` + +Used when removing nodes during traversal. + +--- + +# Reverse Traversal + +## list_for_each_prev() + +```c +list_for_each_prev( + pos, + &etx_linked_list) +{ +} +``` + +--- + +## list_for_each_entry_reverse() + +```c +list_for_each_entry_reverse( + node, + &etx_linked_list, + list) +{ + printk("%d\n", + node->data); +} +``` + +--- + +# Typical Driver Use Cases + +Linux kernel linked lists are heavily used in: + +* Process management +* Device driver queues +* Workqueue management +* Timer management +* Networking subsystem +* USB subsystem +* Block layer +* Scheduler + +Kernel developers frequently embed `struct list_head` inside driver-specific structures rather than storing data directly in the list node. + +--- + +# Example Flow + +```text +Create List Head + | + v +Create Node + | + v +INIT_LIST_HEAD() + | + v +list_add() + | + v +Traverse + | + v +list_del() + | + v +Free Memory +``` + +--- + +# Important APIs Summary + +## Initialization + +```c +LIST_HEAD() +INIT_LIST_HEAD() +``` + +## Add + +```c +list_add() +list_add_tail() +``` + +## Delete + +```c +list_del() +list_del_init() +``` + +## Replace + +```c +list_replace() +list_replace_init() +``` + +## Move + +```c +list_move() +list_move_tail() +``` + +## Test + +```c +list_empty() +list_is_last() +list_is_singular() +``` + +## Split / Join + +```c +list_cut_position() +list_splice() +``` + +## Traversal + +```c +list_for_each() +list_for_each_entry() +list_for_each_entry_safe() +list_for_each_prev() +list_for_each_entry_reverse() +``` + +--- + +# Key Takeaways + +* Linux kernel provides a built-in circular doubly linked list implementation. +* `struct list_head` is embedded inside user-defined structures. +* List heads are created using `LIST_HEAD()`. +* Nodes are initialized using `INIT_LIST_HEAD()`. +* `list_add()` inserts after head (stack behavior). +* `list_add_tail()` inserts before head (queue behavior). +* `list_del()` removes nodes but does not free memory. +* `list_for_each_entry()` is the preferred traversal method. +* `list_for_each_entry_safe()` should be used when deleting nodes during traversal. +* Linked lists are extensively used throughout Linux kernel subsystems and device drivers. + + +# Conclusion This is just a basic linux device driver which explains about the linked list in linux device driver. Please refer this URL for the complete tutorial of this example source code. -https://embetronicx.com/tutorials/linux/device-drivers/example-linked-list-in-linux-kernel/ \ No newline at end of file +https://embetronicx.com/tutorials/linux/device-drivers/example-linked-list-in-linux-kernel/ From 10cbcbc45faeb67eee51dea990b8c808a62a57f1 Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Fri, 19 Jun 2026 18:32:57 +0530 Subject: [PATCH 30/55] Update ReadMe.md --- Linux/Device_Driver/Linked_List/ReadMe.md | 690 ++++++++++++++++++++++ 1 file changed, 690 insertions(+) diff --git a/Linux/Device_Driver/Linked_List/ReadMe.md b/Linux/Device_Driver/Linked_List/ReadMe.md index 4790ba6..d761929 100644 --- a/Linux/Device_Driver/Linked_List/ReadMe.md +++ b/Linux/Device_Driver/Linked_List/ReadMe.md @@ -676,6 +676,684 @@ list_for_each_prev() list_for_each_entry_reverse() ``` +--- +# Linux Device Driver - Linked List Example Program + +## Overview + +This example combines multiple Linux kernel concepts: + +* Character Device Driver +* Interrupt Handling +* Workqueue +* Kernel Linked List +* Dynamic Memory Allocation (`kmalloc`) +* Safe List Traversal +* Safe Node Deletion + +The driver demonstrates how to: + +1. Receive data from userspace. +2. Trigger a software interrupt. +3. Schedule a Workqueue. +4. Create a linked list node inside the Workqueue. +5. Add the node to a kernel linked list. +6. Traverse and print the linked list. +7. Delete all nodes during module removal. + +--- + +# High-Level Architecture + +```text +echo 10 > /dev/etx_device + | + v + Write Function + | + v + Software Interrupt + | + v + ISR + | + v + queue_work() + | + v + Workqueue + | + v + Create Linked List Node + | + v + Add Node To List + | + v + cat /dev/etx_device + | + v + Traverse Linked List + | + v + Print All Nodes +``` + +--- + +# Core Data Structure + +## Linked List Node + +```c +struct my_list +{ + struct list_head list; + int data; +}; +``` + +### Purpose + +| Member | Description | +| ------ | ----------------------------- | +| list | Linux kernel linked list node | +| data | User supplied value | + +Each node stores one integer value. + +--- + +# Creating List Head + +```c +LIST_HEAD(Head_Node); +``` + +Creates and initializes the list head. + +Equivalent Concept: + +```text +Head_Node + | + +--> Empty List +``` + +Initially: + +```text +Head_Node.next = Head_Node +Head_Node.prev = Head_Node +``` + +--- + +# Workqueue Function + +The actual linked list node is created inside the Workqueue. + +```c +static void workqueue_fn( + struct work_struct *work) +{ + struct my_list *temp_node; + + temp_node = + kmalloc( + sizeof(struct my_list), + GFP_KERNEL); + + temp_node->data = etx_value; + + INIT_LIST_HEAD( + &temp_node->list); + + list_add_tail( + &temp_node->list, + &Head_Node); +} +``` + +--- + +# What Happens Here? + +## Step 1 + +Allocate memory. + +```c +kmalloc() +``` + +Creates: + +```text ++----------------+ +| struct my_list | ++----------------+ +``` + +--- + +## Step 2 + +Store received value. + +```c +temp_node->data = etx_value; +``` + +Example: + +```text +data = 10 +``` + +--- + +## Step 3 + +Initialize embedded list. + +```c +INIT_LIST_HEAD() +``` + +--- + +## Step 4 + +Insert into linked list. + +```c +list_add_tail() +``` + +Example: + +Before: + +```text +HEAD +``` + +After Writing 10: + +```text +HEAD <-> [10] +``` + +After Writing 20: + +```text +HEAD <-> [10] <-> [20] +``` + +After Writing 30: + +```text +HEAD <-> [10] <-> [20] <-> [30] +``` + +--- + +# Interrupt Handler + +```c +static irqreturn_t irq_handler( + int irq, + void *dev_id) +{ + queue_work( + own_workqueue, + &work); + + return IRQ_HANDLED; +} +``` + +Purpose: + +```text +Interrupt + | + v +Schedule Workqueue +``` + +The ISR does not create nodes directly. + +It schedules deferred processing. + +--- + +# Write Operation + +```c +static ssize_t etx_write(...) +{ + sscanf(buf,"%d",&etx_value); + + asm("int $0x3B"); + + return len; +} +``` + +--- + +# Write Flow + +Example: + +```bash +echo 10 > /dev/etx_device +``` + +Execution: + +```text +User Writes 10 + | + v +etx_write() + | + v +etx_value = 10 + | + v +Software Interrupt + | + v +ISR + | + v +Workqueue + | + v +Create Node + | + v +Add Node +``` + +--- + +# Reading the Linked List + +## Traversal + +```c +list_for_each_entry( + temp, + &Head_Node, + list) +{ + printk( + "Node data=%d\n", + temp->data); +} +``` + +--- + +# Example + +Current List: + +```text +HEAD + | + +--> 10 + | + +--> 20 + | + +--> 30 +``` + +Output: + +```text +Node 0 data = 10 +Node 1 data = 20 +Node 2 data = 30 + +Total Nodes = 3 +``` + +--- + +# Traversal Macro + +```c +list_for_each_entry( + pos, + head, + member); +``` + +Parameters: + +| Parameter | Description | +| --------- | ------------------------- | +| pos | Node pointer | +| head | List head | +| member | Embedded list_head member | + +Preferred Linux kernel traversal method. + +--- + +# Example Session + +## Add First Node + +```bash +echo 10 > /dev/etx_device +``` + +List: + +```text +HEAD + | + +--> 10 +``` + +--- + +## Add Second Node + +```bash +echo 20 > /dev/etx_device +``` + +List: + +```text +HEAD + | + +--> 10 + | + +--> 20 +``` + +--- + +## Add Third Node + +```bash +echo 30 > /dev/etx_device +``` + +List: + +```text +HEAD + | + +--> 10 + | + +--> 20 + | + +--> 30 +``` + +--- + +## Read Nodes + +```bash +cat /dev/etx_device +``` + +Output: + +```text +Node 0 data = 10 +Node 1 data = 20 +Node 2 data = 30 + +Total Nodes = 3 +``` + +--- + +# Deleting All Nodes + +During module removal: + +```c +list_for_each_entry_safe( + cursor, + temp, + &Head_Node, + list) +{ + list_del( + &cursor->list); + + kfree(cursor); +} +``` + +--- + +# Why Safe Traversal? + +Unsafe: + +```c +list_for_each_entry() +``` + +Problem: + +```text +Delete Current Node + | + v +Next Pointer Invalid +``` + +May crash. + +--- + +Safe: + +```c +list_for_each_entry_safe() +``` + +Stores next node before deletion. + +Suitable for: + +```text +Delete While Traversing +``` + +--- + +# Module Removal Flow + +```text +rmmod driver + | + v +Traverse List + | + v +list_del() + | + v +kfree() + | + v +Destroy Workqueue + | + v +free_irq() + | + v +Driver Removed +``` + +--- + +# Memory Management + +## Allocation + +```c +kmalloc( + sizeof(struct my_list), + GFP_KERNEL); +``` + +Creates: + +```text +Kernel Heap + | + +--> Node +``` + +--- + +## Free + +```c +kfree(node); +``` + +Releases memory. + +Important: + +```text +list_del() +does NOT free memory +``` + +Both operations are required. + +--- + +# Why Linux Uses Embedded list_head? + +Instead of: + +```c +struct node +{ + int data; + struct node *next; +}; +``` + +Linux uses: + +```c +struct my_list +{ + struct list_head list; + int data; +}; +``` + +Advantages: + +* Generic implementation +* Reusable APIs +* Better cache locality +* Single memory allocation +* Used throughout kernel subsystems + +This intrusive-list design is a common Linux kernel pattern. + +--- + +# Important APIs Used + +## Linked List + +```c +LIST_HEAD() + +INIT_LIST_HEAD() + +list_add_tail() + +list_for_each_entry() + +list_for_each_entry_safe() + +list_del() +``` + +--- + +## Memory + +```c +kmalloc() + +kfree() +``` + +--- + +## Workqueue + +```c +create_workqueue() + +queue_work() + +destroy_workqueue() +``` + +--- + +## Interrupt + +```c +request_irq() + +free_irq() +``` + +--- + +# Driver Concept Demonstrated + +This example is valuable because it combines multiple Linux driver concepts in one workflow: + +```text +Userspace + | + v +Character Driver + | + v +Interrupt + | + v +ISR + | + v +Workqueue + | + v +Linked List + | + v +Kernel Memory Management +``` + --- # Key Takeaways @@ -691,6 +1369,18 @@ list_for_each_entry_reverse() * `list_for_each_entry_safe()` should be used when deleting nodes during traversal. * Linked lists are extensively used throughout Linux kernel subsystems and device drivers. +* `LIST_HEAD()` creates the linked list head. +* Each node embeds `struct list_head`. +* Nodes are dynamically allocated using `kmalloc()`. +* `list_add_tail()` appends nodes to the list. +* Interrupts trigger the Workqueue. +* Workqueue creates linked list nodes. +* `list_for_each_entry()` traverses the list. +* `list_for_each_entry_safe()` is used when deleting nodes. +* `list_del()` removes a node from the list but does not free memory. +* `kfree()` must be called to release allocated memory. +* This example demonstrates a complete producer-storage-traversal-cleanup workflow inside a Linux device driver. + # Conclusion This is just a basic linux device driver which explains about the linked list in linux device driver. From d106fc727a9152ebef0e73e523fe7993540ef4d8 Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Fri, 19 Jun 2026 18:41:40 +0530 Subject: [PATCH 31/55] Update and rename ReadMe.md to README.md --- Linux/Device_Driver/Kernel_Thread/README.md | 706 ++++++++++++++++++++ Linux/Device_Driver/Kernel_Thread/ReadMe.md | 4 - 2 files changed, 706 insertions(+), 4 deletions(-) create mode 100644 Linux/Device_Driver/Kernel_Thread/README.md delete mode 100644 Linux/Device_Driver/Kernel_Thread/ReadMe.md diff --git a/Linux/Device_Driver/Kernel_Thread/README.md b/Linux/Device_Driver/Kernel_Thread/README.md new file mode 100644 index 0000000..a90562d --- /dev/null +++ b/Linux/Device_Driver/Kernel_Thread/README.md @@ -0,0 +1,706 @@ +# Linux Device Driver - Kernel Thread (kthread) + +## Overview + +A Kernel Thread (kthread) is a thread that runs entirely in kernel space and is managed by the Linux kernel scheduler. Unlike user-space threads, kernel threads do not belong to a user process and are typically used for background kernel activities, deferred processing, monitoring, and driver-specific tasks. + +Common kernel threads visible on a Linux system include: + +```bash +ps -eLf | grep kthread +``` + +Examples: + +```text +kthreadd +kworker/* +rcu_tasks_kthread +migration/* +``` + +These are created and managed entirely by the kernel. + +--- + +# Process vs Thread + +## Process + +A process is an executing instance of a program. + +Characteristics: + +* Separate address space +* Higher resource usage +* Expensive context switching + +```text +Process A + | + +-- Memory + +-- Files + +-- Resources +``` + +## Thread + +A thread is an execution path within a process. + +Characteristics: + +* Shares address space +* Lightweight +* Faster context switching + +```text +Process + | + +--> Thread 1 + +--> Thread 2 + +--> Thread 3 +``` + +Threads share memory and resources, making communication easier than between processes. + +--- + +# Types of Threads + +## User-Level Thread + +Managed by user-space libraries. + +Examples: + +```text +POSIX Threads (pthread) +std::thread +Java Threads +``` + +Characteristics: + +* User-space management +* Kernel unaware of thread implementation +* Faster creation + +--- + +## Kernel-Level Thread + +Managed directly by the kernel. + +Characteristics: + +* Scheduled by kernel +* Runs in kernel space +* Has access to kernel APIs +* Commonly used in device drivers + +Examples: + +```text +kworker +ksoftirqd +kthreadd +rcu_tasks_kthread +``` + +--- + +# Why Use Kernel Threads? + +Kernel threads are useful when a driver needs: + +* Continuous background processing +* Periodic monitoring +* Deferred work +* Polling hardware +* Watchdog functionality +* Data collection + +Example: + +```text +Temperature Sensor Driver + | + v +Kernel Thread + | + v +Read Temperature Every Second +``` + +--- + +# Kernel Thread Architecture + +```text +Driver Init + | + v +Create kthread + | + v +Scheduler + | + v +Thread Function + | + v +Periodic Work + | + v +Stop Request + | + v +Thread Exit +``` + +--- + +# Required Header Files + +```c +#include +#include +#include +``` + +--- + +# Thread Management APIs + +## Create Thread + +### kthread_create() + +Creates a kernel thread but does not start it. + +```c +struct task_struct * +kthread_create( + int (*threadfn)(void *data), + void *data, + const char namefmt[], + ...); +``` + +Parameters: + +| Parameter | Description | +| --------- | ------------------------- | +| threadfn | Thread function | +| data | Argument passed to thread | +| namefmt | Thread name | + +Returns: + +```text +task_struct pointer +or +ERR_PTR(-ENOMEM) +``` + +--- + +# Start Thread + +## wake_up_process() + +Starts a thread created using `kthread_create()`. + +```c +wake_up_process( + etx_thread); +``` + +Example: + +```c +etx_thread = +kthread_create( + thread_function, + NULL, + "eTx Thread"); + +wake_up_process( + etx_thread); +``` + +--- + +# Create and Start Together + +## kthread_run() + +Convenience wrapper around: + +```text +kthread_create() + + +wake_up_process() +``` + +Syntax: + +```c +struct task_struct * +kthread_run( + threadfn, + data, + namefmt, + ...); +``` + +Example: + +```c +etx_thread = +kthread_run( + thread_function, + NULL, + "eTx Thread"); +``` + +Preferred approach in modern drivers. + +--- + +# Thread Function + +Every kernel thread executes a function: + +```c +int thread_function( + void *data) +{ + return 0; +} +``` + +Requirements: + +* Return integer +* Accept void pointer argument +* Should periodically check stop condition + +--- + +# kthread_should_stop() + +Checks whether thread termination was requested. + +```c +while (!kthread_should_stop()) +{ + // Thread work +} +``` + +Returns: + +```text +0 -> Continue +1 -> Stop Requested +``` + +--- + +# Example Thread Function + +```c +int thread_function( + void *pv) +{ + int i = 0; + + while (!kthread_should_stop()) + { + printk( + KERN_INFO + "Thread %d\n", + i++); + + msleep(1000); + } + + return 0; +} +``` + +Behavior: + +```text +Print message + | + v +Sleep 1 second + | + v +Repeat +``` + +--- + +# Sleeping Inside Kernel Thread + +Unlike ISR or Tasklet, kernel threads run in process context. + +Allowed: + +```c +msleep() +schedule() +wait_event() +mutex_lock() +``` + +Not allowed in: + +```text +ISR +Tasklet +SoftIRQ +``` + +This is one major advantage of kernel threads. + +--- + +# Stopping a Thread + +## kthread_stop() + +Stops a kernel thread. + +```c +int kthread_stop( + struct task_struct *k); +``` + +Example: + +```c +kthread_stop( + etx_thread); +``` + +What happens internally: + +```text +Set stop flag + | + v +Wake thread + | + v +kthread_should_stop() +returns TRUE + | + v +Thread exits +``` + +--- + +# Thread Life Cycle + +```text +Module Load + | + v +kthread_run() + | + v +Thread Running + | + v +while(!kthread_should_stop()) + | + v +Periodic Work + | + v +kthread_stop() + | + v +Thread Exit + | + v +Module Unload +``` + +--- + +# CPU Affinity + +## kthread_bind() + +Bind thread to a specific CPU. + +```c +kthread_bind( + etx_thread, + cpu); +``` + +Example: + +```c +kthread_bind( + etx_thread, + 0); +``` + +Runs only on CPU0. + +Useful for: + +* Real-time workloads +* CPU-specific processing +* Performance tuning + +--- + +# Typical Driver Example + +## Driver Init + +```c +static struct task_struct *etx_thread; + +etx_thread = +kthread_run( + thread_function, + NULL, + "eTx Thread"); +``` + +--- + +## Thread Function + +```c +int thread_function( + void *data) +{ + while(!kthread_should_stop()) + { + printk("Running\n"); + + msleep(1000); + } + + return 0; +} +``` + +--- + +## Driver Exit + +```c +kthread_stop( + etx_thread); +``` + +--- + +# Execution Flow + +```text +insmod driver.ko + | + v +kthread_run() + | + v +Thread Created + | + v +Thread Function + | + v +Loop + | + v +msleep() + | + v +Repeat + | + v +rmmod driver + | + v +kthread_stop() + | + v +Thread Exit +``` + +--- + +# Sample dmesg Output + +```text +Device Driver Insert...Done!!! + +Kthread Created Successfully... + +In EmbeTronicX Thread Function 0 + +In EmbeTronicX Thread Function 1 + +In EmbeTronicX Thread Function 2 + +In EmbeTronicX Thread Function 3 + +Device Driver Remove...Done!!! +``` + +--- + +# Kernel Thread vs Workqueue + +| Feature | Kernel Thread | Workqueue | +| --------------------- | ------------- | --------------------------- | +| Dedicated Thread | Yes | No (usually shared kworker) | +| Continuous Loop | Yes | No | +| Can Sleep | Yes | Yes | +| Periodic Tasks | Excellent | Possible | +| Resource Usage | Higher | Lower | +| Background Monitoring | Excellent | Limited | +| Scheduler Managed | Yes | Yes | + +--- + +# Kernel Thread vs Tasklet + +| Feature | Kernel Thread | Tasklet | +| ----------------------- | --------------- | -------------- | +| Context | Process Context | Atomic Context | +| Sleep Allowed | Yes | No | +| Mutex Allowed | Yes | No | +| wait_event() | Yes | No | +| Long Processing | Yes | No | +| Interrupt Deferred Work | Possible | Yes | + +--- + +# Common Embedded Linux Use Cases + +## Sensor Monitoring + +```text +Kernel Thread + | + +--> Read Temperature + +--> Read Voltage + +--> Read Pressure +``` + +--- + +## Watchdog Driver + +```text +Kernel Thread + | + +--> Feed Watchdog + Every 1 Second +``` + +--- + +## UART Driver + +```text +Kernel Thread + | + +--> Poll RX Buffer + +--> Process Data +``` + +--- + +## Network Driver + +```text +Kernel Thread + | + +--> Statistics Collection + +--> Link Monitoring +``` + +--- + +# Best Practices + +* Use `kthread_run()` instead of separate create/start calls. +* Always check `kthread_should_stop()`. +* Always stop thread during module unload. +* Avoid busy waiting. +* Use `msleep()` or wait queues when idle. +* Keep thread logic simple and predictable. +* Use workqueues if a dedicated thread is unnecessary. + +--- + +# Important APIs Summary + +## Creation + +```c +kthread_create() +kthread_run() +``` + +## Start + +```c +wake_up_process() +``` + +## Stop + +```c +kthread_stop() +kthread_should_stop() +``` + +## CPU Affinity + +```c +kthread_bind() +``` + +## Sleeping + +```c +msleep() +schedule() +wait_event() +``` + +--- + +# Key Takeaways + +* Kernel threads execute entirely in kernel space. +* They are represented by `struct task_struct`. +* `kthread_run()` is the most common way to create and start a thread. +* `kthread_should_stop()` must be checked in long-running loops. +* `kthread_stop()` is used during cleanup. +* Kernel threads run in process context and can sleep. +* They are ideal for periodic monitoring, polling, watchdogs, and background driver tasks. +* Kernel threads are heavier but more flexible than tasklets and workqueues. + + +## Conclusion +This is just a basic linux device driver which explains about the kernel thread in linux device driver. + +Please refer this URL for the complete tutorial of this example source code. +https://embetronicx.com/tutorials/linux/device-drivers/linux-device-drivers-tutorial-kernel-thread/ diff --git a/Linux/Device_Driver/Kernel_Thread/ReadMe.md b/Linux/Device_Driver/Kernel_Thread/ReadMe.md deleted file mode 100644 index 7919af7..0000000 --- a/Linux/Device_Driver/Kernel_Thread/ReadMe.md +++ /dev/null @@ -1,4 +0,0 @@ -This is just a basic linux device driver which explains about the kernel thread in linux device driver. - -Please refer this URL for the complete tutorial of this example source code. -https://embetronicx.com/tutorials/linux/device-drivers/linux-device-drivers-tutorial-kernel-thread/ \ No newline at end of file From f7a351131572520912eaca1cafdb806eed813afa Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Fri, 19 Jun 2026 18:42:17 +0530 Subject: [PATCH 32/55] Update README.md --- Linux/Device_Driver/Kernel_Thread/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Linux/Device_Driver/Kernel_Thread/README.md b/Linux/Device_Driver/Kernel_Thread/README.md index a90562d..62aa857 100644 --- a/Linux/Device_Driver/Kernel_Thread/README.md +++ b/Linux/Device_Driver/Kernel_Thread/README.md @@ -2,7 +2,8 @@ ## Overview -A Kernel Thread (kthread) is a thread that runs entirely in kernel space and is managed by the Linux kernel scheduler. Unlike user-space threads, kernel threads do not belong to a user process and are typically used for background kernel activities, deferred processing, monitoring, and driver-specific tasks. +- A Kernel Thread (kthread) is a thread that runs entirely in kernel space and is managed by the Linux kernel scheduler. +- Unlike user-space threads, kernel threads do not belong to a user process and are typically used for background kernel activities, deferred processing, monitoring, and driver-specific tasks. Common kernel threads visible on a Linux system include: From 8e2d5abd42cebc817d1c96dfd8db7f088dc18237 Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Fri, 19 Jun 2026 18:44:16 +0530 Subject: [PATCH 33/55] Update ReadMe.md --- .../Tasklet/Static_Method/ReadMe.md | 609 +++++++++++++++++- 1 file changed, 608 insertions(+), 1 deletion(-) diff --git a/Linux/Device_Driver/Tasklet/Static_Method/ReadMe.md b/Linux/Device_Driver/Tasklet/Static_Method/ReadMe.md index 72eb0dc..8d67d35 100644 --- a/Linux/Device_Driver/Tasklet/Static_Method/ReadMe.md +++ b/Linux/Device_Driver/Tasklet/Static_Method/ReadMe.md @@ -1,4 +1,611 @@ +# Linux Device Driver - Tasklet (Static Method) + +## Overview + +A Tasklet is a Linux kernel **Bottom Half** mechanism used to defer interrupt-related work. + +When an interrupt occurs: + +```text +Hardware Interrupt + | + v +Interrupt Handler (Top Half) + | + v +Tasklet (Bottom Half) + | + v +Deferred Processing +``` + +Tasklets execute later with interrupts enabled and are designed for short deferred operations. + +--- + +# Why Tasklets? + +Interrupt handlers should execute as quickly as possible. + +Bad ISR: + +```text +Interrupt + | + +--> Long Processing + +--> Computation + +--> Buffer Handling +``` + +Good ISR: + +```text +Interrupt + | + +--> Acknowledge Device + +--> Schedule Tasklet + +--> Return +``` + +The tasklet performs the deferred processing later. + +--- + +# Linux Bottom Half Mechanisms + +Linux provides four common Bottom Half mechanisms: + +| Mechanism | Context | Sleep Allowed | +| ------------ | --------------- | ------------- | +| Workqueue | Process Context | Yes | +| Threaded IRQ | Process Context | Yes | +| SoftIRQ | Atomic Context | No | +| Tasklet | Atomic Context | No | + +Tasklets are implemented on top of SoftIRQs. + +--- + +# Important Characteristics + +## Atomic Context + +Tasklets run in atomic context. + +Not Allowed: + +```c +msleep(); +schedule(); +mutex_lock(); +down(); +wait_event(); +``` + +Allowed: + +```c +spin_lock(); +spin_unlock(); +``` + +Tasklets cannot block or sleep. + +--- + +## CPU Affinity + +A tasklet runs only on the CPU that scheduled it. + +```text +CPU0 + | + +--> tasklet_schedule() + | + +--> Tasklet executes on CPU0 +``` + +This improves cache locality. + +--- + +## No Self-Concurrency + +The same tasklet cannot run simultaneously on multiple CPUs. + +```text +Tasklet X + +CPU0 --> Running + +CPU1 --> Cannot Run Same Tasklet +``` + +However: + +```text +Tasklet A --> CPU0 + +Tasklet B --> CPU1 +``` + +Different tasklets may execute in parallel. + +--- + +# Tasklet Structure + +Header: + +```c +#include +``` + +Kernel structure: + +```c +struct tasklet_struct +{ + struct tasklet_struct *next; + unsigned long state; + atomic_t count; + void (*func)(unsigned long); + unsigned long data; +}; +``` + +Field Description: + +| Field | Purpose | +| ----- | --------------------------- | +| next | Next tasklet | +| state | Scheduled / Running | +| count | Disable count | +| func | Callback function | +| data | Argument passed to callback | + +--- + +# Creating Tasklet (Static Method) + +## DECLARE_TASKLET() + +Creates and initializes a tasklet. + +Syntax: + +```c +DECLARE_TASKLET( + name, + function, + data); +``` + +Example: + +```c +void tasklet_fn(unsigned long); + +DECLARE_TASKLET( + tasklet, + tasklet_fn, + 1); +``` + +Equivalent Concept: + +```c +struct tasklet_struct tasklet = +{ + NULL, + 0, + 0, + tasklet_fn, + 1 +}; +``` + +The tasklet is initially enabled. + +--- + +# Creating Disabled Tasklet + +## DECLARE_TASKLET_DISABLED() + +Creates tasklet in disabled state. + +```c +DECLARE_TASKLET_DISABLED( + tasklet, + tasklet_fn, + 1); +``` + +Enable later: + +```c +tasklet_enable(&tasklet); +``` + +--- + +# Tasklet Callback Function + +The deferred work executes here. + +```c +void tasklet_fn( + unsigned long arg) +{ + printk( + KERN_INFO, + "Executing Tasklet : %ld\n", + arg); +} +``` + +Parameter: + +```c +unsigned long arg +``` + +Receives the value specified during creation. + +--- + +# Enable Tasklet + +```c +tasklet_enable( + &tasklet); +``` + +Enables execution. + +--- + +# Disable Tasklet + +## tasklet_disable() + +Waits for completion. + +```c +tasklet_disable( + &tasklet); +``` + +--- + +## tasklet_disable_nosync() + +Disables immediately. + +```c +tasklet_disable_nosync( + &tasklet); +``` + +Does not wait for currently running execution. + +--- + +# Scheduling Tasklets + +## tasklet_schedule() + +Schedules tasklet with normal priority. + +```c +tasklet_schedule( + &tasklet); +``` + +Example: + +```c +tasklet_schedule( + &tasklet); +``` + +If already pending: + +```text +Request Ignored +``` + +The tasklet is not queued twice. + +--- + +# High Priority Tasklet + +## tasklet_hi_schedule() + +```c +tasklet_hi_schedule( + &tasklet); +``` + +Schedules tasklet with high priority. + +--- + +## tasklet_hi_schedule_first() + +```c +tasklet_hi_schedule_first( + &tasklet); +``` + +Special-purpose API rarely used in drivers. + +--- + +# Tasklet Queues + +Each CPU maintains: + +```text +CPU0 + | + +--> Normal Queue + | + +--> High Priority Queue + +CPU1 + | + +--> Normal Queue + | + +--> High Priority Queue +``` + +Tasklets are inserted into one of these queues. + +--- + +# Interrupt + Tasklet Example + +## Tasklet Declaration + +```c +void tasklet_fn(unsigned long); + +DECLARE_TASKLET( + tasklet, + tasklet_fn, + 1); +``` + +--- + +## ISR + +```c +static irqreturn_t irq_handler( + int irq, + void *dev_id) +{ + printk( + KERN_INFO, + "Interrupt Occurred\n"); + + tasklet_schedule( + &tasklet); + + return IRQ_HANDLED; +} +``` + +ISR only schedules the tasklet. + +--- + +## Tasklet Function + +```c +void tasklet_fn( + unsigned long arg) +{ + printk( + KERN_INFO, + "Executing Tasklet Function : arg=%ld\n", + arg); +} +``` + +--- + +# Execution Flow + +```text +Interrupt + | + v +ISR + | + v +tasklet_schedule() + | + v +Tasklet Queue + | + v +Tasklet Function +``` + +--- + +# Killing Tasklet + +## tasklet_kill() + +Waits for completion and removes tasklet. + +```c +tasklet_kill( + &tasklet); +``` + +Driver cleanup: + +```c +static void __exit driver_exit(void) +{ + tasklet_kill(&tasklet); + + free_irq( + IRQ_NO, + dev_id); +} +``` + +Always call before unloading the module. + +--- + +# Sample dmesg Output + +```text +Device Driver Insert...Done!!! + +Read function + +Shared IRQ: Interrupt Occurred + +Executing Tasklet Function : arg = 1 + +Device Driver Remove...Done!!! +``` + +This verifies: + +1. Interrupt triggered +2. ISR executed +3. Tasklet scheduled +4. Tasklet callback executed + +--- + +# Tasklet vs Workqueue + +| Feature | Tasklet | Workqueue | +| ---------------- | ------- | --------- | +| Context | Atomic | Process | +| Sleep Allowed | No | Yes | +| Mutex Allowed | No | Yes | +| Uses kworker | No | Yes | +| Long Processing | No | Yes | +| Spinlock Allowed | Yes | Yes | + +--- + +# Common Driver Use Cases + +## UART Driver + +```text +RX Interrupt + | + +--> Tasklet + | + +--> Buffer Processing +``` + +--- + +## Network Driver + +```text +Packet Arrival + | + +--> Tasklet + | + +--> Packet Handling +``` + +--- + +## GPIO Driver + +```text +Button Interrupt + | + +--> Event Processing +``` + +--- + +## SPI Driver + +```text +Transfer Complete + | + +--> Deferred Processing +``` + +--- + +# Best Practices + +* Keep ISR extremely short. +* Use tasklets only for short deferred work. +* Never sleep inside tasklets. +* Use spinlocks instead of mutexes. +* Kill tasklets before unloading driver. +* Use workqueues when sleeping is required. + +--- + +# Important APIs Summary + +## Creation + +```c +DECLARE_TASKLET() +DECLARE_TASKLET_DISABLED() +``` + +## Control + +```c +tasklet_enable() +tasklet_disable() +tasklet_disable_nosync() +``` + +## Scheduling + +```c +tasklet_schedule() +tasklet_hi_schedule() +tasklet_hi_schedule_first() +``` + +## Removal + +```c +tasklet_kill() +tasklet_kill_immediate() +``` + +--- + +# Key Takeaways + +* Tasklets are Bottom Half mechanisms built on SoftIRQs. +* Tasklets execute in atomic context. +* Tasklets cannot sleep or block. +* Same tasklet never runs concurrently on multiple CPUs. +* ISR commonly schedules tasklets for deferred work. +* Tasklets are lighter than workqueues but more restricted. +* Use workqueues whenever deferred work requires sleeping or blocking operations. + + +## Conclusion This is just a basic linux device driver. This will explain taklet static method in the linux device driver. Please refer this URL for the complete tutorial of this source code. -https://embetronicx.com/tutorials/linux/device-drivers/tasklet-static-method/ \ No newline at end of file +https://embetronicx.com/tutorials/linux/device-drivers/tasklet-static-method/ From a9df17bc966192049a0069459e1e407b7f40f294 Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Fri, 19 Jun 2026 18:44:31 +0530 Subject: [PATCH 34/55] Rename ReadMe.md to README.md --- .../Device_Driver/Tasklet/Static_Method/{ReadMe.md => README.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Linux/Device_Driver/Tasklet/Static_Method/{ReadMe.md => README.md} (100%) diff --git a/Linux/Device_Driver/Tasklet/Static_Method/ReadMe.md b/Linux/Device_Driver/Tasklet/Static_Method/README.md similarity index 100% rename from Linux/Device_Driver/Tasklet/Static_Method/ReadMe.md rename to Linux/Device_Driver/Tasklet/Static_Method/README.md From 478f8748be4650ea1ade2eb8b37a9effd94fde02 Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Fri, 19 Jun 2026 18:45:54 +0530 Subject: [PATCH 35/55] Update and rename ReadMe.md to README.md --- .../Tasklet/Dynamic_Method/README.md | 585 ++++++++++++++++++ .../Tasklet/Dynamic_Method/ReadMe.md | 4 - 2 files changed, 585 insertions(+), 4 deletions(-) create mode 100644 Linux/Device_Driver/Tasklet/Dynamic_Method/README.md delete mode 100644 Linux/Device_Driver/Tasklet/Dynamic_Method/ReadMe.md diff --git a/Linux/Device_Driver/Tasklet/Dynamic_Method/README.md b/Linux/Device_Driver/Tasklet/Dynamic_Method/README.md new file mode 100644 index 0000000..ea606cf --- /dev/null +++ b/Linux/Device_Driver/Tasklet/Dynamic_Method/README.md @@ -0,0 +1,585 @@ +# Linux Device Driver - Tasklet (Dynamic Method) + +## Overview + +This tutorial demonstrates **dynamic creation and initialization of Tasklets** using `tasklet_init()`. + +Unlike the static method: + +```c +DECLARE_TASKLET(tasklet, tasklet_fn, 1); +``` + +the dynamic method allocates memory for the tasklet at runtime and initializes it later. + +--- + +# Static vs Dynamic Tasklet + +## Static Method + +```c +DECLARE_TASKLET( + tasklet, + tasklet_fn, + 1); +``` + +* Compile-time initialization +* Fixed declaration +* Simpler implementation + +--- + +## Dynamic Method + +```c +struct tasklet_struct *tasklet; + +tasklet = kmalloc( + sizeof(struct tasklet_struct), + GFP_KERNEL); + +tasklet_init( + tasklet, + tasklet_fn, + 0); +``` + +* Runtime initialization +* Flexible allocation +* Useful when tasklets are embedded in dynamically allocated structures + +--- + +# Why Dynamic Tasklets? + +Dynamic initialization is useful when: + +* Number of tasklets is unknown at compile time +* Driver allocates resources dynamically +* Tasklets are associated with dynamically created devices +* Tasklet lifetime depends on runtime events + +Example: + +```text +Device Detected + | + v +Allocate Memory + | + v +Create Tasklet + | + v +Use Tasklet + | + v +Free Tasklet +``` + +--- + +# Tasklet Architecture + +```text +Hardware Interrupt + | + v +Interrupt Handler + | + v +tasklet_schedule() + | + v +Tasklet Queue + | + v +Tasklet Function +``` + +The ISR schedules the tasklet and exits quickly. The actual processing happens later. + +--- + +# Required Header Files + +```c +#include +#include +``` + +Needed for: + +* tasklet APIs +* kmalloc() +* kfree() + +--- + +# Dynamic Tasklet Declaration + +Pointer declaration: + +```c +struct tasklet_struct *tasklet; +``` + +Initially: + +```c +tasklet = NULL; +``` + +--- + +# Memory Allocation + +Allocate tasklet structure dynamically: + +```c +tasklet = + kmalloc( + sizeof(struct tasklet_struct), + GFP_KERNEL); +``` + +Validation: + +```c +if(tasklet == NULL) +{ + printk( + KERN_INFO + "Cannot allocate memory"); +} +``` + +--- + +# Dynamic Initialization + +## tasklet_init() + +Initializes the dynamically allocated tasklet. + +Syntax: + +```c +void tasklet_init( + struct tasklet_struct *t, + void (*func)(unsigned long), + unsigned long data); +``` + +Parameters: + +| Parameter | Description | +| --------- | --------------------------- | +| t | Tasklet structure | +| func | Callback function | +| data | Argument passed to callback | + +Example: + +```c +tasklet_init( + tasklet, + tasklet_fn, + 0); +``` + +--- + +# What tasklet_init() Does Internally + +Conceptually: + +```c +tasklet->func = tasklet_fn; + +tasklet->data = 0; + +tasklet->state = TASKLET_STATE_SCHED; + +atomic_set( + &tasklet->count, + 0); +``` + +This: + +* Assigns callback function +* Stores argument +* Initializes tasklet state +* Enables tasklet + +--- + +# Tasklet Callback Function + +Executed when tasklet runs. + +```c +void tasklet_fn( + unsigned long arg) +{ + printk( + KERN_INFO + "Executing Tasklet Function : arg=%ld\n", + arg); +} +``` + +Parameter: + +```c +unsigned long arg +``` + +Receives the value passed through `tasklet_init()`. + +--- + +# Scheduling Tasklet + +## tasklet_schedule() + +Schedules tasklet for execution. + +```c +tasklet_schedule( + tasklet); +``` + +Execution: + +```text +ISR + | + +--> tasklet_schedule() + | + +--> Return + +Later... + +Tasklet Function Executes +``` + +--- + +# Interrupt + Dynamic Tasklet Example + +## Tasklet Function + +```c +void tasklet_fn( + unsigned long arg) +{ + printk( + KERN_INFO, + "Executing Tasklet Function : arg=%ld\n", + arg); +} +``` + +--- + +## Interrupt Handler + +```c +static irqreturn_t irq_handler( + int irq, + void *dev_id) +{ + printk( + KERN_INFO, + "Shared IRQ: Interrupt Occurred"); + + tasklet_schedule( + tasklet); + + return IRQ_HANDLED; +} +``` + +ISR schedules the tasklet and exits immediately. + +--- + +# Driver Initialization + +## Register IRQ + +```c +request_irq( + IRQ_NO, + irq_handler, + IRQF_SHARED, + "etx_device", + (void *)irq_handler); +``` + +--- + +## Allocate Tasklet + +```c +tasklet = + kmalloc( + sizeof(struct tasklet_struct), + GFP_KERNEL); +``` + +--- + +## Initialize Tasklet + +```c +tasklet_init( + tasklet, + tasklet_fn, + 0); +``` + +Driver is now ready to schedule tasklets. + +--- + +# Execution Flow + +```text +insmod driver.ko + | + v +kmalloc() + | + v +tasklet_init() + | + v +Interrupt Occurs + | + v +ISR + | + v +tasklet_schedule() + | + v +Tasklet Queue + | + v +tasklet_fn() +``` + +--- + +# Driver Cleanup + +Before unloading: + +```c +tasklet_kill( + tasklet); +``` + +Release memory: + +```c +kfree(tasklet); +``` + +Complete cleanup: + +```c +tasklet_kill(tasklet); + +if(tasklet != NULL) +{ + kfree(tasklet); +} +``` + +Always kill the tasklet before freeing memory. + +--- + +# Sample dmesg Output + +After: + +```bash +cat /dev/etx_device +``` + +Output: + +```text +Device File Opened...!!! + +Read function + +Shared IRQ: Interrupt Occurred + +Executing Tasklet Function : arg = 0 + +Device File Closed...!!! +``` + +This confirms: + +1. Interrupt occurred +2. ISR executed +3. Tasklet scheduled +4. Tasklet callback executed + +--- + +# Dynamic vs Static Tasklet + +| Feature | Static Method | Dynamic Method | +| ----------------- | ----------------- | ----------------- | +| Initialization | DECLARE_TASKLET() | tasklet_init() | +| Allocation | Compile Time | Runtime | +| Memory Management | Automatic | kmalloc()/kfree() | +| Flexibility | Low | High | +| Runtime Creation | No | Yes | + +--- + +# Dynamic Tasklet vs Workqueue + +| Feature | Dynamic Tasklet | Workqueue | +| --------------- | --------------- | --------- | +| Context | Atomic | Process | +| Sleep Allowed | No | Yes | +| Mutex Allowed | No | Yes | +| Uses kworker | No | Yes | +| Deferred Work | Yes | Yes | +| Long Processing | No | Yes | + +--- + +# Common Driver Use Cases + +## UART Driver + +```text +RX Interrupt + | + +--> Tasklet + | + +--> Buffer Processing +``` + +--- + +## Network Driver + +```text +Packet Arrival + | + +--> Tasklet + | + +--> Protocol Processing +``` + +--- + +## SPI Driver + +```text +Transfer Complete + | + +--> Deferred Handling +``` + +--- + +## GPIO Driver + +```text +Button Interrupt + | + +--> Event Processing +``` + +--- + +# Best Practices + +* Keep ISR extremely short. +* Schedule tasklet from ISR. +* Never sleep inside tasklet. +* Use spinlocks if synchronization is required. +* Always call `tasklet_kill()` before freeing memory. +* Use workqueues instead when sleeping or blocking is required. + +--- + +# Important APIs Summary + +## Memory Management + +```c +kmalloc() +kfree() +``` + +--- + +## Initialization + +```c +tasklet_init() +``` + +--- + +## Scheduling + +```c +tasklet_schedule() +tasklet_hi_schedule() +tasklet_hi_schedule_first() +``` + +--- + +## Control + +```c +tasklet_enable() +tasklet_disable() +tasklet_disable_nosync() +``` + +--- + +## Cleanup + +```c +tasklet_kill() +tasklet_kill_immediate() +``` + +--- + +# Key Takeaways + +* Dynamic tasklets are created using `tasklet_init()`. +* Memory is allocated using `kmalloc()`. +* ISR schedules tasklets using `tasklet_schedule()`. +* Tasklets execute in atomic context. +* Tasklets cannot sleep or block. +* `tasklet_kill()` must be called before freeing tasklet memory. +* Dynamic tasklets provide greater flexibility than static tasklets. +* Use dynamic tasklets when tasklet lifetime depends on runtime allocation. + +## Conclusion +This is just a basic linux device driver. This will explain tasklet dynamic method in the linux device driver. + +Please refer this URL for the complete tutorial of this source code. +https://embetronicx.com/tutorials/linux/device-drivers/tasklets-dynamic-method/ diff --git a/Linux/Device_Driver/Tasklet/Dynamic_Method/ReadMe.md b/Linux/Device_Driver/Tasklet/Dynamic_Method/ReadMe.md deleted file mode 100644 index 7696bcf..0000000 --- a/Linux/Device_Driver/Tasklet/Dynamic_Method/ReadMe.md +++ /dev/null @@ -1,4 +0,0 @@ -This is just a basic linux device driver. This will explain tasklet dynamic method in the linux device driver. - -Please refer this URL for the complete tutorial of this source code. -https://embetronicx.com/tutorials/linux/device-drivers/tasklets-dynamic-method/ \ No newline at end of file From 0671a7bc3930f7f5dfb5c963f943e3c51317b7d5 Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Fri, 19 Jun 2026 18:47:25 +0530 Subject: [PATCH 36/55] Update and rename ReadMe.md to README.md --- Linux/Device_Driver/mutex/README.md | 702 ++++++++++++++++++++++++++++ Linux/Device_Driver/mutex/ReadMe.md | 4 - 2 files changed, 702 insertions(+), 4 deletions(-) create mode 100644 Linux/Device_Driver/mutex/README.md delete mode 100644 Linux/Device_Driver/mutex/ReadMe.md diff --git a/Linux/Device_Driver/mutex/README.md b/Linux/Device_Driver/mutex/README.md new file mode 100644 index 0000000..3649354 --- /dev/null +++ b/Linux/Device_Driver/mutex/README.md @@ -0,0 +1,702 @@ +# Linux Device Driver - Mutex in Linux Kernel + +## Overview + +A Mutex (**Mutual Exclusion Lock**) is a synchronization mechanism used to protect shared resources from concurrent access by multiple threads. + +Only **one thread can own a mutex at a time**. + +Mutexes are used to prevent: + +* Race conditions +* Data corruption +* Inconsistent shared data access + +A mutex has **ownership semantics**: + +```text +Thread A locks Mutex + | + v +Thread A must unlock Mutex +``` + +A different thread cannot unlock a mutex it did not acquire. + +--- + +# Why Do We Need Mutex? + +Consider two kernel threads accessing the same global variable. + +Without synchronization: + +```text +Thread1 + | + +--> global_var++ + +Thread2 + | + +--> global_var++ +``` + +Possible execution: + +```text +global_var = 0 + +Thread1 reads 0 +Thread2 reads 0 + +Thread1 writes 1 +Thread2 writes 1 +``` + +Expected: + +```text +2 +``` + +Actual: + +```text +1 +``` + +This is called a **Race Condition**. + +--- + +# Race Condition + +A race condition occurs when: + +* Multiple threads access shared data +* At least one thread modifies the data +* Access is not synchronized + +Result depends on scheduling order. + +```text +Thread A + \ + \ + Shared Data + / + / +Thread B +``` + +Race conditions can cause: + +* Wrong values +* Kernel crashes +* Corrupted linked lists +* Memory corruption + +--- + +# What is a Mutex? + +Mutex stands for: + +```text +Mutual Exclusion +``` + +Concept: + +```text +Shared Resource + | + v + Mutex + | + v +Only One Thread Allowed +``` + +Workflow: + +```text +Lock Mutex + | + v +Access Shared Resource + | + v +Unlock Mutex +``` + +Any thread that arrives while the mutex is held will sleep until it becomes available. + +--- + +# Mutex vs Spinlock + +| Feature | Mutex | Spinlock | +| ---------------------- | --------------- | ----------- | +| Sleep Allowed | Yes | No | +| Context | Process Context | Any Context | +| Ownership | Yes | No | +| Long Critical Sections | Good | Bad | +| ISR Usage | Not Allowed | Allowed | +| Busy Waiting | No | Yes | + +Mutexes put the task to sleep when contention occurs, whereas spinlocks keep spinning while waiting. + +--- + +# Mutex Rules + +## Rule 1 + +Mutexes can sleep. + +Therefore: + +```text +Allowed: + Process Context + Kernel Thread + +Not Allowed: + ISR + Tasklet + SoftIRQ +``` + +--- + +## Rule 2 + +Mutex has ownership. + +```text +Thread A locks +Thread A unlocks +``` + +Not: + +```text +Thread A locks +Thread B unlocks +``` + +--- + +## Rule 3 + +Recursive locking is not allowed. + +Wrong: + +```c +mutex_lock(&lock); +mutex_lock(&lock); +``` + +This may deadlock. + +--- + +# Mutex Lifecycle + +```text +Create Mutex + | + v +mutex_init() + | + v +mutex_lock() + | + v +Critical Section + | + v +mutex_unlock() +``` + +--- + +# Header File + +```c +#include +``` + +Required for all mutex APIs. + +--- + +# Mutex Declaration + +## Static Method + +Used for global mutexes. + +```c +DEFINE_MUTEX(etx_mutex); +``` + +Equivalent concept: + +```text +Create + Initialize +``` + +in a single statement. + +--- + +# Dynamic Method + +Declare: + +```c +struct mutex etx_mutex; +``` + +Initialize: + +```c +mutex_init(&etx_mutex); +``` + +This initializes the mutex in unlocked state. + +--- + +# Locking a Mutex + +## mutex_lock() + +Acquire mutex. + +```c +mutex_lock(&etx_mutex); +``` + +Behavior: + +```text +Mutex Free + | + +--> Acquire Immediately + +Mutex Busy + | + +--> Sleep Until Available +``` + +The calling task sleeps until the mutex becomes available. + +--- + +# mutex_lock_interruptible() + +Interruptible version. + +```c +mutex_lock_interruptible( + &etx_mutex); +``` + +Return Values: + +| Return | Meaning | +| ------ | --------------------- | +| 0 | Lock Acquired | +| -EINTR | Interrupted by Signal | + +Useful when waiting should be interruptible. + +--- + +# mutex_trylock() + +Non-blocking attempt. + +```c +if(mutex_trylock(&etx_mutex)) +{ + /* lock acquired */ +} +``` + +Returns: + +| Return | Meaning | +| ------ | ------- | +| 1 | Success | +| 0 | Busy | + +Does not sleep. + +--- + +# Unlocking a Mutex + +## mutex_unlock() + +Release mutex. + +```c +mutex_unlock(&etx_mutex); +``` + +After unlocking: + +```text +Waiting Thread + | + v +Can Acquire Mutex +``` + +Must be unlocked by the same task that acquired it. + +--- + +# Checking Mutex State + +## mutex_is_locked() + +```c +mutex_is_locked( + &etx_mutex); +``` + +Returns: + +| Return | Meaning | +| ------ | -------- | +| 1 | Locked | +| 0 | Unlocked | + +--- + +# Kernel Thread Example + +## Shared Variable + +```c +unsigned long +etx_global_variable = 0; +``` + +Shared between: + +```text +Thread1 +Thread2 +``` + +--- + +# Thread 1 + +```c +int thread_function1(void *pv) +{ + while(!kthread_should_stop()) + { + mutex_lock( + &etx_mutex); + + etx_global_variable++; + + pr_info( + "Thread1 %lu\n", + etx_global_variable); + + mutex_unlock( + &etx_mutex); + + msleep(1000); + } + + return 0; +} +``` + +--- + +# Thread 2 + +```c +int thread_function2(void *pv) +{ + while(!kthread_should_stop()) + { + mutex_lock( + &etx_mutex); + + etx_global_variable++; + + pr_info( + "Thread2 %lu\n", + etx_global_variable); + + mutex_unlock( + &etx_mutex); + + msleep(1000); + } + + return 0; +} +``` + +--- + +# Execution Flow + +```text +Thread1 + | + +--> mutex_lock() + + Mutex Acquired + + | + +--> Increment Variable + + | + +--> mutex_unlock() + + | + +--> Sleep +``` + +Meanwhile: + +```text +Thread2 + | + +--> Waiting For Mutex +``` + +After unlock: + +```text +Thread2 Acquires Mutex +``` + +--- + +# Example Output + +```text +Thread1 1 +Thread2 2 +Thread1 3 +Thread2 4 +Thread1 5 +Thread2 6 +``` + +The value increments correctly because access is serialized by the mutex. + +--- + +# Mutex vs Semaphore + +| Feature | Mutex | Semaphore | +| -------------------- | ---------------- | -------------------------------- | +| Ownership | Yes | No | +| Unlock By Owner Only | Yes | No | +| Resource Count | One | Multiple | +| Purpose | Mutual Exclusion | Resource Counting | +| Priority Inheritance | Yes | Typically Yes (Kernel Dependent) | + +Mutex is used primarily for protecting critical sections. + +--- + +# Mutex vs Completion + +| Mutex | Completion | | +| ----------------------- | -------------- | -- | +| Protect Shared Resource | Wait For Event | | +| Lock/Unlock | Complete/Wait | | +| Ownership | Yes | No | +| Mutual Exclusion | Yes | No | + +--- + +# Common Driver Use Cases + +## Linked List Protection + +```c +mutex_lock(&list_mutex); + +list_add_tail(...); + +mutex_unlock(&list_mutex); +``` + +--- + +## Device Configuration + +```c +mutex_lock(&device_mutex); + +device_config(); + +mutex_unlock(&device_mutex); +``` + +--- + +## Shared Buffer Access + +```c +mutex_lock(&buffer_mutex); + +copy_data(); + +mutex_unlock(&buffer_mutex); +``` + +--- + +## File Operations + +```c +open() +read() +write() +ioctl() +``` + +Prevent simultaneous modification of shared driver data. + +--- + +# Common Mistakes + +## Forgetting Unlock + +Wrong: + +```c +mutex_lock(&lock); + +/* work */ + +return; +``` + +Correct: + +```c +mutex_lock(&lock); + +/* work */ + +mutex_unlock(&lock); + +return; +``` + +--- + +## Using Mutex in ISR + +Wrong: + +```c +irq_handler() +{ + mutex_lock(&lock); +} +``` + +Reason: + +```text +Mutex Can Sleep +ISR Cannot Sleep +``` + +--- + +## Double Locking + +Wrong: + +```c +mutex_lock(&lock); + +mutex_lock(&lock); +``` + +May cause deadlock. + +--- + +# Important APIs Summary + +## Initialization + +```c +DEFINE_MUTEX() + +mutex_init() +``` + +--- + +## Lock + +```c +mutex_lock() + +mutex_lock_interruptible() + +mutex_trylock() +``` + +--- + +## Unlock + +```c +mutex_unlock() +``` + +--- + +## Status + +```c +mutex_is_locked() +``` + +--- + +# Key Takeaways + +* Mutex provides mutual exclusion for shared resources. +* Only one thread can hold a mutex at a time. +* Mutexes prevent race conditions. +* Mutexes can sleep and therefore cannot be used in ISR, Tasklets, or SoftIRQs. +* `mutex_lock()` blocks until the lock becomes available. +* `mutex_trylock()` does not block. +* The thread that locks a mutex must unlock it. +* Mutexes are ideal for protecting linked lists, buffers, device state, and shared driver data. +* Kernel threads and file operations commonly use mutexes for synchronization. + + +## Conclusion +This is just a basic linux device driver which explains about the mutex in linux device driver. + +Please refer this URL for the complete tutorial of this example source code. +https://embetronicx.com/tutorials/linux/device-drivers/linux-device-driver-tutorial-mutex-in-linux-kernel/ diff --git a/Linux/Device_Driver/mutex/ReadMe.md b/Linux/Device_Driver/mutex/ReadMe.md deleted file mode 100644 index c2568e8..0000000 --- a/Linux/Device_Driver/mutex/ReadMe.md +++ /dev/null @@ -1,4 +0,0 @@ -This is just a basic linux device driver which explains about the mutex in linux device driver. - -Please refer this URL for the complete tutorial of this example source code. -https://embetronicx.com/tutorials/linux/device-drivers/linux-device-driver-tutorial-mutex-in-linux-kernel/ \ No newline at end of file From bd50edb762b3459f28defdefef03410191b5b9c4 Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Fri, 19 Jun 2026 18:48:50 +0530 Subject: [PATCH 37/55] Update and rename ReadMe.md to README.md --- .../Device_Driver/Spinlock/Spinlock/README.md | 717 ++++++++++++++++++ .../Device_Driver/Spinlock/Spinlock/ReadMe.md | 4 - 2 files changed, 717 insertions(+), 4 deletions(-) create mode 100644 Linux/Device_Driver/Spinlock/Spinlock/README.md delete mode 100644 Linux/Device_Driver/Spinlock/Spinlock/ReadMe.md diff --git a/Linux/Device_Driver/Spinlock/Spinlock/README.md b/Linux/Device_Driver/Spinlock/Spinlock/README.md new file mode 100644 index 0000000..5fb06ca --- /dev/null +++ b/Linux/Device_Driver/Spinlock/Spinlock/README.md @@ -0,0 +1,717 @@ +# Linux Device Driver - Spinlock in Linux Kernel (Part 1) + +## Overview + +A Spinlock is a lightweight synchronization mechanism used to protect shared resources from concurrent access. + +Like a mutex, it provides mutual exclusion, but unlike a mutex, a thread does **not sleep** when the lock is unavailable. + +Instead, it continuously checks the lock in a loop (**spins**) until the lock becomes available. + +--- + +# Why Spinlocks? + +Consider two kernel threads updating a shared variable. + +Without synchronization: + +```text +Thread1 Thread2 + | | +Read Value = 0 Read Value = 0 + | | +Increment Increment + | | +Write 1 Write 1 +``` + +Expected: + +```text +Global Variable = 2 +``` + +Actual: + +```text +Global Variable = 1 +``` + +This is a race condition. Spinlocks prevent this problem. + +--- + +# What is a Spinlock? + +A Spinlock is a: + +```text +Single Holder Lock +``` + +States: + +```text +UNLOCKED +LOCKED +``` + +When a thread attempts to acquire a locked spinlock: + +```text +Mutex: + Sleep + +Spinlock: + Keep Trying (Spin) +``` + +This makes spinlocks extremely fast for very short critical sections. + +--- + +# Mutex vs Spinlock + +| Feature | Mutex | Spinlock | +| ---------------- | ----- | ---------- | +| Waiting Method | Sleep | Busy Wait | +| Context Switch | Yes | No | +| Can Sleep | Yes | No | +| ISR Safe | No | Yes | +| Critical Section | Long | Very Short | +| Ownership | Yes | No | + +Spinlocks are preferred when: + +* Critical section is extremely short +* Sleeping is not allowed +* Interrupt context is involved + +--- + +# How Spinlock Works + +```text +CPU0 + | + +--> spin_lock() + | + +--> Critical Section + | + +--> spin_unlock() + +CPU1 + | + +--> spin_lock() + | + +--> Spins Until CPU0 Releases Lock +``` + +Only one CPU enters the protected section at a time. + +--- + +# When to Use Spinlock? + +Suitable for: + +* Shared kernel variables +* Shared linked lists +* Interrupt handlers +* Tasklets +* SoftIRQs +* Device driver state protection + +Example: + +```text +ISR + | + +--> Shared Buffer + +Kernel Thread + | + +--> Same Shared Buffer +``` + +A spinlock protects access to the shared buffer. + +--- + +# Important Rule + +Never hold a spinlock for a long time. + +Bad: + +```c +spin_lock(&lock); + +msleep(1000); + +spin_unlock(&lock); +``` + +Good: + +```c +spin_lock(&lock); + +shared_var++; + +spin_unlock(&lock); +``` + +Because while one CPU holds the lock, other CPUs waste CPU cycles spinning. + +--- + +# Kernel Configuration Behavior + +### SMP Disabled + +If: + +```text +CONFIG_SMP = n +CONFIG_PREEMPT = n +``` + +Spinlocks are effectively unnecessary because only one execution path can run at a time. + +--- + +### SMP Disabled + PREEMPT Enabled + +If: + +```text +CONFIG_SMP = n +CONFIG_PREEMPT = y +``` + +Spinlocks disable preemption to prevent races. + +--- + +# Header File + +```c +#include +``` + +Required for all spinlock APIs. + +--- + +# Spinlock Declaration + +## Static Initialization + +```c +DEFINE_SPINLOCK(etx_spinlock); +``` + +Expands conceptually to: + +```c +spinlock_t etx_spinlock = + __SPIN_LOCK_UNLOCKED( + etx_spinlock); +``` + +Creates a spinlock in unlocked state. + +--- + +# Dynamic Initialization + +Declare: + +```c +spinlock_t etx_spinlock; +``` + +Initialize: + +```c +spin_lock_init( + &etx_spinlock); +``` + +Used when initialization is required at runtime. + +--- + +# Approach 1: User Context Locking + +Used between: + +```text +Kernel Thread + ↔ +Kernel Thread +``` + +--- + +## spin_lock() + +Acquire lock. + +```c +spin_lock( + &etx_spinlock); +``` + +Behavior: + +```text +Unlocked + | + +--> Acquire + +Locked + | + +--> Spin Forever Until Free +``` + +--- + +## spin_trylock() + +Non-blocking lock attempt. + +```c +if(spin_trylock( + &etx_spinlock)) +{ + /* acquired */ +} +``` + +Returns: + +| Return | Meaning | +| -------- | ------- | +| Non-zero | Success | +| 0 | Failed | + +Does not spin. + +--- + +## spin_unlock() + +Release lock. + +```c +spin_unlock( + &etx_spinlock); +``` + +Allows another waiting CPU to acquire it. + +--- + +## spin_is_locked() + +Check lock state. + +```c +spin_is_locked( + &etx_spinlock); +``` + +Returns: + +| Return | Meaning | +| -------- | -------- | +| Non-zero | Locked | +| 0 | Unlocked | + +--- + +# Approach 2: Bottom Half Locking + +Used between: + +```text +Tasklet + ↔ +Tasklet + +SoftIRQ + ↔ +SoftIRQ +``` + +Standard spinlock APIs are typically sufficient. + +--- + +# Approach 3: User Context + Bottom Half + +Used when data is shared between: + +```text +Kernel Thread + ↔ +Tasklet + +Kernel Thread + ↔ +SoftIRQ +``` + +--- + +## spin_lock_bh() + +```c +spin_lock_bh( + &etx_spinlock); +``` + +What it does: + +```text +Disable SoftIRQ + + +Acquire Spinlock +``` + +The `_bh` suffix means: + +```text +Bottom Half +``` + +Prevents tasklets and softirqs from executing on the current CPU. + +--- + +## spin_unlock_bh() + +```c +spin_unlock_bh( + &etx_spinlock); +``` + +What it does: + +```text +Release Spinlock + + +Enable SoftIRQ +``` + +--- + +# Kernel Thread Example + +## Global Variable + +```c +unsigned long +etx_global_variable = 0; +``` + +Protected using: + +```c +DEFINE_SPINLOCK( + etx_spinlock); +``` + +--- + +## Thread 1 + +```c +int thread_function1( + void *pv) +{ + while( + !kthread_should_stop()) + { + spin_lock( + &etx_spinlock); + + etx_global_variable++; + + printk( + "Thread1 %lu\n", + etx_global_variable); + + spin_unlock( + &etx_spinlock); + } + + return 0; +} +``` + +--- + +## Thread 2 + +```c +int thread_function2( + void *pv) +{ + while( + !kthread_should_stop()) + { + spin_lock( + &etx_spinlock); + + etx_global_variable++; + + printk( + "Thread2 %lu\n", + etx_global_variable); + + spin_unlock( + &etx_spinlock); + } + + return 0; +} +``` + +Both threads safely update the shared variable. + +--- + +# Execution Flow + +```text +Thread1 + | + +--> spin_lock() + | + +--> Critical Section + | + +--> spin_unlock() + +Thread2 + | + +--> Waiting (Spinning) +``` + +After unlock: + +```text +Thread2 Acquires Lock +``` + +--- + +# Sample Output + +```text +Thread1 1 +Thread2 2 +Thread1 3 +Thread2 4 +Thread1 5 +Thread2 6 +``` + +The shared variable remains consistent because only one thread enters the critical section at a time. + +--- + +# Spinlock vs Read-Write Spinlock + +| Feature | Spinlock | Read-Write Spinlock | +| -------------------- | -------------- | ------------------- | +| Readers | One at a Time | Multiple Readers | +| Writers | One | One | +| Complexity | Simple | Higher | +| Read-Heavy Workloads | Less Efficient | Better | + +Read-write spinlocks allow multiple simultaneous readers but only one writer. + +--- + +# Common Driver Use Cases + +## Shared Buffer + +```c +spin_lock(&buffer_lock); + +/* access buffer */ + +spin_unlock(&buffer_lock); +``` + +--- + +## Interrupt Handler + +```c +irq_handler() +{ + spin_lock(&irq_lock); + + /* update shared data */ + + spin_unlock(&irq_lock); +} +``` + +--- + +## Linked List Protection + +```c +spin_lock(&list_lock); + +list_add_tail(...); + +spin_unlock(&list_lock); +``` + +--- + +## Statistics Counters + +```c +spin_lock(&stats_lock); + +packet_count++; + +spin_unlock(&stats_lock); +``` + +--- + +# Common Mistakes + +## Sleeping While Holding Spinlock + +Wrong: + +```c +spin_lock(&lock); + +msleep(100); + +spin_unlock(&lock); +``` + +Spinlocks must not sleep. + +--- + +## Large Critical Sections + +Wrong: + +```c +spin_lock(&lock); + +/* lengthy processing */ + +spin_unlock(&lock); +``` + +Keep critical sections extremely short. + +--- + +## Missing Unlock + +Wrong: + +```c +spin_lock(&lock); + +return; +``` + +Causes permanent lockup. + +Correct: + +```c +spin_lock(&lock); + +/* work */ + +spin_unlock(&lock); +``` + +--- + +# Important APIs Summary + +## Initialization + +```c +DEFINE_SPINLOCK() + +spin_lock_init() +``` + +--- + +## Lock + +```c +spin_lock() + +spin_trylock() +``` + +--- + +## Unlock + +```c +spin_unlock() +``` + +--- + +## Status + +```c +spin_is_locked() +``` + +--- + +## Bottom Half Protection + +```c +spin_lock_bh() + +spin_unlock_bh() +``` + +--- + +# Key Takeaways + +* Spinlock is a lightweight mutual exclusion mechanism. +* Waiting threads do not sleep; they continuously spin. +* Spinlocks are ideal for very short critical sections. +* Spinlocks can be used in interrupt context. +* Spinlocks must never sleep or block. +* `spin_lock()` acquires the lock and waits by spinning. +* `spin_trylock()` attempts acquisition without waiting. +* `spin_lock_bh()` protects shared data between user context and bottom halves. +* Use mutexes for long operations and spinlocks for short, low-latency critical sections. +* Excessive spinlock holding time can significantly hurt SMP system performance. + + +## Conclusion +This is just a basic linux device driver. This will explains spinlock in the linux device driver. + +Please refer this URL for the complete tutorial of this source code. +https://embetronicx.com/tutorials/linux/device-drivers/spinlock-in-linux-kernel-1/ diff --git a/Linux/Device_Driver/Spinlock/Spinlock/ReadMe.md b/Linux/Device_Driver/Spinlock/Spinlock/ReadMe.md deleted file mode 100644 index 2be6be5..0000000 --- a/Linux/Device_Driver/Spinlock/Spinlock/ReadMe.md +++ /dev/null @@ -1,4 +0,0 @@ -This is just a basic linux device driver. This will explains spinlock in the linux device driver. - -Please refer this URL for the complete tutorial of this source code. -https://embetronicx.com/tutorials/linux/device-drivers/spinlock-in-linux-kernel-1/ \ No newline at end of file From 532aac789ea85c83c4dd810bf9ec01ef8daad679 Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Fri, 19 Jun 2026 18:50:42 +0530 Subject: [PATCH 38/55] Update and rename ReadMe.md to README.md --- .../Spinlock/Read_Write_Spinlock/README.md | 840 ++++++++++++++++++ .../Spinlock/Read_Write_Spinlock/ReadMe.md | 4 - 2 files changed, 840 insertions(+), 4 deletions(-) create mode 100644 Linux/Device_Driver/Spinlock/Read_Write_Spinlock/README.md delete mode 100644 Linux/Device_Driver/Spinlock/Read_Write_Spinlock/ReadMe.md diff --git a/Linux/Device_Driver/Spinlock/Read_Write_Spinlock/README.md b/Linux/Device_Driver/Spinlock/Read_Write_Spinlock/README.md new file mode 100644 index 0000000..0e6cc8c --- /dev/null +++ b/Linux/Device_Driver/Spinlock/Read_Write_Spinlock/README.md @@ -0,0 +1,840 @@ +# Linux Device Driver - Read-Write Spinlock in Linux Kernel (Spinlock Part 2) + +## Overview + +A Read-Write Spinlock (`rwlock_t`) is an extension of a normal spinlock that differentiates between: + +* Readers +* Writers + +Unlike a normal spinlock where only one thread can enter the critical section, a Read-Write Spinlock allows: + +```text +Multiple Readers + OR +Single Writer +``` + +This improves performance in read-heavy workloads. + +--- + +# Why Read-Write Spinlock? + +Consider a shared variable: + +```c +unsigned long counter; +``` + +Access Pattern: + +```text +Thread1 -> Read +Thread2 -> Read +Thread3 -> Read +Thread4 -> Read +Thread5 -> Write +``` + +With a normal spinlock: + +```text +Reader1 + | + +--> Lock + +Reader2 + | + +--> Wait + +Reader3 + | + +--> Wait +``` + +All readers serialize unnecessarily. + +With Read-Write Spinlock: + +```text +Reader1 +Reader2 +Reader3 +Reader4 + | + +--> Run Together +``` + +Only writers require exclusive access. + +--- + +# What Problem Does It Solve? + +Normal Spinlock: + +```text +One Reader Allowed +``` + +Read-Write Spinlock: + +```text +Many Readers Allowed +One Writer Allowed +``` + +Suitable when: + +```text +Reads >>> Writes +``` + +Examples: + +* Statistics counters +* Configuration tables +* Routing tables +* Driver status structures +* Lookup tables + +--- + +# Working Principle + +## Case 1: No Lock Holder + +```text +Critical Section Empty + +Reader -> Allowed +Writer -> Allowed +``` + +--- + +## Case 2: Reader Holds Lock + +```text +Reader1 Running +``` + +New Reader: + +```text +Reader2 -> Allowed +Reader3 -> Allowed +Reader4 -> Allowed +``` + +Writer: + +```text +Writer -> Must Wait +``` + +--- + +## Case 3: Writer Holds Lock + +```text +Writer Running +``` + +Then: + +```text +Reader -> Blocked +Writer -> Blocked +``` + +No other thread can enter. + +--- + +# Reader Preference + +Read-Write Spinlock favors readers. + +Example: + +```text +Reader1 enters +Reader2 enters +Reader3 enters + +Writer waiting +``` + +While writer is waiting: + +```text +Reader4 enters +Reader5 enters +Reader6 enters +``` + +Writer continues waiting until all readers leave. + +This can cause: + +```text +Writer Starvation +``` + +For writer-priority workloads, Linux provides: + +```text +Seqlock +``` + +instead. + +--- + +# When To Use? + +Use Read Lock: + +```text +Only Reading Data +``` + +Use Write Lock: + +```text +Modifying Data +``` + +Ideal when: + +```text +90% Reads +10% Writes +``` + +Not useful when: + +```text +Frequent Writes +``` + +because writers block everyone. + +--- + +# Header File + +```c +#include +``` + +--- + +# Data Type + +```c +rwlock_t etx_rwlock; +``` + +Represents a Read-Write Spinlock. + +--- + +# Initialization + +## Static Method + +```c +DEFINE_RWLOCK(etx_rwlock); +``` + +Creates and initializes lock. + +Example: + +```c +static DEFINE_RWLOCK(etx_rwlock); +``` + +--- + +## Dynamic Method + +Declaration: + +```c +rwlock_t etx_rwlock; +``` + +Initialization: + +```c +rwlock_init(&etx_rwlock); +``` + +Used when runtime initialization is required. + +--- + +# Approach 1 - User Context Locking + +Used between: + +```text +Kernel Thread + ↔ +Kernel Thread +``` + +--- + +# Read Lock APIs + +## read_lock() + +Acquire reader lock. + +```c +read_lock( + &etx_rwlock); +``` + +Behavior: + +```text +No Writer Present + | + +--> Enter + +Writer Present + | + +--> Spin +``` + +--- + +## read_unlock() + +Release reader lock. + +```c +read_unlock( + &etx_rwlock); +``` + +--- + +# Write Lock APIs + +## write_lock() + +Acquire writer lock. + +```c +write_lock( + &etx_rwlock); +``` + +Behavior: + +```text +No Readers +No Writers + | + +--> Enter + +Otherwise + | + +--> Spin +``` + +--- + +## write_unlock() + +Release writer lock. + +```c +write_unlock( + &etx_rwlock); +``` + +--- + +# Example - Reader/Writer Threads + +## Writer Thread + +```c +int thread_function1( + void *pv) +{ + while( + !kthread_should_stop()) + { + write_lock( + &etx_rwlock); + + etx_global_variable++; + + write_unlock( + &etx_rwlock); + + msleep(1000); + } + + return 0; +} +``` + +--- + +## Reader Thread + +```c +int thread_function2( + void *pv) +{ + while( + !kthread_should_stop()) + { + read_lock( + &etx_rwlock); + + printk( + "Value=%lu\n", + etx_global_variable); + + read_unlock( + &etx_rwlock); + + msleep(1000); + } + + return 0; +} +``` + +--- + +# Approach 2 - Between Bottom Halves + +Used between: + +```text +Tasklet ↔ Tasklet + +SoftIRQ ↔ SoftIRQ +``` + +Use: + +```c +read_lock() +write_lock() +``` + +and corresponding unlock APIs. + +--- + +# Approach 3 - User Context + Bottom Half + +Used between: + +```text +Kernel Thread + ↔ +Tasklet + +Kernel Thread + ↔ +SoftIRQ +``` + +--- + +## Read Lock + +```c +read_lock_bh( + &etx_rwlock); +``` + +--- + +## Read Unlock + +```c +read_unlock_bh( + &etx_rwlock); +``` + +--- + +## Write Lock + +```c +write_lock_bh( + &etx_rwlock); +``` + +--- + +## Write Unlock + +```c +write_unlock_bh( + &etx_rwlock); +``` + +What `_bh` does: + +```text +Disable SoftIRQ +Acquire Lock +``` + +Unlock: + +```text +Release Lock +Enable SoftIRQ +``` + +--- + +# Approach 4 - Hard IRQ + Bottom Half + +Used between: + +```text +ISR + ↔ +Tasklet + +ISR + ↔ +SoftIRQ +``` + +--- + +## Read Lock + +```c +read_lock_irq( + &etx_rwlock); +``` + +--- + +## Read Unlock + +```c +read_unlock_irq( + &etx_rwlock); +``` + +--- + +## Write Lock + +```c +write_lock_irq( + &etx_rwlock); +``` + +--- + +## Write Unlock + +```c +write_unlock_irq( + &etx_rwlock); +``` + +These APIs: + +```text +Disable Local Interrupts +Acquire Lock +``` + +Then: + +```text +Release Lock +Enable Interrupts +``` + +--- + +# Approach 5 - IRQ Save/Restore Variant + +Preferred in many drivers. + +--- + +## Read Side + +```c +unsigned long flags; + +read_lock_irqsave( + &etx_rwlock, + flags); + +... + +read_unlock_irqrestore( + &etx_rwlock, + flags); +``` + +--- + +## Write Side + +```c +unsigned long flags; + +write_lock_irqsave( + &etx_rwlock, + flags); + +... + +write_unlock_irqrestore( + &etx_rwlock, + flags); +``` + +Advantage: + +```text +Restores Previous IRQ State +``` + +instead of blindly enabling interrupts. + +--- + +# Execution Example + +```text +Reader1 + | + +--> read_lock() + +Reader2 + | + +--> read_lock() + +Reader3 + | + +--> read_lock() +``` + +All three execute simultaneously. + +Writer: + +```text +Writer + | + +--> write_lock() + | + +--> Waiting +``` + +After all readers exit: + +```text +Writer Acquires Lock +``` + +--- + +# Read-Write Spinlock vs Spinlock + +| Feature | Spinlock | RW Spinlock | +| -------------------- | -------- | ----------- | +| Readers | 1 | Multiple | +| Writers | 1 | 1 | +| Read Parallelism | No | Yes | +| Write Parallelism | No | No | +| Read Heavy Workloads | Poor | Excellent | +| Complexity | Simple | Higher | + +--- + +# Read-Write Spinlock vs Mutex + +| Feature | RW Spinlock | Mutex | +| --------------------- | ----------- | ----- | +| Sleep Allowed | No | Yes | +| Busy Wait | Yes | No | +| IRQ Context | Yes | No | +| Read Sharing | Yes | No | +| Long Critical Section | No | Yes | + +--- + +# Typical Driver Use Cases + +## Statistics + +```c +read_lock(&stats_lock); +packets = stats.rx_packets; +read_unlock(&stats_lock); +``` + +--- + +## Routing Table + +```c +read_lock(&route_lock); +lookup_route(); +read_unlock(&route_lock); +``` + +--- + +## Device State + +```c +read_lock(&state_lock); +status = device_status; +read_unlock(&state_lock); +``` + +--- + +## Configuration Updates + +```c +write_lock(&cfg_lock); +update_configuration(); +write_unlock(&cfg_lock); +``` + +--- + +# Common Mistakes + +## Sleeping Inside Lock + +Wrong: + +```c +read_lock(&lock); + +msleep(100); + +read_unlock(&lock); +``` + +RW Spinlocks cannot sleep. + +--- + +## Using For Write-Heavy Workloads + +Wrong choice: + +```text +Writes >> Reads +``` + +Use normal spinlock or mutex instead. + +--- + +## Long Critical Sections + +Wrong: + +```c +write_lock(&lock); + +/* lengthy processing */ + +write_unlock(&lock); +``` + +Readers and writers remain blocked/spinning. + +--- + +# Important APIs Summary + +## Initialization + +```c +DEFINE_RWLOCK() + +rwlock_init() +``` + +--- + +## Reader + +```c +read_lock() +read_unlock() + +read_lock_bh() +read_unlock_bh() + +read_lock_irq() +read_unlock_irq() + +read_lock_irqsave() +read_unlock_irqrestore() +``` + +--- + +## Writer + +```c +write_lock() +write_unlock() + +write_lock_bh() +write_unlock_bh() + +write_lock_irq() +write_unlock_irq() + +write_lock_irqsave() +write_unlock_irqrestore() +``` + +--- + +# Key Takeaways + +* Read-Write Spinlock allows **multiple concurrent readers** but only **one writer**. +* Readers can run simultaneously if no writer holds the lock. +* Writers require exclusive access. +* RW spinlocks are best for **read-heavy workloads**. +* RW spinlocks run in atomic context and cannot sleep. +* `_bh` variants protect against SoftIRQ/Tasklet interference. +* `_irq` variants disable interrupts while holding the lock. +* `_irqsave` variants are usually safest because they restore the previous interrupt state. +* RW spinlocks favor readers and can potentially starve writers. +* Use RW spinlocks only when read parallelism provides a measurable benefit. + + +## Conclusion +This is just a basic linux device driver. This will explain read write spinlock in the linux device driver. + +Please refer this URL for the complete tutorial of this source code. +https://embetronicx.com/tutorials/linux/device-drivers/read-write-spinlock/ diff --git a/Linux/Device_Driver/Spinlock/Read_Write_Spinlock/ReadMe.md b/Linux/Device_Driver/Spinlock/Read_Write_Spinlock/ReadMe.md deleted file mode 100644 index d44b250..0000000 --- a/Linux/Device_Driver/Spinlock/Read_Write_Spinlock/ReadMe.md +++ /dev/null @@ -1,4 +0,0 @@ -This is just a basic linux device driver. This will explain read write spinlock in the linux device driver. - -Please refer this URL for the complete tutorial of this source code. -https://embetronicx.com/tutorials/linux/device-drivers/read-write-spinlock/ \ No newline at end of file From d5e22de7e522466bbafb23e601ac32cdc92d8cb5 Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Fri, 19 Jun 2026 18:52:52 +0530 Subject: [PATCH 39/55] Update and rename ReadMe.md to README.md --- .../Signal_in_Linux_kernel/README.md | 680 ++++++++++++++++++ .../Signal_in_Linux_kernel/ReadMe.md | 4 - 2 files changed, 680 insertions(+), 4 deletions(-) create mode 100644 Linux/Device_Driver/Signal_in_Linux_kernel/README.md delete mode 100644 Linux/Device_Driver/Signal_in_Linux_kernel/ReadMe.md diff --git a/Linux/Device_Driver/Signal_in_Linux_kernel/README.md b/Linux/Device_Driver/Signal_in_Linux_kernel/README.md new file mode 100644 index 0000000..4b795d5 --- /dev/null +++ b/Linux/Device_Driver/Signal_in_Linux_kernel/README.md @@ -0,0 +1,680 @@ +# Linux Device Driver - Sending Signal from Kernel Driver to User Space + +## Overview + +Signals are one of the oldest Inter-Process Communication (IPC) mechanisms in Linux. + +They are used to notify a process that a specific event has occurred. + +Examples: + +```text +ATM Transaction + | + +--> SMS Notification + +Microwave Finished + | + +--> Beep Sound + +Linux Driver Event + | + +--> Signal To User Application +``` + +Linux drivers can send signals directly to user-space applications whenever an event occurs, such as: + +* Hardware interrupt +* GPIO event +* DMA completion +* Sensor threshold crossing +* Device error +* Data ready notification + +The EmbeTronicX example demonstrates sending a signal from a device driver to a user-space application when an interrupt occurs. + +--- + +# What is a Signal? + +A signal is an asynchronous notification sent to a process or thread. + +Examples of standard Linux signals: + +| Signal | Description | +| ------- | ------------------ | +| SIGINT | Ctrl+C | +| SIGKILL | Kill process | +| SIGTERM | Terminate | +| SIGSEGV | Segmentation fault | +| SIGUSR1 | User-defined | +| SIGUSR2 | User-defined | + +The tutorial uses a custom signal: + +```c +#define SIGETX 44 +``` + +Signal number 44 is used to notify the application from the driver. + +--- + +# Driver to User Communication Flow + +```text +User Application + | + | Register PID + v +Device Driver + | + | Interrupt Occurs + v +Interrupt Handler + | + | send_sig_info() + v +Linux Signal Subsystem + | + v +Signal Handler + | + v +User Application +``` + +--- + +# Steps Involved + +To send a signal from kernel space to user space: + +```text +1. Select Signal Number + +2. Register Application + +3. Save Process Information + +4. Event Occurs + +5. Driver Sends Signal + +6. User Application Handles Signal +``` + +--- + +# Step 1 - Select Signal Number + +Choose a signal number. + +Example: + +```c +#define SIGETX 44 +``` + +This signal will be delivered to the application whenever the event occurs. + +--- + +# Step 2 - Register User Application + +Before sending a signal, the driver must know: + +```text +Which Process Should Receive It? +``` + +The application registers itself using: + +```text +IOCTL +``` + +Application: + +```c +ioctl( + fd, + REG_CURRENT_TASK, + &number); +``` + +Driver: + +```c +#define REG_CURRENT_TASK \ + _IOW('a','a',int32_t *) +``` + +--- + +# Step 3 - Save Process Information + +The driver stores the current task. + +```c +static struct task_struct *task = NULL; +``` + +Inside IOCTL: + +```c +task = get_current(); +``` + +This returns: + +```text +Current User Process +``` + +Kernel now knows where to send the signal. + +--- + +# Driver Registration Code + +```c +static long etx_ioctl( + struct file *file, + unsigned int cmd, + unsigned long arg) +{ + if(cmd == REG_CURRENT_TASK) + { + task = get_current(); + + signum = SIGETX; + } + + return 0; +} +``` + +Purpose: + +```text +Store User Process Context +``` + +--- + +# Event Trigger + +In the example: + +```text +Read Device File + | + v +Software Interrupt + | + v +Interrupt Handler + | + v +Send Signal +``` + +Driver read function: + +```c +static ssize_t etx_read(...) +{ + asm("int $0x3B"); + + return 0; +} +``` + +This generates IRQ 11. + +--- + +# Interrupt Handler + +When interrupt occurs: + +```c +static irqreturn_t +irq_handler( + int irq, + void *dev_id) +{ + ... +} +``` + +Purpose: + +```text +Prepare Signal Information +``` + +--- + +# Signal Information Structure + +Kernel uses: + +```c +struct siginfo info; +``` + +Initialize: + +```c +memset( + &info, + 0, + sizeof(info)); +``` + +Fill fields: + +```c +info.si_signo = SIGETX; + +info.si_code = SI_QUEUE; + +info.si_int = 1; +``` + +Meaning: + +| Field | Description | +| -------- | ---------------------- | +| si_signo | Signal number | +| si_code | Signal source | +| si_int | Custom integer payload | + +--- + +# Sending Signal + +Core API: + +```c +send_sig_info( + SIGETX, + &info, + task); +``` + +Example: + +```c +if(task != NULL) +{ + send_sig_info( + SIGETX, + &info, + task); +} +``` + +Parameters: + +| Parameter | Description | +| --------- | -------------- | +| SIGETX | Signal number | +| &info | Signal payload | +| task | Target process | + +--- + +# Driver Side Flow + +```text +IRQ Occurs + | + v +Create siginfo + | + v +Fill Data + | + v +send_sig_info() + | + v +Signal Delivered +``` + +--- + +# User Space Signal Handler + +Application installs handler: + +```c +struct sigaction act; +``` + +Register: + +```c +act.sa_flags = SA_SIGINFO; + +act.sa_sigaction = + sig_event_handler; + +sigaction( + SIGETX, + &act, + NULL); +``` + +--- + +# Signal Callback + +```c +void sig_event_handler( + int n, + siginfo_t *info, + void *unused) +{ + if(n == SIGETX) + { + check = info->si_int; + + printf( + "Received signal\n"); + } +} +``` + +This function executes automatically when the signal arrives. + +--- + +# Passing Data with Signal + +Driver: + +```c +info.si_int = 1; +``` + +User Space: + +```c +check = info->si_int; +``` + +Output: + +```text +Received signal from kernel +Value = 1 +``` + +This allows small event data to accompany the signal. + +--- + +# Complete Execution Flow + +```text +Application Starts + | + v +Open Device + | + v +IOCTL Registration + | + v +Driver Stores Task + | + v +Waiting... + | + v +Interrupt Occurs + | + v +ISR Executes + | + v +send_sig_info() + | + v +Signal Arrives + | + v +Signal Handler Executes +``` + +--- + +# Sample Application Output + +```text +Installed signal handler +for SIGETX = 44 + +Opening Driver + +Registering application... +Done!!! + +Waiting for signal... +``` + +After interrupt: + +```text +Received signal +from kernel : Value = 1 +``` + +--- + +# Sample Driver Logs + +```text +Device Driver Insert...Done!!! + +REG_CURRENT_TASK + +Read Function + +Shared IRQ: +Interrupt Occurred + +Sending signal to app +``` + +This confirms: + +```text +Application Registered + +Interrupt Triggered + +Signal Sent Successfully +``` + +--- + +# Common Use Cases + +## GPIO Interrupt + +```text +Button Pressed + | + +--> Signal Application +``` + +--- + +## Sensor Threshold + +```text +Temperature > Limit + | + +--> Notify User Space +``` + +--- + +## DMA Completion + +```text +DMA Transfer Done + | + +--> Signal Process +``` + +--- + +## Data Ready + +```text +UART Data Available + | + +--> Signal Reader +``` + +--- + +## Hardware Error + +```text +Device Fault + | + +--> Alert Application +``` + +--- + +# Advantages + +* Simple implementation +* Low overhead +* Asynchronous notification +* Fast event delivery +* No polling required + +--- + +# Limitations + +Signals are best for: + +```text +Notification +``` + +Not for: + +```text +Large Data Transfer +``` + +Bad use case: + +```text +Send 1 KB Data +``` + +Good use case: + +```text +Data Ready +Go Read It +``` + +For large transfers use: + +* read() +* mmap() +* Netlink +* Shared Memory +* Character Device Buffers + +--- + +# Signal vs Polling + +| Feature | Signal | Polling | +| --------------- | ------ | -------------------- | +| CPU Usage | Low | High | +| Latency | Low | Depends on Poll Rate | +| Event Driven | Yes | No | +| Power Efficient | Yes | No | + +--- + +# Signal vs Netlink + +| Feature | Signal | Netlink | +| ------------------- | --------- | --------- | +| Simple Notification | Excellent | Good | +| Large Data | Poor | Excellent | +| Bidirectional | Limited | Yes | +| Structured Messages | No | Yes | + +--- + +# Important APIs Summary + +## Driver Side + +```c +get_current() + +send_sig_info() +``` + +--- + +## Signal Information + +```c +struct siginfo +``` + +--- + +## User Space + +```c +sigaction() +``` + +--- + +## Registration + +```c +ioctl() +``` + +--- + +# Key Takeaways + +* Linux signals provide asynchronous notifications between kernel and user space. +* The user application must register itself with the driver first. +* The driver stores the application's `task_struct`. +* `send_sig_info()` is the primary kernel API used to send signals. +* `struct siginfo` can carry small payload data. +* Signal handlers are registered using `sigaction()`. +* Signals are ideal for event notification but not for large data transfer. +* Common embedded Linux use cases include GPIO interrupts, DMA completion, sensor events, and hardware fault notifications. +* A signal-based design avoids inefficient polling loops and provides immediate event notification. + + +## Conclusion +This is just a basic linux device driver which explains send signals from kernel to userspace. + +Please refer this URL for the complete tutorial of this example source code. +https://embetronicx.com/tutorials/linux/device-drivers/sending-signal-from-linux-device-driver-to-user-space/ diff --git a/Linux/Device_Driver/Signal_in_Linux_kernel/ReadMe.md b/Linux/Device_Driver/Signal_in_Linux_kernel/ReadMe.md deleted file mode 100644 index ec4e64b..0000000 --- a/Linux/Device_Driver/Signal_in_Linux_kernel/ReadMe.md +++ /dev/null @@ -1,4 +0,0 @@ -This is just a basic linux device driver which explains send signals from kernel to userspace. - -Please refer this URL for the complete tutorial of this example source code. -https://embetronicx.com/tutorials/linux/device-drivers/sending-signal-from-linux-device-driver-to-user-space/ \ No newline at end of file From 2b3a67c30f4ac965e50bb9f59d2b8ae08f7882dc Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Fri, 19 Jun 2026 18:55:35 +0530 Subject: [PATCH 40/55] Update and rename ReadMe.md to README.md --- Linux/Device_Driver/Kernel_Timer/README.md | 787 +++++++++++++++++++++ Linux/Device_Driver/Kernel_Timer/ReadMe.md | 4 - 2 files changed, 787 insertions(+), 4 deletions(-) create mode 100644 Linux/Device_Driver/Kernel_Timer/README.md delete mode 100644 Linux/Device_Driver/Kernel_Timer/ReadMe.md diff --git a/Linux/Device_Driver/Kernel_Timer/README.md b/Linux/Device_Driver/Kernel_Timer/README.md new file mode 100644 index 0000000..d987be0 --- /dev/null +++ b/Linux/Device_Driver/Kernel_Timer/README.md @@ -0,0 +1,787 @@ +# Linux Device Driver - Kernel Timer in Linux + +## Overview + +A Kernel Timer allows a Linux device driver to execute a function after a specified time interval. + +Unlike hardware timers, Linux kernel timers are software timers managed by the kernel timer subsystem using **jiffies** and timer interrupts. They are useful for scheduling future work without blocking a thread. + +Common use cases: + +* Device polling +* Timeout detection +* Periodic status checks +* Retry mechanisms +* Delayed operations +* Heartbeat monitoring + +--- + +# What is a Timer? + +A timer measures a time interval. + +```text +Current Time + | + +-------> Timer Expires + | + +--> Callback Function Executes +``` + +In Linux, timers are driven by periodic kernel timer interrupts. The kernel maintains an internal counter that increments every clock tick since boot. This counter is represented through **jiffies**. + +--- + +# Kernel Timer Architecture + +```text +Driver Loads + | + v +Create Timer + | + v +Start Timer + | + v +Timer Expires + | + v +Callback Function + | + +--> Stop Timer + | + +--> Restart Timer +``` + +If the callback restarts the timer, it behaves like a periodic timer. + +--- + +# Uses of Kernel Timers + +## Device Polling + +```text +Timer + | + +--> Check Device Status +``` + +Used when hardware does not generate interrupts. + +--- + +## Communication Timeout + +```text +Send Request + | + +--> Start Timer + | + +--> No Response + | + +--> Timeout Error +``` + +Used in networking and protocol stacks. + +--- + +## Periodic Monitoring + +```text +Every 5 Seconds + | + +--> Read Sensor +``` + +Useful for watchdogs and health monitoring. + +--- + +# Header Files + +```c +#include +#include +``` + +Required for timer APIs and jiffies support. + +--- + +# Kernel Timer Structure + +```c +struct timer_list +{ + unsigned long expires; + + void (*function)(unsigned long); + + unsigned long data; +}; +``` + +Important Fields: + +| Field | Purpose | +| -------- | -------------------------- | +| expires | Expiration time in jiffies | +| function | Callback function | +| data | Data passed to callback | + +Modern kernels use `timer_setup()` and callback receives: + +```c +struct timer_list *timer +``` + +instead of `unsigned long data`. + +--- + +# Jiffies + +## What are Jiffies? + +Jiffies represent kernel clock ticks. + +```c +jiffies +``` + +Example: + +```text +System Boot + | + +--> jiffies = 0 + +1 Tick Later + | + +--> jiffies = 1 +``` + +Every timer expiration is specified relative to jiffies. + +--- + +# Time Conversion + +## Milliseconds to Jiffies + +```c +msecs_to_jiffies(5000) +``` + +Convert: + +```text +5000 ms + | + +--> Jiffies +``` + +Example: + +```c +jiffies + +msecs_to_jiffies(5000) +``` + +Means: + +```text +Current Time + 5 Seconds +``` + +--- + +# Timer Initialization Methods + +Linux provides multiple initialization APIs. + +--- + +# Method 1 - init_timer() + +```c +init_timer( + &etx_timer); +``` + +Older API. + +After initialization: + +```c +etx_timer.function = timer_callback; +etx_timer.data = 0; +``` + +Not recommended for modern kernels. + +--- + +# Method 2 - setup_timer() + +Older kernels: + +```c +setup_timer( + &etx_timer, + timer_callback, + 0); +``` + +Callback: + +```c +void timer_callback( + unsigned long data) +{ +} +``` + +Used in legacy kernels. + +--- + +# Method 3 - timer_setup() + +Recommended API. + +```c +timer_setup( + &etx_timer, + timer_callback, + 0); +``` + +Callback: + +```c +void timer_callback( + struct timer_list *t) +{ +} +``` + +Most modern kernels use this API. + +--- + +# Method 4 - DEFINE_TIMER() + +Static initialization. + +```c +DEFINE_TIMER( + etx_timer, + timer_callback, + 0, + 0); +``` + +Kernel creates and initializes timer automatically. + +--- + +# Starting a Timer + +## add_timer() + +```c +add_timer( + &etx_timer); +``` + +Starts timer. + +Before calling: + +```c +etx_timer.expires = + jiffies + + msecs_to_jiffies(5000); +``` + +--- + +# Recommended Start Method + +Modern drivers usually use: + +```c +mod_timer( + &etx_timer, + jiffies + + msecs_to_jiffies(5000)); +``` + +because it works for both: + +```text +New Timer +Existing Timer +``` + +--- + +# Modifying Timer Timeout + +## mod_timer() + +```c +mod_timer( + &etx_timer, + expires); +``` + +Example: + +```c +mod_timer( + &etx_timer, + jiffies + + msecs_to_jiffies(5000)); +``` + +Equivalent conceptually to: + +```c +del_timer(); + +update expires; + +add_timer(); +``` + +but much more efficient. + +--- + +# Return Value + +```c +ret = mod_timer(...) +``` + +| Value | Meaning | +| ----- | ------------------ | +| 0 | Timer was inactive | +| 1 | Timer was active | + +This is status information, not an error code. + +--- + +# Creating a Periodic Timer + +Kernel timers are: + +```text +One-Shot Timers +``` + +by default. + +To make them periodic: + +```c +void timer_callback( + struct timer_list *t) +{ + pr_info("Timer Fired\n"); + + mod_timer( + &etx_timer, + jiffies + + msecs_to_jiffies(5000)); +} +``` + +Execution: + +```text +5 Seconds + | + +--> Callback + + | + +--> Restart Timer + + | + +--> Callback Again +``` + +--- + +# Example Driver + +## Timer Declaration + +```c +static struct timer_list etx_timer; +``` + +--- + +## Timer Initialization + +```c +timer_setup( + &etx_timer, + timer_callback, + 0); +``` + +--- + +## Start Timer + +```c +mod_timer( + &etx_timer, + jiffies + + msecs_to_jiffies(5000)); +``` + +--- + +## Callback + +```c +void timer_callback( + struct timer_list *data) +{ + pr_info( + "Timer Callback\n"); + + mod_timer( + &etx_timer, + jiffies + + msecs_to_jiffies(5000)); +} +``` + +This creates a timer that fires every 5 seconds. + +--- + +# Stopping a Timer + +## del_timer() + +```c +del_timer( + &etx_timer); +``` + +Deactivates timer. + +Return: + +| Value | Meaning | +| ----- | ---------------------- | +| 0 | Timer already inactive | +| 1 | Active timer removed | + +--- + +# del_timer_sync() + +```c +del_timer_sync( + &etx_timer); +``` + +Removes timer and waits for callback completion. + +Useful during: + +```text +Module Removal +Driver Cleanup +``` + +Safer than `del_timer()` when timer callback may still be running. + +--- + +# Check Timer Status + +## timer_pending() + +```c +timer_pending( + &etx_timer); +``` + +Returns: + +| Value | Meaning | +| ----- | ----------- | +| 0 | Not Pending | +| 1 | Pending | + +Used to check whether timer is currently active. + +--- + +# Execution Flow + +```text +insmod driver.ko + | + v +timer_setup() + | + v +mod_timer() + | + v +5 Seconds + | + v +timer_callback() + | + v +mod_timer() + | + v +Repeat +``` + +--- + +# Sample Output + +```text +Device Driver Insert...Done!!! + +Timer Callback function Called [0] + +Timer Callback function Called [1] + +Timer Callback function Called [2] + +Timer Callback function Called [3] +``` + +Each callback occurs approximately every 5 seconds. + +--- + +# Important Limitation + +Timer callback executes in: + +```text +Interrupt Context +``` + +NOT process context. + +--- + +# Not Allowed Inside Timer Callback + +## Sleeping + +Wrong: + +```c +msleep(100); +``` + +--- + +## Mutex + +Wrong: + +```c +mutex_lock(&lock); +``` + +--- + +## Access User Space + +Wrong: + +```c +copy_to_user(...); +``` + +--- + +## Long Processing + +Wrong: + +```c +Huge Computation +Large File Operations +``` + +Timer callbacks should be short and fast. + +--- + +# Timer vs Kernel Thread + +| Feature | Kernel Timer | Kernel Thread | +| ------------------ | ------------ | ------------- | +| Context | Interrupt | Process | +| Sleep Allowed | No | Yes | +| Periodic Execution | Yes | Yes | +| Long Processing | No | Yes | +| CPU Usage | Low | Higher | + +--- + +# Timer vs Workqueue + +| Feature | Timer | Workqueue | +| ----------------- | --------- | --------- | +| Context | Interrupt | Process | +| Sleep Allowed | No | Yes | +| Delayed Execution | Yes | Yes | +| Long Processing | No | Yes | + +Common pattern: + +```text +Timer Expires + | + +--> Queue Workqueue + | + +--> Workqueue Does Heavy Work +``` + +--- + +# Common Driver Use Cases + +## Watchdog + +```text +Every 1 Second + | + +--> Feed Watchdog +``` + +--- + +## Network Timeout + +```text +Send Packet + | + +--> Start Timer + | + +--> No ACK + | + +--> Timeout +``` + +--- + +## Device Polling + +```text +Every 100 ms + | + +--> Read Status Register +``` + +--- + +## Heartbeat + +```text +Periodic Timer + | + +--> Health Check +``` + +--- + +# Important APIs Summary + +## Initialization + +```c +init_timer() + +setup_timer() + +timer_setup() + +DEFINE_TIMER() +``` + +--- + +## Start + +```c +add_timer() + +mod_timer() +``` + +--- + +## Stop + +```c +del_timer() + +del_timer_sync() +``` + +--- + +## Status + +```c +timer_pending() +``` + +--- + +## Time Conversion + +```c +jiffies + +msecs_to_jiffies() +``` + +--- + +# Key Takeaways + +* Kernel timers schedule execution of a callback in the future. +* Modern kernels should use `timer_setup()`. +* Timer expiration is based on **jiffies**. +* `mod_timer()` is the preferred API for starting and updating timers. +* Kernel timers are one-shot by default. +* Re-arming the timer inside the callback creates periodic behavior. +* Timer callbacks execute in interrupt context. +* Timer callbacks cannot sleep, acquire mutexes, or perform long operations. +* `del_timer_sync()` is preferred during driver cleanup. +* Timers are ideal for polling, watchdogs, retries, and timeout handling. + + +## Conclusion +This is just a basic linux device driver which explains about the kernel timer in linux device driver. + +Please refer this URL for the complete tutorial of this example source code. +https://embetronicx.com/tutorials/linux/device-drivers/using-kernel-timer-in-linux-device-driver/ diff --git a/Linux/Device_Driver/Kernel_Timer/ReadMe.md b/Linux/Device_Driver/Kernel_Timer/ReadMe.md deleted file mode 100644 index 926ed28..0000000 --- a/Linux/Device_Driver/Kernel_Timer/ReadMe.md +++ /dev/null @@ -1,4 +0,0 @@ -This is just a basic linux device driver which explains about the kernel timer in linux device driver. - -Please refer this URL for the complete tutorial of this example source code. -https://embetronicx.com/tutorials/linux/device-drivers/using-kernel-timer-in-linux-device-driver/ \ No newline at end of file From 6329738171dd9cbd9541a8b98b7b721fdea4ed96 Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Fri, 19 Jun 2026 18:57:52 +0530 Subject: [PATCH 41/55] Update and rename ReadMe.md to README.md --- .../High_Resolution_Timer/README.md | 878 ++++++++++++++++++ .../High_Resolution_Timer/ReadMe.md | 4 - 2 files changed, 878 insertions(+), 4 deletions(-) create mode 100644 Linux/Device_Driver/High_Resolution_Timer/README.md delete mode 100644 Linux/Device_Driver/High_Resolution_Timer/ReadMe.md diff --git a/Linux/Device_Driver/High_Resolution_Timer/README.md b/Linux/Device_Driver/High_Resolution_Timer/README.md new file mode 100644 index 0000000..a74cf93 --- /dev/null +++ b/Linux/Device_Driver/High_Resolution_Timer/README.md @@ -0,0 +1,878 @@ +# Linux Device Driver - High Resolution Timer (hrtimer) + +## Overview + +A High Resolution Timer (**HRT**, `hrtimer`) provides precise timer functionality in the Linux kernel with **nanosecond resolution**. + +Unlike traditional kernel timers that are based on **jiffies**, High Resolution Timers use **64-bit nanosecond time values** and are suitable for applications requiring accurate timing. ([EmbeTronicX][1]) + +--- + +# Why High Resolution Timer? + +## Kernel Timer Limitation + +Traditional kernel timers: + +```text +Kernel Timer + | + +--> Based on Jiffies + | + +--> Tick Resolution +``` + +Example: + +```text +HZ = 100 + +1 Tick = 10 ms +``` + +Cannot accurately schedule: + +```text +1 us +50 us +100 ns +``` + +operations. + +--- + +## High Resolution Timer + +```text +High Resolution Timer + | + +--> Nanosecond Resolution + | + +--> High Accuracy +``` + +Suitable for: + +* Multimedia +* Real-time systems +* Precision device drivers +* Industrial control +* Sensor sampling + +Kernel timers are jiffies-based, whereas hrtimers are based on high-resolution time values. ([EmbeTronicX][1]) + +--- + +# Kernel Requirements + +High-resolution timer support must be enabled: + +```text +CONFIG_HIGH_RES_TIMERS=y +``` + +Check: + +```bash +grep CONFIG_HIGH_RES_TIMERS \ +/boot/config-$(uname -r) +``` + +Expected: + +```text +CONFIG_HIGH_RES_TIMERS=y +``` + +High-resolution timers are available in Linux kernels beginning with version 2.6.21 when enabled in kernel configuration. ([EmbeTronicX][1]) + +--- + +# Kernel Timer vs High Resolution Timer + +| Feature | Kernel Timer | High Resolution Timer | +| ---------------- | ------------ | --------------------- | +| Resolution | Jiffies | Nanoseconds | +| Precision | Lower | Very High | +| Timing Base | Tick Driven | High Resolution Clock | +| Data Structure | Timer Wheel | Red-Black Tree | +| Real-Time Usage | Limited | Excellent | +| Multimedia Usage | Moderate | Excellent | + +Linux uses a red-black tree for hrtimers to maintain timers in time order efficiently. ([EmbeTronicX][1]) + +--- + +# Typical Use Cases + +## Multimedia + +```text +Audio Playback + | + +--> Precise Timing +``` + +--- + +## Sensor Sampling + +```text +Every 100 us + | + +--> Read Sensor +``` + +--- + +## Industrial Control + +```text +Motor Control + | + +--> Accurate Trigger +``` + +--- + +## Driver Timeout + +```text +Command Sent + | + +--> Start hrtimer + | + +--> Timeout Event +``` + +Primary users include multimedia subsystems and applications needing precise timed events. ([EmbeTronicX][1]) + +--- + +# Required Header Files + +```c +#include +#include +``` + +--- + +# hrtimer Structure + +```c +struct hrtimer +{ + struct rb_node node; + + ktime_t expires; + + int (*function)( + struct hrtimer *); + + struct hrtimer_base *base; +}; +``` + +Important fields: + +| Field | Purpose | +| -------- | ------------------- | +| node | Red-black tree node | +| expires | Expiration time | +| function | Callback | +| base | Timer base | + +([EmbeTronicX][1]) + +--- + +# ktime_t + +High Resolution Timers use: + +```c +ktime_t +``` + +which stores time values with nanosecond precision. + +Example: + +```c +ktime_t time; +``` + +--- + +# ktime_set() + +Creates a ktime value. + +```c +ktime_t ktime_set( + long secs, + long nsecs); +``` + +Example: + +```c +ktime_t ktime; + +ktime = + ktime_set( + 5, + 0); +``` + +Represents: + +```text +5 Seconds +``` + +Example: + +```c +ktime_set( + 4, + 1000000000); +``` + +Represents: + +```text +4 Seconds ++ +1 Second + += +5 Seconds +``` + +([EmbeTronicX][1]) + +--- + +# Timer Callback Function + +Callback executes when timer expires. + +```c +enum hrtimer_restart +timer_callback( + struct hrtimer *timer) +{ + return HRTIMER_NORESTART; +} +``` + +Return values: + +| Return Value | Meaning | +| ----------------- | -------------- | +| HRTIMER_NORESTART | One-shot timer | +| HRTIMER_RESTART | Periodic timer | + +([EmbeTronicX][1]) + +--- + +# Initialize High Resolution Timer + +## hrtimer_init() + +```c +void hrtimer_init( + struct hrtimer *timer, + clockid_t clock_id, + enum hrtimer_mode mode); +``` + +Parameters: + +| Parameter | Description | +| --------- | -------------------- | +| timer | Timer object | +| clock_id | Clock source | +| mode | Relative or absolute | + +Example: + +```c +hrtimer_init( + &etx_hr_timer, + CLOCK_MONOTONIC, + HRTIMER_MODE_REL); +``` + +([EmbeTronicX][1]) + +--- + +# Clock Sources + +## CLOCK_MONOTONIC + +```text +System Boot + | + +--> Time Always Increases +``` + +Never jumps backwards. + +Most common choice for drivers. + +--- + +## CLOCK_REALTIME + +```text +Wall Clock Time +``` + +Affected by: + +```text +date command +NTP adjustments +RTC updates +``` + +([EmbeTronicX][1]) + +--- + +# Timer Modes + +## Relative Mode + +```c +HRTIMER_MODE_REL +``` + +Timer expires: + +```text +Current Time + Interval +``` + +Example: + +```c +5 Seconds From Now +``` + +--- + +## Absolute Mode + +```c +HRTIMER_MODE_ABS +``` + +Expires at a specific timestamp. + +([EmbeTronicX][1]) + +--- + +# Assign Callback + +After initialization: + +```c +etx_hr_timer.function = + &timer_callback; +``` + +Associates callback function with timer. + +--- + +# Start Timer + +## hrtimer_start() + +```c +int hrtimer_start( + struct hrtimer *timer, + ktime_t time, + enum hrtimer_mode mode); +``` + +Example: + +```c +ktime_t ktime; + +ktime = ktime_set(5, 0); + +hrtimer_start( + &etx_hr_timer, + ktime, + HRTIMER_MODE_REL); +``` + +Meaning: + +```text +Fire After 5 Seconds +``` + +Returns: + +| Value | Meaning | +| ----- | -------------------- | +| 0 | Timer inactive | +| 1 | Timer already active | + +([EmbeTronicX][1]) + +--- + +# One-Shot Timer + +```c +enum hrtimer_restart +timer_callback( + struct hrtimer *timer) +{ + printk("Expired\n"); + + return HRTIMER_NORESTART; +} +``` + +Execution: + +```text +Start + | + v +Expire + | + v +Callback + | + v +Stop +``` + +--- + +# Periodic Timer + +For periodic behavior: + +```c +enum hrtimer_restart +timer_callback( + struct hrtimer *timer) +{ + hrtimer_forward_now( + timer, + interval); + + return HRTIMER_RESTART; +} +``` + +Execution: + +```text +Expire + | + v +Callback + | + v +Forward Timer + | + v +Restart +``` + +([EmbeTronicX][1]) + +--- + +# hrtimer_forward() + +Move timer forward. + +```c +u64 hrtimer_forward( + struct hrtimer *timer, + ktime_t now, + ktime_t interval); +``` + +Used for periodic timers. + +Returns: + +```text +Overrun Count +``` + +([EmbeTronicX][1]) + +--- + +# hrtimer_forward_now() + +Most common periodic timer API. + +```c +u64 hrtimer_forward_now( + struct hrtimer *timer, + ktime_t interval); +``` + +Example: + +```c +hrtimer_forward_now( + timer, + interval); +``` + +Schedules next expiration relative to current time. ([EmbeTronicX][1]) + +--- + +# Stop Timer + +## hrtimer_cancel() + +```c +int hrtimer_cancel( + struct hrtimer *timer); +``` + +Behavior: + +```text +Cancel Timer +Wait For Callback +Return +``` + +Returns: + +| Value | Meaning | +| ----- | -------------- | +| 0 | Timer inactive | +| 1 | Timer active | + +([EmbeTronicX][1]) + +--- + +# hrtimer_try_to_cancel() + +```c +int hrtimer_try_to_cancel( + struct hrtimer *timer); +``` + +Returns: + +| Value | Meaning | +| ----- | ---------------- | +| 1 | Stopped | +| 0 | Not Active | +| -1 | Callback Running | + +([EmbeTronicX][1]) + +--- + +# Timer Status APIs + +## hrtimer_get_remaining() + +```c +ktime_t +hrtimer_get_remaining( + const struct hrtimer *timer); +``` + +Returns remaining time. + +--- + +## hrtimer_callback_running() + +```c +int +hrtimer_callback_running( + struct hrtimer *timer); +``` + +Returns: + +```text +0 -> Not Running +1 -> Running +``` + +--- + +## hrtimer_cb_get_time() + +```c +ktime_t +hrtimer_cb_get_time( + struct hrtimer *timer); +``` + +Returns current timer time. + +([EmbeTronicX][1]) + +--- + +# Example Driver Flow + +## Initialization + +```c +ktime_t ktime; + +ktime = + ktime_set( + 5, + 0); + +hrtimer_init( + &etx_hr_timer, + CLOCK_MONOTONIC, + HRTIMER_MODE_REL); + +etx_hr_timer.function = + &timer_callback; + +hrtimer_start( + &etx_hr_timer, + ktime, + HRTIMER_MODE_REL); +``` + +--- + +## Callback + +```c +enum hrtimer_restart +timer_callback( + struct hrtimer *timer) +{ + printk( + "Timer Fired\n"); + + hrtimer_forward_now( + timer, + interval); + + return HRTIMER_RESTART; +} +``` + +--- + +## Cleanup + +```c +hrtimer_cancel( + &etx_hr_timer); +``` + +--- + +# Execution Flow + +```text +Module Load + | + v +hrtimer_init() + | + v +hrtimer_start() + | + v +Timer Expires + | + v +Callback + | + +--> HRTIMER_NORESTART + | | + | +--> Stop + | + +--> HRTIMER_RESTART + | + +--> Restart +``` + +--- + +# Callback Context + +High-resolution timer callbacks execute in: + +```text +SoftIRQ Context +``` + +Therefore: + +### Allowed + +```c +spin_lock(); +atomic operations; +``` + +### Not Allowed + +```c +msleep(); +schedule(); +mutex_lock(); +copy_to_user(); +``` + +Callbacks must be short and non-blocking. This design is part of why hrtimers are suitable for precision timing. ([EmbeTronicX][1]) + +--- + +# Kernel Timer vs HRTimer vs Workqueue + +| Feature | Kernel Timer | HRTimer | Workqueue | +| --------------- | ------------ | ----------- | --------- | +| Resolution | Jiffies | Nanoseconds | N/A | +| Context | SoftIRQ | SoftIRQ | Process | +| Sleep Allowed | No | No | Yes | +| Precision | Low | High | N/A | +| Long Processing | No | No | Yes | + +--- + +# Common Embedded Linux Use Cases + +## Periodic Sensor Sampling + +```text +100 us + | + +--> Read ADC +``` + +--- + +## Multimedia Synchronization + +```text +Audio Frame + | + +--> Precise Playback +``` + +--- + +## Protocol Timing + +```text +Industrial Bus + | + +--> Precise Timeout +``` + +--- + +## Motor Control + +```text +Control Loop + | + +--> Accurate Period +``` + +--- + +# Important APIs Summary + +## Time Creation + +```c +ktime_set() +``` + +## Initialization + +```c +hrtimer_init() +``` + +## Start + +```c +hrtimer_start() +``` + +## Stop + +```c +hrtimer_cancel() + +hrtimer_try_to_cancel() +``` + +## Periodic Support + +```c +hrtimer_forward() + +hrtimer_forward_now() +``` + +## Status + +```c +hrtimer_get_remaining() + +hrtimer_callback_running() + +hrtimer_cb_get_time() +``` + +--- + +# Key Takeaways + +* High Resolution Timers provide **nanosecond-resolution timing**. +* They are not based on jiffies and are far more precise than traditional kernel timers. +* `ktime_t` is the primary time representation. +* `hrtimer_init()` initializes the timer. +* `hrtimer_start()` starts the timer. +* `hrtimer_cancel()` safely stops the timer. +* Returning `HRTIMER_RESTART` creates periodic behavior. +* Callbacks execute in SoftIRQ context and cannot sleep. +* HRTimers are commonly used in multimedia, real-time control, industrial automation, and precision driver timing. ([EmbeTronicX][1]) + +**Source:** EmbeTronicX Linux Device Driver Tutorial Part 27 – High Resolution Timer in Linux Device Driver. ([EmbeTronicX][1]) + +[1]: https://embetronicx.com/tutorials/linux/device-drivers/using-high-resolution-timer-in-linux-device-driver/?utm_source=chatgpt.com "High Resolution Timer - Linux Device Driver Tutorial Part 27" + + +## Conclusion +This is just a basic linux device driver which explains about the kernel timer in linux device driver. + +Please refer this URL for the complete tutorial of this example source code. +https://embetronicx.com/tutorials/linux/device-drivers/using-high-resolution-timer-in-linux-device-driver/ diff --git a/Linux/Device_Driver/High_Resolution_Timer/ReadMe.md b/Linux/Device_Driver/High_Resolution_Timer/ReadMe.md deleted file mode 100644 index 080dbe4..0000000 --- a/Linux/Device_Driver/High_Resolution_Timer/ReadMe.md +++ /dev/null @@ -1,4 +0,0 @@ -This is just a basic linux device driver which explains about the kernel timer in linux device driver. - -Please refer this URL for the complete tutorial of this example source code. -https://embetronicx.com/tutorials/linux/device-drivers/using-high-resolution-timer-in-linux-device-driver/ \ No newline at end of file From 7a7043b6ead65747ad747dbb08557e8c52c5593d Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Fri, 19 Jun 2026 18:58:43 +0530 Subject: [PATCH 42/55] Update README.md --- Linux/Device_Driver/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Linux/Device_Driver/README.md b/Linux/Device_Driver/README.md index 48cbb44..9cd9d08 100644 --- a/Linux/Device_Driver/README.md +++ b/Linux/Device_Driver/README.md @@ -1 +1,4 @@ refer: https://embetronicx.com/linux-device-driver-tutorials/ + +Contents +1. From d8a49783f1c775a0d665ed9bf3d0c9db1a3d16c0 Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Fri, 19 Jun 2026 19:00:47 +0530 Subject: [PATCH 43/55] Update ReadMe.md --- Linux/Device_Driver/Completion/ReadMe.md | 827 ++++++++++++++++++++++- 1 file changed, 826 insertions(+), 1 deletion(-) diff --git a/Linux/Device_Driver/Completion/ReadMe.md b/Linux/Device_Driver/Completion/ReadMe.md index 0775bcb..8dfd83d 100644 --- a/Linux/Device_Driver/Completion/ReadMe.md +++ b/Linux/Device_Driver/Completion/ReadMe.md @@ -1,4 +1,829 @@ +# Linux Device Driver - Completion in Linux Kernel + +## Overview + +A **Completion** is a synchronization mechanism used when one thread must wait until another thread finishes a specific task. + +Think of it as: + +```text +Thread A + | + +--> Wait Until Event Happens + | + v + Thread B + | + +--> Finish Work + | + +--> Notify Thread A +``` + +Completion provides a simple, race-free mechanism for one execution context to wait for an event and another execution context to signal that the event has occurred. It is built on top of Linux waitqueues. ([EmbeTronicX][1]) + +--- + +# Why Do We Need Completion? + +Without completion: + +```text +Thread A + | + +--> while(flag == 0) + ; +``` + +Problems: + +* CPU waste (busy waiting) +* Race conditions +* Poor readability +* Difficult synchronization + +With completion: + +```text +Thread A + | + +--> Sleep + +Thread B + | + +--> Work Finished + | + +--> Wake Thread A +``` + +Completion provides efficient sleep/wakeup behavior using the scheduler. ([Kernel][2]) + +--- + +# Real World Example + +Imagine ordering food: + +```text +Customer + | + +--> Wait + +Chef + | + +--> Cook Food + | + +--> Ring Bell + +Customer + | + +--> Resume +``` + +Customer = Waiting Thread + +Chef = Worker Thread + +Bell = Completion Event + +--- + +# Completion vs Wait Queue + +| Feature | Wait Queue | Completion | +| ---------------------------- | ---------- | ---------- | +| General Purpose | Yes | No | +| Event Synchronization | Possible | Excellent | +| Complexity | Higher | Lower | +| Readability | Moderate | High | +| Race-Free Event Notification | Manual | Built-In | + +Completion is essentially a specialized waitqueue designed for event synchronization. ([EmbeTronicX][1]) + +--- + +# Completion Architecture + +```text +Thread A + | + +--> wait_for_completion() + | + +--> Sleep + +Thread B + | + +--> complete() + | + +--> Wake Thread A +``` + +--- + +# Internal Structure + +Include: + +```c +#include +``` + +Kernel structure: + +```c +struct completion +{ + unsigned int done; + wait_queue_head_t wait; +}; +``` + +Fields: + +| Field | Description | +| ----- | --------------- | +| done | Completion flag | +| wait | Wait queue | + +The `done` field indicates whether the event has been completed. ([EmbeTronicX][1]) + +--- + +# Completion Lifecycle + +```text +Create Completion + | + v +Initialize + | + v +wait_for_completion() + | + v +Sleep + | + v +complete() + | + v +Wake Up +``` + +--- + +# Static Initialization + +## DECLARE_COMPLETION() + +```c +DECLARE_COMPLETION( + data_read_done); +``` + +Creates and initializes completion. + +Example: + +```c +static DECLARE_COMPLETION( + data_ready); +``` + +No need for `init_completion()`. ([EmbeTronicX][1]) + +--- + +# Dynamic Initialization + +Declare: + +```c +struct completion + data_ready; +``` + +Initialize: + +```c +init_completion( + &data_ready); +``` + +This: + +```text +Initializes Wait Queue +Sets done = 0 +``` + +Meaning: + +```text +Not Completed Yet +``` + +([EmbeTronicX][1]) + +--- + +# Reinitialize Completion + +## reinit_completion() + +```c +reinit_completion( + &data_ready); +``` + +Used when: + +```text +Reuse Existing Completion +``` + +Resets: + +```text +done = 0 +``` + +without reinitializing the waitqueue. ([EmbeTronicX][1]) + +--- + +# Waiting For Completion + +The waiting thread sleeps until another thread signals completion. + +--- + +## wait_for_completion() + +```c +wait_for_completion( + &data_ready); +``` + +Behavior: + +```text +Not Completed + | + +--> Sleep + +Completed + | + +--> Continue +``` + +Characteristics: + +* Sleeps indefinitely +* Not interruptible +* No timeout + +([EmbeTronicX][1]) + +--- + +## wait_for_completion_timeout() + +```c +wait_for_completion_timeout( + &data_ready, + timeout); +``` + +Example: + +```c +wait_for_completion_timeout( + &data_ready, + msecs_to_jiffies(5000)); +``` + +Wait: + +```text +Maximum 5 Seconds +``` + +Return: + +| Value | Meaning | +| ----- | --------- | +| 0 | Timed Out | +| >0 | Completed | + +([EmbeTronicX][1]) + +--- + +## wait_for_completion_interruptible() + +```c +wait_for_completion_interruptible( + &data_ready); +``` + +Can be interrupted by signals. + +Returns: + +| Value | Meaning | +| ------------ | ----------- | +| 0 | Completed | +| -ERESTARTSYS | Interrupted | + +([EmbeTronicX][1]) + +--- + +## wait_for_completion_interruptible_timeout() + +```c +wait_for_completion_interruptible_timeout( + &data_ready, + timeout); +``` + +Features: + +* Interruptible +* Timeout supported + +([EmbeTronicX][1]) + +--- + +## wait_for_completion_killable() + +```c +wait_for_completion_killable( + &data_ready); +``` + +Interruptible only by fatal signals. + +([EmbeTronicX][1]) + +--- + +## wait_for_completion_killable_timeout() + +```c +wait_for_completion_killable_timeout( + &data_ready, + timeout); +``` + +Supports: + +* Kill signal +* Timeout + +([EmbeTronicX][1]) + +--- + +# Non-Blocking Wait + +## try_wait_for_completion() + +```c +if(try_wait_for_completion( + &data_ready)) +{ + /* completed */ +} +``` + +Behavior: + +```text +Completed + | + +--> Return TRUE + +Not Completed + | + +--> Return FALSE +``` + +No sleeping. + +Safe in IRQ context. ([EmbeTronicX][1]) + +--- + +# Signaling Completion + +The worker thread notifies waiting threads. + +--- + +## complete() + +Wake one waiting task. + +```c +complete( + &data_ready); +``` + +Behavior: + +```text +Thread Sleeping + | + +--> Wake One +``` + +FIFO wake-up order is maintained. ([Kernel][2]) + +--- + +## complete_all() + +Wake all waiting tasks. + +```c +complete_all( + &data_ready); +``` + +Behavior: + +```text +Thread1 Sleeping +Thread2 Sleeping +Thread3 Sleeping + + | + +--> Wake All +``` + +Useful when multiple threads wait for the same event. ([EmbeTronicX][1]) + +--- + +# Checking Completion Status + +## completion_done() + +```c +completion_done( + &data_ready); +``` + +Returns: + +| Value | Meaning | +| ----- | ------------- | +| 0 | Not Completed | +| 1 | Completed | + +Safe in interrupt context. ([EmbeTronicX][1]) + +--- + +# Simple Example + +## Waiting Thread + +```c +static int wait_thread_fn( + void *data) +{ + pr_info( + "Waiting...\n"); + + wait_for_completion( + &data_ready); + + pr_info( + "Completed\n"); + + return 0; +} +``` + +--- + +## Worker Thread + +```c +static int worker_thread_fn( + void *data) +{ + msleep(5000); + + complete( + &data_ready); + + return 0; +} +``` + +--- + +# Execution Flow + +```text +Thread A + | + +--> wait_for_completion() + | + +--> Sleep + +Thread B + | + +--> Do Work + | + +--> complete() + +Thread A + | + +--> Wake Up +``` + +--- + +# Typical Driver Example + +## Firmware Loading + +```text +Driver + | + +--> Request Firmware + | + +--> Wait + +Firmware Thread + | + +--> Load Firmware + | + +--> complete() +``` + +--- + +## DMA Transfer + +```text +Start DMA + | + +--> Wait + +DMA ISR + | + +--> complete() +``` + +--- + +## Device Initialization + +```text +Main Driver + | + +--> Wait + +Worker Thread + | + +--> Hardware Setup + | + +--> complete() +``` + +--- + +# Completion vs Semaphore + +| Feature | Completion | Semaphore | +| ------------------ | ---------- | --------- | +| Event Notification | Yes | Limited | +| Resource Counting | No | Yes | +| One-Time Event | Excellent | Poor | +| Simplicity | High | Moderate | + +--- + +# Completion vs Mutex + +| Feature | Completion | Mutex | +| --------------------- | ---------- | ----- | +| Synchronization Event | Yes | No | +| Resource Protection | No | Yes | +| Lock Ownership | No | Yes | +| Sleep/Wakeup | Yes | Yes | + +--- + +# Completion vs Wait Queue + +| Feature | Completion | Wait Queue | +| ----------------------- | ---------- | ---------- | +| Specialized Event Sync | Yes | No | +| Simplicity | High | Lower | +| Explicit Wake Condition | No | Yes | +| Readability | Excellent | Moderate | + +--- + +# Common Driver Use Cases + +## DMA Completion + +```text +Start DMA + | + +--> Wait + +DMA Interrupt + | + +--> complete() +``` + +--- + +## Firmware Loading + +```text +Load Firmware + | + +--> Wait + +Firmware Ready + | + +--> complete() +``` + +--- + +## Hardware Initialization + +```text +Init Driver + | + +--> Wait + +Hardware Ready + | + +--> complete() +``` + +--- + +## Thread Synchronization + +```text +Thread A Waits + +Thread B Finishes + +Thread B Calls complete() +``` + +--- + +# Common Mistakes + +## Forgetting Initialization + +Wrong: + +```c +struct completion comp; + +wait_for_completion( + &comp); +``` + +Correct: + +```c +init_completion( + &comp); +``` + +--- + +## Double init_completion() + +Wrong: + +```c +init_completion(&comp); + +init_completion(&comp); +``` + +Use: + +```c +reinit_completion( + &comp); +``` + +instead. ([Linux Kernel Documentation][3]) + +--- + +## Waiting in Atomic Context + +Wrong: + +```c +spin_lock(&lock); + +wait_for_completion( + &comp); +``` + +Reason: + +```text +wait_for_completion() +Can Sleep +``` + +Only use in process context. ([Linux Kernel Documentation][3]) + +--- + +# Important APIs Summary + +## Initialization + +```c +DECLARE_COMPLETION() + +init_completion() + +reinit_completion() +``` + +--- + +## Waiting + +```c +wait_for_completion() + +wait_for_completion_timeout() + +wait_for_completion_interruptible() + +wait_for_completion_interruptible_timeout() + +wait_for_completion_killable() + +wait_for_completion_killable_timeout() + +try_wait_for_completion() +``` + +--- + +## Wake Up + +```c +complete() + +complete_all() +``` + +--- + +## Status + +```c +completion_done() +``` + +--- + +# Key Takeaways + +* Completion is a synchronization mechanism for **event notification**. +* It is built on top of Linux waitqueues. +* One thread waits using `wait_for_completion()`. +* Another thread signals using `complete()`. +* `complete()` wakes one waiter; `complete_all()` wakes all waiters. +* Completion eliminates busy waiting and race-prone polling loops. +* It is ideal for DMA completion, firmware loading, hardware initialization, and thread synchronization. +* Waiting APIs can sleep and must be used only in process context. +* Completion code is generally simpler and clearer than using semaphores or raw waitqueues for event synchronization. ([EmbeTronicX][1]) + +[1]: https://embetronicx.com/tutorials/linux/device-drivers/completion-in-linux/?utm_source=chatgpt.com "Completion in Linux - Linux Device Driver Tutorial Part 28" +[2]: https://www.kernel.org/doc/html/latest/scheduler/completion.html?utm_source=chatgpt.com "Completions - “wait for completion” barrier APIs — The Linux Kernel documentation" +[3]: https://docs.kernel.org/scheduler/completion.html?utm_source=chatgpt.com "Completions - “wait for completion” barrier APIs — The Linux Kernel documentation" + + +## Conclusion This is just a basic linux device driver. This will explain completion in the linux device driver. Please refer this URL for the complete tutorial of this source code. -https://embetronicx.com/tutorials/linux/device-drivers/completion-in-linux/ \ No newline at end of file +https://embetronicx.com/tutorials/linux/device-drivers/completion-in-linux/ From bdc213d28e08633644f1d28197f435cef092bf40 Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Fri, 19 Jun 2026 19:02:51 +0530 Subject: [PATCH 44/55] Update and rename ReadMe.md to README.md --- Linux/Device_Driver/EXPORT_SYMBOL/README.md | 776 ++++++++++++++++++++ Linux/Device_Driver/EXPORT_SYMBOL/ReadMe.md | 4 - 2 files changed, 776 insertions(+), 4 deletions(-) create mode 100644 Linux/Device_Driver/EXPORT_SYMBOL/README.md delete mode 100644 Linux/Device_Driver/EXPORT_SYMBOL/ReadMe.md diff --git a/Linux/Device_Driver/EXPORT_SYMBOL/README.md b/Linux/Device_Driver/EXPORT_SYMBOL/README.md new file mode 100644 index 0000000..c7f7960 --- /dev/null +++ b/Linux/Device_Driver/EXPORT_SYMBOL/README.md @@ -0,0 +1,776 @@ +# Linux Device Driver - EXPORT_SYMBOL in Linux Kernel + +## Overview + +`EXPORT_SYMBOL()` is a Linux kernel macro used to make a function or variable available to other loadable kernel modules. Without exporting a symbol, it remains private to the module where it is defined. ([EmbeTronicX][1]) + +Think of it as: + +```text +Driver A + | + +--> Function + +--> Variable + | + +--> EXPORT_SYMBOL() + | + v +Kernel Symbol Table + | + v +Driver B Can Access It +``` + +--- + +# What is a Symbol? + +In Linux kernel terminology, a symbol is: + +* Function name +* Global variable +* Data structure instance + +Examples: + +```c +int device_count; + +void device_init(void); +``` + +Both are symbols. + +A symbol represents a named location in memory containing either: + +```text +Data -> Variables +Code -> Functions +``` + +([EmbeTronicX][1]) + +--- + +# Why EXPORT_SYMBOL? + +Suppose we have two drivers: + +```text +Driver1 + | + +--> Common Function + +--> Shared Variable + +Driver2 + | + +--> Wants To Use Them +``` + +Without exporting: + +```text +Driver2 + | + +--> Unknown Symbol Error +``` + +With exporting: + +```text +Driver1 + | + +--> EXPORT_SYMBOL() + +Driver2 + | + +--> Access Allowed +``` + +This enables inter-module communication without modifying kernel source code. ([EmbeTronicX][1]) + +--- + +# Historical Background + +## Linux 2.4 + +All non-static symbols were exported automatically. + +```text +Global Function + | + +--> Visible Everywhere +``` + +--- + +## Linux 2.6 and Later + +Only explicitly exported symbols are visible. + +```text +Function + | + +--> EXPORT_SYMBOL() + | + +--> Visible +``` + +Otherwise: + +```text +Private Symbol +``` + +This reduced unnecessary symbol exposure. ([EmbeTronicX][1]) + +--- + +# EXPORT_SYMBOL Architecture + +```text +Driver1 + | + +--> Function + | + +--> EXPORT_SYMBOL() + | + v + Kernel Symbol Table + | + v +Driver2 + | + +--> extern Declaration + | + +--> Function Call +``` + +--- + +# Basic Syntax + +## Export Function + +```c +void shared_function(void) +{ + pr_info("Hello\n"); +} + +EXPORT_SYMBOL(shared_function); +``` + +--- + +## Export Variable + +```c +int device_count = 0; + +EXPORT_SYMBOL(device_count); +``` + +This makes both symbols available to other modules. ([EmbeTronicX][1]) + +--- + +# Exporting Functions + +## Provider Module + +```c +void etx_shared_func(void) +{ + pr_info("Shared function called\n"); +} + +EXPORT_SYMBOL(etx_shared_func); +``` + +--- + +## Consumer Module + +```c +void etx_shared_func(void); + +etx_shared_func(); +``` + +Execution: + +```text +Consumer Module + | + +--> Calls Function + | + v +Provider Module + | + +--> Function Executes +``` + +([EmbeTronicX][1]) + +--- + +# Exporting Variables + +## Provider + +```c +int etx_count = 0; + +EXPORT_SYMBOL(etx_count); +``` + +--- + +## Consumer + +```c +extern int etx_count; + +pr_info("%d\n", etx_count); +``` + +Execution: + +```text +Provider + | + +--> etx_count + +Consumer + | + +--> Read/Modify etx_count +``` + +([EmbeTronicX][1]) + +--- + +# Example Architecture + +```text ++------------------+ +| Driver 1 | ++------------------+ +| etx_shared_func | +| etx_count | ++------------------+ + | + | +EXPORT_SYMBOL() + | + v ++------------------+ +| Kernel Symbol | +| Table | ++------------------+ + | + | + v ++------------------+ +| Driver 2 | ++------------------+ +| Uses Function | +| Uses Variable | ++------------------+ +``` + +--- + +# Example Provider Driver + +## Shared Variable + +```c +int etx_count = 0; +``` + +--- + +## Shared Function + +```c +void etx_shared_func(void) +{ + pr_info("Shared function called\n"); + + etx_count++; +} +``` + +--- + +## Export Symbols + +```c +EXPORT_SYMBOL(etx_shared_func); + +EXPORT_SYMBOL(etx_count); +``` + +Now both become globally visible to loadable modules. ([EmbeTronicX][1]) + +--- + +# Example Consumer Driver + +## Import Variable + +```c +extern int etx_count; +``` + +--- + +## Import Function + +```c +void etx_shared_func(void); +``` + +--- + +## Use Them + +```c +etx_shared_func(); + +pr_info("%d\n", etx_count); +``` + +Execution: + +```text +Read Device + | + +--> Shared Function + | + +--> Increment Counter + | + +--> Print Counter +``` + +([EmbeTronicX][1]) + +--- + +# Module Loading Order + +This is extremely important. + +Correct: + +```text +insmod driver1.ko + +insmod driver2.ko +``` + +Because: + +```text +Driver1 + | + +--> Defines Symbol + +Driver2 + | + +--> Uses Symbol +``` + +--- + +Wrong: + +```text +insmod driver2.ko +``` + +Error: + +```text +Unknown symbol +``` + +Because the symbol does not exist in the kernel symbol table yet. ([EmbeTronicX][1]) + +--- + +# Module Unloading Order + +Correct: + +```text +rmmod driver2 + +rmmod driver1 +``` + +Wrong: + +```text +rmmod driver1 +``` + +while driver2 is using it. + +Error: + +```text +Module in use +``` + +([EmbeTronicX][1]) + +--- + +# Module.symvers + +After compilation: + +```bash +make +``` + +Kernel generates: + +```text +Module.symvers +``` + +Example: + +```text +0x1db7034a etx_shared_func EXPORT_SYMBOL + +0x6dcb135c etx_count EXPORT_SYMBOL +``` + +This file records exported symbols and version information. ([EmbeTronicX][1]) + +--- + +# Checking Exported Symbols + +## Using kallsyms + +```bash +cat /proc/kallsyms | grep etx_shared_func +``` + +or + +```bash +cat /proc/kallsyms | grep etx_count +``` + +If visible: + +```text +Symbol Successfully Exported +``` + +([EmbeTronicX][1]) + +--- + +# EXPORT_SYMBOL_GPL + +Linux also provides: + +```c +EXPORT_SYMBOL_GPL(symbol); +``` + +Difference: + +| Macro | Accessible By | +| ----------------- | ---------------- | +| EXPORT_SYMBOL | Any Module | +| EXPORT_SYMBOL_GPL | GPL Modules Only | + +Example: + +```c +EXPORT_SYMBOL_GPL(my_func); +``` + +Only GPL licensed modules can use it. ([EmbeTronicX][1]) + +--- + +# EXPORT_SYMBOL vs EXPORT_SYMBOL_GPL + +| Feature | EXPORT_SYMBOL | EXPORT_SYMBOL_GPL | +| ------------------ | ------------- | -------------------- | +| GPL Module | Yes | Yes | +| Proprietary Module | Yes | No | +| Kernel Enforcement | Normal | GPL Only | +| Common Usage | Generic APIs | Internal Kernel APIs | + +--- + +# Limitations + +## Cannot Export Static Symbols + +Wrong: + +```c +static int count; + +EXPORT_SYMBOL(count); +``` + +Reason: + +```text +static + | + +--> File Scope Only +``` + +Exported symbols must have global visibility. ([EmbeTronicX][1]) + +--- + +## Avoid Inline Functions + +Wrong: + +```c +inline void my_func(void) +{ +} +``` + +```c +EXPORT_SYMBOL(my_func); +``` + +Inline functions may not generate a standalone symbol. ([EmbeTronicX][1]) + +--- + +# Execution Flow + +```text +Load Driver1 + | + v +Export Symbols + | + v +Kernel Symbol Table + | + v +Load Driver2 + | + v +Resolve Symbols + | + v +Driver2 Uses Them +``` + +--- + +# Common Use Cases + +## Shared Utility Functions + +```text +Driver A + | + +--> CRC Calculation + +Driver B + | + +--> Reuse Same Function +``` + +--- + +## Shared Device State + +```text +Driver A + | + +--> Device Status + +Driver B + | + +--> Read Status +``` + +--- + +## Common Hardware Layer + +```text +GPIO Driver + | + +--> Export API + +Other Drivers + | + +--> Use API +``` + +--- + +## Platform Frameworks + +```text +Core Driver + | + +--> Export Services + +Child Drivers + | + +--> Consume Services +``` + +--- + +# Common Errors + +## Unknown Symbol + +```text +insmod: ERROR: +Unknown symbol +``` + +Possible reasons: + +* Provider module not loaded +* Symbol not exported +* Name mismatch + +--- + +## Static Symbol Export + +Wrong: + +```c +static int value; + +EXPORT_SYMBOL(value); +``` + +--- + +## Missing extern + +Wrong: + +```c +int etx_count; +``` + +Correct: + +```c +extern int etx_count; +``` + +--- + +# EXPORT_SYMBOL vs Header Files + +Many beginners ask: + +```text +Why not just include a header? +``` + +Header files provide: + +```text +Declaration +``` + +EXPORT_SYMBOL provides: + +```text +Kernel Module Linkage +``` + +Both are required. + +```text +Header File + | + +--> Compiler Knows Symbol + +EXPORT_SYMBOL + | + +--> Kernel Loader Resolves Symbol +``` + +([Reddit][2]) + +--- + +# Important APIs Summary + +## Export + +```c +EXPORT_SYMBOL() + +EXPORT_SYMBOL_GPL() +``` + +--- + +## Import + +```c +extern variable; + +function declaration; +``` + +--- + +## Verification + +```bash +cat /proc/kallsyms + +cat Module.symvers +``` + +--- + +# Key Takeaways + +* `EXPORT_SYMBOL()` exposes functions or variables to other kernel modules. +* Only exported symbols can be resolved by loadable modules. +* Provider module must be loaded before consumer module. +* Exported symbols appear in the kernel symbol table. +* `EXPORT_SYMBOL_GPL()` restricts usage to GPL-licensed modules. +* Symbols should not be `static` or `inline`. +* `Module.symvers` records exported symbol information. +* Commonly used for sharing APIs, utility functions, hardware abstraction layers, and global state between kernel modules. ([EmbeTronicX][1]) + +**Source:** EmbeTronicX Linux Device Driver Tutorial Part 29 – EXPORT_SYMBOL in Linux Device Driver. ([EmbeTronicX][1]) + +[1]: https://embetronicx.com/tutorials/linux/device-drivers/export_symbol-in-linux-device-driver/?utm_source=chatgpt.com "EXPORT_SYMBOL in Linux Kernel - Linux Device Driver Part 29" +[2]: https://www.reddit.com/r/kernel/comments/180ktd8?utm_source=chatgpt.com "Why do we need the EXPORT_SYMBOL() macro?" + + +## Conclusion +This is just a basic linux device driver which explains about the EXPORT_SYMBOL in linux device driver. + +Please refer this URL for the complete tutorial of this example source code. +https://embetronicx.com/tutorials/linux/device-drivers/export_symbol-in-linux-device-driver/ diff --git a/Linux/Device_Driver/EXPORT_SYMBOL/ReadMe.md b/Linux/Device_Driver/EXPORT_SYMBOL/ReadMe.md deleted file mode 100644 index 35f11bf..0000000 --- a/Linux/Device_Driver/EXPORT_SYMBOL/ReadMe.md +++ /dev/null @@ -1,4 +0,0 @@ -This is just a basic linux device driver which explains about the EXPORT_SYMBOL in linux device driver. - -Please refer this URL for the complete tutorial of this example source code. -https://embetronicx.com/tutorials/linux/device-drivers/export_symbol-in-linux-device-driver/ \ No newline at end of file From cc156d7cfb233a523fc3a65ba02e36d7679baf05 Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Fri, 19 Jun 2026 19:04:59 +0530 Subject: [PATCH 45/55] Update and rename ReadMe.md to README.md --- Linux/Device_Driver/Atomic_variable/README.md | 933 ++++++++++++++++++ Linux/Device_Driver/Atomic_variable/ReadMe.md | 4 - 2 files changed, 933 insertions(+), 4 deletions(-) create mode 100644 Linux/Device_Driver/Atomic_variable/README.md delete mode 100644 Linux/Device_Driver/Atomic_variable/ReadMe.md diff --git a/Linux/Device_Driver/Atomic_variable/README.md b/Linux/Device_Driver/Atomic_variable/README.md new file mode 100644 index 0000000..c9d9135 --- /dev/null +++ b/Linux/Device_Driver/Atomic_variable/README.md @@ -0,0 +1,933 @@ +# Linux Device Driver - Atomic Variables and Atomic Operations in Linux Kernel + +## Overview + +Atomic operations provide a way to safely manipulate shared integer variables without using mutexes or spinlocks. + +The operation is performed as a single indivisible action, preventing race conditions when multiple CPUs, threads, or interrupt handlers access the same variable simultaneously. ([EmbeTronicX][1]) + +--- + +# Why Atomic Variables? + +Consider a shared variable: + +```c +int counter = 0; +``` + +Two threads execute: + +```c +counter++; +``` + +Internally this is not a single operation: + +```text +1. Read counter +2. Increment value +3. Write back counter +``` + +Possible execution: + +```text +Thread1 reads 0 +Thread2 reads 0 + +Thread1 writes 1 +Thread2 writes 1 +``` + +Expected: + +```text +counter = 2 +``` + +Actual: + +```text +counter = 1 +``` + +This is a race condition. ([EmbeTronicX][1]) + +--- + +# Traditional Solution + +Using a mutex: + +```c +mutex_lock(&lock); + +counter++; + +mutex_unlock(&lock); +``` + +or spinlock: + +```c +spin_lock(&lock); + +counter++; + +spin_unlock(&lock); +``` + +Works correctly but introduces synchronization overhead. ([EmbeTronicX][1]) + +--- + +# Atomic Solution + +Use an atomic variable: + +```c +atomic_t counter = ATOMIC_INIT(0); + +atomic_inc(&counter); +``` + +Internally: + +```text +Read + Modify + Write + | + +--> One Atomic Operation +``` + +No additional lock required. ([EmbeTronicX][1]) + +--- + +# What Does "Atomic" Mean? + +Atomic means: + +```text +Indivisible +``` + +An operation either: + +```text +Completes Entirely + OR +Does Not Happen +``` + +No other CPU can observe a partially completed atomic operation. ([Reddit][2]) + +--- + +# When Should Atomic Variables Be Used? + +Good candidates: + +```text +Reference Counters +Packet Counters +Statistics +Flags +Device Usage Count +Simple Shared Integers +``` + +Example: + +```c +atomic_t packet_count; +``` + +--- + +# When NOT To Use Atomic Variables + +Bad candidates: + +```text +Complex Data Structures +Linked Lists +Multiple Variables +Large Critical Sections +``` + +Use: + +```text +Mutex +Spinlock +RW Spinlock +RCU +``` + +instead. + +--- + +# Atomic Variable Types + +Linux provides two primary atomic integer types. + +--- + +## atomic_t + +Stores a 32-bit integer. + +```c +atomic_t counter; +``` + +Kernel definition conceptually: + +```c +typedef struct { + int counter; +} atomic_t; +``` + +([EmbeTronicX][1]) + +--- + +## atomic64_t + +Stores a 64-bit integer. + +```c +atomic64_t counter64; +``` + +Conceptually: + +```c +typedef struct { + long counter; +} atomic64_t; +``` + +Available on supported architectures. ([EmbeTronicX][1]) + +--- + +# Header Files + +```c +#include +``` + +Older kernels may use: + +```c +#include +``` + +([EmbeTronicX][1]) + +--- + +# Creating Atomic Variables + +## Method 1 + +Declaration only: + +```c +atomic_t etx_counter; +``` + +Must initialize later. + +--- + +## Method 2 + +Initialize during declaration: + +```c +atomic_t etx_counter = + ATOMIC_INIT(0); +``` + +Creates: + +```text +Atomic Integer +Initial Value = 0 +``` + +([EmbeTronicX][1]) + +--- + +# Reading Atomic Variables + +## atomic_read() + +Reads the atomic variable. + +```c +int value; + +value = atomic_read( + &etx_counter); +``` + +Example: + +```c +pr_info( + "Value=%d\n", + atomic_read( + &etx_counter)); +``` + +Returns current value. ([EmbeTronicX][1]) + +--- + +# Writing Atomic Variables + +## atomic_set() + +Assign value atomically. + +```c +atomic_set( + &etx_counter, + 10); +``` + +Result: + +```text +etx_counter = 10 +``` + +([EmbeTronicX][1]) + +--- + +# Atomic Arithmetic Operations + +--- + +## atomic_inc() + +Increment by one. + +```c +atomic_inc( + &etx_counter); +``` + +Equivalent: + +```c +counter++; +``` + +but atomic. ([EmbeTronicX][1]) + +--- + +## atomic_dec() + +Decrement by one. + +```c +atomic_dec( + &etx_counter); +``` + +Equivalent: + +```c +counter--; +``` + +but atomic. ([EmbeTronicX][1]) + +--- + +## atomic_add() + +Add value. + +```c +atomic_add( + 5, + &etx_counter); +``` + +Result: + +```text +counter += 5 +``` + +([EmbeTronicX][1]) + +--- + +## atomic_sub() + +Subtract value. + +```c +atomic_sub( + 5, + &etx_counter); +``` + +Result: + +```text +counter -= 5 +``` + +([EmbeTronicX][1]) + +--- + +# Test Operations + +Useful when checking conditions immediately after modification. + +--- + +## atomic_inc_and_test() + +```c +if (atomic_inc_and_test( + &counter)) +{ +} +``` + +Returns: + +```text +true -> Result became 0 +false -> Otherwise +``` + +([EmbeTronicX][1]) + +--- + +## atomic_dec_and_test() + +```c +if (atomic_dec_and_test( + &counter)) +{ +} +``` + +Returns: + +```text +true -> Counter reached 0 +``` + +Commonly used in reference counting. ([EmbeTronicX][1]) + +--- + +## atomic_sub_and_test() + +```c +if (atomic_sub_and_test( + 5, + &counter)) +{ +} +``` + +Returns: + +```text +true -> Result equals 0 +``` + +([EmbeTronicX][1]) + +--- + +# Return Value Operations + +--- + +## atomic_add_return() + +```c +int value; + +value = + atomic_add_return( + 5, + &counter); +``` + +Returns: + +```text +New Value After Addition +``` + +Example: + +```text +counter = 10 + +atomic_add_return(5) + +returns 15 +``` + +([EmbeTronicX][1]) + +--- + +## atomic_inc_return() + +```c +value = + atomic_inc_return( + &counter); +``` + +Returns incremented value. + +--- + +## atomic_dec_return() + +```c +value = + atomic_dec_return( + &counter); +``` + +Returns decremented value. + +--- + +# Conditional Atomic Operations + +## atomic_add_unless() + +```c +atomic_add_unless( + &counter, + 1, + 100); +``` + +Meaning: + +```text +Add 1 +Unless Value == 100 +``` + +Useful for reference counting. ([EmbeTronicX][1]) + +--- + +# Atomic Bit Operations + +Linux also supports atomic operations on individual bits. + +Example: + +```c +unsigned long flags; +``` + +--- + +## set_bit() + +```c +set_bit( + 0, + &flags); +``` + +Set bit 0. + +--- + +## clear_bit() + +```c +clear_bit( + 0, + &flags); +``` + +Clear bit 0. + +--- + +## test_bit() + +```c +if(test_bit( + 0, + &flags)) +{ +} +``` + +Check bit. + +--- + +## test_and_set_bit() + +```c +old = +test_and_set_bit( + 0, + &flags); +``` + +Returns previous value and sets bit atomically. ([EmbeTronicX][1]) + +--- + +# Example Driver + +## Atomic Variable + +```c +atomic_t etx_counter = + ATOMIC_INIT(0); +``` + +--- + +## Thread 1 + +```c +while(!kthread_should_stop()) +{ + atomic_inc( + &etx_counter); + + pr_info( + "Thread1=%d\n", + atomic_read( + &etx_counter)); + + msleep(1000); +} +``` + +--- + +## Thread 2 + +```c +while(!kthread_should_stop()) +{ + atomic_inc( + &etx_counter); + + pr_info( + "Thread2=%d\n", + atomic_read( + &etx_counter)); + + msleep(1000); +} +``` + +Both threads update the same variable safely without locks. ([EmbeTronicX][1]) + +--- + +# Execution Flow + +```text +Thread1 + | + +--> atomic_inc() + +Thread2 + | + +--> atomic_inc() + +CPU Guarantees +Atomic Update +``` + +Result: + +```text +0 +1 +2 +3 +4 +5 +... +``` + +No lost updates. + +--- + +# Atomic Variable vs Mutex + +| Feature | Atomic Variable | Mutex | +| ---------------- | --------------- | -------- | +| Single Integer | Excellent | Overkill | +| Sleep | No | Yes | +| Ownership | No | Yes | +| Critical Section | No | Yes | +| Performance | Very High | Lower | +| ISR Safe | Yes | No | + +([EmbeTronicX][1]) + +--- + +# Atomic Variable vs Spinlock + +| Feature | Atomic | Spinlock | +| ------------------ | --------- | --------- | +| Single Variable | Excellent | Overkill | +| Multiple Variables | Poor | Excellent | +| Locking Required | No | Yes | +| Complexity | Low | Medium | +| Performance | Higher | Lower | + +([EmbeTronicX][1]) + +--- + +# Common Driver Use Cases + +## Packet Counter + +```c +atomic_t rx_packets; +``` + +```c +atomic_inc( + &rx_packets); +``` + +--- + +## Open Count + +```c +atomic_t open_count; +``` + +```c +atomic_inc( + &open_count); + +atomic_dec( + &open_count); +``` + +--- + +## Reference Counter + +```c +atomic_t refcount; +``` + +```c +if (atomic_dec_and_test( + &refcount)) +{ + free_resource(); +} +``` + +--- + +## Device State Flags + +```c +set_bit(0, &flags); +clear_bit(0, &flags); +``` + +--- + +# Common Mistakes + +## Using Atomic Variable for Complex Logic + +Wrong: + +```c +if(counter == 0) +{ + counter++; +} +``` + +Race possible. + +Use: + +```c +atomic operations +or +locks +``` + +--- + +## Protecting Multiple Variables + +Wrong: + +```c +atomic_t a; +atomic_t b; +``` + +Need consistency between both. + +Use: + +```c +spinlock +mutex +``` + +instead. + +--- + +## Sleeping Assumption + +Atomic operations: + +```text +Do NOT Sleep +Do NOT Block +``` + +They only guarantee atomic access to the variable. + +--- + +# Important APIs Summary + +## Declaration + +```c +atomic_t +atomic64_t +ATOMIC_INIT() +``` + +--- + +## Read / Write + +```c +atomic_read() + +atomic_set() +``` + +--- + +## Arithmetic + +```c +atomic_inc() + +atomic_dec() + +atomic_add() + +atomic_sub() +``` + +--- + +## Test Operations + +```c +atomic_inc_and_test() + +atomic_dec_and_test() + +atomic_sub_and_test() +``` + +--- + +## Return Operations + +```c +atomic_add_return() + +atomic_inc_return() + +atomic_dec_return() +``` + +--- + +## Conditional + +```c +atomic_add_unless() +``` + +--- + +## Bit Operations + +```c +set_bit() + +clear_bit() + +test_bit() + +test_and_set_bit() +``` + +--- + +# Key Takeaways + +* Atomic operations provide lock-free synchronization for simple integer and bit variables. +* `atomic_t` is used for 32-bit atomic integers; `atomic64_t` for 64-bit values. +* Atomic operations prevent race conditions without mutexes or spinlocks. +* They are ideal for counters, flags, statistics, and reference counts. +* Atomic variables are not a replacement for mutexes or spinlocks when protecting complex data structures. +* Use atomic operations when the shared resource is a single integer or bit field and performance is important. ([EmbeTronicX][1]) + +[1]: https://embetronicx.com/tutorials/linux/device-drivers/atomic-variables-atomic-operation/?utm_source=chatgpt.com "Atomic variable in Linux - Linux Device Driver Tutorial Part 30" +[2]: https://www.reddit.com/r/linux/comments/1dxdfoy?utm_source=chatgpt.com "Linux 6.11 To Introduce Block Atomic Writes - Including NVMe & SCSI Support" + + +## Conclusion +This is just a basic linux device driver which explains about the atomic variables in linux device driver. + +Please refer this URL for the complete tutorial of this example source code. +https://embetronicx.com/tutorials/linux/device-drivers/atomic-variables-atomic-operation/ diff --git a/Linux/Device_Driver/Atomic_variable/ReadMe.md b/Linux/Device_Driver/Atomic_variable/ReadMe.md deleted file mode 100644 index c14a13f..0000000 --- a/Linux/Device_Driver/Atomic_variable/ReadMe.md +++ /dev/null @@ -1,4 +0,0 @@ -This is just a basic linux device driver which explains about the atomic variables in linux device driver. - -Please refer this URL for the complete tutorial of this example source code. -https://embetronicx.com/tutorials/linux/device-drivers/atomic-variables-atomic-operation/ \ No newline at end of file From b712e48f7882228808e95a6f2b0cadd9f6bc5c45 Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Fri, 19 Jun 2026 19:07:34 +0530 Subject: [PATCH 46/55] Update ReadMe.md --- Linux/Device_Driver/Seqlock/ReadMe.md | 916 +++++++++++++++++++++++++- 1 file changed, 915 insertions(+), 1 deletion(-) diff --git a/Linux/Device_Driver/Seqlock/ReadMe.md b/Linux/Device_Driver/Seqlock/ReadMe.md index 41cd6f9..9a6ccd7 100644 --- a/Linux/Device_Driver/Seqlock/ReadMe.md +++ b/Linux/Device_Driver/Seqlock/ReadMe.md @@ -1,4 +1,918 @@ +# Linux Device Driver - Seqlock in Linux Kernel + +## Overview + +A **Seqlock (Sequential Lock)** is a synchronization mechanism that gives **priority to writers** while allowing readers to read data without taking a traditional lock. It was introduced in Linux 2.5.60 to solve the writer-starvation problem that can occur with Read-Write Spinlocks. ([EmbeTronicX][1]) + +In simple terms: + +```text +Spinlock + | + +--> Readers and Writers treated equally + +RW Spinlock + | + +--> Readers favored + +Seqlock + | + +--> Writers favored +``` + +--- + +# Why Seqlock? + +Consider a system where: + +```text +95% Reads +5% Writes +``` + +Using a RW Spinlock: + +```text +Reader1 +Reader2 +Reader3 +Reader4 +Reader5 + | + +--> Writer Waiting +``` + +New readers can continue entering, causing: + +```text +Writer Starvation +``` + +Seqlock solves this by allowing writers to proceed while readers retry if a write occurs during their read. ([EmbeTronicX][1]) + +--- + +# Core Idea + +Seqlock uses a **sequence counter**. + +```text +Sequence Number +``` + +Rules: + +```text +Even Number + | + +--> No Writer Active + +Odd Number + | + +--> Writer Active +``` + +Writer operation: + +```text +Acquire Lock + | + +--> seq++ + | (odd) + | + +--> Modify Data + | + +--> seq++ + (even) +``` + +Readers use the sequence number to determine whether the data they read was consistent. ([EmbeTronicX][1]) + +--- + +# How Seqlock Works + +## Writer Side + +Suppose: + +```text +seq = 10 +``` + +Writer enters: + +```text +seq = 11 +``` + +Now: + +```text +Odd Value + | + +--> Writing In Progress +``` + +After update: + +```text +seq = 12 +``` + +Now: + +```text +Even Value + | + +--> Write Completed +``` + +([EmbeTronicX][1]) + +--- + +## Reader Side + +Reader performs: + +```text +Step 1: +Read Sequence Number + +Step 2: +Read Data + +Step 3: +Read Sequence Number Again + +Step 4: +Compare +``` + +If: + +```text +Same Even Number +``` + +Data is valid. + +If: + +```text +Sequence Changed + OR +Sequence Odd +``` + +Reader retries. ([EmbeTronicX][1]) + +--- + +# Reader Example + +Initial state: + +```text +seq = 20 +``` + +Reader: + +```text +Read seq = 20 + +Read data + +Read seq = 20 +``` + +Result: + +```text +Valid Read +``` + +--- + +# Reader During Write + +```text +Read seq = 20 + +Writer Starts + +seq = 21 + +Writer Updates Data + +seq = 22 + +Reader Reads seq = 22 +``` + +Comparison: + +```text +20 != 22 +``` + +Result: + +```text +Retry Read +``` + +([EmbeTronicX][1]) + +--- + +# Advantages of Seqlock + +## Fast Readers + +Readers: + +```text +No Lock Acquisition +No Spinlock +No Mutex +``` + +Just: + +```text +Read +Verify +Retry If Needed +``` + +--- + +## No Writer Starvation + +Writer: + +```text +Never Waits For Readers +``` + +Readers retry instead. ([EmbeTronicX][1]) + +--- + +## Scales Well + +Read-heavy workloads: + +```text +Many Readers +Few Writers +``` + +perform very efficiently. ([Kernel Internals][2]) + +--- + +# Limitations + +Seqlock is **not a general-purpose lock**. + +--- + +## Cannot Protect Pointers + +Bad: + +```c +struct node *head; +``` + +Reason: + +```text +Reader May Follow Pointer + +Writer Changes Pointer + +Reader Crashes +``` + +Seqlocks are generally unsuitable for pointer-based data structures. ([EmbeTronicX][1]) + +--- + +## Reader May Retry Forever + +Heavy writes: + +```text +Writer +Writer +Writer +Writer +``` + +Reader: + +```text +Read +Retry + +Read +Retry + +Read +Retry +``` + +Possible starvation of readers. + +--- + +## Not Suitable For Large Data + +Best for: + +```text +Counters +Timestamps +Statistics +Simple Structures +``` + +Not ideal for complex structures. ([EmbeTronicX][1]) + +--- + +# When To Use Seqlock + +Good: + +```text +Timekeeping +Jiffies +Statistics +Configuration Values +Network Counters +Device Status +``` + +Bad: + +```text +Linked Lists +Trees +Pointer Structures +Dynamic Objects +``` + +([Kernel Internals][2]) + +--- + +# Header File + +```c +#include +``` + +--- + +# Seqlock Data Type + +```c +seqlock_t etx_seq_lock; +``` + +--- + +# Initialization + +## Dynamic + +```c +seqlock_t etx_seq_lock; + +seqlock_init( + &etx_seq_lock); +``` + +--- + +## Static + +```c +DEFINE_SEQLOCK( + etx_seq_lock); +``` + +([Kernel][3]) + +--- + +# Writer APIs + +Writers use an embedded spinlock. + +--- + +## write_seqlock() + +Acquire writer lock. + +```c +write_seqlock( + &etx_seq_lock); +``` + +Internally: + +```text +Lock Spinlock +Increment Sequence +``` + +([EmbeTronicX][1]) + +--- + +## write_sequnlock() + +Release writer lock. + +```c +write_sequnlock( + &etx_seq_lock); +``` + +Internally: + +```text +Increment Sequence +Unlock Spinlock +``` + +([EmbeTronicX][1]) + +--- + +## Example Writer + +```c +write_seqlock( + &etx_seq_lock); + +etx_global_variable++; + +write_sequnlock( + &etx_seq_lock); +``` + +--- + +# Non-Blocking Writer + +## write_tryseqlock() + +```c +if(write_tryseqlock( + &etx_seq_lock)) +{ + /* write */ +} +``` + +Returns: + +| Value | Meaning | +| -------- | ------------- | +| Non-zero | Lock Acquired | +| 0 | Lock Busy | + +([EmbeTronicX][1]) + +--- + +# IRQ Variants + +--- + +## write_seqlock_irq() + +```c +write_seqlock_irq( + &etx_seq_lock); +``` + +Disables interrupts. + +--- + +## write_sequnlock_irq() + +```c +write_sequnlock_irq( + &etx_seq_lock); +``` + +Enables interrupts. + +--- + +## write_seqlock_irqsave() + +```c +unsigned long flags; + +write_seqlock_irqsave( + &etx_seq_lock, + flags); +``` + +--- + +## write_sequnlock_irqrestore() + +```c +write_sequnlock_irqrestore( + &etx_seq_lock, + flags); +``` + +Restores original interrupt state. ([EmbeTronicX][1]) + +--- + +# Bottom Half Variants + +```c +write_seqlock_bh() +write_sequnlock_bh() +``` + +Used in: + +```text +Tasklets +SoftIRQs +``` + +([EmbeTronicX][1]) + +--- + +# Reader APIs + +Readers never acquire a lock. + +--- + +## read_seqbegin() + +Begin reading. + +```c +unsigned int seq; + +seq = +read_seqbegin( + &etx_seq_lock); +``` + +Returns current sequence number. ([EmbeTronicX][1]) + +--- + +## read_seqretry() + +Verify read consistency. + +```c +read_seqretry( + &etx_seq_lock, + seq); +``` + +Returns: + +| Value | Meaning | +| ----- | -------------- | +| 0 | Data Valid | +| 1 | Retry Required | + +([EmbeTronicX][1]) + +--- + +# Reader Example + +```c +unsigned int seq; + +do +{ + seq = + read_seqbegin( + &etx_seq_lock); + + value = + etx_global_variable; + +} while( + read_seqretry( + &etx_seq_lock, + seq)); +``` + +Execution: + +```text +Read Seq +Read Data +Verify Seq + +Changed? + | + +--> Retry + +Unchanged? + | + +--> Success +``` + +([EmbeTronicX][1]) + +--- + +# Complete Example + +## Shared Variable + +```c +unsigned long +etx_global_variable = 0; +``` + +--- + +## Seqlock + +```c +DEFINE_SEQLOCK( + etx_seq_lock); +``` + +--- + +## Writer Thread + +```c +while( + !kthread_should_stop()) +{ + write_seqlock( + &etx_seq_lock); + + etx_global_variable++; + + write_sequnlock( + &etx_seq_lock); + + msleep(1000); +} +``` + +--- + +## Reader Thread + +```c +unsigned int seq; +unsigned long value; + +do +{ + seq = + read_seqbegin( + &etx_seq_lock); + + value = + etx_global_variable; + +} while( + read_seqretry( + &etx_seq_lock, + seq)); +``` + +([EmbeTronicX][1]) + +--- + +# Execution Flow + +```text +Writer + | + +--> seq = 1 + | + +--> Update Data + | + +--> seq = 2 + +Reader + | + +--> Read seq = 2 + | + +--> Read Data + | + +--> Read seq = 2 + | + +--> Success +``` + +--- + +# Seqlock vs Spinlock + +| Feature | Spinlock | Seqlock | +| ---------------- | -------- | ------- | +| Readers Lock | Yes | No | +| Writers Lock | Yes | Yes | +| Reader Retry | No | Yes | +| Writer Priority | No | Yes | +| Pointer Safety | Yes | No | +| Read Performance | Moderate | High | + +([EmbeTronicX][1]) + +--- + +# Seqlock vs Read-Write Spinlock + +| Feature | RW Spinlock | Seqlock | +| ------------------ | ----------- | -------- | +| Multiple Readers | Yes | Yes | +| Reader Locking | Yes | No | +| Writer Starvation | Possible | No | +| Reader Starvation | Rare | Possible | +| Pointer Protection | Yes | No | +| Read Overhead | Higher | Lower | + +([EmbeTronicX][1]) + +--- + +# Common Kernel Uses + +Linux itself uses sequence counters and seqlocks extensively for: + +```text +Timekeeping +Jiffies +Clock Sources +Statistics +Kernel Counters +``` + +because reads are extremely frequent and writes are relatively rare. ([Kernel Internals][2]) + +--- + +# Common Mistakes + +## Using Pointers + +Wrong: + +```c +struct node *head; +``` + +Protected by seqlock. + +Potential: + +```text +Reader Uses Invalid Pointer +``` + +([EmbeTronicX][1]) + +--- + +## Long Write Sections + +Wrong: + +```c +write_seqlock(&lock); + +/* lengthy work */ + +write_sequnlock(&lock); +``` + +Readers may retry repeatedly. + +--- + +## Sleeping While Holding Write Lock + +Wrong: + +```c +write_seqlock(&lock); + +msleep(100); + +write_sequnlock(&lock); +``` + +Writer lock uses a spinlock internally. + +--- + +# Important APIs Summary + +## Initialization + +```c +seqlock_init() + +DEFINE_SEQLOCK() +``` + +--- + +## Writer + +```c +write_seqlock() + +write_tryseqlock() + +write_sequnlock() +``` + +--- + +## IRQ Variants + +```c +write_seqlock_irq() + +write_sequnlock_irq() + +write_seqlock_irqsave() + +write_sequnlock_irqrestore() +``` + +--- + +## Bottom Half Variants + +```c +write_seqlock_bh() + +write_sequnlock_bh() +``` + +--- + +## Reader + +```c +read_seqbegin() + +read_seqretry() +``` + +--- + +# Key Takeaways + +* Seqlock is a **writer-priority synchronization mechanism**. +* Readers never acquire a traditional lock. +* Writers use an embedded spinlock for mutual exclusion. +* Readers validate data using a sequence counter. +* If a write occurs during a read, the reader retries. +* Seqlocks eliminate writer starvation. +* Best suited for small, simple, read-mostly data. +* Not suitable for pointer-based or complex dynamic data structures. +* Frequently used in Linux timekeeping and statistics subsystems. ([EmbeTronicX][1]) + +[1]: https://embetronicx.com/tutorials/linux/device-drivers/seqlock-in-linux-kernel/?utm_source=chatgpt.com "Seqlock in Linux Kernel - Linux Device DriverTutorial Part 31" +[2]: https://kernel-internals.org/locking/seqlock/?utm_source=chatgpt.com "Seqlock - Linux Kernel Internals" +[3]: https://www.kernel.org/doc/html/latest/locking/seqlock.html?utm_source=chatgpt.com "Sequence counters and sequential locks — The Linux Kernel documentation" + + +## Conclusion This is just a basic linux device driver which explains about the Seqlock in linux device driver. Please refer this URL for the complete tutorial of this example source code. -https://embetronicx.com/tutorials/linux/device-drivers/seqlock-in-linux-kernel/ \ No newline at end of file +https://embetronicx.com/tutorials/linux/device-drivers/seqlock-in-linux-kernel/ From 114ce85d4a41285b0518a54bce0c565fe92985d0 Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Fri, 19 Jun 2026 19:16:30 +0530 Subject: [PATCH 47/55] Update README.md --- Linux/Device_Driver/README.md | 49 ++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/Linux/Device_Driver/README.md b/Linux/Device_Driver/README.md index 9cd9d08..fdf1903 100644 --- a/Linux/Device_Driver/README.md +++ b/Linux/Device_Driver/README.md @@ -1,4 +1,51 @@ refer: https://embetronicx.com/linux-device-driver-tutorials/ Contents -1. +1. Introduction +2. First Driver +3. Passing Arguments +4. Major & Minor Number +5. Creating Device File +6. File Operations +7. Real Device Driver +8. IOCTL Tutorial +9. Procfs Tutorial +10. Waitqueue Tutorial +11. SysFS Tutorial +12. Interrupts Tutorial +13. Interrupt Programming +14. Workqueue (Static Method) +15. Workqueue (Dynamic Method) +16. Own Workqueue +17. Linked List 1 +18. Linked List 2 +19. Kernel Thread +20. Tasklet (Static Method) +21. Tasklet (Dynamic Method) +22. Mutex Tutorial +23. Spinlock Tutorial 1 +24. Spinlock Part 2 (Read/Write Spinlock) +25. Sending Signals +26. Kernel Timer Tutorial +27. High Resolution Timer Tutorial +28. Completion Tutorial +29. EXPORT_SYMBOL +30. Atomic Variables Tutorial +31. Seqlock +32. Misc Device Driver +33. USB Device Driver Basics +34. USB Device Driver Example Program +35. GPIO Driver Basic +36. GPIO Interrupt +37. I2C Linux Device Driver +38. Dummy I2C Bus Driver +39. Real I2C Bus Driver +40. I2C Bus Driver using I2C-GPIO +41. SSD1306 I2C Linux Device Driver +42. Poll Linux Example +43. Select Linux Example +44. E-Poll Linux Example +45. Softirq Linux Example +46. Threaded IRQ in Linux +47. SPI Protocol Driver +48. BMP280 I2C Pressure sensor Driver From 0d804a230b5c3696cdb99d048bd958bc1a11a4aa Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Fri, 19 Jun 2026 19:17:46 +0530 Subject: [PATCH 48/55] Update README.md --- Linux/Device_Driver/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Linux/Device_Driver/README.md b/Linux/Device_Driver/README.md index fdf1903..5e9978e 100644 --- a/Linux/Device_Driver/README.md +++ b/Linux/Device_Driver/README.md @@ -1,7 +1,7 @@ refer: https://embetronicx.com/linux-device-driver-tutorials/ Contents -1. Introduction +1. (Introduction)[https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/1%20LDD%20Introduction] 2. First Driver 3. Passing Arguments 4. Major & Minor Number From ee973d044ea62320aca4dd6e67265c13a4b2a643 Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Fri, 19 Jun 2026 19:18:16 +0530 Subject: [PATCH 49/55] Update README.md --- Linux/Device_Driver/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Linux/Device_Driver/README.md b/Linux/Device_Driver/README.md index 5e9978e..7c5ef6a 100644 --- a/Linux/Device_Driver/README.md +++ b/Linux/Device_Driver/README.md @@ -1,7 +1,7 @@ refer: https://embetronicx.com/linux-device-driver-tutorials/ Contents -1. (Introduction)[https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/1%20LDD%20Introduction] +1. [Introduction](https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/1%20LDD%20Introduction) 2. First Driver 3. Passing Arguments 4. Major & Minor Number From bc145d19b9cd52d742bf7e1bce51e532f8ac4a1d Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Tue, 23 Jun 2026 10:30:35 +0530 Subject: [PATCH 50/55] Update README.md --- Linux/Device_Driver/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Linux/Device_Driver/README.md b/Linux/Device_Driver/README.md index 7c5ef6a..84c36ec 100644 --- a/Linux/Device_Driver/README.md +++ b/Linux/Device_Driver/README.md @@ -2,7 +2,7 @@ refer: https://embetronicx.com/linux-device-driver-tutorials/ Contents 1. [Introduction](https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/1%20LDD%20Introduction) -2. First Driver +2. [First Driver](https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/Hello_World) 3. Passing Arguments 4. Major & Minor Number 5. Creating Device File From e2c9511b465cc22dd52f31f43cbc9ea5102f5e06 Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Tue, 23 Jun 2026 10:32:03 +0530 Subject: [PATCH 51/55] Update README.md --- Linux/Device_Driver/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Linux/Device_Driver/README.md b/Linux/Device_Driver/README.md index 84c36ec..d8c505b 100644 --- a/Linux/Device_Driver/README.md +++ b/Linux/Device_Driver/README.md @@ -3,9 +3,9 @@ refer: https://embetronicx.com/linux-device-driver-tutorials/ Contents 1. [Introduction](https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/1%20LDD%20Introduction) 2. [First Driver](https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/Hello_World) -3. Passing Arguments -4. Major & Minor Number -5. Creating Device File +3. [Passing Arguments](https://embetronicx.com/tutorials/linux/device-drivers/linux-device-driver-tutorial-part-3-passing-arguments-to-device-driver/) +4. [Major & Minor Number](https://embetronicx.com/tutorials/linux/device-drivers/character-device-driver-major-number-and-minor-number/) +5. [Creating Device File](https://embetronicx.com/tutorials/linux/device-drivers/device-file-creation-for-character-drivers/) 6. File Operations 7. Real Device Driver 8. IOCTL Tutorial From 1e8a0e13af1e9abb7c322fb20c2c8770b8db320b Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Tue, 23 Jun 2026 11:00:01 +0530 Subject: [PATCH 52/55] Update README.md --- Linux/Device_Driver/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Linux/Device_Driver/README.md b/Linux/Device_Driver/README.md index d8c505b..0d24a75 100644 --- a/Linux/Device_Driver/README.md +++ b/Linux/Device_Driver/README.md @@ -3,10 +3,10 @@ refer: https://embetronicx.com/linux-device-driver-tutorials/ Contents 1. [Introduction](https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/1%20LDD%20Introduction) 2. [First Driver](https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/Hello_World) -3. [Passing Arguments](https://embetronicx.com/tutorials/linux/device-drivers/linux-device-driver-tutorial-part-3-passing-arguments-to-device-driver/) -4. [Major & Minor Number](https://embetronicx.com/tutorials/linux/device-drivers/character-device-driver-major-number-and-minor-number/) -5. [Creating Device File](https://embetronicx.com/tutorials/linux/device-drivers/device-file-creation-for-character-drivers/) -6. File Operations +3. [Passing Arguments](https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/Passing_arguments_to_Linux_device_driver) +4. [Major & Minor Number](https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/Major_and_Minor_number) +5. [Creating Device File](https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/Device_File_Creation) +6. [File Operations](https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/File_Operations) 7. Real Device Driver 8. IOCTL Tutorial 9. Procfs Tutorial From 1603236a5db789206cead3bb37db36dcdd4edc57 Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Tue, 23 Jun 2026 11:30:42 +0530 Subject: [PATCH 53/55] Update README.md --- Linux/Device_Driver/README.md | 80 +++++++++++++++++------------------ 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/Linux/Device_Driver/README.md b/Linux/Device_Driver/README.md index 0d24a75..20c7baf 100644 --- a/Linux/Device_Driver/README.md +++ b/Linux/Device_Driver/README.md @@ -7,45 +7,45 @@ Contents 4. [Major & Minor Number](https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/Major_and_Minor_number) 5. [Creating Device File](https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/Device_File_Creation) 6. [File Operations](https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/File_Operations) -7. Real Device Driver -8. IOCTL Tutorial -9. Procfs Tutorial -10. Waitqueue Tutorial -11. SysFS Tutorial -12. Interrupts Tutorial -13. Interrupt Programming -14. Workqueue (Static Method) -15. Workqueue (Dynamic Method) -16. Own Workqueue -17. Linked List 1 -18. Linked List 2 -19. Kernel Thread -20. Tasklet (Static Method) -21. Tasklet (Dynamic Method) -22. Mutex Tutorial -23. Spinlock Tutorial 1 -24. Spinlock Part 2 (Read/Write Spinlock) -25. Sending Signals -26. Kernel Timer Tutorial -27. High Resolution Timer Tutorial -28. Completion Tutorial -29. EXPORT_SYMBOL -30. Atomic Variables Tutorial -31. Seqlock -32. Misc Device Driver -33. USB Device Driver Basics +7. [Real Device Driver](https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/Real_device_driver) +8. [IOCTL Tutorial](https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/IOCTL) +9. [Procfs Tutorial](https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/procfs) +10. [Waitqueue Tutorial](https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/Waitqueue-Tutorial) +11. [SysFS Tutorial](https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/sysfs) +12. [Interrupts Tutorial](https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/Interrupt-in-Linux-Kernel) +13. [Interrupt Programming](https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/Interrupt-in-Linux-Kernel) +14. [Workqueue (Static Method)](https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/Waitqueue-Tutorial) +15. [Workqueue (Dynamic Method)](https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/Waitqueue-Tutorial) +16. [Own Workqueue](https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/Workqueue-in-Linux-kernel/Own_Workqueue) +17. [Linked List 1](https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/Linked_List) +18. [Linked List 2](https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/Linked_List) +19. [Kernel Thread](https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/Kernel_Thread) +20. [Tasklet (Static Method)](https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/Tasklet) +21. [Tasklet (Dynamic Method)](https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/Tasklet) +22. [Mutex Tutorial](https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/mutex) +23. [Spinlock Tutorial 1](https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/Spinlock) +24. [Spinlock Part 2 (Read/Write Spinlock)](https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/Spinlock) +25. [Sending Signals](https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/Signal_in_Linux_kernel) +26. [Kernel Timer Tutorial](https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/Kernel_Timer) +27. [High Resolution Timer Tutorial](https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/High_Resolution_Timer) +28. [Completion Tutorial](https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/Completion) +29. [EXPORT_SYMBOL](https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/EXPORT_SYMBOL) +30. [Atomic Variables Tutorial](https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/Atomic_variable) +31. [Seqlock](https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/Seqlock) +32. [Misc Device Driver](https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/Misc_Driver) +33. [USB Device Driver Basics](https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/usb_device_driver) 34. USB Device Driver Example Program -35. GPIO Driver Basic -36. GPIO Interrupt -37. I2C Linux Device Driver -38. Dummy I2C Bus Driver -39. Real I2C Bus Driver -40. I2C Bus Driver using I2C-GPIO -41. SSD1306 I2C Linux Device Driver -42. Poll Linux Example -43. Select Linux Example -44. E-Poll Linux Example -45. Softirq Linux Example -46. Threaded IRQ in Linux -47. SPI Protocol Driver +35. [GPIO Driver Basic](https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/GPIO-in-Linux-Device-Driver) +36. [GPIO Interrupt](https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/GPIO-Interrupt-in-Linux-Device-Driver) +37. [I2C Linux Device Driver](https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/I2C-Linux-Device-Driver) +38. [Dummy I2C Bus Driver](https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/I2C-Linux-Device-Driver) +39. [Real I2C Bus Driver](https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/I2C-Linux-Device-Driver) +40. [I2C Bus Driver using I2C-GPIO](https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/I2C-Linux-Device-Driver) +41. [SSD1306 I2C Linux Device Driver](https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/I2C-Linux-Device-Driver) +42. [Poll Linux Example](https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/Poll) +43. [Select Linux Example](https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/Poll) +44. [E-Poll Linux Example](https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/Poll) +45. [Softirq Linux Example](https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/Softirq) +46. [Threaded IRQ in Linux](https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/ThreadedIRQ) +47. [SPI Protocol Driver](https://github.com/darshankharbikar/embetronix-Tutorials/tree/master/Linux/Device_Driver/SPI_Driver/SPI-driver-example-protocol-driver) 48. BMP280 I2C Pressure sensor Driver From d4a2b7e8fb7da0021d85354f5d437dd92a55be66 Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Tue, 23 Jun 2026 15:35:17 +0530 Subject: [PATCH 54/55] Update ReadMe.md --- Linux/Device_Driver/Hello_World/ReadMe.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Linux/Device_Driver/Hello_World/ReadMe.md b/Linux/Device_Driver/Hello_World/ReadMe.md index 232fc00..6ecd210 100644 --- a/Linux/Device_Driver/Hello_World/ReadMe.md +++ b/Linux/Device_Driver/Hello_World/ReadMe.md @@ -13,7 +13,7 @@ The main goals of this example are: ## Files in this Repository -- `first_driver.c` – The main driver source file implementing a character device +- `hello_world.c` – The main driver source file implementing a character device - `Makefile` – Uses the kernel build system to build the module - `README.md` – This documentation From 5859b8eb23ad65f5d6a01cbb2a7edb25e2ee4181 Mon Sep 17 00:00:00 2001 From: Darshan Kharbikar Date: Tue, 23 Jun 2026 15:37:24 +0530 Subject: [PATCH 55/55] Update hello_world.c --- Linux/Device_Driver/Hello_World/hello_world.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Linux/Device_Driver/Hello_World/hello_world.c b/Linux/Device_Driver/Hello_World/hello_world.c index 7609096..61b8db1 100644 --- a/Linux/Device_Driver/Hello_World/hello_world.c +++ b/Linux/Device_Driver/Hello_World/hello_world.c @@ -1,5 +1,5 @@ /***************************************************************************//** -* \file driver.c +* \file hello_world.c * * \details Simple hello world driver * @@ -35,4 +35,4 @@ module_exit(hello_world_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("EmbeTronicX "); MODULE_DESCRIPTION("A simple hello world driver"); -MODULE_VERSION("2:1.0"); \ No newline at end of file +MODULE_VERSION("2:1.0");