Reader small image

You're reading from  Linux Device Driver Development Cookbook

Product typeBook
Published inMay 2019
Reading LevelIntermediate
PublisherPackt
ISBN-139781838558802
Edition1st Edition
Languages
Tools
Right arrow
Author (1)
Rodolfo Giometti
Rodolfo Giometti
author image
Rodolfo Giometti

Rodolfo Giometti is an engineer, IT specialist, GNU/Linux expert and software libre evangelist. He is the author of the books BeagleBone Essentials, BeagleBone Home Automation Blueprints and GNU/Linux Rapid Embedded Programming by Packt Publishing and maintainer of the LinuxPPS projects. He still actively contributes to the Linux source code with several patches and new device drivers for industrial applications devices. During his 20+ years of experience, he has worked on the x86, ARM, MIPS, and PowerPC-based platforms. Now, he is the co-chief at HCE Engineering S.r.l., where he designs new hardware and software systems for the quick prototyping in industry environment, control automation, and remote monitoring.
Read more about Rodolfo Giometti

Right arrow

Preface

Kernel device driver development is one of the most important parts of a complex operating system, which is what Linux is. Device drivers are very important for developers that use a computer as a monitoring or administrative machine in real environments such as industry, domestic, or medical applications. In fact, even if Linux is now widely supported everywhere, new peripherals are created every day, and these devices need drivers to be efficiently used on a GNU/Linux machine.

This book will present the implementation of a complete character driver (usually called a char driver) by presenting all the necessary techniques to exchange data between the kernel and userspace, to implement process synchronization with the peripheral's interrupts, to get access to I/O memory mapped to (internal or external) devices, and to efficiently manage the time within the kernel.

All code presented in this book is compatible with Linux 4.18+ releases (that is, as far as the latest 5.x kernels). The code can be tested on the Marvell ESPRESSObin, which has an onboard ARM 64-bit CPU, but any other similar GNU/Linux embedded device can be used. In this manner, the readers can verify whether what they have read has been correctly understood.

Who this book is for

If you want to learn about how to implement a complete character driver on a Linux machine, or to find out how several kernel mechanisms work (such as workqueues, completions, and kernel timers, among others) in order to better understand how a generic driver works, then this book is for you.

If you need to know how to write a custom kernel module and how to pass parameters to it, or how to read and better manage kernel messages, or even how to add custom code to the kernel sources, then this book has been written with you in mind.

If you need to better understand a device tree, how to modify it, or even how to write a new device tree in order to meet your requirements and learn how to manage your new device driver, then you will also benefit from this book.

What this book covers

Chapter 1, Installing the Development System, presents how to install a complete development system based on Ubuntu 18.04.1 LTS, along with a complete testing system based on the Marvell ESPRESSObin board. The chapter will also present how to use the serial console and how to recompile the kernel from scratch, and will teach you some tricks for performing cross-compilations and software emulations.

Chapter 2, A Peek Inside the Kernel, discusses how to create a custom kernel module, and how to read and manage kernel messages. Both of these skills are very useful for helping the developer to understand what is happening inside the kernel.

Chapter 3, Working with Char Drivers, examines how to implement a really simple char driver, and how to exchange data between it and the userspace. The chapter ends by proposing some examples in order to underline the Everything is a file abstraction against a device driver.

Chapter 4, Using the Device Tree, presents the device tree. The reader will learn how to read and understand it, how to write a custom device tree and then how to compile it in order to get a binary form that can be passed to the kernel. The chapter ends with a section about downloading firmware (within a peripheral) and how to configure the CPU's pins by using a Pin MUX tool. Examples are provided using the Armada 3720, i.Mx 7Dual, and SAMA5D3 CPUs.

Chapter 5, Managing Interrupts and Concurrency, looks at how to manage interrupts and concurrency within the Linux kernel. It shows how to install an interrupt handler, how to defer a job to a later time, and how to manage kernel timers. At the end of the chapter, the reader will learn how to wait for an event (such as waiting for some data to be read) and how to protect their data against race conditions.

