Linux Device Driver Development Cookbook - Rodolfo Giometti - E-Book

Linux Device Driver Development Cookbook E-Book

Rodolfo Giometti

0,0
29,99 €

-100%
Sammeln Sie Punkte in unserem Gutscheinprogramm und kaufen Sie E-Books und Hörbücher mit bis zu 100% Rabatt.

Mehr erfahren.
Beschreibung

Linux is a unified kernel that is widely used to develop embedded systems. As Linux has turned out to be one of the most popular operating systems worldwide, the interest in developing proprietary device drivers has also increased. Device drivers play a critical role in how the system performs and ensure that the device works in the manner intended. By exploring several examples on the development of character devices, the technique of managing a device tree, and how to use other kernel internals, such as interrupts, kernel timers, and wait queue, you’ll be able to add proper management for custom peripherals to your embedded system.
You’ll begin by installing the Linux kernel and then configuring it. Once you have installed the system, you will learn to use different kernel features and character drivers. You will also cover interrupts in-depth and understand how you can manage them. Later, you will explore the kernel internals required for developing applications. As you approach the concluding chapters, you will learn to implement advanced character drivers and also discover how to write important Linux device drivers.
By the end of this book, you will be equipped with the skills you need to write a custom character driver and kernel code according to your requirements.

Das E-Book können Sie in Legimi-Apps oder einer beliebigen App lesen, die das folgende Format unterstützen:

EPUB
MOBI

Seitenzahl: 385

Veröffentlichungsjahr: 2019

Bewertungen
0,0
0
0
0
0
0
Mehr Informationen
Mehr Informationen
Legimi prüft nicht, ob Rezensionen von Nutzern stammen, die den betreffenden Titel tatsächlich gekauft oder gelesen/gehört haben. Wir entfernen aber gefälschte Rezensionen.



Linux Device Driver Development Cookbook
Develop custom drivers for your embedded Linux applications
Rodolfo Giometti
BIRMINGHAM - MUMBAI

Linux Device Driver Development Cookbook

Copyright © 2019 Packt Publishing

All rights reserved. No part of this book may be reproduced, stored in a retrieval system, or transmitted in any form or by any means, without the prior written permission of the publisher, except in the case of brief quotations embedded in critical articles or reviews.

Every effort has been made in the preparation of this book to ensure the accuracy of the information presented. However, the information contained in this book is sold without warranty, either express or implied. Neither the author, nor Packt Publishing or its dealers and distributors, will be held liable for any damages caused or alleged to have been caused directly or indirectly by this book.

Packt Publishing has endeavored to provide trademark information about all of the companies and products mentioned in this book by the appropriate use of capitals. However, Packt Publishing cannot guarantee the accuracy of this information.

Commissioning Editor: Karan SadawanaAcquisition Editor: Meeta RajaniContent Development Editor: Ronn KurienTechnical Editor: Pratik ShetCopy Editor:Safis EditingProject Coordinator: Jagdish PrabhuProofreader: Safis EditingIndexer: Rekha NairGraphics: Alishon MendonsaProduction Coordinator: Jisha Chirayil

First published: May 2019

Production reference: 1300519

Published by Packt Publishing Ltd. Livery Place 35 Livery Street Birmingham B3 2PB, UK.

ISBN 978-1-83855-880-2

www.packtpub.com

mapt.io

Mapt is an online digital library that gives you full access to over 5,000 books and videos, as well as industry leading tools to help you plan your personal development and advance your career. For more information, please visit our website.

Why subscribe?

Spend less time learning and more time coding with practical eBooks and Videos from over 4,000 industry professionals

Improve your learning with Skill Plans built especially for you

Get a free eBook or video every month

Mapt is fully searchable

Copy and paste, print, and bookmark content

Packt.com

Did you know that Packt offers eBook versions of every book published, with PDF and ePub files available? You can upgrade to the eBook version at www.packt.com and as a print book customer, you are entitled to a discount on the eBook copy. Get in touch with us at [email protected] for more details.

At www.packt.com, you can also read a collection of free technical articles, sign up for a range of free newsletters, and receive exclusive discounts and offers on Packt books and eBooks.