Chapter 6, Miscellaneous Kernel Internals, discusses how to dynamically allocate memory inside the kernel, and how to use several helper functions that are useful for several everyday programming actions (such as strings manipulations, lists, and hash tables manipulations). The chapter will also introduce how to do I/O memory access, and how to safely spend time within the kernel in order to create well-defined busy loop delays.

Chapter 7, Advanced Char Driver Operations, presents all the advanced operations that are available on character drivers: ioctl(), mmap(), lseek(), the poll()/select() system calls implementation, and asynchronous I/O via the SIGIO signal.

Appendix A, Additional Information: Working with Char Drivers, This contains additional information on chapter 3.

Appendix B, Additional Information: Using the Device Tree, This contains additional information on chapter 4.

Appendix C, Additional Information: Managing Interrupts and Concurrency, This contains additional information on chapter 5.

Appendix D, Additional Information: Miscellaneous Kernel Internals, This contains additional information on chapter 6.

Appendix E, Additional Information: Advanced Char Driver Operations, This contains additional information on chapter 7.

To get the most out of this book

  • You should have a little knowledge of a non-graphical text editor such as vi , emacs, or nano. You can't connect an LCD display, a keyboard, and a mouse directly to the embedded kit to carry out little modifications to text files, so you should have a working knowledge of these tools to do such modifications remotely.
  • You should know how to manage an Ubuntu system, or at least a generic GNU/Linux-based one. My host PC is running on Ubuntu 18.04.1 LTS, but you can use also a newer Ubuntu LTS release, or a Debian-based system with a few modifications. You can also use another GNU/Linux distribution, but this will require a little effort from you, mainly with regard to the installation of cross-compile tools, libraries dependencies, and package management.
    Foreign systems, such as Windows, macOS, and others, are not covered by this book due the fact that you should not use low-tech systems to develop code for a high-tech system!
  • Working knowledge of the C programming language, how a C compiler works, and how to manage a makefile are all mandatory requirements.

Download the example code files

You can download the example code files for this book from your account at www.packt.com. If you purchased this book elsewhere, you can visit www.packt.com/support and register to have the files emailed directly to you.

You can download the code files by following these steps:

  1. Log in or register at www.packt.com.
  2. Select the SUPPORT tab.
  3. Click on Code Downloads & Errata.
  4. Enter the name of the book in the Search box and follow the onscreen instructions.

Once the file is downloaded, please make sure that you unzip or extract the folder using the latest version of:

  • WinRAR/7-Zip for Windows
  • Zipeg/iZip/UnRarX for Mac
  • 7-Zip/PeaZip for Linux

The code bundle for the book is hosted on GitHub at https://github.com/giometti/linux_device_driver_development_cookbook. In case there's an update to the code, it will be updated on the existing GitHub repository.

The code bundle for the book is also hosted on GitHub at https://github.com/PacktPublishing/Linux-Device-Driver-Development-Cookbook. In case there's an update to the code, it will be updated on the existing GitHub repository.

We also have other code bundles from our rich catalog of books and videos available at https://github.com/PacktPublishing/. Check them out!

Download the color images

Conventions used

There are a number of text conventions used throughout this book.

Code words in text folder names, filenames, file extensions, pathnames, dummy URLs and user input are shown as follows: "To get the preceding kernel messages, we can use both the dmesg and tail -f /var/log/kern.log commands."

A block of code is set as follows:

#include <stdio.h>

int main(int argc, char *argv[])
{
printf("Hello World!\n");

return 0;
}

You should note that most code in this book has 4-space indentation, while the example code you can find in the files provided with this book on the GitHub or Packt sites uses 8-space indentation. So, the preceding code will look as follows:

#include <stdio.h>

int main(int argc, char *argv[])
{
printf("Hello World!\n");

return 0;
}

Obviously, they are perfectly equivalent in practice!

Any command-line input or output on the embedded kit used in this book is presented as follows:

# make CFLAGS="-Wall -O2" helloworld
cc -Wall -O2 helloworld.c -o helloworld

Commands are in bold, while their output is in normal text. You should also notice that the prompt string has been removed due to space constraints; in fact, on your Terminal, the complete prompt should look like the following:

root@espressobin:~# make CFLAGS="-Wall -O2" helloworld
cc -Wall -O2 helloworld.c -o helloworld

Note also that due to space constraints in the book, you may encounter very long command lines as follows:

$ make CFLAGS="-Wall -O2" \
CC=aarch64-linux-gnu-gcc \
chrdev_test
aarch64-linux-gnu-gcc -Wall -O2 chrdev_test.c -o chrdev_test

Otherwise, I have had to break the command line. However, in some special cases, you can find broken output lines (especially on kernel messages) as follows:

[ 526.318674] mem_alloc:mem_alloc_init: kmalloc(..., GFP_KERNEL) =ffff80007982f
000
[ 526.325210] mem_alloc:mem_alloc_init: kmalloc(..., GFP_ATOMIC) =ffff80007982f
000

Unluckily, these lines cannot easily be reproduced in a printed book, but you should consider them as a single line.

Any command-line input or output given on my host computer as a non-privileged user is written as follows:

$ tail -f /var/log/kern.log

When I need to give a command as a privileged user (root) on my host computer, the command-line input or output is then written as follows:

# insmod mem_alloc.ko

You should note that all privileged commands can be executed by a normal user, too, by using the sudo command in the following format:

$ sudo <command>

So, the preceding command can be executed by a normal user as follows:

$ sudo /insmod mem_alloc.ko

Kernel and logging messages

On several GNU/Linux distribution, kernel messages have this usual form:

[ 3.421397] mvneta d0030000.ethernet eth0: Using random mac address 3e:a1:6b:
f5:c3:2f

This is a quite a long line for this book, so that's why we drop the characters from the start of each line up to the point where the real information begins. So, in the preceding example, the lines output will be reported as follow:

mvneta d0030000.ethernet eth0: Using random mac address 3e:a1:6b:f5:c3:2f

However, as already said, if the line is still too long, it will be broken anyway.

Long outputs, or repeated or less important lines in the Terminal, are dropped by replacing them with three dots, ..., as follows:

output begin
output line 1
output line 2
...
output line 10
output end

When the three dots are at the end of a line, it means that the output continues, but I decided cut it for space reasons.

File modifications

When you should modify a text file, I'm going to use the unified context diff format since this is a very efficient and compact way to represent a text modification. This format can be obtained by using the diff command with the -u option argument, or by using the git diff command within a git repository.

As a simple example, let's consider the following text in file1.old :

This is first line
This is the second line
This is the third line
...
...
This is the last line

Suppose we have to modify the third line, as highlighted in the following snippet:

This is first line
This is the second line
This is the new third line modified by me
...
...
This is the last line

You can easily understand that reporting the whole file each time for a simple modification is unnecessary and space-consuming; however, by using the unified context diff format, the preceding modification can be written as follows:

$ diff -u file1.old file1.new
--- file1.old 2019-05-18 14:49:04.354377460 +0100
+++ file1.new 2019-05-18 14:51:57.450373836 +0100
@@ -1,6 +1,6 @@
This is first line
This is the second line
-This is the third line
+This is the new third line modified by me
...
...
This is the last line

Now, the modification is very clear and written in a compact form! It starts with a two-line header, where the original file is preceded by --- and the new file is preceded by +++. Then, it follows one or more change hunks that contain the line differences in the file. The preceding example has just one hunk where the unchanged lines are preceded by a space character, while the lines to be added are preceded by a + character and the lines to be removed are preceded by a - character.

Nonetheless, for space reasons, most patches reproduced in this book have reduced indentation in order to fit the width of printed pages; however, they are still perfectly readable. For the full patch, you should refer to the provided files on GitHub or the Packt site.

Serial and network connections

In this book, I'm mainly going to use two different kinds of connections to interact with the embedded kit: the serial console, and an SSH terminal and Ethernet connection.

The serial console, implemented over a USB connection, is mainly used to manage the system from the command line. It's largely used for monitoring the system, and especially for taking control of kernel messages.