Contributors

About the author

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.

I would like to thank my wife, Valentina, and my children, Romina and Raffaele, for their patience during the writing of this book. Thanks to Packt's guys: Meeta, who gave me the opportunity; and Ronn, who helped me in finishing this book. Many thanks to Antonio and Cristian for their efforts in reviewing this book.
Finally, I would thank my parents for giving me my first computer when I was a child, which allowed me to do what I do today.

About the reviewers

Cristian Marussi earned his bachelor's degree in Computer Science at the University of Udine (Italy), and spent almost 15 years working with embedded Linux. Cristian has been lucky enough to journey all the way through the software stack, from the userspace down to the lands of the kernel and firmware, while spanning a wide set of different products, from network appliances to consumer mobile devices. He has a keen interest in OS and system software development and internals. He has worked for companies such as Eurotech SPA, VDS Rail, and Samsung Cambridge Solution Center; he is currently a kernel developer in the OSS department at ARM Ltd. in Cambridge (UK).Antonio Tringali is an electronic engineer working as a freelancer. He specializes in automation and remote system control. Most of his work in recent years is concentrated on automated parking systems, security access control, renewable energy data processing, and 3D printers. He likes to work from the silicon up, equally at ease with an oscilloscope as he is with a compiler.

Antonio had the pleasure of getting to know Rodolfo years ago, when writing for the same leading Italian Linux magazine. In 2015, he reviewed another of Rodolfo's books, BeagleBone Essentials. Now, he is eagerly awaiting the next book to come from this prolific author's keyboard.

Packt is searching for authors like you

If you're interested in becoming an author for Packt, please visit authors.packtpub.com and apply today. We have worked with thousands of developers and tech professionals, just like you, to help them share their insight with the global tech community. You can make a general application, apply for a specific hot topic that we are recruiting an author for, or submit your own idea.

Table of Contents

Title Page

Copyright and Credits

Linux Device Driver Development Cookbook

About Packt

Why subscribe?

Packt.com

Contributors

About the author

About the reviewers

Packt is searching for authors like you

Preface

Who this book is for

What this book covers

To get the most out of this book

Download the example code files

Download the color images

Conventions used

Kernel and logging messages

File modifications

Serial and network connections

Other conventions

Sections

Getting ready

How to do it...

How it works...

There's more...

See also

Get in touch

Reviews

Installing the Development System

Technical requirements

Setting up the host machine

Getting ready

How to do it...

See also

Working with the serial console

Getting ready

How to do it...

See also

Configuring and building the kernel

Getting ready

How to do it...

See also

Setting up the target machine

Getting ready

How to do it...

Adding Debian files

Adding the kernel

Setting up the booting variables

Setting up the networking

See also

Doing native compiling on foreign hardware

Getting ready

How to do it...

Installing and configuring schroot

Configuring the emulated OS

See also

A Peek Inside the Kernel

Technical requirements

Adding custom code to the sources

Getting ready

How to do it...

How it works...

See also

Using kernel messages

Getting ready

How to do it...

How it works...

There's more...

Filtering kernel messages

See also

Working with kernel modules

Getting ready

How to do it...

How it works...

See also

Using module parameters

Getting ready

How to do it...

How it works...

See also

Working with Char Drivers

Technical requirements

Creating the simplest char driver

Getting ready

How to do it...

How it works...

There's more...

See also

Exchanging data with a char driver

Getting ready

How to do it...

How it works...

There's more...

See also

Using the "Everything Is a File" abstraction

Getting ready

How to do it...

How it works...

Using the Device Tree

Technical requirements

Using the device tree compiler and utilities

Getting ready

How to do it...

How it works...

There's more...

Reverting a binary device tree into its source

See also

Getting application-specific data from a device tree

Getting ready

How to do it...

How it works...

There's more...

See also

Using a device tree to describe a character driver

Getting ready

How to do it...

How it works...

There's more...

How device files are created in /dev

Downloading the firmware

Getting ready

How to do it...

How it works...

There's more

See also

Configuring CPU pins for specific peripherals

How to do it...

How it works...

See also

Managing Interrupts and Concurrency

Technical requirements

Implementing an interrupt handler

Getting ready

How to do it...

How it works...

There's more...

See also

Deferring work

Getting ready

How to do it...

Tasklets

Workqueues

There's more...

Tasklets

Workqueues

See also

Managing time with kernel timers

Getting ready

How to do it...

How it works...

There's more...

Legacy kernel timers

See also

Waiting for an event

Getting ready

How to do it...

Waitqueues

Completions

How it works...

Waitqueues

Completions

There's more...

Waitqueues

Completions

See also

Performing atomic operations

Getting ready

How to do it...

Mutexes

Spinlocks

How it works...

Mutexes

Spinlocks

There's more...

Mutexes

Spinlocks

The atomic data type

See also

Miscellaneous Kernel Internals

Technical requirements

Using kernel data types

Getting ready

How to do it...

How it works...

There's more...

See also

Managing helper functions

Getting ready

How to do it...

There's more...

See also

Dynamic memory allocation

How to do it...

There's more...

See also

Managing kernel linked lists

Getting ready

How to do it...

There's more...

See also

Using kernel hash tables

Getting ready

How to do it...

There's more...

See also

Getting access to I/O memory

Getting ready

How to do it...

How it works...

See also

Spending time in the kernel

Getting ready

How to do it...

There's more...

See also

Advanced Char Driver Operations

Technical requirements

Going up and down within a file with lseek()

Getting ready

How to do it...

How it works...

There's more...

See also

Using ioctl() for custom commands

Getting ready

How to do it...

How it works...

There's more...

See also

Accessing I/O memory with mmap()

Getting ready

How to do it...

How it works...

There's more...

See also

Locking with the process context

How to do it...

How it works...

See also

Locking (and syncing) with the interrupt context

Getting ready

How to do it...

How it works...

There's more...

See also

Waiting for I/O operations with poll() and select()

Getting ready

How to do it...

There's more...

See also

Managing asynchronous notifications with fasync()

Getting ready

How to do it...

There's more...

See also

Additional Information: Working with Char Drivers

Exchanging data with a char driver

Additional Information: Using the Device Tree

Device tree internals

Using the device tree compiler and utilities

Obtaining a source form of a running device tree

Notes on the device tree utilities

Getting application-specific data from a device tree

Using a device tree to describe a character driver

How to manage different device types

How to add sysfs properties to devices

Configuring the CPU pins for specific peripherals

The Armada 3720

The i.MX7Dual

The SAMA5D3

Using a device tree to describe a character driver

Additional Information: Managing Interrupts and Concurrency

Deferring work

The shared work queue

The container_of() macro

Notifiers

Kernel timers

Additional Information: Miscellaneous Kernel Internals

Dynamic memory allocation

Kernel doubly linked lists

Kernel hash tables

Getting access to I/O memory

Spending time in the kernel

Additional Information: Advanced Char Driver Operations

Technical requirements

Going up and down within a file with lseek()

Using ioctl() for custom commands

Accessing I/O memory with mmap()

Locking with the process context

Waiting for I/O operations with poll() and select()

Managing asynchronous notifications with fasync()

Other Books You May Enjoy

Leave a review - let other readers know what you think

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:

Log in or register at

www.packt.com

.

Select the

SUPPORT

tab.

Click on

Code Downloads & Errata

.

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 athttps://github.com/PacktPublishing/. Check them out!

Download the color images

We also provide a PDF file that has color images of the screenshots/diagrams used in this book. You can download it here: https://www.packtpub.com/sites/default/files/downloads/9781838558802_ColorImages.pdf.

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:

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 beginoutput line 1output line 2...output line 10output 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 lineThis is the second lineThis 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 lineThis is the second lineThis 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 [email protected].

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 [email protected] 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.

Installing the Development System

In this chapter, we will present and set up our working platform. In fact, even if we write and then test our own device drivers on our working PC, it is recommended to use a second device to test the code. This is because we're going to work in the kernel space where even a little bug can cause severe malfunctioning! Also, using a platform where several kinds of peripherals are available allows us to test a large variety of devices that are not always available on a PC. Of course, you are free to use your own system to write and test your drivers but, in this case, you should take care of the modifications needed to fit your board specifications.