An SSH terminal is quite similar to the serial console, even if is not exactly the same (for example, kernel messages do not automatically appear on a Terminal), but it can be used in the same manner as a serial console to give commands and edit files from the command line.

In the chapters, I'm going to use a Terminal on the serial console or over an SSH connection to give the most of the commands and configuration settings needed to implement all the prototypes explained in this book.

To get access to the serial console from your host PC, you can use the minicon command, as follows:

$ minicom -o -D /dev/ttyUSB0

However, in Chapter 1 , Installing the Development System, these aspects are explained and you should not worry about them. Note also that on some systems, you may need root privileges to get access to the /dev/ttyUSB0 device. In this case, you can fix this issue or by using the sudo command or, better, by properly adding your system's user to the right group by using the following command:

$ sudo adduser $LOGNAME dialout

Then log out and log back in again, and you should be able to access the serial devices without any problem.

To get access to the SSH Terminal, you can use Ethernet connection. It is used mainly to download files from the host PC or the internet and can be established by connecting an Ethernet cable to the embedded kit's Ethernet port, and then configuring the port accordingly to the reader's LAN settings (see all the instructions in Chapter 1 , Installing the Development System).

Other conventions

Bold: Indicates a new term, an important word, or words that you see onscreen. For example, words in menus or dialog boxes appear in the text like this. Here is an example: "Select System info from the Administration panel."

Warnings or important notes appear like this.
Tips and tricks appear like this.

Sections

In this book, you will find several headings that appear frequently (Getting ready, How to do it..., How it works..., There's more..., and See also).

To give clear instructions on how to complete a recipe, use these sections as follows:

Getting ready

This section tells you what to expect in the recipe and describes how to set up any software or any preliminary settings required for the recipe.

How to do it...

This section contains the steps required to follow the recipe.

How it works...

This section usually consists of a detailed explanation of what happened in the previous section.

There's more...

This section consists of additional information about the recipe in order to make you more knowledgeable about the recipe.

See also

This section provides helpful links to other useful information for the recipe.

Get in touch

Feedback from our readers is always welcome.

General feedback: If you have questions about any aspect of this book, mention the book title in the subject of your message and email us at customercare@packtpub.com.

Errata: Although we have taken every care to ensure the accuracy of our content, mistakes do happen. If you have found a mistake in this book, we would be grateful if you would report this to us. Please visit www.packt.com/submit-errata, selecting your book, clicking on the Errata Submission Form link, and entering the details.

Piracy: If you come across any illegal copies of our works in any form on the Internet, we would be grateful if you would provide us with the location address or website name. Please contact us at copyright@packt.com with a link to the material.

If you are interested in becoming an author: If there is a topic that you have expertise in and you are interested in either writing or contributing to a book, please visit authors.packtpub.com.

Reviews

Please leave a review. Once you have read and used this book, why not leave a review on the site that you purchased it from? Potential readers can then see and use your unbiased opinion to make purchase decisions, we at Packt can understand what you think about our products, and our authors can see your feedback on their book. Thank you!

For more information about Packt, please visit packt.com.

lock icon
The rest of the chapter is locked
You have been reading a chapter from
Linux Device Driver Development Cookbook
Published in: May 2019Publisher: PacktISBN-13: 9781838558802
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
undefined
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $15.99/month. Cancel anytime

Author (1)

author image
Rodolfo Giometti

Rodolfo Giometti is an engineer, IT specialist, GNU/Linux expert and software libre evangelist. He is the author of the books BeagleBone Essentials, BeagleBone Home Automation Blueprints and GNU/Linux Rapid Embedded Programming by Packt Publishing and maintainer of the LinuxPPS projects. He still actively contributes to the Linux source code with several patches and new device drivers for industrial applications devices. During his 20+ years of experience, he has worked on the x86, ARM, MIPS, and PowerPC-based platforms. Now, he is the co-chief at HCE Engineering S.r.l., where he designs new hardware and software systems for the quick prototyping in industry environment, control automation, and remote monitoring.
Read more about Rodolfo Giometti