In this book, I'm going to use the Marvell ESPRESSObin system, which is a powerful Advanced RISC Machines (ARM) 64-bit machine with a lot of interesting features. In the following figure, you can see the ESPRESSObin alongside a credit card and can gain an idea about the real dimensions of the board:

My board is the v5 release of ESPRESSObin while the latest version at the time of writing (announced on September 2018) is v7, so the reader should be able to get this new release by the timethis book is published. The new ESPRESSObin v7 will feature 1GB DDR4 and 2GB DDR4 configurations (while v5 has DDR3 RAM chips), and a new 1.2GHz chipset will replace the currently sold configurations, which sports 800MHz and 1GHz CPU frequency limits. Even by taking a quick look at the new board layout, we see that a single SATA connector has taken the place of the existing two-pieces combination of SATA power and interface, the LED layout is now rearranged in a row, and an on-board eMMC is now in place. Moreover, this new revision will ship with an optional 802.11ac + Bluetooth 4.2 mini PCIe Wi-Fi card, which is sold separately.

Lastly, you will now have the option to order your v7 ESPRESSObin with a complete enclosure. This product has FCC and CE certifications to help to enable mass deployment. Further information regarding the revision v7 (and v5) can be found at http://wiki.espressobin.net/tiki-index.php?page=Quick+User+Guide.

In order to test our new drivers, we will cover the following recipes in this first chapter:

Setting up the host machine

Working with the serial console

Configuring and building the kernel

Setting up the target machine

Doing native compiling on foreign hardware

Technical requirements

Following are some interesting URLs where we can get useful technical information regarding the board:

The home page:

http://espressobin.net/

The documentation wiki:

http://wiki.espressobin.net/tiki-index.php

Forums:

http://espressobin.net/forums/

Taking a look at the technical specifications at http://espressobin.net/tech-spec/, we get the following information where we can see what the ESPRESSObin v5 can offer in terms of computational power, storage, networking, and expandability:

System on chip

(

SoC

)

Marvell Armada 3700LP (88F3720) dual core ARM Cortex A53 processor up to 1.2GHz

System memory

1 GB DDR3 or optional 2GB DDR3

Storage

1x SATA interface 1x micro SD card slot with footprint for an optional 4GB EMMC

Network connectivity

1x Topaz Networking Switch 2x GbE Ethernet LAN 1x Ethernet WAN 1x MiniPCIe slot for wireless/BLE peripherals

USB

1x USB 3.0 1x USB 2.0 1x micro USB port

Expansion

2x 46-pin GPIO headers for accessories and shields with I2C, GPIOs, PWM, UART, SPI, MMC, and so on.

Misc

Reset button and JTAG interface

Power supply

12V DC jack or 5V via micro USB port

Power consumption

Less than 1W thermal dissipation at 1 GHz

In particular, the following screenshot shows the top view of the Marvell ESPRESSObin v5 (from now on, please take into account that I'm not going to explicitly add "v5" anymore):

In the preceding screenshot, we can see the following components:

The power connector (12V DC jack)

The reset switch

The micro USB device port (serial console)

The Ethernet ports

The USB host ports

The next screenshot shows the bottom view of the board where the microSD slot is located; this is where we should plug in the microSD we're going to create later on in this chapter:

In this book, we'll see how we can manage (and reinstall) a complete Debian distribution, something that will allow us to have a wide set of ready-to-run software packages, as in a normal PC (in fact, the Debian ARM64 version is equivalent to the Debian x86 version). Afterward, we will develop our device drivers for the board, and then, when possible, we will test them with real devices connected to the ESPRESSObin itself. A little tutorial about how to set up the host system is also present in this chapter, and you can use it to set up a GNU/Linux-based working machine or a dedicated virtual one.

The code and other files used in this chapter can be downloaded from GitHub at https://github.com/giometti/linux_device_driver_development_cookbook/tree/master/chapter_01.

Setting up the host machine

As every good device driver developer knows, a host machine is absolutely necessary. Even if the embedded devices are getting more powerful nowadays (and the ESPRESSObin is one of these), there are some resource-consuming tasks where a host machine can help. That's why, in this section, we're going to show how to set up our host machine.

The host machine we decide to use could be a normal PC or a virtualized one—they are equivalent—but the important thing is that it must run a GNU/Linux-based OS.

Getting ready

In this book, I will use an Ubuntu 18.04 LTS based system but you can decide to try to replicate some settings and installation commands that we will use during the course of this book into another major Linux distribution, with little effort for a Debian derivative, or in a bit more of a complicated manner in the case of non-Debian derivative distributions.

I'm not going to show how to install a fresh Ubuntu system on a PC nor on a virtualized machine since it's a really easy task for a real programmer; however, as the last step of this chapter (the Doing native compiling on foreign hardware recipe), I will introduce, with detailed steps about how to install it, an interesting cross-platform environment that proved useful to compile foreign target code on the host machine as we were on the target. This procedure is very useful when we need several different OSes running on your development PC.

So, at this point, the reader should have their own PC running (natively or virtualized) a fresh installed Ubuntu 18.04 LTS OS.

The main usage of a host PC is to edit and then cross-compile our new device drivers and to manage our target device via the serial console, to create its root filesystem, and so on.

In order to do it properly, we need some basic tools; some of them are general while others depend on the specific platform onto which we are going to write our drivers.

General tools are surely an editor, a version control system, and a compiler and its related components, while specific platform tools are essentially the cross-compiler and its related components (on some platforms we may need additional tools but our mileage may vary and, in any case, each manufacturer will give us all of the needed requirements for a comfortable compilation environment).

About the editor: I'm not going to spend any words on it because the reader can use whatever they want (regarding myself, for example, I'm still programming with vi editor) but regarding others tools, I'll have to be more specific.

How to do it...

Now that our GNU/Linux distribution is up and running on our host PC we can start to install some programs we're going to use in this book:

First of all, let's install the basic compiling tools:

$ sudo apt install gcc make pkg-config \

bison flex ncurses-dev libssl-dev \

qemu-user-static debootstrap

As you know already, the sudo command is used to execute a command as a privileged user. It should be already present in your system, otherwise you can install it by using the apt install sudo command as the root user.

Next, we have to test the compiling tools. We should be able to compile a C program. As a simple test, let's use the following standard

Hello World

code stored in the

helloworld.c

file:

#include <stdio.h>int main(int argc, char *argv[]){ printf("Hello World!\n"); return 0;}

Remember that code can be downloaded from our GitHub repository.

Now, we should be able to compile it by using the following command:

$ make CFLAGS="-Wall -O2" helloworld

cc -Wall -O2 helloworld.c -o helloworld

In the preceding command, we used both the compiler and the make tool, which is required to compile every Linux driver in a comfortable and reliable manner.

You can get more information regarding make by taking a look at https://www.gnu.org/software/make/, and for gcc, you can go to https://www.gnu.org/software/gcc/.

Finally, we can test it on the host PC, as follows:

$ ./helloworld

Hello World!

The next step is to install the cross-compiler. Since we're going to work with an ARM64 system, we need a cross-compiler and its related tools. To install them, we simply use the following command:

$ sudo apt install gcc-7-aarch64-linux-gnu

Note that we can also use an external toolchain as reported in the ESPRESSObin wiki at http://wiki.espressobin.net/tiki-index.php?page=Build+From+Source+-+Toolchain; however, the Ubuntu toolchain works perfectly!

When the installation is complete, test our new cross-compiler by using the preceding

Hello World

program, as follows:

$ sudo ln -s /usr/bin/aarch64-linux-gnu-gcc-7 /usr/bin/aarch64-linux-gnu-gcc

$ make CC=aarch64-linux-gnu-gcc CFLAGS="-Wall -O2" helloworld

aarch64-linux-gnu-gcc-7 -Wall -O2 helloworld.c -o helloworld

Note that I've removed the previously compiled helloworld program in order to be able to correctly compile this new version. To do so, I used the mv helloworld helloworld.x86_64command due to the fact I'll need the x86 version again. Also, note that since Ubuntu doesn't automatically create the standard cross-compiler name, aarch64-linux-gnu-gcc, we have to do it manually by using the preceding ln command before executing make.

OK, now we can verify that newly created version of the

helloworld

program for ARM64 by using the following

file

command. This will point out which platform the program is compiled for:

$ file helloworld

helloworld: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, for GNU/Linux 3.7.0, BuildID[sha1]=c0d6e9ab89057e8f9101f51ad517a253e5fc4f10, not stripped

If we again use the file command on the previously renamed version, helloworld.x86_64, we get the following:

$ file helloworld.x86_64

helloworld.x86_64: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=cf932fab45d36f89c30889df98ed382f6f648203, not stripped

To test whether this new release is really for the ARM64 platform, we can use

QEMU

, which is an open source and generic machine emulator and virtualizer that is able to execute foreign code on the running platform. To install it, we can use

apt

command as in the preceding code, specifying the

qemu-user-static

package:

$ sudo apt install qemu-user-static

Then, we can execute our ARM64 program:

$ qemu-aarch64-static -L /usr/aarch64-linux-gnu/ ./helloworld

Hello World!

To get further information about QEMU, a good staring point is its home page at https://www.qemu.org/.

The next step is to install the version control system. We must install the version control system used for the Linux project, that is,

git

. To install it, we can use the following command in a similar manner as before:

$ sudo apt install git

If everything works well, we should be able to execute it as follows:

$ git --help

usage: git [--version] [--help] [-C <path>] [-c <name>=<value>] [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path] [-p | --paginate | --no-pager] [--no-replace-objects] [--bare] [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>] <command> [<args>]These are common Git commands used in various situations:start a working area (see also: git help tutorial) clone Clone a repository into a new directory init Create an empty Git repository or reinitialise an existing one...

In this book, I'm going to explain every git command used but for complete knowledge of this powerful tool, I suggest you start reading https://git-scm.com/.

See also

For further information regarding Debian's packages management, you can surf the internet, but a good starting point is at

https://wiki.debian.org/Apt,

while regarding the compiling tools (

gcc

,

make

, and other GNU software), the best documentation is at

https://www.gnu.org/software/

.

Then, the best place for better documentation

about

git

is at

https://git-scm.com/book/en/v2

, where the wonderful book

Pro Git

is available online!

Working with the serial console

As already stated (and as any real programmer of embedded devices knows), the serial console is a must-have during the device drivers development stages! So, let's see how we can get access to our ESPRESSObin through its serial console.

Getting ready

As shown in the screenshot in the Technical requirements section, a micro USB connector is available and it's directly connected with ESPRESSObin's serial console. So, using a proper USB cable, we can connect it to our host PC.

If all connections are OK, we can execute any serial Terminal emulator to see data from the serial console. Regarding this tool, I have to state that, as editor program, we can use whatever we prefer. However, I'm going to show how to install two of the more used Terminal emulation programs—minicom and screen.

Note that this tool is not strictly required and its usage depends on the platform you're going to work on; however, in my humble opinion, this is the most powerful development and debugging tool ever! So, you definitely need it.

To install minicom, use the following command:

$ sudo apt install minicom

Now, to install the Terminal emulator named screen, we just have to replace minicom string with the screen packet name, as shown in the following:

$ sudo apt install screen

Both of them need a serial port to work on and the invocation command is quite similar. For brevity, I'm going to report their usage to get connected with the ESPRESSObin only; however, for further information about them, you should refer to their man pages (use man minicom and man screen to show them).

How to do it...

To test the serial connection with our target system we can do the following steps:

First of all, we have to locate the right serial port. Since the ESPRESSObin uses an USB emulated serial port (at 115,200 baud rate), usually our target port is named

ttyUSB0

(but your mileage may vary, so let's verify it before continuing) so the

minicom

command we have to use to get connected with the ESPRESSObin serial console is the following:

$ minicom -o -D /dev/ttyUSB0

To correctly get access to the serial console, we may need proper privileges. In fact, we may try to execute the preceding minicom command, and we don't get an output! This is because the minicom