mirror of
https://github.com/sysprog21/lkmpg.git
synced 2025-04-25 22:14:05 +08:00
6765 lines
906 KiB
HTML
6765 lines
906 KiB
HTML
<!DOCTYPE html>
|
|
<html lang='en-US' xml:lang='en-US'>
|
|
<head> <title>The Linux Kernel Module Programming Guide</title>
|
|
<meta charset='utf-8' />
|
|
<meta content='TeX4ht (https://tug.org/tex4ht/)' name='generator' />
|
|
<meta content='width=device-width,initial-scale=1' name='viewport' />
|
|
<link href='lkmpg-for-ht.css' rel='stylesheet' type='text/css' />
|
|
<meta content='lkmpg-for-ht.tex' name='src' />
|
|
<script src='https://buttons.github.io/buttons.js'></script> <div class='right'> <a aria-label='View on GitHub' class='github-button' data-size='large' href='https://github.com/sysprog21/lkmpg'>View on GitHub</a> <a aria-label='Download PDF document' class='github-button' data-icon='octicon-download' data-size='large' href='https://github.com/sysprog21/lkmpg/releases/download/latest/lkmpg.pdf'>Download PDF document</a> <br /><br /> </div>
|
|
</head><body>
|
|
<div class='maketitle'>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<h2 class='titleHead'>The Linux Kernel Module Programming Guide</h2>
|
|
<div class='author'><span class='ecrm-1200'>Peter Jay Salzman, Michael Burian, Ori Pomerantz, Bob Mottram, Jim Huang</span></div><br />
|
|
<div class='date'><span class='ecrm-1200'>April 20, 2024</span></div>
|
|
|
|
|
|
|
|
</div><p><img alt='PIC' src='assets/cover-with-names.png' /></p>
|
|
<div class='tableofcontents'>
|
|
<span class='sectionToc'>1 <a href='#introduction' id='QQ2-1-1'>Introduction</a></span>
|
|
<br /> <span class='subsectionToc'>1.1 <a href='#authorship' id='QQ2-1-2'>Authorship</a></span>
|
|
<br /> <span class='subsectionToc'>1.2 <a href='#acknowledgements' id='QQ2-1-3'>Acknowledgements</a></span>
|
|
<br /> <span class='subsectionToc'>1.3 <a href='#what-is-a-kernel-module' id='QQ2-1-4'>What Is A Kernel Module?</a></span>
|
|
<br /> <span class='subsectionToc'>1.4 <a href='#kernel-module-package' id='QQ2-1-5'>Kernel module package</a></span>
|
|
<br /> <span class='subsectionToc'>1.5 <a href='#what-modules-are-in-my-kernel' id='QQ2-1-6'>What Modules are in my Kernel?</a></span>
|
|
<br /> <span class='subsectionToc'>1.6 <a href='#is-there-a-need-to-download-and-compile-the-kernel' id='QQ2-1-7'>Is there a need to download and compile the kernel?</a></span>
|
|
<br /> <span class='subsectionToc'>1.7 <a href='#before-we-begin' id='QQ2-1-8'>Before We Begin</a></span>
|
|
<br /> <span class='sectionToc'>2 <a href='#headers' id='QQ2-1-9'>Headers</a></span>
|
|
<br /> <span class='sectionToc'>3 <a href='#examples' id='QQ2-1-10'>Examples</a></span>
|
|
<br /> <span class='sectionToc'>4 <a href='#hello-world' id='QQ2-1-11'>Hello World</a></span>
|
|
<br /> <span class='subsectionToc'>4.1 <a href='#the-simplest-module' id='QQ2-1-12'>The Simplest Module</a></span>
|
|
<br /> <span class='subsectionToc'>4.2 <a href='#hello-and-goodbye' id='QQ2-1-13'>Hello and Goodbye</a></span>
|
|
<br /> <span class='subsectionToc'>4.3 <a href='#the-init-and-exit-macros' id='QQ2-1-14'>The __init and __exit Macros</a></span>
|
|
<br /> <span class='subsectionToc'>4.4 <a href='#licensing-and-module-documentation' id='QQ2-1-15'>Licensing and Module Documentation</a></span>
|
|
<br /> <span class='subsectionToc'>4.5 <a href='#passing-command-line-arguments-to-a-module' id='QQ2-1-16'>Passing Command Line Arguments to a Module</a></span>
|
|
<br /> <span class='subsectionToc'>4.6 <a href='#modules-spanning-multiple-files' id='QQ2-1-17'>Modules Spanning Multiple Files</a></span>
|
|
<br /> <span class='subsectionToc'>4.7 <a href='#building-modules-for-a-precompiled-kernel' id='QQ2-1-18'>Building modules for a precompiled kernel</a></span>
|
|
<br /> <span class='sectionToc'>5 <a href='#preliminaries' id='QQ2-1-19'>Preliminaries</a></span>
|
|
<br /> <span class='subsectionToc'>5.1 <a href='#how-modules-begin-and-end' id='QQ2-1-20'>How modules begin and end</a></span>
|
|
<br /> <span class='subsectionToc'>5.2 <a href='#functions-available-to-modules' id='QQ2-1-21'>Functions available to modules</a></span>
|
|
<br /> <span class='subsectionToc'>5.3 <a href='#user-space-vs-kernel-space' id='QQ2-1-22'>User Space vs Kernel Space</a></span>
|
|
<br /> <span class='subsectionToc'>5.4 <a href='#name-space' id='QQ2-1-23'>Name Space</a></span>
|
|
<br /> <span class='subsectionToc'>5.5 <a href='#code-space' id='QQ2-1-24'>Code space</a></span>
|
|
<br /> <span class='subsectionToc'>5.6 <a href='#device-drivers' id='QQ2-1-25'>Device Drivers</a></span>
|
|
<br /> <span class='sectionToc'>6 <a href='#character-device-drivers' id='QQ2-1-26'>Character Device drivers</a></span>
|
|
<br /> <span class='subsectionToc'>6.1 <a href='#the-fileoperations-structure' id='QQ2-1-27'>The file_operations Structure</a></span>
|
|
<br /> <span class='subsectionToc'>6.2 <a href='#the-file-structure' id='QQ2-1-28'>The file structure</a></span>
|
|
<br /> <span class='subsectionToc'>6.3 <a href='#registering-a-device' id='QQ2-1-29'>Registering A Device</a></span>
|
|
<br /> <span class='subsectionToc'>6.4 <a href='#unregistering-a-device' id='QQ2-1-30'>Unregistering A Device</a></span>
|
|
<br /> <span class='subsectionToc'>6.5 <a href='#chardevc' id='QQ2-1-31'>chardev.c</a></span>
|
|
<br /> <span class='subsectionToc'>6.6 <a href='#writing-modules-for-multiple-kernel-versions' id='QQ2-1-32'>Writing Modules for Multiple Kernel Versions</a></span>
|
|
<br /> <span class='sectionToc'>7 <a href='#the-proc-file-system' id='QQ2-1-33'>The /proc File System</a></span>
|
|
<br /> <span class='subsectionToc'>7.1 <a href='#the-procops-structure' id='QQ2-1-34'>The proc_ops Structure</a></span>
|
|
<br /> <span class='subsectionToc'>7.2 <a href='#read-and-write-a-proc-file' id='QQ2-1-35'>Read and Write a /proc File</a></span>
|
|
<br /> <span class='subsectionToc'>7.3 <a href='#manage-proc-file-with-standard-filesystem' id='QQ2-1-36'>Manage /proc file with standard filesystem</a></span>
|
|
<br /> <span class='subsectionToc'>7.4 <a href='#manage-proc-file-with-seqfile' id='QQ2-1-37'>Manage /proc file with seq_file</a></span>
|
|
<br /> <span class='sectionToc'>8 <a href='#sysfs-interacting-with-your-module' id='QQ2-1-39'>sysfs: Interacting with your module</a></span>
|
|
<br /> <span class='sectionToc'>9 <a href='#talking-to-device-files' id='QQ2-1-40'>Talking To Device Files</a></span>
|
|
<br /> <span class='sectionToc'>10 <a href='#system-calls' id='QQ2-1-41'>System Calls</a></span>
|
|
<br /> <span class='sectionToc'>11 <a href='#blocking-processes-and-threads' id='QQ2-1-42'>Blocking Processes and threads</a></span>
|
|
|
|
|
|
|
|
<br /> <span class='subsectionToc'>11.1 <a href='#sleep' id='QQ2-1-43'>Sleep</a></span>
|
|
<br /> <span class='subsectionToc'>11.2 <a href='#completions' id='QQ2-1-44'>Completions</a></span>
|
|
<br /> <span class='sectionToc'>12 <a href='#avoiding-collisions-and-deadlocks' id='QQ2-1-45'>Avoiding Collisions and Deadlocks</a></span>
|
|
<br /> <span class='subsectionToc'>12.1 <a href='#mutex' id='QQ2-1-46'>Mutex</a></span>
|
|
<br /> <span class='subsectionToc'>12.2 <a href='#spinlocks' id='QQ2-1-47'>Spinlocks</a></span>
|
|
<br /> <span class='subsectionToc'>12.3 <a href='#read-and-write-locks' id='QQ2-1-48'>Read and write locks</a></span>
|
|
<br /> <span class='subsectionToc'>12.4 <a href='#atomic-operations' id='QQ2-1-49'>Atomic operations</a></span>
|
|
<br /> <span class='sectionToc'>13 <a href='#replacing-print-macros' id='QQ2-1-50'>Replacing Print Macros</a></span>
|
|
<br /> <span class='subsectionToc'>13.1 <a href='#replacement' id='QQ2-1-51'>Replacement</a></span>
|
|
<br /> <span class='subsectionToc'>13.2 <a href='#flashing-keyboard-leds' id='QQ2-1-52'>Flashing keyboard LEDs</a></span>
|
|
<br /> <span class='sectionToc'>14 <a href='#scheduling-tasks' id='QQ2-1-53'>Scheduling Tasks</a></span>
|
|
<br /> <span class='subsectionToc'>14.1 <a href='#tasklets' id='QQ2-1-54'>Tasklets</a></span>
|
|
<br /> <span class='subsectionToc'>14.2 <a href='#work-queues' id='QQ2-1-55'>Work queues</a></span>
|
|
<br /> <span class='sectionToc'>15 <a href='#interrupt-handlers' id='QQ2-1-56'>Interrupt Handlers</a></span>
|
|
<br /> <span class='subsectionToc'>15.1 <a href='#interrupt-handlers1' id='QQ2-1-57'>Interrupt Handlers</a></span>
|
|
<br /> <span class='subsectionToc'>15.2 <a href='#detecting-button-presses' id='QQ2-1-58'>Detecting button presses</a></span>
|
|
<br /> <span class='subsectionToc'>15.3 <a href='#bottom-half' id='QQ2-1-59'>Bottom Half</a></span>
|
|
<br /> <span class='subsectionToc'>15.4 <a href='#threaded-irq' id='QQ2-1-60'>Threaded IRQ</a></span>
|
|
<br /> <span class='sectionToc'>16 <a href='#virtual-input-device-driver' id='QQ2-1-61'>Virtual Input Device Driver</a></span>
|
|
<br /> <span class='sectionToc'>17 <a href='#standardizing-the-interfaces-the-device-model' id='QQ2-1-62'>Standardizing the interfaces: The Device Model</a></span>
|
|
<br /> <span class='sectionToc'>18 <a href='#optimizations' id='QQ2-1-63'>Optimizations</a></span>
|
|
<br /> <span class='subsectionToc'>18.1 <a href='#likely-and-unlikely-conditions' id='QQ2-1-64'>Likely and Unlikely conditions</a></span>
|
|
<br /> <span class='subsectionToc'>18.2 <a href='#static-keys' id='QQ2-1-65'>Static keys</a></span>
|
|
<br /> <span class='sectionToc'>19 <a href='#common-pitfalls' id='QQ2-1-66'>Common Pitfalls</a></span>
|
|
<br /> <span class='subsectionToc'>19.1 <a href='#using-standard-libraries' id='QQ2-1-67'>Using standard libraries</a></span>
|
|
<br /> <span class='subsectionToc'>19.2 <a href='#disabling-interrupts' id='QQ2-1-68'>Disabling interrupts</a></span>
|
|
<br /> <span class='sectionToc'>20 <a href='#where-to-go-from-here' id='QQ2-1-69'>Where To Go From Here?</a></span>
|
|
</div>
|
|
<h3 class='sectionHead' id='introduction'><span class='titlemark'>1 </span> <a id='x1-10001'></a>Introduction</h3>
|
|
<!-- l. 65 --><p class='noindent'>The Linux Kernel Module Programming Guide is a free book; you may reproduce
|
|
and/or modify it under the terms of the <a href='https://opensource.org/licenses/OSL-3.0'>Open Software License</a>, version
|
|
3.0.
|
|
</p><!-- l. 67 --><p class='indent'> This book is distributed in the hope that it would be useful, but without any
|
|
warranty, without even the implied warranty of merchantability or fitness for a
|
|
particular purpose.
|
|
</p><!-- l. 69 --><p class='indent'> The author encourages wide distribution of this book for personal or commercial
|
|
use, provided the above copyright notice remains intact and the method adheres to
|
|
the provisions of the <a href='https://opensource.org/licenses/OSL-3.0'>Open Software License</a>. In summary, you may copy and
|
|
distribute this book free of charge or for a profit. No explicit permission is required
|
|
from the author for reproduction of this book in any medium, physical or
|
|
electronic.
|
|
</p><!-- l. 72 --><p class='indent'> Derivative works and translations of this document must be placed under the
|
|
Open Software License, and the original copyright notice must remain intact. If you
|
|
have contributed new material to this book, you must make the material and source
|
|
code available for your revisions. Please make revisions and updates available directly
|
|
|
|
|
|
|
|
to the document maintainer, Jim Huang <jserv@ccns.ncku.edu.tw>. This will allow
|
|
for the merging of updates and provide consistent revisions to the Linux
|
|
community.
|
|
</p><!-- l. 77 --><p class='indent'> If you publish or distribute this book commercially, donations, royalties, and/or
|
|
printed copies are greatly appreciated by the author and the <a href='https://tldp.org/'>Linux Documentation
|
|
Project</a> (LDP). Contributing in this way shows your support for free software and
|
|
the LDP. If you have questions or comments, please contact the address
|
|
above.
|
|
</p><!-- l. 80 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='authorship'><span class='titlemark'>1.1 </span> <a id='x1-20001.1'></a>Authorship</h4>
|
|
<!-- l. 83 --><p class='noindent'>The Linux Kernel Module Programming Guide was initially authored by Ori
|
|
Pomerantz for Linux v2.2. As the Linux kernel evolved, Ori’s availability to maintain
|
|
the document diminished. Consequently, Peter Jay Salzman assumed the role of
|
|
maintainer and updated the guide for Linux v2.4. Similar constraints arose for Peter
|
|
when tracking developments in Linux v2.6, leading to Michael Burian joining
|
|
as a co-maintainer to bring the guide up to speed with Linux v2.6. Bob
|
|
Mottram contributed to the guide by updating examples for Linux v3.8
|
|
and later. Jim Huang then undertook the task of updating the guide for
|
|
recent Linux versions (v5.0 and beyond), along with revising the LaTeX
|
|
document.
|
|
</p><!-- l. 92 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='acknowledgements'><span class='titlemark'>1.2 </span> <a id='x1-30001.2'></a>Acknowledgements</h4>
|
|
<!-- l. 95 --><p class='noindent'>The following people have contributed corrections or good suggestions:
|
|
</p>
|
|
<div class='flushleft'>
|
|
<!-- l. 97 --><p class='noindent'>
|
|
Amit Dhingra, Andy Shevchenko, Arush Sharma, Benno Bielmeier, Bob Lee,
|
|
Brad Baker, Che-Chia Chang, Chih-En Lin, Chih-Hsuan Yang, Chih-Yu Chen,
|
|
Ching-Hua (Vivian) Lin, Chin Yik Ming, Cyril Brulebois, Daniele Paolo
|
|
Scarpazza, David Porter, demonsome, Dimo Velev, Ekang Monyet, Ethan
|
|
Chan, Francois Audeon, Gilad Reti, heartofrain, Horst Schirmeier,
|
|
Hsin-Hsiang Peng, Ignacio Martin, I-Hsin Cheng, Iûnn Kiàn-îng,
|
|
Jian-Xing Wu, Johan Calle, keytouch, Kohei Otsuka, Kuan-Wei Chiu,
|
|
manbing, Marconi Jiang, mengxinayan, Meng-Zong Tsai, Peter Lin, Roman
|
|
Lakeev, Sam Erickson, Shao-Tse Hung, Shih-Sheng Yang, Stacy Prowell,
|
|
Steven Lung, Tristan Lelong, Tse-Wei Lin, Tucker Polomik, Tyler Fanelli,
|
|
VxTeemo, Wei-Hsin Yeh, weihsinyeh, Wei-Lun Tsai, Xatierlike Lee, Yen-Yu
|
|
Chen, Yin-Chiuan Chen, Yi-Wei Lin, Yo-Jung Lin, Yu-Hsiang Tseng, YYGO. </p></div>
|
|
|
|
|
|
|
|
<!-- l. 101 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='what-is-a-kernel-module'><span class='titlemark'>1.3 </span> <a id='x1-40001.3'></a>What Is A Kernel Module?</h4>
|
|
<!-- l. 104 --><p class='noindent'>Involvement in the development of Linux kernel modules requires a foundation in the
|
|
C programming language and a track record of creating conventional programs
|
|
intended for process execution. This pursuit delves into a domain where an
|
|
unregulated pointer, if disregarded, may potentially trigger the total elimination of
|
|
an entire file system, resulting in a scenario that necessitates a complete system
|
|
reboot.
|
|
</p><!-- l. 109 --><p class='indent'> A Linux kernel module is precisely defined as a code segment capable of dynamic
|
|
loading and unloading within the kernel as needed. These modules enhance kernel
|
|
capabilities without necessitating a system reboot. A notable example is seen in the
|
|
device driver module, which facilitates kernel interaction with hardware components
|
|
linked to the system. In the absence of modules, the prevailing approach leans toward
|
|
monolithic kernels, requiring direct integration of new functionalities into the
|
|
kernel image. This approach leads to larger kernels and necessitates kernel
|
|
rebuilding and subsequent system rebooting when new functionalities are
|
|
desired.
|
|
</p><!-- l. 116 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='kernel-module-package'><span class='titlemark'>1.4 </span> <a id='x1-50001.4'></a>Kernel module package</h4>
|
|
<!-- l. 119 --><p class='noindent'>Linux distributions provide the commands
|
|
<code> <span class='ectt-1000'>modprobe</span>
|
|
</code>, <code> <span class='ectt-1000'>insmod</span>
|
|
</code> and <code> <span class='ectt-1000'>depmod</span>
|
|
</code> within a package.
|
|
</p><!-- l. 121 --><p class='indent'> On Ubuntu/Debian GNU/Linux:
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb1'><a id='x1-5006r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>sudo apt-get install build-essential kmod</span></pre>
|
|
<!-- l. 126 --><p class='indent'> On Arch Linux:
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb2'><a id='x1-5009r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>sudo pacman -S gcc kmod</span></pre>
|
|
|
|
|
|
|
|
<!-- l. 131 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='what-modules-are-in-my-kernel'><span class='titlemark'>1.5 </span> <a id='x1-60001.5'></a>What Modules are in my Kernel?</h4>
|
|
<!-- l. 134 --><p class='noindent'>To discover what modules are already loaded within your current kernel use the command
|
|
<code> <span class='ectt-1000'>lsmod</span>
|
|
</code>.
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb3'><a id='x1-6004r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>sudo lsmod</span></pre>
|
|
<!-- l. 139 --><p class='indent'> Modules are stored within the file <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc/modules</span></span></span>, so you can also see them with:
|
|
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb4'><a id='x1-6007r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>sudo cat /proc/modules</span></pre>
|
|
<!-- l. 144 --><p class='indent'> This can be a long list, and you might prefer to search for something particular.
|
|
To search for the <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>fat</span></span></span> module:
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb5'><a id='x1-6010r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>sudo lsmod | grep fat</span></pre>
|
|
<!-- l. 150 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='is-there-a-need-to-download-and-compile-the-kernel'><span class='titlemark'>1.6 </span> <a id='x1-70001.6'></a>Is there a need to download and compile the kernel?</h4>
|
|
<!-- l. 152 --><p class='noindent'>To effectively follow this guide, there is no obligatory requirement for performing
|
|
such actions. Nonetheless, a prudent approach involves executing the examples within
|
|
a test distribution on a virtual machine, thus mitigating any potential risk of
|
|
disrupting the system.
|
|
</p><!-- l. 156 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='before-we-begin'><span class='titlemark'>1.7 </span> <a id='x1-80001.7'></a>Before We Begin</h4>
|
|
<!-- l. 158 --><p class='noindent'>Before delving into code, certain matters require attention. Variances exist among
|
|
individuals’ systems, and distinct personal approaches are evident. The achievement
|
|
of successful compilation and loading of the inaugural “hello world” program may, at
|
|
times, present challenges. It is reassuring to note that overcoming the initial
|
|
obstacle in the first attempt paves the way for subsequent endeavors to proceed
|
|
seamlessly.
|
|
</p><!-- l. 164 --><p class='indent'>
|
|
|
|
|
|
|
|
</p><ol class='enumerate1'>
|
|
<li class='enumerate' id='x1-8002x1'>Modversioning. A module compiled for one kernel will not load if a different
|
|
kernel is booted, unless <code> <span class='ectt-1000'>CONFIG_MODVERSIONS</span>
|
|
</code> is enabled in the kernel. Module versioning will be discussed later in
|
|
this guide. Until module versioning is covered, the examples in this guide
|
|
may not work correctly if running a kernel with modversioning turned on.
|
|
However, most stock Linux distribution kernels come with modversioning
|
|
enabled. If difficulties arise when loading the modules due to versioning
|
|
errors, consider compiling a kernel with modversioning turned off.
|
|
</li>
|
|
<li class='enumerate' id='x1-8005x2'>
|
|
<!-- l. 173 --><p class='noindent'>Using X Window System. It is highly recommended to extract, compile,
|
|
and load all the examples discussed in this guide from a console. Working
|
|
on these tasks within the X Window System is discouraged.
|
|
</p><!-- l. 177 --><p class='noindent'>Modules cannot directly print to the screen like <code> <span class='ectt-1000'>printf()</span>
|
|
</code> can, but they can log information and warnings that are eventually
|
|
displayed on the screen, specifically within a console. If a module is loaded
|
|
from an <code> <span class='ectt-1000'>xterm</span>
|
|
</code>, the information and warnings will be logged, but solely within the systemd
|
|
journal. These logs will not be visible unless consulting the <code> <span class='ectt-1000'>journalctl</span>
|
|
</code>. Refer to <a href='#hello-world'>4<!-- tex4ht:ref: sec:helloworld --></a> for more information. For instant access to this information,
|
|
it is advisable to perform all tasks from the console.
|
|
</p></li>
|
|
<li class='enumerate' id='x1-8010x3'>
|
|
<!-- l. 184 --><p class='noindent'>SecureBoot. Numerous modern computers arrive pre-configured with
|
|
UEFI SecureBoot enabled—an essential security standard ensuring
|
|
booting exclusively through trusted software endorsed by the original
|
|
equipment manufacturer. Certain Linux distributions even ship with the
|
|
default Linux kernel configured to support SecureBoot. In these cases, the
|
|
kernel module necessitates a signed security key.
|
|
</p><!-- l. 189 --><p class='noindent'>Failing this, an attempt to insert your first “hello world” module would
|
|
result in the message: “<span class='ecti-1000'>ERROR: could not insert module</span>”. If this message
|
|
<span class='ecti-1000'>Lockdown: insmod: unsigned module loading is restricted; see man kernel
|
|
</span><span class='ecti-1000'>lockdown.7 </span>appears in the <code> <span class='ectt-1000'>dmesg</span>
|
|
|
|
|
|
|
|
</code> output, the simplest approach involves disabling UEFI SecureBoot from
|
|
the boot menu of your PC or laptop, allowing the successful insertion
|
|
of “hello world” module. Naturally, an alternative involves undergoing
|
|
intricate procedures such as generating keys, system key installation, and
|
|
module signing to achieve functionality. However, this intricate process
|
|
is less appropriate for beginners. If interested, more detailed steps for
|
|
<a href='https://wiki.debian.org/SecureBoot'>SecureBoot</a> can be explored and followed.</p></li></ol>
|
|
<!-- l. 200 --><p class='noindent'>
|
|
</p>
|
|
<h3 class='sectionHead' id='headers'><span class='titlemark'>2 </span> <a id='x1-90002'></a>Headers</h3>
|
|
<!-- l. 202 --><p class='noindent'>Before building anything, it is necessary to install the header files for the
|
|
kernel.
|
|
</p><!-- l. 204 --><p class='indent'> On Ubuntu/Debian GNU/Linux:
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb6'><a id='x1-9004r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>sudo apt-get update</span>
|
|
<a id='x1-9006r2'></a><span class='ecrm-0500'>2</span><span class='ectt-1000'>apt-cache search linux-headers-</span><span id='textcolor1'><span class='tctt-1000'>`</span></span><span class='ectt-1000'>uname -r</span><span id='textcolor2'><span class='tctt-1000'>`</span></span></pre>
|
|
<!-- l. 210 --><p class='indent'> The following command provides information on the available kernel header files.
|
|
Then for example:
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb7'><a id='x1-9009r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>sudo apt-get install kmod linux-headers-5.4.0-80-generic</span></pre>
|
|
<!-- l. 216 --><p class='indent'> On Arch Linux:
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb8'><a id='x1-9012r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>sudo pacman -S linux-headers</span></pre>
|
|
<!-- l. 221 --><p class='indent'> On Fedora:
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb9'><a id='x1-9015r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>sudo dnf install kernel-devel kernel-headers</span></pre>
|
|
<!-- l. 226 --><p class='noindent'>
|
|
</p>
|
|
<h3 class='sectionHead' id='examples'><span class='titlemark'>3 </span> <a id='x1-100003'></a>Examples</h3>
|
|
<!-- l. 228 --><p class='noindent'>All the examples from this document are available within the <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>examples</span></span></span>
|
|
subdirectory.
|
|
|
|
|
|
|
|
</p><!-- l. 230 --><p class='indent'> Should compile errors occur, it may be due to a more recent kernel version being
|
|
in use, or there might be a need to install the corresponding kernel header
|
|
files.
|
|
</p><!-- l. 233 --><p class='noindent'>
|
|
</p>
|
|
<h3 class='sectionHead' id='hello-world'><span class='titlemark'>4 </span> <a id='x1-110004'></a>Hello World</h3>
|
|
<!-- l. 235 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='the-simplest-module'><span class='titlemark'>4.1 </span> <a id='x1-120004.1'></a>The Simplest Module</h4>
|
|
<!-- l. 237 --><p class='noindent'>Most individuals beginning their programming journey typically start with some
|
|
variant of a <span class='ecti-1000'>hello world </span>example. It is unclear what the outcomes are for those who
|
|
deviate from this tradition, but it seems prudent to adhere to it. The learning process
|
|
will begin with a series of hello world programs that illustrate various fundamental
|
|
aspects of writing a kernel module.
|
|
</p><!-- l. 241 --><p class='indent'> Presented next is the simplest possible module.
|
|
</p><!-- l. 243 --><p class='indent'> Make a test directory:
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb10'><a id='x1-12004r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>mkdir -p ~/develop/kernel/hello-1</span>
|
|
<a id='x1-12006r2'></a><span class='ecrm-0500'>2</span><span class='ectt-1000'>cd ~/develop/kernel/hello-1</span></pre>
|
|
<!-- l. 249 --><p class='indent'> Paste this into your favorite editor and save it as <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>hello-1.c</span></span></span>:
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb11'><a id='x1-12008r1'></a><span class='ecrm-0500'>1</span><span id='textcolor3'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-12010r2'></a><span class='ecrm-0500'>2</span><span id='textcolor4'><span class='ectt-0800'> * hello-1.c - The simplest kernel module.</span></span>
|
|
<a id='x1-12012r3'></a><span class='ecrm-0500'>3</span><span id='textcolor5'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-12014r4'></a><span class='ecrm-0500'>4</span><span id='textcolor6'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor7'><span class='ectt-0800'><linux/module.h> /* Needed by all modules */</span></span>
|
|
<a id='x1-12016r5'></a><span class='ecrm-0500'>5</span><span id='textcolor8'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor9'><span class='ectt-0800'><linux/printk.h> /* Needed for pr_info() */</span></span>
|
|
<a id='x1-12018r6'></a><span class='ecrm-0500'>6</span>
|
|
<a id='x1-12020r7'></a><span class='ecrm-0500'>7</span><span id='textcolor10'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> init_module(</span><span id='textcolor11'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-12022r8'></a><span class='ecrm-0500'>8</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-12024r9'></a><span class='ecrm-0500'>9</span><span class='ectt-0800'> pr_info(</span><span id='textcolor12'><span class='ectt-0800'>"Hello world 1.</span></span><span id='textcolor13'><span class='ectt-0800'>\n</span></span><span id='textcolor14'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-12026r10'></a><span class='ecrm-0500'>10</span>
|
|
<a id='x1-12028r11'></a><span class='ecrm-0500'>11</span><span class='ectt-0800'> </span><span id='textcolor15'><span class='ectt-0800'>/* A non 0 return means init_module failed; module can</span><span class='tctt-0800'>'</span><span class='ectt-0800'>t be loaded. */</span></span>
|
|
<a id='x1-12030r12'></a><span class='ecrm-0500'>12</span><span class='ectt-0800'> </span><span id='textcolor16'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-12032r13'></a><span class='ecrm-0500'>13</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-12034r14'></a><span class='ecrm-0500'>14</span>
|
|
<a id='x1-12036r15'></a><span class='ecrm-0500'>15</span><span id='textcolor17'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> cleanup_module(</span><span id='textcolor18'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-12038r16'></a><span class='ecrm-0500'>16</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-12040r17'></a><span class='ecrm-0500'>17</span><span class='ectt-0800'> pr_info(</span><span id='textcolor19'><span class='ectt-0800'>"Goodbye world 1.</span></span><span id='textcolor20'><span class='ectt-0800'>\n</span></span><span id='textcolor21'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-12042r18'></a><span class='ecrm-0500'>18</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-12044r19'></a><span class='ecrm-0500'>19</span>
|
|
<a id='x1-12046r20'></a><span class='ecrm-0500'>20</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor22'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span></pre>
|
|
<!-- l. 253 --><p class='indent'> Now you will need a <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>Makefile</span></span></span>. If you copy and paste this, change the indentation
|
|
to use <span class='ecti-1000'>tabs</span>, not spaces.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb12'><a id='x1-12057r1'></a><span class='ecrm-0500'>1</span><span class='ectt-0800'>obj-m += hello-1.o</span>
|
|
<a id='x1-12059r2'></a><span class='ecrm-0500'>2</span>
|
|
<a id='x1-12061r3'></a><span class='ecrm-0500'>3</span><span class='ectt-0800'>PWD := </span><span class='colorbox' id='colorbox23'><span class='ectt-0800'>$</span></span><span class='ectt-0800'>(CURDIR)</span>
|
|
<a id='x1-12063r4'></a><span class='ecrm-0500'>4</span>
|
|
<a id='x1-12065r5'></a><span class='ecrm-0500'>5</span><span class='ectt-0800'>all:</span>
|
|
<a id='x1-12067r6'></a><span class='ecrm-0500'>6</span><span class='ectt-0800'> make -C /lib/modules/</span><span class='colorbox' id='colorbox24'><span class='ectt-0800'>$</span></span><span class='ectt-0800'>(shell uname -r)/build M=</span><span class='colorbox' id='colorbox25'><span class='ectt-0800'>$</span></span><span class='ectt-0800'>(PWD) modules</span>
|
|
<a id='x1-12069r7'></a><span class='ecrm-0500'>7</span>
|
|
<a id='x1-12071r8'></a><span class='ecrm-0500'>8</span><span class='ectt-0800'>clean:</span>
|
|
<a id='x1-12073r9'></a><span class='ecrm-0500'>9</span><span class='ectt-0800'> make -C /lib/modules/</span><span class='colorbox' id='colorbox26'><span class='ectt-0800'>$</span></span><span class='ectt-0800'>(shell uname -r)/build M=</span><span class='colorbox' id='colorbox27'><span class='ectt-0800'>$</span></span><span class='ectt-0800'>(PWD) clean</span></pre>
|
|
<!-- l. 267 --><p class='indent'> In <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>Makefile</span></span></span>, <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>$(CURDIR)</span></span></span> can set to the absolute pathname of the current working
|
|
directory(after all <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>-C</span></span></span> options are processed, if any). See more about <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>CURDIR</span></span></span> in <a href='https://www.gnu.org/software/make/manual/make.html'>GNU
|
|
make manual</a>.
|
|
</p><!-- l. 270 --><p class='indent'> And finally, just run <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>make</span></span></span> directly.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb13'><a id='x1-12076r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>make</span></pre>
|
|
|
|
|
|
|
|
<!-- l. 276 --><p class='indent'> If there is no <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>PWD := $(CURDIR)</span></span></span> statement in Makefile, then it may not compile
|
|
correctly with <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>sudo make</span></span></span>. Because some environment variables are specified by
|
|
the security policy, they can’t be inherited. The default security policy is
|
|
<span class='obeylines-h'><span class='verb'><span class='ectt-1000'>sudoers</span></span></span>. In the <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>sudoers</span></span></span> security policy, <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>env_reset</span></span></span> is enabled by default,
|
|
which restricts environment variables. Specifically, path variables are not
|
|
retained from the user environment, they are set to default values (For more
|
|
information see: <a href='https://www.sudo.ws/docs/man/sudoers.man/'>sudoers manual</a>). You can see the environment variable settings
|
|
by:
|
|
|
|
|
|
|
|
</p>
|
|
<pre class='verbatim' id='verbatim-1'>
|
|
$ sudo -s
|
|
# sudo -V
|
|
</pre>
|
|
<!-- l. 286 --><p class='nopar'>
|
|
</p><!-- l. 288 --><p class='indent'> Here is a simple Makefile as an example to demonstrate the problem mentioned
|
|
above.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb14'><a id='x1-12080r1'></a><span class='ecrm-0500'>1</span><span class='ectt-0800'>all:</span>
|
|
<a id='x1-12082r2'></a><span class='ecrm-0500'>2</span><span class='ectt-0800'> echo </span><span class='colorbox' id='colorbox28'><span class='ectt-0800'>$</span></span><span class='ectt-0800'>(PWD)</span></pre>
|
|
<!-- l. 295 --><p class='indent'> Then, we can use <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>-p</span></span></span> flag to print out the environment variable values from the
|
|
Makefile.
|
|
|
|
|
|
|
|
</p>
|
|
<pre class='verbatim' id='verbatim-2'>
|
|
$ make -p | grep PWD
|
|
PWD = /home/ubuntu/temp
|
|
OLDPWD = /home/ubuntu
|
|
echo $(PWD)
|
|
</pre>
|
|
<!-- l. 302 --><p class='nopar'>
|
|
</p><!-- l. 304 --><p class='indent'> The <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>PWD</span></span></span> variable won’t be inherited with <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>sudo</span></span></span>.
|
|
|
|
|
|
|
|
</p>
|
|
<pre class='verbatim' id='verbatim-3'>
|
|
$ sudo make -p | grep PWD
|
|
echo $(PWD)
|
|
</pre>
|
|
<!-- l. 309 --><p class='nopar'>
|
|
</p><!-- l. 311 --><p class='indent'> However, there are three ways to solve this problem.
|
|
</p><!-- l. 313 --><p class='indent'>
|
|
</p><ol class='enumerate1'>
|
|
<li class='enumerate' id='x1-12084x1'>
|
|
<!-- l. 314 --><p class='noindent'> You can use the <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>-E</span></span></span> flag to temporarily preserve them.
|
|
</p><!-- l. 1 --><p class='noindent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb15'><a id='x1-12090r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'> $ sudo -E make -p | grep PWD</span>
|
|
<a id='x1-12092r2'></a><span class='ecrm-0500'>2</span><span class='ectt-1000'> PWD = /home/ubuntu/temp</span>
|
|
<a id='x1-12094r3'></a><span class='ecrm-0500'>3</span><span class='ectt-1000'> OLDPWD = /home/ubuntu</span>
|
|
<a id='x1-12096r4'></a><span class='ecrm-0500'>4</span><span class='ectt-1000'> echo </span><span id='textcolor29'><span class='ectt-1000'>$(</span></span><span class='ectt-1000'>PWD</span><span id='textcolor30'><span class='ectt-1000'>)</span></span></pre>
|
|
</li>
|
|
<li class='enumerate' id='x1-12098x2'>
|
|
<!-- l. 325 --><p class='noindent'> You can set the <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>env_reset</span></span></span> disabled by editing the <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/etc/sudoers</span></span></span> with
|
|
root and <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>visudo</span></span></span>.
|
|
</p><!-- l. 1 --><p class='noindent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb16'><a id='x1-12105r1'></a><span class='ecrm-0500'>1</span><span class='ectt-0800'> </span><span id='textcolor31'><span class='ectt-0800'>## sudoers file.</span></span>
|
|
<a id='x1-12107r2'></a><span class='ecrm-0500'>2</span><span class='ectt-0800'> </span><span id='textcolor32'><span class='ectt-0800'>##</span></span>
|
|
<a id='x1-12109r3'></a><span class='ecrm-0500'>3</span><span class='ectt-0800'> ...</span>
|
|
<a id='x1-12111r4'></a><span class='ecrm-0500'>4</span><span class='ectt-0800'> Defaults env_reset</span>
|
|
<a id='x1-12113r5'></a><span class='ecrm-0500'>5</span><span class='ectt-0800'> </span><span id='textcolor33'><span class='ectt-0800'>## Change env_reset to !env_reset in previous line to keep all environment variables</span></span></pre>
|
|
<!-- l. 336 --><p class='noindent'>Then execute <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>env</span></span></span> and <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>sudo env</span></span></span> individually.
|
|
</p><!-- l. 1 --><p class='noindent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb17'><a id='x1-12121r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'> </span><span id='textcolor34'><span class='ectt-1000'># disable the env_reset</span></span>
|
|
<a id='x1-12123r2'></a><span class='ecrm-0500'>2</span><span class='ectt-1000'> echo </span><span id='textcolor35'><span class='ectt-1000'>"user:"</span></span><span class='ectt-1000'> > non-env_reset.log; env >> non-env_reset.log</span>
|
|
<a id='x1-12125r3'></a><span class='ecrm-0500'>3</span><span class='ectt-1000'> echo </span><span id='textcolor36'><span class='ectt-1000'>"root:"</span></span><span class='ectt-1000'> >> non-env_reset.log; sudo env >> non-env_reset.log</span>
|
|
<a id='x1-12127r4'></a><span class='ecrm-0500'>4</span><span class='ectt-1000'> </span><span id='textcolor37'><span class='ectt-1000'># enable the env_reset</span></span>
|
|
<a id='x1-12129r5'></a><span class='ecrm-0500'>5</span><span class='ectt-1000'> echo </span><span id='textcolor38'><span class='ectt-1000'>"user:"</span></span><span class='ectt-1000'> > env_reset.log; env >> env_reset.log</span>
|
|
<a id='x1-12131r6'></a><span class='ecrm-0500'>6</span><span class='ectt-1000'> echo </span><span id='textcolor39'><span class='ectt-1000'>"root:"</span></span><span class='ectt-1000'> >> env_reset.log; sudo env >> env_reset.log</span></pre>
|
|
<!-- l. 347 --><p class='noindent'>You can view and compare these logs to find differences between
|
|
<span class='obeylines-h'><span class='verb'><span class='ectt-1000'>env_reset</span></span></span> and <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>!env_reset</span></span></span>.
|
|
</p></li>
|
|
<li class='enumerate' id='x1-12133x3'>
|
|
<!-- l. 350 --><p class='noindent'>You can preserve environment variables by appending them to <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>env_keep</span></span></span>
|
|
in <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/etc/sudoers</span></span></span>.
|
|
</p><!-- l. 1 --><p class='noindent'>
|
|
|
|
|
|
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb18'><a id='x1-12136r1'></a><span class='ecrm-0500'>1</span><span class='ectt-0800'> Defaults env_keep += </span><span id='textcolor40'><span class='ectt-0800'>"PWD"</span></span></pre>
|
|
<!-- l. 356 --><p class='noindent'>After applying the above change, you can check the environment variable
|
|
settings by:
|
|
|
|
|
|
|
|
</p>
|
|
<pre class='verbatim' id='verbatim-4'>
|
|
$ sudo -s
|
|
# sudo -V
|
|
|
|
</pre>
|
|
<!-- l. 361 --><p class='nopar'></p></li></ol>
|
|
<!-- l. 365 --><p class='indent'> If all goes smoothly you should then find that you have a compiled <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>hello-1.ko</span></span></span>
|
|
module. You can find info on it with the command:
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb19'><a id='x1-12139r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>modinfo hello-1.ko</span></pre>
|
|
<!-- l. 371 --><p class='indent'> At this point the command:
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb20'><a id='x1-12142r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>sudo lsmod | grep hello</span></pre>
|
|
<!-- l. 376 --><p class='indent'> should return nothing. You can try loading your shiny new module with:
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb21'><a id='x1-12145r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>sudo insmod hello-1.ko</span></pre>
|
|
<!-- l. 382 --><p class='indent'> The dash character will get converted to an underscore, so when you again try:
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb22'><a id='x1-12148r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>sudo lsmod | grep hello</span></pre>
|
|
<!-- l. 387 --><p class='indent'> You should now see your loaded module. It can be removed again with:
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb23'><a id='x1-12151r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>sudo rmmod hello_1</span></pre>
|
|
<!-- l. 392 --><p class='indent'> Notice that the dash was replaced by an underscore. To see what just happened in
|
|
the logs:
|
|
|
|
|
|
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb24'><a id='x1-12154r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>sudo journalctl --since </span><span id='textcolor41'><span class='ectt-1000'>"1 hour ago"</span></span><span class='ectt-1000'> | grep kernel</span></pre>
|
|
<!-- l. 398 --><p class='indent'> You now know the basics of creating, compiling, installing and removing modules.
|
|
Now for more of a description of how this module works.
|
|
</p><!-- l. 401 --><p class='indent'> Kernel modules must have at least two functions: a "start" (initialization) function
|
|
called <code> <span class='ectt-1000'>init_module()</span>
|
|
</code> which is called when the module is <code> <span class='ectt-1000'>insmod</span>
|
|
</code>ed into the kernel, and an "end" (cleanup) function called
|
|
<code> <span class='ectt-1000'>cleanup_module()</span>
|
|
</code> which is called just before it is removed from the kernel. Actually, things have
|
|
changed starting with kernel 2.3.13. You can now use whatever name you like for the
|
|
start and end functions of a module, and you will learn how to do this in Section <a href='#hello-and-goodbye'>4.2<!-- tex4ht:ref: hello_n_goodbye --></a>.
|
|
In fact, the new method is the preferred method. However, many people still use
|
|
<code> <span class='ectt-1000'>init_module()</span>
|
|
</code> and <code> <span class='ectt-1000'>cleanup_module()</span>
|
|
</code> for their start and end functions.
|
|
</p><!-- l. 408 --><p class='indent'> Typically, <code> <span class='ectt-1000'>init_module()</span>
|
|
</code> either registers a handler for something with the kernel, or it replaces one of the kernel
|
|
functions with its own code (usually code to do something and then call the original function).
|
|
The <code> <span class='ectt-1000'>cleanup_module()</span>
|
|
</code> function is supposed to undo whatever
|
|
<code> <span class='ectt-1000'>init_module()</span>
|
|
</code> did, so the module can be unloaded safely.
|
|
</p><!-- l. 411 --><p class='indent'> Lastly, every kernel module needs to include <span class='obeylines-h'><span class='verb'><span class='ectt-1000'><linux/module.h></span></span></span>. We
|
|
needed to include <span class='obeylines-h'><span class='verb'><span class='ectt-1000'><linux/printk.h></span></span></span> only for the macro expansion for the
|
|
<code> <span class='ectt-1000'>pr_alert()</span>
|
|
</code> log level, which you’ll learn about in Section <a href='#x1-121662'>2<!-- tex4ht:ref: sec:printk --></a>.
|
|
</p><!-- l. 415 --><p class='indent'>
|
|
</p><ol class='enumerate1'>
|
|
<li class='enumerate' id='x1-12165x1'>A point about coding style. Another thing which may not be immediately
|
|
obvious to anyone getting started with kernel programming is that
|
|
indentation within your code should be using <span class='ecbx-1000'>tabs </span>and <span class='ecbx-1000'>not spaces</span>. It is
|
|
one of the coding conventions of the kernel. You may not like it, but you’ll
|
|
need to get used to it if you ever submit a patch upstream.
|
|
</li>
|
|
<li class='enumerate' id='x1-12167x2'>Introducing print macros. <a id='x1-121662'></a>In the beginning there was <code> <span class='ectt-1000'>printk</span>
|
|
</code>, usually followed by a priority such as <code> <span class='ectt-1000'>KERN_INFO</span>
|
|
|
|
|
|
|
|
</code> or <code> <span class='ectt-1000'>KERN_DEBUG</span>
|
|
</code>. More recently this can also be expressed in abbreviated form using a set of
|
|
print macros, such as <code> <span class='ectt-1000'>pr_info</span>
|
|
</code> and <code> <span class='ectt-1000'>pr_debug</span>
|
|
</code>. This just saves some mindless keyboard bashing and looks a bit neater.
|
|
They can be found within <a href='https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/include/linux/printk.h'>include/linux/printk.h</a>. Take time to read through
|
|
the available priority macros.
|
|
</li>
|
|
<li class='enumerate' id='x1-12174x3'>
|
|
<!-- l. 429 --><p class='noindent'>About Compiling. Kernel modules need to be compiled a bit differently
|
|
from regular userspace apps. Former kernel versions required us to
|
|
care much about these settings, which are usually stored in Makefiles.
|
|
Although hierarchically organized, many redundant settings accumulated
|
|
in sublevel Makefiles and made them large and rather difficult to maintain.
|
|
Fortunately, there is a new way of doing these things, called kbuild, and
|
|
the build process for external loadable modules is now fully integrated into
|
|
the standard kernel build mechanism. To learn more on how to compile
|
|
modules which are not part of the official kernel (such as all the examples
|
|
you will find in this guide), see file <a href='https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/Documentation/kbuild/modules.rst'>Documentation/kbuild/modules.rst</a>.
|
|
</p><!-- l. 436 --><p class='noindent'>Additional details about Makefiles for kernel modules are available in
|
|
<a href='https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/Documentation/kbuild/makefiles.rst'>Documentation/kbuild/makefiles.rst</a>. Be sure to read this and the related
|
|
files before starting to hack Makefiles. It will probably save you lots of
|
|
work.
|
|
</p><!-- l. 438 --><p class='noindent'>
|
|
</p><blockquote class='quote'>
|
|
<!-- l. 439 --><p class='noindent'>Here is another exercise for the reader. See that comment above
|
|
the return statement in <code> <span class='ectt-1000'>init_module()</span>
|
|
</code>? Change the return value to something negative, recompile and
|
|
load the module again. What happens?</p></blockquote>
|
|
</li></ol>
|
|
<!-- l. 446 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='hello-and-goodbye'><span class='titlemark'>4.2 </span> <a id='x1-130004.2'></a>Hello and Goodbye</h4>
|
|
<!-- l. 448 --><p class='noindent'>In early kernel versions you had to use the
|
|
|
|
|
|
|
|
<code> <span class='ectt-1000'>init_module</span>
|
|
</code> and <code> <span class='ectt-1000'>cleanup_module</span>
|
|
</code> functions, as in the first hello world example, but these days you can name those anything you
|
|
want by using the <code> <span class='ectt-1000'>module_init</span>
|
|
</code> and <code> <span class='ectt-1000'>module_exit</span>
|
|
</code> macros. These macros are defined in <a href='https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/include/linux/module.h'>include/linux/module.h</a>. The only requirement
|
|
is that your init and cleanup functions must be defined before calling the those
|
|
macros, otherwise you’ll get compilation errors. Here is an example of this
|
|
technique:
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb25'><a id='x1-13006r1'></a><span class='ecrm-0500'>1</span><span id='textcolor42'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-13008r2'></a><span class='ecrm-0500'>2</span><span id='textcolor43'><span class='ectt-0800'> * hello-2.c - Demonstrating the module_init() and module_exit() macros.</span></span>
|
|
<a id='x1-13010r3'></a><span class='ecrm-0500'>3</span><span id='textcolor44'><span class='ectt-0800'> * This is preferred over using init_module() and cleanup_module().</span></span>
|
|
<a id='x1-13012r4'></a><span class='ecrm-0500'>4</span><span id='textcolor45'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-13014r5'></a><span class='ecrm-0500'>5</span><span id='textcolor46'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor47'><span class='ectt-0800'><linux/init.h> /* Needed for the macros */</span></span>
|
|
<a id='x1-13016r6'></a><span class='ecrm-0500'>6</span><span id='textcolor48'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor49'><span class='ectt-0800'><linux/module.h> /* Needed by all modules */</span></span>
|
|
<a id='x1-13018r7'></a><span class='ecrm-0500'>7</span><span id='textcolor50'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor51'><span class='ectt-0800'><linux/printk.h> /* Needed for pr_info() */</span></span>
|
|
<a id='x1-13020r8'></a><span class='ecrm-0500'>8</span>
|
|
<a id='x1-13022r9'></a><span class='ecrm-0500'>9</span><span id='textcolor52'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor53'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __init hello_2_init(</span><span id='textcolor54'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-13024r10'></a><span class='ecrm-0500'>10</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-13026r11'></a><span class='ecrm-0500'>11</span><span class='ectt-0800'> pr_info(</span><span id='textcolor55'><span class='ectt-0800'>"Hello, world 2</span></span><span id='textcolor56'><span class='ectt-0800'>\n</span></span><span id='textcolor57'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-13028r12'></a><span class='ecrm-0500'>12</span><span class='ectt-0800'> </span><span id='textcolor58'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-13030r13'></a><span class='ecrm-0500'>13</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-13032r14'></a><span class='ecrm-0500'>14</span>
|
|
<a id='x1-13034r15'></a><span class='ecrm-0500'>15</span><span id='textcolor59'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor60'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> __exit hello_2_exit(</span><span id='textcolor61'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-13036r16'></a><span class='ecrm-0500'>16</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-13038r17'></a><span class='ecrm-0500'>17</span><span class='ectt-0800'> pr_info(</span><span id='textcolor62'><span class='ectt-0800'>"Goodbye, world 2</span></span><span id='textcolor63'><span class='ectt-0800'>\n</span></span><span id='textcolor64'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-13040r18'></a><span class='ecrm-0500'>18</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-13042r19'></a><span class='ecrm-0500'>19</span>
|
|
<a id='x1-13044r20'></a><span class='ecrm-0500'>20</span><span class='ectt-0800'>module_init(hello_2_init);</span>
|
|
<a id='x1-13046r21'></a><span class='ecrm-0500'>21</span><span class='ectt-0800'>module_exit(hello_2_exit);</span>
|
|
<a id='x1-13048r22'></a><span class='ecrm-0500'>22</span>
|
|
<a id='x1-13050r23'></a><span class='ecrm-0500'>23</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor65'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span></pre>
|
|
<!-- l. 455 --><p class='indent'> So now we have two real kernel modules under our belt. Adding another module
|
|
is as simple as this:
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb26'><a id='x1-13062r1'></a><span class='ecrm-0500'>1</span><span class='ectt-0800'>obj-m += hello-1.o</span>
|
|
<a id='x1-13064r2'></a><span class='ecrm-0500'>2</span><span class='ectt-0800'>obj-m += hello-2.o</span>
|
|
<a id='x1-13066r3'></a><span class='ecrm-0500'>3</span>
|
|
<a id='x1-13068r4'></a><span class='ecrm-0500'>4</span><span class='ectt-0800'>PWD := </span><span class='colorbox' id='colorbox66'><span class='ectt-0800'>$</span></span><span class='ectt-0800'>(CURDIR)</span>
|
|
<a id='x1-13070r5'></a><span class='ecrm-0500'>5</span>
|
|
<a id='x1-13072r6'></a><span class='ecrm-0500'>6</span><span class='ectt-0800'>all:</span>
|
|
<a id='x1-13074r7'></a><span class='ecrm-0500'>7</span><span class='ectt-0800'> make -C /lib/modules/</span><span class='colorbox' id='colorbox67'><span class='ectt-0800'>$</span></span><span class='ectt-0800'>(shell uname -r)/build M=</span><span class='colorbox' id='colorbox68'><span class='ectt-0800'>$</span></span><span class='ectt-0800'>(PWD) modules</span>
|
|
<a id='x1-13076r8'></a><span class='ecrm-0500'>8</span>
|
|
<a id='x1-13078r9'></a><span class='ecrm-0500'>9</span><span class='ectt-0800'>clean:</span>
|
|
<a id='x1-13080r10'></a><span class='ecrm-0500'>10</span><span class='ectt-0800'> make -C /lib/modules/</span><span class='colorbox' id='colorbox69'><span class='ectt-0800'>$</span></span><span class='ectt-0800'>(shell uname -r)/build M=</span><span class='colorbox' id='colorbox70'><span class='ectt-0800'>$</span></span><span class='ectt-0800'>(PWD) clean</span></pre>
|
|
<!-- l. 470 --><p class='indent'> Now have a look at <a href='https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/drivers/char/Makefile'>drivers/char/Makefile</a> for a real world example. As
|
|
you can see, some things got hardwired into the kernel (<span class='obeylines-h'><span class='verb'><span class='ectt-1000'>obj-y</span></span></span>) but where
|
|
have all those <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>obj-m</span></span></span> gone? Those familiar with shell scripts will easily be
|
|
able to spot them. For those who are not, the <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>obj-$(CONFIG_FOO)</span></span></span> entries
|
|
you see everywhere expand into <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>obj-y</span></span></span> or <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>obj-m</span></span></span>, depending on whether the
|
|
<span class='obeylines-h'><span class='verb'><span class='ectt-1000'>CONFIG_FOO</span></span></span> variable has been set to <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>y</span></span></span> or <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>m</span></span></span>. While we are at it, those were
|
|
exactly the kind of variables that you have set in the <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>.config</span></span></span> file in the
|
|
top-level directory of Linux kernel source tree, the last time when you said
|
|
<code> <span class='ectt-1000'>make menuconfig</span>
|
|
</code> or something like that.
|
|
</p><!-- l. 476 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='the-init-and-exit-macros'><span class='titlemark'>4.3 </span> <a id='x1-140004.3'></a>The __init and __exit Macros</h4>
|
|
<!-- l. 478 --><p class='noindent'>The <code> <span class='ectt-1000'>__init</span>
|
|
</code> macro causes the init function to be discarded and its memory freed once the init
|
|
function finishes for built-in drivers, but not loadable modules. If you think about
|
|
when the init function is invoked, this makes perfect sense.
|
|
</p><!-- l. 481 --><p class='indent'> There is also an <code> <span class='ectt-1000'>__initdata</span>
|
|
</code> which works similarly to <code> <span class='ectt-1000'>__init</span>
|
|
</code> but for init variables rather than functions.
|
|
</p><!-- l. 483 --><p class='indent'> The <code> <span class='ectt-1000'>__exit</span>
|
|
</code> macro causes the omission of the function when the module is built into the kernel, and
|
|
like <code> <span class='ectt-1000'>__init</span>
|
|
</code>, has no effect for loadable modules. Again, if you consider when the cleanup function
|
|
runs, this makes complete sense; built-in drivers do not need a cleanup function,
|
|
|
|
|
|
|
|
while loadable modules do.
|
|
</p><!-- l. 486 --><p class='indent'> These macros are defined in <a href='https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/include/linux/init.h'>include/linux/init.h</a> and serve to free up kernel
|
|
memory. When you boot your kernel and see something like Freeing unused kernel
|
|
memory: 236k freed, this is precisely what the kernel is freeing.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb27'><a id='x1-14007r1'></a><span class='ecrm-0500'>1</span><span id='textcolor71'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-14009r2'></a><span class='ecrm-0500'>2</span><span id='textcolor72'><span class='ectt-0800'> * hello-3.c - Illustrating the __init, __initdata and __exit macros.</span></span>
|
|
<a id='x1-14011r3'></a><span class='ecrm-0500'>3</span><span id='textcolor73'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-14013r4'></a><span class='ecrm-0500'>4</span><span id='textcolor74'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor75'><span class='ectt-0800'><linux/init.h> /* Needed for the macros */</span></span>
|
|
<a id='x1-14015r5'></a><span class='ecrm-0500'>5</span><span id='textcolor76'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor77'><span class='ectt-0800'><linux/module.h> /* Needed by all modules */</span></span>
|
|
<a id='x1-14017r6'></a><span class='ecrm-0500'>6</span><span id='textcolor78'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor79'><span class='ectt-0800'><linux/printk.h> /* Needed for pr_info() */</span></span>
|
|
<a id='x1-14019r7'></a><span class='ecrm-0500'>7</span>
|
|
<a id='x1-14021r8'></a><span class='ecrm-0500'>8</span><span id='textcolor80'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor81'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> hello3_data __initdata = 3;</span>
|
|
<a id='x1-14023r9'></a><span class='ecrm-0500'>9</span>
|
|
<a id='x1-14025r10'></a><span class='ecrm-0500'>10</span><span id='textcolor82'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor83'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __init hello_3_init(</span><span id='textcolor84'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-14027r11'></a><span class='ecrm-0500'>11</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-14029r12'></a><span class='ecrm-0500'>12</span><span class='ectt-0800'> pr_info(</span><span id='textcolor85'><span class='ectt-0800'>"Hello, world %d</span></span><span id='textcolor86'><span class='ectt-0800'>\n</span></span><span id='textcolor87'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, hello3_data);</span>
|
|
<a id='x1-14031r13'></a><span class='ecrm-0500'>13</span><span class='ectt-0800'> </span><span id='textcolor88'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-14033r14'></a><span class='ecrm-0500'>14</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-14035r15'></a><span class='ecrm-0500'>15</span>
|
|
<a id='x1-14037r16'></a><span class='ecrm-0500'>16</span><span id='textcolor89'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor90'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> __exit hello_3_exit(</span><span id='textcolor91'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-14039r17'></a><span class='ecrm-0500'>17</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-14041r18'></a><span class='ecrm-0500'>18</span><span class='ectt-0800'> pr_info(</span><span id='textcolor92'><span class='ectt-0800'>"Goodbye, world 3</span></span><span id='textcolor93'><span class='ectt-0800'>\n</span></span><span id='textcolor94'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-14043r19'></a><span class='ecrm-0500'>19</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-14045r20'></a><span class='ecrm-0500'>20</span>
|
|
<a id='x1-14047r21'></a><span class='ecrm-0500'>21</span><span class='ectt-0800'>module_init(hello_3_init);</span>
|
|
<a id='x1-14049r22'></a><span class='ecrm-0500'>22</span><span class='ectt-0800'>module_exit(hello_3_exit);</span>
|
|
<a id='x1-14051r23'></a><span class='ecrm-0500'>23</span>
|
|
<a id='x1-14053r24'></a><span class='ecrm-0500'>24</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor95'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span></pre>
|
|
<!-- l. 491 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='licensing-and-module-documentation'><span class='titlemark'>4.4 </span> <a id='x1-150004.4'></a>Licensing and Module Documentation</h4>
|
|
<!-- l. 493 --><p class='noindent'>Honestly, who loads or even cares about proprietary modules? If you do then you
|
|
might have seen something like this:
|
|
|
|
|
|
|
|
</p>
|
|
<pre class='verbatim' id='verbatim-5'>
|
|
$ sudo insmod xxxxxx.ko
|
|
loading out-of-tree module taints kernel.
|
|
module license 'unspecified' taints kernel.
|
|
</pre>
|
|
<!-- l. 499 --><p class='nopar'>
|
|
</p><!-- l. 501 --><p class='indent'> You can use a few macros to indicate the license for your module. Some examples
|
|
are "GPL", "GPL v2", "GPL and additional rights", "Dual BSD/GPL", "Dual
|
|
MIT/GPL", "Dual MPL/GPL" and "Proprietary". They are defined within
|
|
<a href='https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/include/linux/module.h'>include/linux/module.h</a>.
|
|
</p><!-- l. 505 --><p class='indent'> To reference what license you’re using a macro is available called
|
|
<code> <span class='ectt-1000'>MODULE_LICENSE</span>
|
|
</code>. This and a few other macros describing the module are illustrated in the below
|
|
example.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb28'><a id='x1-15003r1'></a><span class='ecrm-0500'>1</span><span id='textcolor96'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-15005r2'></a><span class='ecrm-0500'>2</span><span id='textcolor97'><span class='ectt-0800'> * hello-4.c - Demonstrates module documentation.</span></span>
|
|
<a id='x1-15007r3'></a><span class='ecrm-0500'>3</span><span id='textcolor98'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-15009r4'></a><span class='ecrm-0500'>4</span><span id='textcolor99'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor100'><span class='ectt-0800'><linux/init.h> /* Needed for the macros */</span></span>
|
|
<a id='x1-15011r5'></a><span class='ecrm-0500'>5</span><span id='textcolor101'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor102'><span class='ectt-0800'><linux/module.h> /* Needed by all modules */</span></span>
|
|
<a id='x1-15013r6'></a><span class='ecrm-0500'>6</span><span id='textcolor103'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor104'><span class='ectt-0800'><linux/printk.h> /* Needed for pr_info() */</span></span>
|
|
<a id='x1-15015r7'></a><span class='ecrm-0500'>7</span>
|
|
<a id='x1-15017r8'></a><span class='ecrm-0500'>8</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor105'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-15019r9'></a><span class='ecrm-0500'>9</span><span class='ectt-0800'>MODULE_AUTHOR(</span><span id='textcolor106'><span class='ectt-0800'>"LKMPG"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-15021r10'></a><span class='ecrm-0500'>10</span><span class='ectt-0800'>MODULE_DESCRIPTION(</span><span id='textcolor107'><span class='ectt-0800'>"A sample driver"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-15023r11'></a><span class='ecrm-0500'>11</span>
|
|
<a id='x1-15025r12'></a><span class='ecrm-0500'>12</span><span id='textcolor108'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor109'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __init init_hello_4(</span><span id='textcolor110'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-15027r13'></a><span class='ecrm-0500'>13</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-15029r14'></a><span class='ecrm-0500'>14</span><span class='ectt-0800'> pr_info(</span><span id='textcolor111'><span class='ectt-0800'>"Hello, world 4</span></span><span id='textcolor112'><span class='ectt-0800'>\n</span></span><span id='textcolor113'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-15031r15'></a><span class='ecrm-0500'>15</span><span class='ectt-0800'> </span><span id='textcolor114'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-15033r16'></a><span class='ecrm-0500'>16</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-15035r17'></a><span class='ecrm-0500'>17</span>
|
|
<a id='x1-15037r18'></a><span class='ecrm-0500'>18</span><span id='textcolor115'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor116'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> __exit cleanup_hello_4(</span><span id='textcolor117'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-15039r19'></a><span class='ecrm-0500'>19</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-15041r20'></a><span class='ecrm-0500'>20</span><span class='ectt-0800'> pr_info(</span><span id='textcolor118'><span class='ectt-0800'>"Goodbye, world 4</span></span><span id='textcolor119'><span class='ectt-0800'>\n</span></span><span id='textcolor120'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-15043r21'></a><span class='ecrm-0500'>21</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-15045r22'></a><span class='ecrm-0500'>22</span>
|
|
<a id='x1-15047r23'></a><span class='ecrm-0500'>23</span><span class='ectt-0800'>module_init(init_hello_4);</span>
|
|
<a id='x1-15049r24'></a><span class='ecrm-0500'>24</span><span class='ectt-0800'>module_exit(cleanup_hello_4);</span></pre>
|
|
<!-- l. 510 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='passing-command-line-arguments-to-a-module'><span class='titlemark'>4.5 </span> <a id='x1-160004.5'></a>Passing Command Line Arguments to a Module</h4>
|
|
<!-- l. 512 --><p class='noindent'>Modules can take command line arguments, but not with the argc/argv you might be
|
|
used to.
|
|
</p><!-- l. 514 --><p class='indent'> To allow arguments to be passed to your module, declare the variables that will
|
|
take the values of the command line arguments as global and then use the
|
|
<code> <span class='ectt-1000'>module_param()</span>
|
|
</code> macro, (defined in <a href='https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/include/linux/moduleparam.h'>include/linux/moduleparam.h</a>) to set the mechanism up. At runtime,
|
|
<code> <span class='ectt-1000'>insmod</span>
|
|
</code> will fill the variables with any command line arguments that are given, like
|
|
<code> <span class='ectt-1000'>insmod mymodule.ko myvariable=5</span>
|
|
</code>. The variable declarations and macros should be placed at the beginning of the
|
|
module for clarity. The example code should clear up my admittedly lousy
|
|
explanation.
|
|
</p><!-- l. 519 --><p class='indent'> The <code> <span class='ectt-1000'>module_param()</span>
|
|
</code> macro takes 3 arguments: the name of the variable, its type and
|
|
permissions for the corresponding file in sysfs. Integer types can be signed
|
|
as usual or unsigned. If you’d like to use arrays of integers or strings see
|
|
<code> <span class='ectt-1000'>module_param_array()</span>
|
|
</code> and <code> <span class='ectt-1000'>module_param_string()</span>
|
|
</code>.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
|
|
|
|
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb29'><a id='x1-16010r1'></a><span class='ecrm-0500'>1</span><span id='textcolor121'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> myint = 3;</span>
|
|
<a id='x1-16012r2'></a><span class='ecrm-0500'>2</span><span class='ectt-0800'>module_param(myint, </span><span id='textcolor122'><span class='ectt-0800'>int</span></span><span class='ectt-0800'>, 0);</span></pre>
|
|
<!-- l. 527 --><p class='indent'> Arrays are supported too, but things are a bit different now than they were in the
|
|
olden days. To keep track of the number of parameters you need to pass a pointer to
|
|
a count variable as third parameter. At your option, you could also ignore the count and
|
|
pass <code> <span class='ectt-1000'>NULL</span>
|
|
</code> instead. We show both possibilities here:
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb30'><a id='x1-16021r1'></a><span class='ecrm-0500'>1</span><span id='textcolor123'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> myintarray[2];</span>
|
|
<a id='x1-16023r2'></a><span class='ecrm-0500'>2</span><span class='ectt-0800'>module_param_array(myintarray, </span><span id='textcolor124'><span class='ectt-0800'>int</span></span><span class='ectt-0800'>, NULL, 0); </span><span id='textcolor125'><span class='ectt-0800'>/* not interested in count */</span></span>
|
|
<a id='x1-16025r3'></a><span class='ecrm-0500'>3</span>
|
|
<a id='x1-16027r4'></a><span class='ecrm-0500'>4</span><span id='textcolor126'><span class='ectt-0800'>short</span></span><span class='ectt-0800'> myshortarray[4];</span>
|
|
<a id='x1-16029r5'></a><span class='ecrm-0500'>5</span><span id='textcolor127'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> count;</span>
|
|
<a id='x1-16031r6'></a><span class='ecrm-0500'>6</span><span class='ectt-0800'>module_param_array(myshortarray, </span><span id='textcolor128'><span class='ectt-0800'>short</span></span><span class='ectt-0800'>, &count, 0); </span><span id='textcolor129'><span class='ectt-0800'>/* put count into "count" variable */</span></span></pre>
|
|
<!-- l. 540 --><p class='indent'> A good use for this is to have the module variable’s default values set, like a port
|
|
or IO address. If the variables contain the default values, then perform autodetection
|
|
(explained elsewhere). Otherwise, keep the current value. This will be made clear
|
|
later on.
|
|
</p><!-- l. 544 --><p class='indent'> Lastly, there is a macro function, <code> <span class='ectt-1000'>MODULE_PARM_DESC()</span>
|
|
</code>, that is used to document arguments that the module can take. It takes two
|
|
parameters: a variable name and a free form string describing that variable.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb31'><a id='x1-16034r1'></a><span class='ecrm-0500'>1</span><span id='textcolor130'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-16036r2'></a><span class='ecrm-0500'>2</span><span id='textcolor131'><span class='ectt-0800'> * hello-5.c - Demonstrates command line argument passing to a module.</span></span>
|
|
<a id='x1-16038r3'></a><span class='ecrm-0500'>3</span><span id='textcolor132'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-16040r4'></a><span class='ecrm-0500'>4</span><span id='textcolor133'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor134'><span class='ectt-0800'><linux/init.h></span></span>
|
|
<a id='x1-16042r5'></a><span class='ecrm-0500'>5</span><span id='textcolor135'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor136'><span class='ectt-0800'><linux/kernel.h> /* for ARRAY_SIZE() */</span></span>
|
|
<a id='x1-16044r6'></a><span class='ecrm-0500'>6</span><span id='textcolor137'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor138'><span class='ectt-0800'><linux/module.h></span></span>
|
|
<a id='x1-16046r7'></a><span class='ecrm-0500'>7</span><span id='textcolor139'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor140'><span class='ectt-0800'><linux/moduleparam.h></span></span>
|
|
<a id='x1-16048r8'></a><span class='ecrm-0500'>8</span><span id='textcolor141'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor142'><span class='ectt-0800'><linux/printk.h></span></span>
|
|
<a id='x1-16050r9'></a><span class='ecrm-0500'>9</span><span id='textcolor143'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor144'><span class='ectt-0800'><linux/stat.h></span></span>
|
|
<a id='x1-16052r10'></a><span class='ecrm-0500'>10</span>
|
|
<a id='x1-16054r11'></a><span class='ecrm-0500'>11</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor145'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-16056r12'></a><span class='ecrm-0500'>12</span>
|
|
<a id='x1-16058r13'></a><span class='ecrm-0500'>13</span><span id='textcolor146'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor147'><span class='ectt-0800'>short</span></span><span class='ectt-0800'> </span><span id='textcolor148'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> myshort = 1;</span>
|
|
<a id='x1-16060r14'></a><span class='ecrm-0500'>14</span><span id='textcolor149'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor150'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> myint = 420;</span>
|
|
<a id='x1-16062r15'></a><span class='ecrm-0500'>15</span><span id='textcolor151'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor152'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> </span><span id='textcolor153'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> mylong = 9999;</span>
|
|
<a id='x1-16064r16'></a><span class='ecrm-0500'>16</span><span id='textcolor154'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor155'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *mystring = </span><span id='textcolor156'><span class='ectt-0800'>"blah"</span></span><span class='ectt-0800'>;</span>
|
|
<a id='x1-16066r17'></a><span class='ecrm-0500'>17</span><span id='textcolor157'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor158'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> myintarray[2] = { 420, 420 };</span>
|
|
<a id='x1-16068r18'></a><span class='ecrm-0500'>18</span><span id='textcolor159'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor160'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> arr_argc = 0;</span>
|
|
<a id='x1-16070r19'></a><span class='ecrm-0500'>19</span>
|
|
<a id='x1-16072r20'></a><span class='ecrm-0500'>20</span><span id='textcolor161'><span class='ectt-0800'>/* module_param(foo, int, 0000)</span></span>
|
|
<a id='x1-16074r21'></a><span class='ecrm-0500'>21</span><span id='textcolor162'><span class='ectt-0800'> * The first param is the parameter</span><span class='tctt-0800'>'</span><span class='ectt-0800'>s name.</span></span>
|
|
<a id='x1-16076r22'></a><span class='ecrm-0500'>22</span><span id='textcolor163'><span class='ectt-0800'> * The second param is its data type.</span></span>
|
|
<a id='x1-16078r23'></a><span class='ecrm-0500'>23</span><span id='textcolor164'><span class='ectt-0800'> * The final argument is the permissions bits,</span></span>
|
|
<a id='x1-16080r24'></a><span class='ecrm-0500'>24</span><span id='textcolor165'><span class='ectt-0800'> * for exposing parameters in sysfs (if non-zero) at a later stage.</span></span>
|
|
<a id='x1-16082r25'></a><span class='ecrm-0500'>25</span><span id='textcolor166'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-16084r26'></a><span class='ecrm-0500'>26</span><span class='ectt-0800'>module_param(myshort, </span><span id='textcolor167'><span class='ectt-0800'>short</span></span><span class='ectt-0800'>, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);</span>
|
|
<a id='x1-16086r27'></a><span class='ecrm-0500'>27</span><span class='ectt-0800'>MODULE_PARM_DESC(myshort, </span><span id='textcolor168'><span class='ectt-0800'>"A short integer"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-16088r28'></a><span class='ecrm-0500'>28</span><span class='ectt-0800'>module_param(myint, </span><span id='textcolor169'><span class='ectt-0800'>int</span></span><span class='ectt-0800'>, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);</span>
|
|
<a id='x1-16090r29'></a><span class='ecrm-0500'>29</span><span class='ectt-0800'>MODULE_PARM_DESC(myint, </span><span id='textcolor170'><span class='ectt-0800'>"An integer"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-16092r30'></a><span class='ecrm-0500'>30</span><span class='ectt-0800'>module_param(mylong, </span><span id='textcolor171'><span class='ectt-0800'>long</span></span><span class='ectt-0800'>, S_IRUSR);</span>
|
|
<a id='x1-16094r31'></a><span class='ecrm-0500'>31</span><span class='ectt-0800'>MODULE_PARM_DESC(mylong, </span><span id='textcolor172'><span class='ectt-0800'>"A long integer"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-16096r32'></a><span class='ecrm-0500'>32</span><span class='ectt-0800'>module_param(mystring, charp, 0000);</span>
|
|
<a id='x1-16098r33'></a><span class='ecrm-0500'>33</span><span class='ectt-0800'>MODULE_PARM_DESC(mystring, </span><span id='textcolor173'><span class='ectt-0800'>"A character string"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-16100r34'></a><span class='ecrm-0500'>34</span>
|
|
<a id='x1-16102r35'></a><span class='ecrm-0500'>35</span><span id='textcolor174'><span class='ectt-0800'>/* module_param_array(name, type, num, perm);</span></span>
|
|
<a id='x1-16104r36'></a><span class='ecrm-0500'>36</span><span id='textcolor175'><span class='ectt-0800'> * The first param is the parameter</span><span class='tctt-0800'>'</span><span class='ectt-0800'>s (in this case the array</span><span class='tctt-0800'>'</span><span class='ectt-0800'>s) name.</span></span>
|
|
<a id='x1-16106r37'></a><span class='ecrm-0500'>37</span><span id='textcolor176'><span class='ectt-0800'> * The second param is the data type of the elements of the array.</span></span>
|
|
<a id='x1-16108r38'></a><span class='ecrm-0500'>38</span><span id='textcolor177'><span class='ectt-0800'> * The third argument is a pointer to the variable that will store the number</span></span>
|
|
<a id='x1-16110r39'></a><span class='ecrm-0500'>39</span><span id='textcolor178'><span class='ectt-0800'> * of elements of the array initialized by the user at module loading time.</span></span>
|
|
<a id='x1-16112r40'></a><span class='ecrm-0500'>40</span><span id='textcolor179'><span class='ectt-0800'> * The fourth argument is the permission bits.</span></span>
|
|
<a id='x1-16114r41'></a><span class='ecrm-0500'>41</span><span id='textcolor180'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-16116r42'></a><span class='ecrm-0500'>42</span><span class='ectt-0800'>module_param_array(myintarray, </span><span id='textcolor181'><span class='ectt-0800'>int</span></span><span class='ectt-0800'>, &arr_argc, 0000);</span>
|
|
<a id='x1-16118r43'></a><span class='ecrm-0500'>43</span><span class='ectt-0800'>MODULE_PARM_DESC(myintarray, </span><span id='textcolor182'><span class='ectt-0800'>"An array of integers"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-16120r44'></a><span class='ecrm-0500'>44</span>
|
|
<a id='x1-16122r45'></a><span class='ecrm-0500'>45</span><span id='textcolor183'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor184'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __init hello_5_init(</span><span id='textcolor185'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-16124r46'></a><span class='ecrm-0500'>46</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-16126r47'></a><span class='ecrm-0500'>47</span><span class='ectt-0800'> </span><span id='textcolor186'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> i;</span>
|
|
<a id='x1-16128r48'></a><span class='ecrm-0500'>48</span>
|
|
<a id='x1-16130r49'></a><span class='ecrm-0500'>49</span><span class='ectt-0800'> pr_info(</span><span id='textcolor187'><span class='ectt-0800'>"Hello, world 5</span></span><span id='textcolor188'><span class='ectt-0800'>\n</span></span><span id='textcolor189'><span class='ectt-0800'>=============</span></span><span id='textcolor190'><span class='ectt-0800'>\n</span></span><span id='textcolor191'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-16132r50'></a><span class='ecrm-0500'>50</span><span class='ectt-0800'> pr_info(</span><span id='textcolor192'><span class='ectt-0800'>"myshort is a short integer: %hd</span></span><span id='textcolor193'><span class='ectt-0800'>\n</span></span><span id='textcolor194'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, myshort);</span>
|
|
<a id='x1-16134r51'></a><span class='ecrm-0500'>51</span><span class='ectt-0800'> pr_info(</span><span id='textcolor195'><span class='ectt-0800'>"myint is an integer: %d</span></span><span id='textcolor196'><span class='ectt-0800'>\n</span></span><span id='textcolor197'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, myint);</span>
|
|
<a id='x1-16136r52'></a><span class='ecrm-0500'>52</span><span class='ectt-0800'> pr_info(</span><span id='textcolor198'><span class='ectt-0800'>"mylong is a long integer: %ld</span></span><span id='textcolor199'><span class='ectt-0800'>\n</span></span><span id='textcolor200'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, mylong);</span>
|
|
<a id='x1-16138r53'></a><span class='ecrm-0500'>53</span><span class='ectt-0800'> pr_info(</span><span id='textcolor201'><span class='ectt-0800'>"mystring is a string: %s</span></span><span id='textcolor202'><span class='ectt-0800'>\n</span></span><span id='textcolor203'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, mystring);</span>
|
|
<a id='x1-16140r54'></a><span class='ecrm-0500'>54</span>
|
|
<a id='x1-16142r55'></a><span class='ecrm-0500'>55</span><span class='ectt-0800'> </span><span id='textcolor204'><span class='ectt-0800'>for</span></span><span class='ectt-0800'> (i = 0; i < ARRAY_SIZE(myintarray); i++)</span>
|
|
<a id='x1-16144r56'></a><span class='ecrm-0500'>56</span><span class='ectt-0800'> pr_info(</span><span id='textcolor205'><span class='ectt-0800'>"myintarray[%d] = %d</span></span><span id='textcolor206'><span class='ectt-0800'>\n</span></span><span id='textcolor207'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, i, myintarray[i]);</span>
|
|
<a id='x1-16146r57'></a><span class='ecrm-0500'>57</span>
|
|
<a id='x1-16148r58'></a><span class='ecrm-0500'>58</span><span class='ectt-0800'> pr_info(</span><span id='textcolor208'><span class='ectt-0800'>"got %d arguments for myintarray.</span></span><span id='textcolor209'><span class='ectt-0800'>\n</span></span><span id='textcolor210'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, arr_argc);</span>
|
|
<a id='x1-16150r59'></a><span class='ecrm-0500'>59</span><span class='ectt-0800'> </span><span id='textcolor211'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-16152r60'></a><span class='ecrm-0500'>60</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-16154r61'></a><span class='ecrm-0500'>61</span>
|
|
<a id='x1-16156r62'></a><span class='ecrm-0500'>62</span><span id='textcolor212'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor213'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> __exit hello_5_exit(</span><span id='textcolor214'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-16158r63'></a><span class='ecrm-0500'>63</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-16160r64'></a><span class='ecrm-0500'>64</span><span class='ectt-0800'> pr_info(</span><span id='textcolor215'><span class='ectt-0800'>"Goodbye, world 5</span></span><span id='textcolor216'><span class='ectt-0800'>\n</span></span><span id='textcolor217'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-16162r65'></a><span class='ecrm-0500'>65</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-16164r66'></a><span class='ecrm-0500'>66</span>
|
|
<a id='x1-16166r67'></a><span class='ecrm-0500'>67</span><span class='ectt-0800'>module_init(hello_5_init);</span>
|
|
<a id='x1-16168r68'></a><span class='ecrm-0500'>68</span><span class='ectt-0800'>module_exit(hello_5_exit);</span></pre>
|
|
<!-- l. 549 --><p class='indent'> It is recommended to experiment with the following code:
|
|
|
|
|
|
|
|
</p>
|
|
<pre class='verbatim' id='verbatim-6'>
|
|
$ sudo insmod hello-5.ko mystring="bebop" myintarray=-1
|
|
$ sudo dmesg -t | tail -7
|
|
myshort is a short integer: 1
|
|
myint is an integer: 420
|
|
mylong is a long integer: 9999
|
|
mystring is a string: bebop
|
|
myintarray[0] = -1
|
|
myintarray[1] = 420
|
|
got 1 arguments for myintarray.
|
|
|
|
$ sudo rmmod hello-5
|
|
$ sudo dmesg -t | tail -1
|
|
Goodbye, world 5
|
|
|
|
$ sudo insmod hello-5.ko mystring="supercalifragilisticexpialidocious" myintarray=-1,-1
|
|
$ sudo dmesg -t | tail -7
|
|
myshort is a short integer: 1
|
|
myint is an integer: 420
|
|
mylong is a long integer: 9999
|
|
mystring is a string: supercalifragilisticexpialidocious
|
|
myintarray[0] = -1
|
|
myintarray[1] = -1
|
|
got 2 arguments for myintarray.
|
|
|
|
$ sudo rmmod hello-5
|
|
$ sudo dmesg -t | tail -1
|
|
Goodbye, world 5
|
|
|
|
$ sudo insmod hello-5.ko mylong=hello
|
|
insmod: ERROR: could not insert module hello-5.ko: Invalid parameters
|
|
</pre>
|
|
<!-- l. 581 --><p class='nopar'>
|
|
</p><!-- l. 583 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='modules-spanning-multiple-files'><span class='titlemark'>4.6 </span> <a id='x1-170004.6'></a>Modules Spanning Multiple Files</h4>
|
|
<!-- l. 585 --><p class='noindent'>Sometimes it makes sense to divide a kernel module between several source
|
|
files.
|
|
</p><!-- l. 587 --><p class='indent'> Here is an example of such a kernel module.
|
|
</p>
|
|
|
|
|
|
|
|
<pre class='fancyvrb' id='fancyvrb32'><a id='x1-17002r1'></a><span class='ecrm-0500'>1</span><span id='textcolor218'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-17004r2'></a><span class='ecrm-0500'>2</span><span id='textcolor219'><span class='ectt-0800'> * start.c - Illustration of multi filed modules</span></span>
|
|
<a id='x1-17006r3'></a><span class='ecrm-0500'>3</span><span id='textcolor220'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-17008r4'></a><span class='ecrm-0500'>4</span>
|
|
<a id='x1-17010r5'></a><span class='ecrm-0500'>5</span><span id='textcolor221'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor222'><span class='ectt-0800'><linux/kernel.h> /* We are doing kernel work */</span></span>
|
|
<a id='x1-17012r6'></a><span class='ecrm-0500'>6</span><span id='textcolor223'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor224'><span class='ectt-0800'><linux/module.h> /* Specifically, a module */</span></span>
|
|
<a id='x1-17014r7'></a><span class='ecrm-0500'>7</span>
|
|
<a id='x1-17016r8'></a><span class='ecrm-0500'>8</span><span id='textcolor225'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> init_module(</span><span id='textcolor226'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-17018r9'></a><span class='ecrm-0500'>9</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-17020r10'></a><span class='ecrm-0500'>10</span><span class='ectt-0800'> pr_info(</span><span id='textcolor227'><span class='ectt-0800'>"Hello, world - this is the kernel speaking</span></span><span id='textcolor228'><span class='ectt-0800'>\n</span></span><span id='textcolor229'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-17022r11'></a><span class='ecrm-0500'>11</span><span class='ectt-0800'> </span><span id='textcolor230'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-17024r12'></a><span class='ecrm-0500'>12</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-17026r13'></a><span class='ecrm-0500'>13</span>
|
|
<a id='x1-17028r14'></a><span class='ecrm-0500'>14</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor231'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span></pre>
|
|
<!-- l. 590 --><p class='indent'> The next file:
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb33'><a id='x1-17030r1'></a><span class='ecrm-0500'>1</span><span id='textcolor232'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-17032r2'></a><span class='ecrm-0500'>2</span><span id='textcolor233'><span class='ectt-0800'> * stop.c - Illustration of multi filed modules</span></span>
|
|
<a id='x1-17034r3'></a><span class='ecrm-0500'>3</span><span id='textcolor234'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-17036r4'></a><span class='ecrm-0500'>4</span>
|
|
<a id='x1-17038r5'></a><span class='ecrm-0500'>5</span><span id='textcolor235'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor236'><span class='ectt-0800'><linux/kernel.h> /* We are doing kernel work */</span></span>
|
|
<a id='x1-17040r6'></a><span class='ecrm-0500'>6</span><span id='textcolor237'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor238'><span class='ectt-0800'><linux/module.h> /* Specifically, a module */</span></span>
|
|
<a id='x1-17042r7'></a><span class='ecrm-0500'>7</span>
|
|
<a id='x1-17044r8'></a><span class='ecrm-0500'>8</span><span id='textcolor239'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> cleanup_module(</span><span id='textcolor240'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-17046r9'></a><span class='ecrm-0500'>9</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-17048r10'></a><span class='ecrm-0500'>10</span><span class='ectt-0800'> pr_info(</span><span id='textcolor241'><span class='ectt-0800'>"Short is the life of a kernel module</span></span><span id='textcolor242'><span class='ectt-0800'>\n</span></span><span id='textcolor243'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-17050r11'></a><span class='ecrm-0500'>11</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-17052r12'></a><span class='ecrm-0500'>12</span>
|
|
<a id='x1-17054r13'></a><span class='ecrm-0500'>13</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor244'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span></pre>
|
|
<!-- l. 593 --><p class='indent'> And finally, the makefile:
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb34'><a id='x1-17071r1'></a><span class='ecrm-0500'>1</span><span class='ectt-0800'>obj-m += hello-1.o</span>
|
|
<a id='x1-17073r2'></a><span class='ecrm-0500'>2</span><span class='ectt-0800'>obj-m += hello-2.o</span>
|
|
<a id='x1-17075r3'></a><span class='ecrm-0500'>3</span><span class='ectt-0800'>obj-m += hello-3.o</span>
|
|
<a id='x1-17077r4'></a><span class='ecrm-0500'>4</span><span class='ectt-0800'>obj-m += hello-4.o</span>
|
|
<a id='x1-17079r5'></a><span class='ecrm-0500'>5</span><span class='ectt-0800'>obj-m += hello-5.o</span>
|
|
<a id='x1-17081r6'></a><span class='ecrm-0500'>6</span><span class='ectt-0800'>obj-m += startstop.o</span>
|
|
<a id='x1-17083r7'></a><span class='ecrm-0500'>7</span><span class='ectt-0800'>startstop-objs := start.o stop.o</span>
|
|
<a id='x1-17085r8'></a><span class='ecrm-0500'>8</span>
|
|
<a id='x1-17087r9'></a><span class='ecrm-0500'>9</span><span class='ectt-0800'>PWD := </span><span class='colorbox' id='colorbox245'><span class='ectt-0800'>$</span></span><span class='ectt-0800'>(CURDIR)</span>
|
|
<a id='x1-17089r10'></a><span class='ecrm-0500'>10</span>
|
|
<a id='x1-17091r11'></a><span class='ecrm-0500'>11</span><span class='ectt-0800'>all:</span>
|
|
<a id='x1-17093r12'></a><span class='ecrm-0500'>12</span><span class='ectt-0800'> make -C /lib/modules/</span><span class='colorbox' id='colorbox246'><span class='ectt-0800'>$</span></span><span class='ectt-0800'>(shell uname -r)/build M=</span><span class='colorbox' id='colorbox247'><span class='ectt-0800'>$</span></span><span class='ectt-0800'>(PWD) modules</span>
|
|
<a id='x1-17095r13'></a><span class='ecrm-0500'>13</span>
|
|
<a id='x1-17097r14'></a><span class='ecrm-0500'>14</span><span class='ectt-0800'>clean:</span>
|
|
<a id='x1-17099r15'></a><span class='ecrm-0500'>15</span><span class='ectt-0800'> make -C /lib/modules/</span><span class='colorbox' id='colorbox248'><span class='ectt-0800'>$</span></span><span class='ectt-0800'>(shell uname -r)/build M=</span><span class='colorbox' id='colorbox249'><span class='ectt-0800'>$</span></span><span class='ectt-0800'>(PWD) clean</span></pre>
|
|
<!-- l. 613 --><p class='indent'> This is the complete makefile for all the examples we have seen so far. The first
|
|
five lines are nothing special, but for the last example we will need two lines.
|
|
First we invent an object name for our combined module, second we tell
|
|
<code> <span class='ectt-1000'>make</span>
|
|
</code> what object files are part of that module.
|
|
</p><!-- l. 617 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='building-modules-for-a-precompiled-kernel'><span class='titlemark'>4.7 </span> <a id='x1-180004.7'></a>Building modules for a precompiled kernel</h4>
|
|
<!-- l. 619 --><p class='noindent'>Obviously, we strongly suggest you to recompile your kernel, so that you can enable
|
|
a number of useful debugging features, such as forced module unloading
|
|
(<code> <span class='ectt-1000'>MODULE_FORCE_UNLOAD</span>
|
|
</code>): when this option is enabled, you can force the kernel to unload a module even when it believes
|
|
it is unsafe, via a <code> <span class='ectt-1000'>sudo rmmod -f module</span>
|
|
</code> command. This option can save you a lot of time and a number of reboots during
|
|
the development of a module. If you do not want to recompile your kernel then you
|
|
should consider running the examples within a test distribution on a virtual machine.
|
|
If you mess anything up then you can easily reboot or restore the virtual machine
|
|
(VM).
|
|
</p><!-- l. 624 --><p class='indent'> There are a number of cases in which you may want to load your module into a
|
|
precompiled running kernel, such as the ones shipped with common Linux
|
|
distributions, or a kernel you have compiled in the past. In certain circumstances you
|
|
could require to compile and insert a module into a running kernel which you are not
|
|
allowed to recompile, or on a machine that you prefer not to reboot. If you
|
|
can’t think of a case that will force you to use modules for a precompiled
|
|
kernel you might want to skip this and treat the rest of this chapter as a big
|
|
footnote.
|
|
</p><!-- l. 628 --><p class='indent'> Now, if you just install a kernel source tree, use it to compile your kernel module
|
|
and you try to insert your module into the kernel, in most cases you would obtain an
|
|
error as follows:
|
|
|
|
|
|
|
|
</p>
|
|
<pre class='verbatim' id='verbatim-7'>
|
|
insmod: ERROR: could not insert module poet.ko: Invalid module format
|
|
</pre>
|
|
<!-- l. 632 --><p class='nopar'>
|
|
</p><!-- l. 634 --><p class='indent'> Less cryptic information is logged to the systemd journal:
|
|
|
|
|
|
|
|
</p>
|
|
<pre class='verbatim' id='verbatim-8'>
|
|
kernel: poet: disagrees about version of symbol module_layout
|
|
</pre>
|
|
<!-- l. 638 --><p class='nopar'>
|
|
</p><!-- l. 640 --><p class='indent'> In other words, your kernel refuses to accept your module because version strings
|
|
(more precisely, <span class='ecti-1000'>version magic</span>, see <a href='https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/include/linux/vermagic.h'>include/linux/vermagic.h</a>) do not match. Incidentally,
|
|
version magic strings are stored in the module object in the form of a static string, starting
|
|
with <code> <span class='ectt-1000'>vermagic:</span>
|
|
</code>. Version data are inserted in your module when it is linked against the <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>kernel/module.o</span></span></span>
|
|
file. To inspect version magics and other strings stored in a given module, issue the
|
|
command <code> <span class='ectt-1000'>modinfo module.ko</span>
|
|
</code>:
|
|
|
|
|
|
|
|
</p>
|
|
<pre class='verbatim' id='verbatim-9'>
|
|
$ modinfo hello-4.ko
|
|
description: A sample driver
|
|
author: LKMPG
|
|
license: GPL
|
|
srcversion: B2AA7FBFCC2C39AED665382
|
|
depends:
|
|
retpoline: Y
|
|
name: hello_4
|
|
vermagic: 5.4.0-70-generic SMP mod_unload modversions
|
|
</pre>
|
|
<!-- l. 655 --><p class='nopar'>
|
|
</p><!-- l. 657 --><p class='indent'> To overcome this problem we could resort to the <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>--force-vermagic</span></span></span> option,
|
|
but this solution is potentially unsafe, and unquestionably unacceptable
|
|
in production modules. Consequently, we want to compile our module in
|
|
an environment which was identical to the one in which our precompiled
|
|
kernel was built. How to do this, is the subject of the remainder of this
|
|
chapter.
|
|
</p><!-- l. 661 --><p class='indent'> First of all, make sure that a kernel source tree is available, having exactly the same
|
|
version as your current kernel. Then, find the configuration file which was used to
|
|
compile your precompiled kernel. Usually, this is available in your current <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>boot</span></span></span> directory,
|
|
under a name like <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>config-5.14.x</span></span></span>. You may just want to copy it to your kernel source
|
|
tree: <code> <span class='ectt-1000'>cp /boot/config-</span><span id='textcolor250'><span class='tctt-1000'>`</span></span><span class='ectt-1000'>uname -r</span><span id='textcolor251'><span class='tctt-1000'>`</span></span><span class='ectt-1000'> .config</span>
|
|
</code>.
|
|
</p><!-- l. 666 --><p class='indent'> Let’s focus again on the previous error message: a closer look at the version magic
|
|
strings suggests that, even with two configuration files which are exactly the same, a
|
|
slight difference in the version magic could be possible, and it is sufficient to prevent
|
|
insertion of the module into the kernel. That slight difference, namely the
|
|
custom string which appears in the module’s version magic and not in the
|
|
kernel’s one, is due to a modification with respect to the original, in the
|
|
makefile that some distributions include. Then, examine your <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>Makefile</span></span></span>,
|
|
and make sure that the specified version information matches exactly the
|
|
one used for your current kernel. For example, your makefile could start as
|
|
follows:
|
|
|
|
|
|
|
|
</p>
|
|
<pre class='verbatim' id='verbatim-10'>
|
|
VERSION = 5
|
|
PATCHLEVEL = 14
|
|
SUBLEVEL = 0
|
|
EXTRAVERSION = -rc2
|
|
</pre>
|
|
<!-- l. 676 --><p class='nopar'>
|
|
</p><!-- l. 678 --><p class='indent'> In this case, you need to restore the value of symbol <span class='ecbx-1000'>EXTRAVERSION </span>to
|
|
<span class='ecbx-1000'>-rc2</span>. We suggest keeping a backup copy of the makefile used to compile your kernel
|
|
available in <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/lib/modules/5.14.0-rc2/build</span></span></span>. A simple command as following
|
|
should suffice.
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb35'><a id='x1-18008r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>cp /lib/modules/</span><span id='textcolor252'><span class='tctt-1000'>`</span></span><span class='ectt-1000'>uname -r</span><span id='textcolor253'><span class='tctt-1000'>`</span></span><span class='ectt-1000'>/build/Makefile linux-</span><span id='textcolor254'><span class='tctt-1000'>`</span></span><span class='ectt-1000'>uname -r</span><span id='textcolor255'><span class='tctt-1000'>`</span></span></pre>
|
|
<!-- l. 684 --><p class='noindent'>Here <code> <span class='ectt-1000'>linux-</span><span id='textcolor256'><span class='tctt-1000'>`</span></span><span class='ectt-1000'>uname -r</span><span id='textcolor257'><span class='tctt-1000'>`</span></span>
|
|
</code> is the Linux kernel source you are attempting to build.
|
|
</p><!-- l. 686 --><p class='indent'> Now, please run <code> <span class='ectt-1000'>make</span>
|
|
</code> to update configuration and version headers and objects:
|
|
|
|
|
|
|
|
</p>
|
|
<pre class='verbatim' id='verbatim-11'>
|
|
$ make
|
|
SYNC include/config/auto.conf.cmd
|
|
HOSTCC scripts/basic/fixdep
|
|
HOSTCC scripts/kconfig/conf.o
|
|
HOSTCC scripts/kconfig/confdata.o
|
|
HOSTCC scripts/kconfig/expr.o
|
|
LEX scripts/kconfig/lexer.lex.c
|
|
YACC scripts/kconfig/parser.tab.[ch]
|
|
HOSTCC scripts/kconfig/preprocess.o
|
|
HOSTCC scripts/kconfig/symbol.o
|
|
HOSTCC scripts/kconfig/util.o
|
|
HOSTCC scripts/kconfig/lexer.lex.o
|
|
HOSTCC scripts/kconfig/parser.tab.o
|
|
HOSTLD scripts/kconfig/conf
|
|
</pre>
|
|
<!-- l. 703 --><p class='nopar'>
|
|
</p><!-- l. 705 --><p class='indent'> If you do not desire to actually compile the kernel, you can interrupt the build
|
|
process (CTRL-C) just after the SPLIT line, because at that time, the files you need
|
|
are ready. Now you can turn back to the directory of your module and compile it: It
|
|
will be built exactly according to your current kernel settings, and it will load into it
|
|
without any errors.
|
|
</p><!-- l. 708 --><p class='noindent'>
|
|
</p>
|
|
<h3 class='sectionHead' id='preliminaries'><span class='titlemark'>5 </span> <a id='x1-190005'></a>Preliminaries</h3>
|
|
<!-- l. 709 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='how-modules-begin-and-end'><span class='titlemark'>5.1 </span> <a id='x1-200005.1'></a>How modules begin and end</h4>
|
|
<!-- l. 711 --><p class='noindent'>A typical program starts with a |main()| function, executes a series of
|
|
instructions, and terminates after completing these instructions. Kernel modules,
|
|
however, follow a different pattern. A module always begins with either the
|
|
<code> <span class='ectt-1000'>init_module</span>
|
|
</code> function or a function designated by the
|
|
<code> <span class='ectt-1000'>module_init</span>
|
|
</code> call. This function acts as the module’s entry point, informing the kernel of the
|
|
module’s functionalities and preparing the kernel to utilize the module’s functions
|
|
when necessary. After performing these tasks, the entry function returns, and the
|
|
module remains inactive until the kernel requires its code.
|
|
|
|
|
|
|
|
</p><!-- l. 719 --><p class='indent'> All modules conclude by invoking either
|
|
<code> <span class='ectt-1000'>cleanup_module</span>
|
|
</code> or a function specified through the <code> <span class='ectt-1000'>module_exit</span>
|
|
</code>call. This serves as the module’s exit function, reversing the actions of the entry
|
|
function by unregistering the previously registered functionalities.
|
|
</p><!-- l. 722 --><p class='indent'> It is mandatory for every module to have both an entry and an exit function. While
|
|
there are multiple methods to define these functions, the terms “entry function” and
|
|
“exit function” are generally used. However, they may occasionally be referred to as
|
|
<code> <span class='ectt-1000'>init_module</span>
|
|
</code> and <code> <span class='ectt-1000'>cleanup_module</span>
|
|
</code>, which are understood to mean the same.
|
|
</p><!-- l. 727 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='functions-available-to-modules'><span class='titlemark'>5.2 </span> <a id='x1-210005.2'></a>Functions available to modules</h4>
|
|
<!-- l. 729 --><p class='noindent'>Programmers use functions they do not define all the time. A prime example of this
|
|
is <code> <span class='ectt-1000'>printf()</span>
|
|
</code>. You use these library functions which are provided by the standard C
|
|
library, libc. The definitions for these functions do not actually enter
|
|
your program until the linking stage, which insures that the code (for
|
|
<code> <span class='ectt-1000'>printf()</span>
|
|
</code> for example) is available, and fixes the call instruction to point to that
|
|
code.
|
|
</p><!-- l. 734 --><p class='indent'> Kernel modules are different here, too. In the hello world
|
|
example, you might have noticed that we used a function,
|
|
<code> <span class='ectt-1000'>pr_info()</span>
|
|
</code> but did not include a standard I/O library. That is because
|
|
modules are object files whose symbols get resolved upon running
|
|
<code> <span class='ectt-1000'>insmod</span>
|
|
</code> or <code> <span class='ectt-1000'>modprobe</span>
|
|
</code>. The definition for the symbols comes from the kernel itself; the only external
|
|
functions you can use are the ones provided by the kernel. If you’re curious about
|
|
what symbols have been exported by your kernel, take a look at <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc/kallsyms</span></span></span>.
|
|
</p><!-- l. 739 --><p class='indent'> One point to keep in mind is the difference between library functions and system
|
|
calls. Library functions are higher level, run completely in user space and
|
|
provide a more convenient interface for the programmer to the functions
|
|
that do the real work — system calls. System calls run in kernel mode on
|
|
the user’s behalf and are provided by the kernel itself. The library function
|
|
<code> <span class='ectt-1000'>printf()</span>
|
|
</code> may look like a very general printing function, but all it really does is format the
|
|
data into strings and write the string data using the low-level system call
|
|
<code> <span class='ectt-1000'>write()</span>
|
|
</code>, which then sends the data to standard output.
|
|
</p><!-- l. 743 --><p class='indent'> Would you like to see what system calls are made by
|
|
|
|
|
|
|
|
<code> <span class='ectt-1000'>printf()</span>
|
|
</code>? It is easy! Compile the following program:
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb36'><a id='x1-21017r1'></a><span class='ecrm-0500'>1</span><span id='textcolor258'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor259'><span class='ectt-0800'><stdio.h></span></span>
|
|
<a id='x1-21019r2'></a><span class='ecrm-0500'>2</span>
|
|
<a id='x1-21021r3'></a><span class='ecrm-0500'>3</span><span id='textcolor260'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> main(</span><span id='textcolor261'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-21023r4'></a><span class='ecrm-0500'>4</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-21025r5'></a><span class='ecrm-0500'>5</span><span class='ectt-0800'> printf(</span><span id='textcolor262'><span class='ectt-0800'>"hello"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-21027r6'></a><span class='ecrm-0500'>6</span><span class='ectt-0800'> </span><span id='textcolor263'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-21029r7'></a><span class='ecrm-0500'>7</span><span class='ectt-0800'>}</span></pre>
|
|
<!-- l. 757 --><p class='indent'> with <code> <span class='ectt-1000'>gcc -Wall -o hello hello.c</span>
|
|
</code>. Run the executable with <code> <span class='ectt-1000'>strace ./hello</span>
|
|
</code>. Are you impressed? Every line you see corresponds to a system call. <a href='https://strace.io/'>strace</a> is a
|
|
handy program that gives you details about what system calls a program is
|
|
making, including which call is made, what its arguments are and what it
|
|
returns. It is an invaluable tool for figuring out things like what files a program
|
|
is trying to access. Towards the end, you will see a line which looks like
|
|
<code> <span class='ectt-1000'>write(1, </span><span id='textcolor264'><span class='ectt-1000'>"hello"</span></span><span class='ectt-1000'>, 5hello)</span>
|
|
</code>. There it is. The face behind the <code> <span class='ectt-1000'>printf()</span>
|
|
</code> mask. You may not be familiar with write, since most people use library functions for file
|
|
I/O (like <code> <span class='ectt-1000'>fopen</span>
|
|
</code>, <code> <span class='ectt-1000'>fputs</span>
|
|
</code>, <code> <span class='ectt-1000'>fclose</span>
|
|
</code>). If that is the case, try looking at man 2 write. The 2nd man section is devoted to system
|
|
calls (like <code> <span class='ectt-1000'>kill()</span>
|
|
</code> and <code> <span class='ectt-1000'>read()</span>
|
|
</code>). The 3rd man section is devoted to library calls, which you would probably be more familiar
|
|
with (like <code> <span class='ectt-1000'>cosh()</span>
|
|
</code> and <code> <span class='ectt-1000'>random()</span>
|
|
</code>).
|
|
</p><!-- l. 771 --><p class='indent'> You can even write modules to replace the kernel’s system calls, which we will do
|
|
shortly. Crackers often make use of this sort of thing for backdoors or trojans, but
|
|
you can write your own modules to do more benign things, like have the kernel
|
|
write Tee hee, that tickles! every time someone tries to delete a file on your
|
|
system.
|
|
</p><!-- l. 774 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='user-space-vs-kernel-space'><span class='titlemark'>5.3 </span> <a id='x1-220005.3'></a>User Space vs Kernel Space</h4>
|
|
<!-- l. 776 --><p class='noindent'>The kernel primarily manages access to resources, be it a video card, hard drive, or
|
|
memory. Programs frequently vie for the same resources. For instance, as a document
|
|
is saved, updatedb might commence updating the locate database. Sessions in editors
|
|
like vim and processes like updatedb can simultaneously utilize the hard drive. The
|
|
kernel’s role is to maintain order, ensuring that users do not access resources
|
|
indiscriminately.
|
|
</p><!-- l. 782 --><p class='indent'> To manage this, CPUs operate in different modes, each offering varying levels of
|
|
system control. The Intel 80386 architecture, for example, featured four such modes,
|
|
known as rings. Unix, however, utilizes only two of these rings: the highest ring (ring
|
|
0, also known as “supervisor mode”, where all actions are permissible) and the lowest
|
|
|
|
|
|
|
|
ring, referred to as “user mode”.
|
|
</p><!-- l. 787 --><p class='indent'> Recall the discussion about library functions vs system calls. Typically, you use a
|
|
library function in user mode. The library function calls one or more system calls,
|
|
and these system calls execute on the library function’s behalf, but do so in
|
|
supervisor mode since they are part of the kernel itself. Once the system call
|
|
completes its task, it returns and execution gets transferred back to user
|
|
mode.
|
|
</p><!-- l. 792 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='name-space'><span class='titlemark'>5.4 </span> <a id='x1-230005.4'></a>Name Space</h4>
|
|
<!-- l. 794 --><p class='noindent'>When you write a small C program, you use variables which are convenient and make
|
|
sense to the reader. If, on the other hand, you are writing routines which will be part
|
|
of a bigger problem, any global variables you have are part of a community of other
|
|
peoples’ global variables; some of the variable names can clash. When a program has
|
|
lots of global variables which aren’t meaningful enough to be distinguished, you get
|
|
namespace pollution. In large projects, effort must be made to remember reserved
|
|
names, and to find ways to develop a scheme for naming unique variable names and
|
|
symbols.
|
|
</p><!-- l. 799 --><p class='indent'> When writing kernel code, even the smallest module will be linked against the
|
|
entire kernel, so this is definitely an issue. The best way to deal with this is to declare
|
|
all your variables as static and to use a well-defined prefix for your symbols. By
|
|
convention, all kernel prefixes are lowercase. If you do not want to declare everything
|
|
as static, another option is to declare a symbol table and register it with the kernel.
|
|
We will get to this later.
|
|
</p><!-- l. 804 --><p class='indent'> The file <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc/kallsyms</span></span></span> holds all the symbols that the kernel knows about and
|
|
which are therefore accessible to your modules since they share the kernel’s
|
|
codespace.
|
|
</p><!-- l. 806 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='code-space'><span class='titlemark'>5.5 </span> <a id='x1-240005.5'></a>Code space</h4>
|
|
<!-- l. 808 --><p class='noindent'>Memory management is a very complicated subject and the majority of O’Reilly’s
|
|
<a href='https://www.oreilly.com/library/view/understanding-the-linux/0596005652/'>Understanding The Linux Kernel</a> exclusively covers memory management!
|
|
We are not setting out to be experts on memory managements, but we do
|
|
need to know a couple of facts to even begin worrying about writing real
|
|
modules.
|
|
</p><!-- l. 811 --><p class='indent'> If you have not thought about what a segfault really means, you may be surprised
|
|
to hear that pointers do not actually point to memory locations. Not real
|
|
ones, anyway. When a process is created, the kernel sets aside a portion of
|
|
real physical memory and hands it to the process to use for its executing
|
|
code, variables, stack, heap and other things which a computer scientist
|
|
would know about. This memory begins with 0x00000000 and extends up to
|
|
|
|
|
|
|
|
whatever it needs to be. Since the memory space for any two processes do not
|
|
overlap, every process that can access a memory address, say 0xbffff978, would
|
|
be accessing a different location in real physical memory! The processes
|
|
would be accessing an index named 0xbffff978 which points to some kind of
|
|
offset into the region of memory set aside for that particular process. For
|
|
the most part, a process like our Hello, World program can’t access the
|
|
space of another process, although there are ways which we will talk about
|
|
later.
|
|
</p><!-- l. 818 --><p class='indent'> The kernel has its own space of memory as well. Since a module is code which
|
|
can be dynamically inserted and removed in the kernel (as opposed to a
|
|
semi-autonomous object), it shares the kernel’s codespace rather than having its own.
|
|
Therefore, if your module segfaults, the kernel segfaults. And if you start writing
|
|
over data because of an off-by-one error, then you’re trampling on kernel
|
|
data (or code). This is even worse than it sounds, so try your best to be
|
|
careful.
|
|
</p><!-- l. 823 --><p class='indent'> It should be noted that the aforementioned discussion applies to any operating
|
|
system utilizing a monolithic kernel. This concept differs slightly from <span class='ecti-1000'>“building all
|
|
</span><span class='ecti-1000'>your modules into the kernel”</span>, although the underlying principle is similar. In
|
|
contrast, there are microkernels, where modules are allocated their own code space.
|
|
Two notable examples of microkernels include the <a href='https://www.gnu.org/software/hurd/'>GNU Hurd</a> and the <a href='https://fuchsia.dev/fuchsia-src/concepts/kernel'>Zircon kernel</a>
|
|
of Google’s Fuchsia.
|
|
</p><!-- l. 829 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='device-drivers'><span class='titlemark'>5.6 </span> <a id='x1-250005.6'></a>Device Drivers</h4>
|
|
<!-- l. 831 --><p class='noindent'>One class of module is the device driver, which provides functionality for hardware
|
|
like a serial port. On Unix, each piece of hardware is represented by a file located in
|
|
<span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/dev</span></span></span> named a device file which provides the means to communicate with the
|
|
hardware. The device driver provides the communication on behalf of a
|
|
user program. So the es1370.ko sound card device driver might connect the
|
|
<span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/dev/sound</span></span></span> device file to the Ensoniq IS1370 sound card. A userspace program like
|
|
mp3blaster can use <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/dev/sound</span></span></span> without ever knowing what kind of sound card is
|
|
installed.
|
|
</p><!-- l. 838 --><p class='indent'> Let’s look at some device files. Here are device files which represent the first three
|
|
partitions on the primary master IDE hard drive:
|
|
|
|
|
|
|
|
</p>
|
|
<pre class='verbatim' id='verbatim-12'>
|
|
$ ls -l /dev/hda[1-3]
|
|
brw-rw---- 1 root disk 3, 1 Jul 5 2000 /dev/hda1
|
|
brw-rw---- 1 root disk 3, 2 Jul 5 2000 /dev/hda2
|
|
brw-rw---- 1 root disk 3, 3 Jul 5 2000 /dev/hda3
|
|
</pre>
|
|
<!-- l. 847 --><p class='nopar'>
|
|
</p><!-- l. 849 --><p class='indent'> Notice the column of numbers separated by a comma. The first number is called
|
|
the device’s major number. The second number is the minor number. The major
|
|
number tells you which driver is used to access the hardware. Each driver is assigned
|
|
a unique major number; all device files with the same major number are controlled
|
|
by the same driver. All the above major numbers are 3, because they’re all controlled
|
|
by the same driver.
|
|
</p><!-- l. 856 --><p class='indent'> The minor number is used by the driver to distinguish between the various
|
|
hardware it controls. Returning to the example above, although all three devices are
|
|
handled by the same driver they have unique minor numbers because the driver sees
|
|
them as being different pieces of hardware.
|
|
</p><!-- l. 859 --><p class='indent'> Devices are divided into two types: character devices and block devices. The
|
|
difference is that block devices have a buffer for requests, so they can choose the best
|
|
order in which to respond to the requests. This is important in the case of storage
|
|
devices, where it is faster to read or write sectors which are close to each
|
|
other, rather than those which are further apart. Another difference is that
|
|
block devices can only accept input and return output in blocks (whose size
|
|
can vary according to the device), whereas character devices are allowed
|
|
to use as many or as few bytes as they like. Most devices in the world are
|
|
character, because they don’t need this type of buffering, and they don’t
|
|
operate with a fixed block size. You can tell whether a device file is for a block
|
|
device or a character device by looking at the first character in the output of
|
|
<code> <span class='ectt-1000'>ls -l</span>
|
|
</code>. If it is ‘b’ then it is a block device, and if it is ‘c’ then it is a character device. The
|
|
devices you see above are block devices. Here are some character devices (the serial
|
|
ports):
|
|
|
|
|
|
|
|
</p>
|
|
<pre class='verbatim' id='verbatim-13'>
|
|
crw-rw---- 1 root dial 4, 64 Feb 18 23:34 /dev/ttyS0
|
|
crw-r----- 1 root dial 4, 65 Nov 17 10:26 /dev/ttyS1
|
|
crw-rw---- 1 root dial 4, 66 Jul 5 2000 /dev/ttyS2
|
|
crw-rw---- 1 root dial 4, 67 Jul 5 2000 /dev/ttyS3
|
|
</pre>
|
|
<!-- l. 873 --><p class='nopar'>
|
|
</p><!-- l. 875 --><p class='indent'> If you want to see which major numbers have been assigned, you can look at
|
|
<a href='https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/Documentation/admin-guide/devices.txt'>Documentation/admin-guide/devices.txt</a>.
|
|
</p><!-- l. 877 --><p class='indent'> When the system was installed, all of those device files were created by the
|
|
<code> <span class='ectt-1000'>mknod</span>
|
|
</code> command. To create a new char device named <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>coffee</span></span></span> with major/minor number 12 and 2,
|
|
simply do <code> <span class='ectt-1000'>mknod /dev/coffee c 12 2</span>
|
|
</code>. You do not have to put your device files into <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/dev</span></span></span>, but it is done by convention.
|
|
Linus put his device files in <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/dev</span></span></span>, and so should you. However, when creating a
|
|
device file for testing purposes, it is probably OK to place it in your working
|
|
directory where you compile the kernel module. Just be sure to put it in the right
|
|
place when you’re done writing the device driver.
|
|
</p><!-- l. 884 --><p class='indent'> A few final points, although implicit in the previous discussion, are worth stating
|
|
explicitly for clarity. When a device file is accessed, the kernel utilizes the file’s major
|
|
number to identify the appropriate driver for handling the access. This indicates that
|
|
the kernel does not necessarily rely on or need to be aware of the minor number. It is
|
|
the driver that concerns itself with the minor number, using it to differentiate
|
|
between various pieces of hardware.
|
|
</p><!-- l. 889 --><p class='indent'> It is important to note that when referring to <span class='ecti-1000'>“hardware”</span>, the term is used in a
|
|
slightly more abstract sense than just a physical PCI card that can be held in hand.
|
|
Consider the following two device files:
|
|
|
|
|
|
|
|
</p>
|
|
<pre class='verbatim' id='verbatim-14'>
|
|
$ ls -l /dev/sda /dev/sdb
|
|
brw-rw---- 1 root disk 8, 0 Jan 3 09:02 /dev/sda
|
|
brw-rw---- 1 root disk 8, 16 Jan 3 09:02 /dev/sdb
|
|
</pre>
|
|
<!-- l. 897 --><p class='nopar'>
|
|
</p><!-- l. 899 --><p class='indent'> By now you can look at these two device files and know instantly that they are
|
|
block devices and are handled by same driver (block major 8). Sometimes two device
|
|
files with the same major but different minor number can actually represent the same
|
|
piece of physical hardware. So just be aware that the word “hardware” in our
|
|
discussion can mean something very abstract.
|
|
</p><!-- l. 903 --><p class='noindent'>
|
|
</p>
|
|
<h3 class='sectionHead' id='character-device-drivers'><span class='titlemark'>6 </span> <a id='x1-260006'></a>Character Device drivers</h3>
|
|
<!-- l. 905 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='the-fileoperations-structure'><span class='titlemark'>6.1 </span> <a id='x1-270006.1'></a>The file_operations Structure</h4>
|
|
<!-- l. 907 --><p class='noindent'>The <code> <span class='ectt-1000'>file_operations</span>
|
|
</code> structure is defined in <a href='https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/include/linux/fs.h'>include/linux/fs.h</a>, and holds pointers to functions defined by
|
|
the driver that perform various operations on the device. Each field of the structure
|
|
corresponds to the address of some function defined by the driver to handle a
|
|
requested operation.
|
|
</p><!-- l. 910 --><p class='indent'> For example, every character driver needs to define a function that reads from the
|
|
device. The <code> <span class='ectt-1000'>file_operations</span>
|
|
</code> structure holds the address of the module’s function that performs that operation.
|
|
Here is what the definition looks like for kernel 5.4:
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb37'><a id='x1-27042r1'></a><span class='ecrm-0500'>1</span><span id='textcolor265'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file_operations {</span>
|
|
<a id='x1-27044r2'></a><span class='ecrm-0500'>2</span><span class='ectt-0800'> </span><span id='textcolor266'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> module *owner;</span>
|
|
<a id='x1-27046r3'></a><span class='ecrm-0500'>3</span><span class='ectt-0800'> loff_t (*llseek) (</span><span id='textcolor267'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *, loff_t, </span><span id='textcolor268'><span class='ectt-0800'>int</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-27048r4'></a><span class='ecrm-0500'>4</span><span class='ectt-0800'> </span><span id='textcolor269'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> (*read) (</span><span id='textcolor270'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *, </span><span id='textcolor271'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *, </span><span id='textcolor272'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'>, loff_t *);</span>
|
|
<a id='x1-27050r5'></a><span class='ecrm-0500'>5</span><span class='ectt-0800'> </span><span id='textcolor273'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> (*write) (</span><span id='textcolor274'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *, </span><span id='textcolor275'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor276'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *, </span><span id='textcolor277'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'>, loff_t *);</span>
|
|
<a id='x1-27052r6'></a><span class='ecrm-0500'>6</span><span class='ectt-0800'> </span><span id='textcolor278'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> (*read_iter) (</span><span id='textcolor279'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> kiocb *, </span><span id='textcolor280'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> iov_iter *);</span>
|
|
<a id='x1-27054r7'></a><span class='ecrm-0500'>7</span><span class='ectt-0800'> </span><span id='textcolor281'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> (*write_iter) (</span><span id='textcolor282'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> kiocb *, </span><span id='textcolor283'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> iov_iter *);</span>
|
|
<a id='x1-27056r8'></a><span class='ecrm-0500'>8</span><span class='ectt-0800'> </span><span id='textcolor284'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> (*iopoll)(</span><span id='textcolor285'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> kiocb *kiocb, </span><span id='textcolor286'><span class='ectt-0800'>bool</span></span><span class='ectt-0800'> spin);</span>
|
|
<a id='x1-27058r9'></a><span class='ecrm-0500'>9</span><span class='ectt-0800'> </span><span id='textcolor287'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> (*iterate) (</span><span id='textcolor288'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *, </span><span id='textcolor289'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> dir_context *);</span>
|
|
<a id='x1-27060r10'></a><span class='ecrm-0500'>10</span><span class='ectt-0800'> </span><span id='textcolor290'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> (*iterate_shared) (</span><span id='textcolor291'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *, </span><span id='textcolor292'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> dir_context *);</span>
|
|
<a id='x1-27062r11'></a><span class='ecrm-0500'>11</span><span class='ectt-0800'> __poll_t (*poll) (</span><span id='textcolor293'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *, </span><span id='textcolor294'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> poll_table_struct *);</span>
|
|
<a id='x1-27064r12'></a><span class='ecrm-0500'>12</span><span class='ectt-0800'> </span><span id='textcolor295'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> (*unlocked_ioctl) (</span><span id='textcolor296'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *, </span><span id='textcolor297'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor298'><span class='ectt-0800'>int</span></span><span class='ectt-0800'>, </span><span id='textcolor299'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor300'><span class='ectt-0800'>long</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-27066r13'></a><span class='ecrm-0500'>13</span><span class='ectt-0800'> </span><span id='textcolor301'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> (*compat_ioctl) (</span><span id='textcolor302'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *, </span><span id='textcolor303'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor304'><span class='ectt-0800'>int</span></span><span class='ectt-0800'>, </span><span id='textcolor305'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor306'><span class='ectt-0800'>long</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-27068r14'></a><span class='ecrm-0500'>14</span><span class='ectt-0800'> </span><span id='textcolor307'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> (*mmap) (</span><span id='textcolor308'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *, </span><span id='textcolor309'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> vm_area_struct *);</span>
|
|
<a id='x1-27070r15'></a><span class='ecrm-0500'>15</span><span class='ectt-0800'> </span><span id='textcolor310'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor311'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> mmap_supported_flags;</span>
|
|
<a id='x1-27072r16'></a><span class='ecrm-0500'>16</span><span class='ectt-0800'> </span><span id='textcolor312'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> (*open) (</span><span id='textcolor313'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> inode *, </span><span id='textcolor314'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *);</span>
|
|
<a id='x1-27074r17'></a><span class='ecrm-0500'>17</span><span class='ectt-0800'> </span><span id='textcolor315'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> (*flush) (</span><span id='textcolor316'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *, fl_owner_t id);</span>
|
|
<a id='x1-27076r18'></a><span class='ecrm-0500'>18</span><span class='ectt-0800'> </span><span id='textcolor317'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> (*release) (</span><span id='textcolor318'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> inode *, </span><span id='textcolor319'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *);</span>
|
|
<a id='x1-27078r19'></a><span class='ecrm-0500'>19</span><span class='ectt-0800'> </span><span id='textcolor320'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> (*fsync) (</span><span id='textcolor321'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *, loff_t, loff_t, </span><span id='textcolor322'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> datasync);</span>
|
|
<a id='x1-27080r20'></a><span class='ecrm-0500'>20</span><span class='ectt-0800'> </span><span id='textcolor323'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> (*fasync) (</span><span id='textcolor324'><span class='ectt-0800'>int</span></span><span class='ectt-0800'>, </span><span id='textcolor325'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *, </span><span id='textcolor326'><span class='ectt-0800'>int</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-27082r21'></a><span class='ecrm-0500'>21</span><span class='ectt-0800'> </span><span id='textcolor327'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> (*lock) (</span><span id='textcolor328'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *, </span><span id='textcolor329'><span class='ectt-0800'>int</span></span><span class='ectt-0800'>, </span><span id='textcolor330'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file_lock *);</span>
|
|
<a id='x1-27084r22'></a><span class='ecrm-0500'>22</span><span class='ectt-0800'> </span><span id='textcolor331'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> (*sendpage) (</span><span id='textcolor332'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *, </span><span id='textcolor333'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> page *, </span><span id='textcolor334'><span class='ectt-0800'>int</span></span><span class='ectt-0800'>, </span><span id='textcolor335'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'>, loff_t *, </span><span id='textcolor336'><span class='ectt-0800'>int</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-27086r23'></a><span class='ecrm-0500'>23</span><span class='ectt-0800'> </span><span id='textcolor337'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> long (*get_unmapped_area)(</span><span id='textcolor338'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *, </span><span id='textcolor339'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor340'><span class='ectt-0800'>long</span></span><span class='ectt-0800'>, </span><span id='textcolor341'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor342'><span class='ectt-0800'>long</span></span><span class='ectt-0800'>, </span><span id='textcolor343'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor344'><span class='ectt-0800'>long</span></span><span class='ectt-0800'>, </span><span id='textcolor345'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor346'><span class='ectt-0800'>long</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-27088r24'></a><span class='ecrm-0500'>24</span><span class='ectt-0800'> </span><span id='textcolor347'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> (*check_flags)(</span><span id='textcolor348'><span class='ectt-0800'>int</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-27090r25'></a><span class='ecrm-0500'>25</span><span class='ectt-0800'> </span><span id='textcolor349'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> (*flock) (</span><span id='textcolor350'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *, </span><span id='textcolor351'><span class='ectt-0800'>int</span></span><span class='ectt-0800'>, </span><span id='textcolor352'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file_lock *);</span>
|
|
<a id='x1-27092r26'></a><span class='ecrm-0500'>26</span><span class='ectt-0800'> </span><span id='textcolor353'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> (*splice_write)(</span><span id='textcolor354'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> pipe_inode_info *, </span><span id='textcolor355'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *, loff_t *, </span><span id='textcolor356'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'>, </span><span id='textcolor357'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor358'><span class='ectt-0800'>int</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-27094r27'></a><span class='ecrm-0500'>27</span><span class='ectt-0800'> </span><span id='textcolor359'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> (*splice_read)(</span><span id='textcolor360'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *, loff_t *, </span><span id='textcolor361'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> pipe_inode_info *, </span><span id='textcolor362'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'>, </span><span id='textcolor363'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor364'><span class='ectt-0800'>int</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-27096r28'></a><span class='ecrm-0500'>28</span><span class='ectt-0800'> </span><span id='textcolor365'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> (*setlease)(</span><span id='textcolor366'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *, </span><span id='textcolor367'><span class='ectt-0800'>long</span></span><span class='ectt-0800'>, </span><span id='textcolor368'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file_lock **, </span><span id='textcolor369'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> **);</span>
|
|
<a id='x1-27098r29'></a><span class='ecrm-0500'>29</span><span class='ectt-0800'> </span><span id='textcolor370'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> (*fallocate)(</span><span id='textcolor371'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file, </span><span id='textcolor372'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> mode, loff_t offset,</span>
|
|
<a id='x1-27100r30'></a><span class='ecrm-0500'>30</span><span class='ectt-0800'> loff_t len);</span>
|
|
<a id='x1-27102r31'></a><span class='ecrm-0500'>31</span><span class='ectt-0800'> </span><span id='textcolor373'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> (*show_fdinfo)(</span><span id='textcolor374'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> seq_file *m, </span><span id='textcolor375'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *f);</span>
|
|
<a id='x1-27104r32'></a><span class='ecrm-0500'>32</span><span class='ectt-0800'> </span><span id='textcolor376'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> (*copy_file_range)(</span><span id='textcolor377'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *, loff_t, </span><span id='textcolor378'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *,</span>
|
|
<a id='x1-27106r33'></a><span class='ecrm-0500'>33</span><span class='ectt-0800'> loff_t, </span><span id='textcolor379'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'>, </span><span id='textcolor380'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor381'><span class='ectt-0800'>int</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-27108r34'></a><span class='ecrm-0500'>34</span><span class='ectt-0800'> loff_t (*remap_file_range)(</span><span id='textcolor382'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file_in, loff_t pos_in,</span>
|
|
<a id='x1-27110r35'></a><span class='ecrm-0500'>35</span><span class='ectt-0800'> </span><span id='textcolor383'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file_out, loff_t pos_out,</span>
|
|
<a id='x1-27112r36'></a><span class='ecrm-0500'>36</span><span class='ectt-0800'> loff_t len, </span><span id='textcolor384'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor385'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> remap_flags);</span>
|
|
<a id='x1-27114r37'></a><span class='ecrm-0500'>37</span><span class='ectt-0800'> </span><span id='textcolor386'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> (*fadvise)(</span><span id='textcolor387'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *, loff_t, loff_t, </span><span id='textcolor388'><span class='ectt-0800'>int</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-27116r38'></a><span class='ecrm-0500'>38</span><span class='ectt-0800'>} __randomize_layout;</span></pre>
|
|
<!-- l. 955 --><p class='indent'> Some operations are not implemented by a driver. For example, a driver that handles
|
|
a video card will not need to read from a directory structure. The corresponding entries
|
|
in the <code> <span class='ectt-1000'>file_operations</span>
|
|
</code> structure should be set to <code> <span class='ectt-1000'>NULL</span>
|
|
</code>.
|
|
</p><!-- l. 959 --><p class='indent'> There is a gcc extension that makes assigning to this structure more convenient.
|
|
You will see it in modern drivers, and may catch you by surprise. This is what the
|
|
new way of assigning to the structure looks like:
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
|
|
|
|
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb38'><a id='x1-27126r1'></a><span class='ecrm-0500'>1</span><span id='textcolor389'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file_operations fops = {</span>
|
|
<a id='x1-27128r2'></a><span class='ecrm-0500'>2</span><span class='ectt-0800'> read: device_read,</span>
|
|
<a id='x1-27130r3'></a><span class='ecrm-0500'>3</span><span class='ectt-0800'> write: device_write,</span>
|
|
<a id='x1-27132r4'></a><span class='ecrm-0500'>4</span><span class='ectt-0800'> open: device_open,</span>
|
|
<a id='x1-27134r5'></a><span class='ecrm-0500'>5</span><span class='ectt-0800'> release: device_release</span>
|
|
<a id='x1-27136r6'></a><span class='ecrm-0500'>6</span><span class='ectt-0800'>};</span></pre>
|
|
<!-- l. 972 --><p class='indent'> However, there is also a C99 way of assigning to elements of a structure,
|
|
<a href='https://gcc.gnu.org/onlinedocs/gcc/Designated-Inits.html'>designated initializers</a>, and this is definitely preferred over using the GNU extension.
|
|
You should use this syntax in case someone wants to port your driver. It will help
|
|
with compatibility:
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb39'><a id='x1-27144r1'></a><span class='ecrm-0500'>1</span><span id='textcolor390'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file_operations fops = {</span>
|
|
<a id='x1-27146r2'></a><span class='ecrm-0500'>2</span><span class='ectt-0800'> .read = device_read,</span>
|
|
<a id='x1-27148r3'></a><span class='ecrm-0500'>3</span><span class='ectt-0800'> .write = device_write,</span>
|
|
<a id='x1-27150r4'></a><span class='ecrm-0500'>4</span><span class='ectt-0800'> .open = device_open,</span>
|
|
<a id='x1-27152r5'></a><span class='ecrm-0500'>5</span><span class='ectt-0800'> .release = device_release</span>
|
|
<a id='x1-27154r6'></a><span class='ecrm-0500'>6</span><span class='ectt-0800'>};</span></pre>
|
|
<!-- l. 985 --><p class='indent'> The meaning is clear, and you should be aware that any member of
|
|
the structure which you do not explicitly assign will be initialized to
|
|
<code> <span class='ectt-1000'>NULL</span>
|
|
</code> by gcc.
|
|
</p><!-- l. 987 --><p class='indent'> An instance of <code> <span id='textcolor391'><span class='ectt-1000'>struct</span></span><span class='ectt-1000'> file_operations</span>
|
|
</code> containing pointers to functions that are used to implement
|
|
<code> <span class='ectt-1000'>read</span>
|
|
</code>, <code> <span class='ectt-1000'>write</span>
|
|
</code>, <code> <span class='ectt-1000'>open</span>
|
|
</code>, … system calls is commonly named <code> <span class='ectt-1000'>fops</span>
|
|
</code>.
|
|
</p><!-- l. 989 --><p class='indent'> Since Linux v3.14, the read, write and seek operations are guaranteed for thread-safe by
|
|
using the <code> <span class='ectt-1000'>f_pos</span>
|
|
</code> specific lock, which makes the file position update to become the mutual
|
|
exclusion. So, we can safely implement those operations without unnecessary
|
|
locking.
|
|
</p><!-- l. 992 --><p class='indent'> Additionally, since Linux v5.6, the <code> <span class='ectt-1000'>proc_ops</span>
|
|
</code> structure was introduced to replace the use of the
|
|
<code> <span class='ectt-1000'>file_operations</span>
|
|
</code> structure when registering proc handlers. See more information in the <a href='#the-procops-structure'>7.1<!-- tex4ht:ref: sec:proc_ops --></a>
|
|
section.
|
|
</p><!-- l. 995 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='the-file-structure'><span class='titlemark'>6.2 </span> <a id='x1-280006.2'></a>The file structure</h4>
|
|
<!-- l. 998 --><p class='noindent'>Each device is represented in the kernel by a file structure, which is defined
|
|
in <a href='https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/include/linux/fs.h'>include/linux/fs.h</a>. Be aware that a file is a kernel level structure and
|
|
never appears in a user space program. It is not the same thing as a
|
|
<code> <span id='textcolor392'><span class='ectt-1000'>FILE</span></span>
|
|
</code>, which is defined by glibc and would never appear in a kernel space
|
|
function. Also, its name is a bit misleading; it represents an abstract open
|
|
‘file’, not a file on a disk, which is represented by a structure named
|
|
<code> <span class='ectt-1000'>inode</span>
|
|
</code>.
|
|
|
|
|
|
|
|
</p><!-- l. 1003 --><p class='indent'> An instance of struct file is commonly named
|
|
<code> <span class='ectt-1000'>filp</span>
|
|
</code>. You’ll also see it referred to as a struct file object. Resist the temptation.
|
|
</p><!-- l. 1007 --><p class='indent'> Go ahead and look at the definition of file. Most of the entries you see, like struct
|
|
dentry are not used by device drivers, and you can ignore them. This is because
|
|
drivers do not fill file directly; they only use structures contained in file which are
|
|
created elsewhere.
|
|
</p><!-- l. 1011 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='registering-a-device'><span class='titlemark'>6.3 </span> <a id='x1-290006.3'></a>Registering A Device</h4>
|
|
<!-- l. 1013 --><p class='noindent'>As discussed earlier, char devices are accessed through device files, usually located in
|
|
<span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/dev</span></span></span>. This is by convention. When writing a driver, it is OK to put the
|
|
device file in your current directory. Just make sure you place it in <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/dev</span></span></span> for a
|
|
production driver. The major number tells you which driver handles which
|
|
device file. The minor number is used only by the driver itself to differentiate
|
|
which device it is operating on, just in case the driver handles more than one
|
|
device.
|
|
</p><!-- l. 1019 --><p class='indent'> Adding a driver to your system means registering it with the kernel. This is synonymous
|
|
with assigning it a major number during the module’s initialization. You do this by
|
|
using the <code> <span class='ectt-1000'>register_chrdev</span>
|
|
</code> function, defined by <a href='https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/include/linux/fs.h'>include/linux/fs.h</a>.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb40'><a id='x1-29004r1'></a><span class='ecrm-0500'>1</span><span id='textcolor393'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> register_chrdev(</span><span id='textcolor394'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor395'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> major, </span><span id='textcolor396'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor397'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *name, </span><span id='textcolor398'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file_operations *fops);</span></pre>
|
|
<!-- l. 1027 --><p class='indent'> Where unsigned int major is the major number you want to request,
|
|
<code> <span id='textcolor399'><span class='ectt-1000'>const</span></span><span class='ectt-1000'> </span><span id='textcolor400'><span class='ectt-1000'>char</span></span><span class='ectt-1000'> *name</span>
|
|
</code> is the name of the device as it will appear in <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc/devices</span></span></span> and
|
|
<code> <span id='textcolor401'><span class='ectt-1000'>struct</span></span><span class='ectt-1000'> file_operations *fops</span>
|
|
</code> is a pointer to the <code> <span class='ectt-1000'>file_operations</span>
|
|
</code> table for your driver. A negative return value means the
|
|
registration failed. Note that we didn’t pass the minor number to
|
|
<code> <span class='ectt-1000'>register_chrdev</span>
|
|
</code>. That is because the kernel doesn’t care about the minor number; only our driver
|
|
uses it.
|
|
</p><!-- l. 1031 --><p class='indent'> Now the question is, how do you get a major number without hijacking
|
|
one that’s already in use? The easiest way would be to look through
|
|
<a href='https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/Documentation/admin-guide/devices.txt'>Documentation/admin-guide/devices.txt</a> and pick an unused one. That is a bad way
|
|
of doing things because you will never be sure if the number you picked will be
|
|
assigned later. The answer is that you can ask the kernel to assign you a dynamic
|
|
major number.
|
|
</p><!-- l. 1036 --><p class='indent'> If you pass a major number of 0 to <code> <span class='ectt-1000'>register_chrdev</span>
|
|
</code>, the return value will be the dynamically allocated major number. The
|
|
downside is that you can not make a device file in advance, since you do not
|
|
|
|
|
|
|
|
know what the major number will be. There are a couple of ways to do
|
|
this. First, the driver itself can print the newly assigned number and we
|
|
can make the device file by hand. Second, the newly registered device will
|
|
have an entry in <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc/devices</span></span></span>, and we can either make the device file by
|
|
hand or write a shell script to read the file in and make the device file. The
|
|
third method is that we can have our driver make the device file using the
|
|
<code> <span class='ectt-1000'>device_create</span>
|
|
</code> function after a successful registration and
|
|
<code> <span class='ectt-1000'>device_destroy</span>
|
|
</code> during the call to <code> <span class='ectt-1000'>cleanup_module</span>
|
|
</code>.
|
|
</p><!-- l. 1043 --><p class='indent'> However, <code> <span class='ectt-1000'>register_chrdev()</span>
|
|
</code> would occupy a range of minor numbers associated with the given major. The
|
|
recommended way to reduce waste for char device registration is using cdev
|
|
interface.
|
|
</p><!-- l. 1046 --><p class='indent'> The newer interface completes the char device registration in two distinct steps.
|
|
First, we should register a range of device numbers, which can be completed with
|
|
<code> <span class='ectt-1000'>register_chrdev_region</span>
|
|
</code> or <code> <span class='ectt-1000'>alloc_chrdev_region</span>
|
|
</code>.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb41'><a id='x1-29019r1'></a><span class='ecrm-0500'>1</span><span id='textcolor402'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> register_chrdev_region(</span><span id='textcolor403'><span class='ectt-0800'>dev_t</span></span><span class='ectt-0800'> from, </span><span id='textcolor404'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> count, </span><span id='textcolor405'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor406'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *name);</span>
|
|
<a id='x1-29021r2'></a><span class='ecrm-0500'>2</span><span id='textcolor407'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> alloc_chrdev_region(</span><span id='textcolor408'><span class='ectt-0800'>dev_t</span></span><span class='ectt-0800'> *dev, </span><span id='textcolor409'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> baseminor, </span><span id='textcolor410'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> count, </span><span id='textcolor411'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor412'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *name);</span></pre>
|
|
<!-- l. 1054 --><p class='indent'> The choice between two different functions depends on
|
|
whether you know the major numbers for your device. Using
|
|
<code> <span class='ectt-1000'>register_chrdev_region</span>
|
|
</code> if you know the device major number and
|
|
<code> <span class='ectt-1000'>alloc_chrdev_region</span>
|
|
</code> if you would like to allocate a dynamically-allocated major number.
|
|
</p><!-- l. 1057 --><p class='indent'> Second, we should initialize the data structure
|
|
<code> <span id='textcolor413'><span class='ectt-1000'>struct</span></span><span class='ectt-1000'> cdev</span>
|
|
</code> for our char device and associate it with the device numbers. To initialize the
|
|
<code> <span id='textcolor414'><span class='ectt-1000'>struct</span></span><span class='ectt-1000'> cdev</span>
|
|
</code>, we can achieve by the similar sequence of the following codes.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb42'><a id='x1-29029r1'></a><span class='ecrm-0500'>1</span><span id='textcolor415'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> cdev *my_dev = cdev_alloc();</span>
|
|
<a id='x1-29031r2'></a><span class='ecrm-0500'>2</span><span class='ectt-0800'>my_cdev->ops = &my_fops;</span></pre>
|
|
<!-- l. 1065 --><p class='indent'> However, the common usage pattern will embed the
|
|
<code> <span id='textcolor416'><span class='ectt-1000'>struct</span></span><span class='ectt-1000'> cdev</span>
|
|
</code> within a device-specific structure of your own. In this case, we’ll need
|
|
<code> <span class='ectt-1000'>cdev_init</span>
|
|
</code> for the initialization.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb43'><a id='x1-29036r1'></a><span class='ecrm-0500'>1</span><span id='textcolor417'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> cdev_init(</span><span id='textcolor418'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> cdev *cdev, </span><span id='textcolor419'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor420'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file_operations *fops);</span></pre>
|
|
|
|
|
|
|
|
<!-- l. 1072 --><p class='indent'> Once we finish the initialization, we can add the char device to the system by using
|
|
the <code> <span class='ectt-1000'>cdev_add</span>
|
|
</code>.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb44'><a id='x1-29040r1'></a><span class='ecrm-0500'>1</span><span id='textcolor421'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> cdev_add(</span><span id='textcolor422'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> cdev *p, </span><span id='textcolor423'><span class='ectt-0800'>dev_t</span></span><span class='ectt-0800'> dev, </span><span id='textcolor424'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> count);</span></pre>
|
|
<!-- l. 1078 --><p class='indent'> To find an example using the interface, you can see <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>ioctl.c</span></span></span> described in section
|
|
<a href='#talking-to-device-files'>9<!-- tex4ht:ref: sec:device_files --></a>.
|
|
</p><!-- l. 1080 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='unregistering-a-device'><span class='titlemark'>6.4 </span> <a id='x1-300006.4'></a>Unregistering A Device</h4>
|
|
<!-- l. 1082 --><p class='noindent'>We can not allow the kernel module to be
|
|
<code> <span class='ectt-1000'>rmmod</span>
|
|
</code>’ed whenever root feels like it. If the device file is opened by a process and then we
|
|
remove the kernel module, using the file would cause a call to the memory location
|
|
where the appropriate function (read/write) used to be. If we are lucky, no
|
|
other code was loaded there, and we’ll get an ugly error message. If we are
|
|
unlucky, another kernel module was loaded into the same location, which
|
|
means a jump into the middle of another function within the kernel. The
|
|
results of this would be impossible to predict, but they can not be very
|
|
positive.
|
|
</p><!-- l. 1088 --><p class='indent'> Normally, when you do not want to allow something, you return an error code
|
|
(a negative number) from the function which is supposed to do it. With
|
|
<code> <span class='ectt-1000'>cleanup_module</span>
|
|
</code> that’s impossible because it is a void function. However, there is a counter
|
|
which keeps track of how many processes are using your module. You
|
|
can see what its value is by looking at the 3rd field with the command
|
|
<code> <span class='ectt-1000'>cat /proc/modules</span>
|
|
</code> or <code> <span class='ectt-1000'>sudo lsmod</span>
|
|
</code>. If this number isn’t zero, <code> <span class='ectt-1000'>rmmod</span>
|
|
</code> will fail. Note that you do not have to check the counter within
|
|
<code> <span class='ectt-1000'>cleanup_module</span>
|
|
</code> because the check will be performed for you by the system call
|
|
<code> <span class='ectt-1000'>sys_delete_module</span>
|
|
</code>, defined in <a href='https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/include/linux/syscalls.h'>include/linux/syscalls.h</a>. You should not use this counter directly, but
|
|
there are functions defined in <a href='https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/include/linux/module.h'>include/linux/module.h</a> which let you increase,
|
|
decrease and display this counter:
|
|
</p>
|
|
<ul class='itemize1'>
|
|
<li class='itemize'><code> <span class='ectt-1000'>try_module_get(THIS_MODULE)</span>
|
|
</code>: Increment the reference count of current module.
|
|
</li>
|
|
<li class='itemize'><code> <span class='ectt-1000'>module_put(THIS_MODULE)</span>
|
|
</code>: Decrement the reference count of current module.
|
|
</li>
|
|
<li class='itemize'><code> <span class='ectt-1000'>module_refcount(THIS_MODULE)</span>
|
|
</code>: Return the value of reference count of current module.</li></ul>
|
|
<!-- l. 1102 --><p class='indent'> It is important to keep the counter accurate; if you ever do lose track of the
|
|
correct usage count, you will never be able to unload the module; it’s now reboot
|
|
time, boys and girls. This is bound to happen to you sooner or later during a
|
|
module’s development.
|
|
</p><!-- l. 1105 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='chardevc'><span class='titlemark'>6.5 </span> <a id='x1-310006.5'></a>chardev.c</h4>
|
|
<!-- l. 1107 --><p class='noindent'>The next code sample creates a char driver named <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>chardev</span></span></span>. You can dump its device
|
|
file.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb45'><a id='x1-31003r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>cat /proc/devices</span></pre>
|
|
<!-- l. 1114 --><p class='indent'> (or open the file with a program) and the driver will put the number of times the
|
|
device file has been read from into the file. We do not support writing to the file (like
|
|
<code> <span class='ectt-1000'>echo </span><span id='textcolor425'><span class='ectt-1000'>"hi"</span></span><span class='ectt-1000'> > /dev/hello</span>
|
|
</code>), but catch these attempts and tell the user that the operation is not supported.
|
|
Don’t worry if you don’t see what we do with the data we read into the buffer; we
|
|
don’t do much with it. We simply read in the data and print a message
|
|
acknowledging that we received it.
|
|
</p><!-- l. 1119 --><p class='indent'> In the multiple-threaded environment, without any protection, concurrent access
|
|
to the same memory may lead to the race condition, and will not preserve the
|
|
performance. In the kernel module, this problem may happen due to multiple
|
|
instances accessing the shared resources. Therefore, a solution is to enforce the
|
|
exclusive access. We use atomic Compare-And-Swap (CAS) to maintain the states,
|
|
<code> <span class='ectt-1000'>CDEV_NOT_USED</span>
|
|
</code> and <code> <span class='ectt-1000'>CDEV_EXCLUSIVE_OPEN</span>
|
|
|
|
|
|
|
|
</code>, to determine whether the file is currently opened by someone or not. CAS compares
|
|
the contents of a memory location with the expected value and, only if they are the
|
|
same, modifies the contents of that memory location to the desired value. See more
|
|
concurrency details in the <a href='#avoiding-collisions-and-deadlocks'>12<!-- tex4ht:ref: sec:synchronization --></a> section.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb46'><a id='x1-31008r1'></a><span class='ecrm-0500'>1</span><span id='textcolor426'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-31010r2'></a><span class='ecrm-0500'>2</span><span id='textcolor427'><span class='ectt-0800'> * chardev.c: Creates a read-only char device that says how many times</span></span>
|
|
<a id='x1-31012r3'></a><span class='ecrm-0500'>3</span><span id='textcolor428'><span class='ectt-0800'> * you have read from the dev file</span></span>
|
|
<a id='x1-31014r4'></a><span class='ecrm-0500'>4</span><span id='textcolor429'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-31016r5'></a><span class='ecrm-0500'>5</span>
|
|
<a id='x1-31018r6'></a><span class='ecrm-0500'>6</span><span id='textcolor430'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor431'><span class='ectt-0800'><linux/atomic.h></span></span>
|
|
<a id='x1-31020r7'></a><span class='ecrm-0500'>7</span><span id='textcolor432'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor433'><span class='ectt-0800'><linux/cdev.h></span></span>
|
|
<a id='x1-31022r8'></a><span class='ecrm-0500'>8</span><span id='textcolor434'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor435'><span class='ectt-0800'><linux/delay.h></span></span>
|
|
<a id='x1-31024r9'></a><span class='ecrm-0500'>9</span><span id='textcolor436'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor437'><span class='ectt-0800'><linux/device.h></span></span>
|
|
<a id='x1-31026r10'></a><span class='ecrm-0500'>10</span><span id='textcolor438'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor439'><span class='ectt-0800'><linux/fs.h></span></span>
|
|
<a id='x1-31028r11'></a><span class='ecrm-0500'>11</span><span id='textcolor440'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor441'><span class='ectt-0800'><linux/init.h></span></span>
|
|
<a id='x1-31030r12'></a><span class='ecrm-0500'>12</span><span id='textcolor442'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor443'><span class='ectt-0800'><linux/kernel.h> /* for sprintf() */</span></span>
|
|
<a id='x1-31032r13'></a><span class='ecrm-0500'>13</span><span id='textcolor444'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor445'><span class='ectt-0800'><linux/module.h></span></span>
|
|
<a id='x1-31034r14'></a><span class='ecrm-0500'>14</span><span id='textcolor446'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor447'><span class='ectt-0800'><linux/printk.h></span></span>
|
|
<a id='x1-31036r15'></a><span class='ecrm-0500'>15</span><span id='textcolor448'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor449'><span class='ectt-0800'><linux/types.h></span></span>
|
|
<a id='x1-31038r16'></a><span class='ecrm-0500'>16</span><span id='textcolor450'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor451'><span class='ectt-0800'><linux/uaccess.h> /* for get_user and put_user */</span></span>
|
|
<a id='x1-31040r17'></a><span class='ecrm-0500'>17</span><span id='textcolor452'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor453'><span class='ectt-0800'><linux/version.h></span></span>
|
|
<a id='x1-31042r18'></a><span class='ecrm-0500'>18</span>
|
|
<a id='x1-31044r19'></a><span class='ecrm-0500'>19</span><span id='textcolor454'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor455'><span class='ectt-0800'><asm/errno.h></span></span>
|
|
<a id='x1-31046r20'></a><span class='ecrm-0500'>20</span>
|
|
<a id='x1-31048r21'></a><span class='ecrm-0500'>21</span><span id='textcolor456'><span class='ectt-0800'>/* Prototypes - this would normally go in a .h file */</span></span>
|
|
<a id='x1-31050r22'></a><span class='ecrm-0500'>22</span><span id='textcolor457'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor458'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> device_open(</span><span id='textcolor459'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> inode *, </span><span id='textcolor460'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *);</span>
|
|
<a id='x1-31052r23'></a><span class='ecrm-0500'>23</span><span id='textcolor461'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor462'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> device_release(</span><span id='textcolor463'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> inode *, </span><span id='textcolor464'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *);</span>
|
|
<a id='x1-31054r24'></a><span class='ecrm-0500'>24</span><span id='textcolor465'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor466'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> device_read(</span><span id='textcolor467'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *, </span><span id='textcolor468'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *, </span><span id='textcolor469'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'>, loff_t *);</span>
|
|
<a id='x1-31056r25'></a><span class='ecrm-0500'>25</span><span id='textcolor470'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor471'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> device_write(</span><span id='textcolor472'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *, </span><span id='textcolor473'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor474'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *, </span><span id='textcolor475'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'>,</span>
|
|
<a id='x1-31058r26'></a><span class='ecrm-0500'>26</span><span class='ectt-0800'> loff_t *);</span>
|
|
<a id='x1-31060r27'></a><span class='ecrm-0500'>27</span>
|
|
<a id='x1-31062r28'></a><span class='ecrm-0500'>28</span><span id='textcolor476'><span class='ectt-0800'>#define SUCCESS 0</span></span>
|
|
<a id='x1-31064r29'></a><span class='ecrm-0500'>29</span><span id='textcolor477'><span class='ectt-0800'>#define DEVICE_NAME "chardev" </span></span><span id='textcolor478'><span class='ectt-0800'>/* Dev name as it appears in /proc/devices */</span></span>
|
|
<a id='x1-31066r30'></a><span class='ecrm-0500'>30</span><span id='textcolor479'><span class='ectt-0800'>#define BUF_LEN 80 </span></span><span id='textcolor480'><span class='ectt-0800'>/* Max length of the message from the device */</span></span>
|
|
<a id='x1-31068r31'></a><span class='ecrm-0500'>31</span>
|
|
<a id='x1-31070r32'></a><span class='ecrm-0500'>32</span><span id='textcolor481'><span class='ectt-0800'>/* Global variables are declared as static, so are global within the file. */</span></span>
|
|
<a id='x1-31072r33'></a><span class='ecrm-0500'>33</span>
|
|
<a id='x1-31074r34'></a><span class='ecrm-0500'>34</span><span id='textcolor482'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor483'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> major; </span><span id='textcolor484'><span class='ectt-0800'>/* major number assigned to our device driver */</span></span>
|
|
<a id='x1-31076r35'></a><span class='ecrm-0500'>35</span>
|
|
<a id='x1-31078r36'></a><span class='ecrm-0500'>36</span><span id='textcolor485'><span class='ectt-0800'>enum</span></span><span class='ectt-0800'> {</span>
|
|
<a id='x1-31080r37'></a><span class='ecrm-0500'>37</span><span class='ectt-0800'> CDEV_NOT_USED = 0,</span>
|
|
<a id='x1-31082r38'></a><span class='ecrm-0500'>38</span><span class='ectt-0800'> CDEV_EXCLUSIVE_OPEN = 1,</span>
|
|
<a id='x1-31084r39'></a><span class='ecrm-0500'>39</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-31086r40'></a><span class='ecrm-0500'>40</span>
|
|
<a id='x1-31088r41'></a><span class='ecrm-0500'>41</span><span id='textcolor486'><span class='ectt-0800'>/* Is device open? Used to prevent multiple access to device */</span></span>
|
|
<a id='x1-31090r42'></a><span class='ecrm-0500'>42</span><span id='textcolor487'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> atomic_t already_open = ATOMIC_INIT(CDEV_NOT_USED);</span>
|
|
<a id='x1-31092r43'></a><span class='ecrm-0500'>43</span>
|
|
<a id='x1-31094r44'></a><span class='ecrm-0500'>44</span><span id='textcolor488'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor489'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> msg[BUF_LEN + 1]; </span><span id='textcolor490'><span class='ectt-0800'>/* The msg the device will give when asked */</span></span>
|
|
<a id='x1-31096r45'></a><span class='ecrm-0500'>45</span>
|
|
<a id='x1-31098r46'></a><span class='ecrm-0500'>46</span><span id='textcolor491'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor492'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> class *cls;</span>
|
|
<a id='x1-31100r47'></a><span class='ecrm-0500'>47</span>
|
|
<a id='x1-31102r48'></a><span class='ecrm-0500'>48</span><span id='textcolor493'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor494'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file_operations chardev_fops = {</span>
|
|
<a id='x1-31104r49'></a><span class='ecrm-0500'>49</span><span class='ectt-0800'> .read = device_read,</span>
|
|
<a id='x1-31106r50'></a><span class='ecrm-0500'>50</span><span class='ectt-0800'> .write = device_write,</span>
|
|
<a id='x1-31108r51'></a><span class='ecrm-0500'>51</span><span class='ectt-0800'> .open = device_open,</span>
|
|
<a id='x1-31110r52'></a><span class='ecrm-0500'>52</span><span class='ectt-0800'> .release = device_release,</span>
|
|
<a id='x1-31112r53'></a><span class='ecrm-0500'>53</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-31114r54'></a><span class='ecrm-0500'>54</span>
|
|
<a id='x1-31116r55'></a><span class='ecrm-0500'>55</span><span id='textcolor495'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor496'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __init chardev_init(</span><span id='textcolor497'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-31118r56'></a><span class='ecrm-0500'>56</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-31120r57'></a><span class='ecrm-0500'>57</span><span class='ectt-0800'> major = register_chrdev(0, DEVICE_NAME, &chardev_fops);</span>
|
|
<a id='x1-31122r58'></a><span class='ecrm-0500'>58</span>
|
|
<a id='x1-31124r59'></a><span class='ecrm-0500'>59</span><span class='ectt-0800'> </span><span id='textcolor498'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (major < 0) {</span>
|
|
<a id='x1-31126r60'></a><span class='ecrm-0500'>60</span><span class='ectt-0800'> pr_alert(</span><span id='textcolor499'><span class='ectt-0800'>"Registering char device failed with %d</span></span><span id='textcolor500'><span class='ectt-0800'>\n</span></span><span id='textcolor501'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, major);</span>
|
|
<a id='x1-31128r61'></a><span class='ecrm-0500'>61</span><span class='ectt-0800'> </span><span id='textcolor502'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> major;</span>
|
|
<a id='x1-31130r62'></a><span class='ecrm-0500'>62</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-31132r63'></a><span class='ecrm-0500'>63</span>
|
|
<a id='x1-31134r64'></a><span class='ecrm-0500'>64</span><span class='ectt-0800'> pr_info(</span><span id='textcolor503'><span class='ectt-0800'>"I was assigned major number %d.</span></span><span id='textcolor504'><span class='ectt-0800'>\n</span></span><span id='textcolor505'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, major);</span>
|
|
<a id='x1-31136r65'></a><span class='ecrm-0500'>65</span>
|
|
<a id='x1-31138r66'></a><span class='ecrm-0500'>66</span><span id='textcolor506'><span class='ectt-0800'>#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0)</span></span>
|
|
<a id='x1-31140r67'></a><span class='ecrm-0500'>67</span><span class='ectt-0800'> cls = class_create(DEVICE_NAME);</span>
|
|
<a id='x1-31142r68'></a><span class='ecrm-0500'>68</span><span id='textcolor507'><span class='ectt-0800'>#else</span></span>
|
|
<a id='x1-31144r69'></a><span class='ecrm-0500'>69</span><span class='ectt-0800'> cls = class_create(THIS_MODULE, DEVICE_NAME);</span>
|
|
<a id='x1-31146r70'></a><span class='ecrm-0500'>70</span><span id='textcolor508'><span class='ectt-0800'>#endif</span></span>
|
|
<a id='x1-31148r71'></a><span class='ecrm-0500'>71</span><span class='ectt-0800'> device_create(cls, NULL, MKDEV(major, 0), NULL, DEVICE_NAME);</span>
|
|
<a id='x1-31150r72'></a><span class='ecrm-0500'>72</span>
|
|
<a id='x1-31152r73'></a><span class='ecrm-0500'>73</span><span class='ectt-0800'> pr_info(</span><span id='textcolor509'><span class='ectt-0800'>"Device created on /dev/%s</span></span><span id='textcolor510'><span class='ectt-0800'>\n</span></span><span id='textcolor511'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, DEVICE_NAME);</span>
|
|
<a id='x1-31154r74'></a><span class='ecrm-0500'>74</span>
|
|
<a id='x1-31156r75'></a><span class='ecrm-0500'>75</span><span class='ectt-0800'> </span><span id='textcolor512'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> SUCCESS;</span>
|
|
<a id='x1-31158r76'></a><span class='ecrm-0500'>76</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-31160r77'></a><span class='ecrm-0500'>77</span>
|
|
<a id='x1-31162r78'></a><span class='ecrm-0500'>78</span><span id='textcolor513'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor514'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> __exit chardev_exit(</span><span id='textcolor515'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-31164r79'></a><span class='ecrm-0500'>79</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-31166r80'></a><span class='ecrm-0500'>80</span><span class='ectt-0800'> device_destroy(cls, MKDEV(major, 0));</span>
|
|
<a id='x1-31168r81'></a><span class='ecrm-0500'>81</span><span class='ectt-0800'> class_destroy(cls);</span>
|
|
<a id='x1-31170r82'></a><span class='ecrm-0500'>82</span>
|
|
<a id='x1-31172r83'></a><span class='ecrm-0500'>83</span><span class='ectt-0800'> </span><span id='textcolor516'><span class='ectt-0800'>/* Unregister the device */</span></span>
|
|
<a id='x1-31174r84'></a><span class='ecrm-0500'>84</span><span class='ectt-0800'> unregister_chrdev(major, DEVICE_NAME);</span>
|
|
<a id='x1-31176r85'></a><span class='ecrm-0500'>85</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-31178r86'></a><span class='ecrm-0500'>86</span>
|
|
<a id='x1-31180r87'></a><span class='ecrm-0500'>87</span><span id='textcolor517'><span class='ectt-0800'>/* Methods */</span></span>
|
|
<a id='x1-31182r88'></a><span class='ecrm-0500'>88</span>
|
|
<a id='x1-31184r89'></a><span class='ecrm-0500'>89</span><span id='textcolor518'><span class='ectt-0800'>/* Called when a process tries to open the device file, like</span></span>
|
|
<a id='x1-31186r90'></a><span class='ecrm-0500'>90</span><span id='textcolor519'><span class='ectt-0800'> * "sudo cat /dev/chardev"</span></span>
|
|
<a id='x1-31188r91'></a><span class='ecrm-0500'>91</span><span id='textcolor520'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-31190r92'></a><span class='ecrm-0500'>92</span><span id='textcolor521'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor522'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> device_open(</span><span id='textcolor523'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> inode *inode, </span><span id='textcolor524'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file)</span>
|
|
<a id='x1-31192r93'></a><span class='ecrm-0500'>93</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-31194r94'></a><span class='ecrm-0500'>94</span><span class='ectt-0800'> </span><span id='textcolor525'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor526'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> counter = 0;</span>
|
|
<a id='x1-31196r95'></a><span class='ecrm-0500'>95</span>
|
|
<a id='x1-31198r96'></a><span class='ecrm-0500'>96</span><span class='ectt-0800'> </span><span id='textcolor527'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (atomic_cmpxchg(&already_open, CDEV_NOT_USED, CDEV_EXCLUSIVE_OPEN))</span>
|
|
<a id='x1-31200r97'></a><span class='ecrm-0500'>97</span><span class='ectt-0800'> </span><span id='textcolor528'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -EBUSY;</span>
|
|
<a id='x1-31202r98'></a><span class='ecrm-0500'>98</span>
|
|
<a id='x1-31204r99'></a><span class='ecrm-0500'>99</span><span class='ectt-0800'> sprintf(msg, </span><span id='textcolor529'><span class='ectt-0800'>"I already told you %d times Hello world!</span></span><span id='textcolor530'><span class='ectt-0800'>\n</span></span><span id='textcolor531'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, counter++);</span>
|
|
<a id='x1-31206r100'></a><span class='ecrm-0500'>100</span><span class='ectt-0800'> try_module_get(THIS_MODULE);</span>
|
|
<a id='x1-31208r101'></a><span class='ecrm-0500'>101</span>
|
|
<a id='x1-31210r102'></a><span class='ecrm-0500'>102</span><span class='ectt-0800'> </span><span id='textcolor532'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> SUCCESS;</span>
|
|
<a id='x1-31212r103'></a><span class='ecrm-0500'>103</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-31214r104'></a><span class='ecrm-0500'>104</span>
|
|
<a id='x1-31216r105'></a><span class='ecrm-0500'>105</span><span id='textcolor533'><span class='ectt-0800'>/* Called when a process closes the device file. */</span></span>
|
|
<a id='x1-31218r106'></a><span class='ecrm-0500'>106</span><span id='textcolor534'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor535'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> device_release(</span><span id='textcolor536'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> inode *inode, </span><span id='textcolor537'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file)</span>
|
|
<a id='x1-31220r107'></a><span class='ecrm-0500'>107</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-31222r108'></a><span class='ecrm-0500'>108</span><span class='ectt-0800'> </span><span id='textcolor538'><span class='ectt-0800'>/* We</span><span class='tctt-0800'>'</span><span class='ectt-0800'>re now ready for our next caller */</span></span>
|
|
<a id='x1-31224r109'></a><span class='ecrm-0500'>109</span><span class='ectt-0800'> atomic_set(&already_open, CDEV_NOT_USED);</span>
|
|
<a id='x1-31226r110'></a><span class='ecrm-0500'>110</span>
|
|
<a id='x1-31228r111'></a><span class='ecrm-0500'>111</span><span class='ectt-0800'> </span><span id='textcolor539'><span class='ectt-0800'>/* Decrement the usage count, or else once you opened the file, you will</span></span>
|
|
<a id='x1-31230r112'></a><span class='ecrm-0500'>112</span><span id='textcolor540'><span class='ectt-0800'> * never get rid of the module.</span></span>
|
|
<a id='x1-31232r113'></a><span class='ecrm-0500'>113</span><span id='textcolor541'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-31234r114'></a><span class='ecrm-0500'>114</span><span class='ectt-0800'> module_put(THIS_MODULE);</span>
|
|
<a id='x1-31236r115'></a><span class='ecrm-0500'>115</span>
|
|
<a id='x1-31238r116'></a><span class='ecrm-0500'>116</span><span class='ectt-0800'> </span><span id='textcolor542'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> SUCCESS;</span>
|
|
<a id='x1-31240r117'></a><span class='ecrm-0500'>117</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-31242r118'></a><span class='ecrm-0500'>118</span>
|
|
<a id='x1-31244r119'></a><span class='ecrm-0500'>119</span><span id='textcolor543'><span class='ectt-0800'>/* Called when a process, which already opened the dev file, attempts to</span></span>
|
|
<a id='x1-31246r120'></a><span class='ecrm-0500'>120</span><span id='textcolor544'><span class='ectt-0800'> * read from it.</span></span>
|
|
<a id='x1-31248r121'></a><span class='ecrm-0500'>121</span><span id='textcolor545'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-31250r122'></a><span class='ecrm-0500'>122</span><span id='textcolor546'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor547'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> device_read(</span><span id='textcolor548'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *filp, </span><span id='textcolor549'><span class='ectt-0800'>/* see include/linux/fs.h */</span></span>
|
|
<a id='x1-31252r123'></a><span class='ecrm-0500'>123</span><span class='ectt-0800'> </span><span id='textcolor550'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *buffer, </span><span id='textcolor551'><span class='ectt-0800'>/* buffer to fill with data */</span></span>
|
|
<a id='x1-31254r124'></a><span class='ecrm-0500'>124</span><span class='ectt-0800'> </span><span id='textcolor552'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'> length, </span><span id='textcolor553'><span class='ectt-0800'>/* length of the buffer */</span></span>
|
|
<a id='x1-31256r125'></a><span class='ecrm-0500'>125</span><span class='ectt-0800'> loff_t *offset)</span>
|
|
<a id='x1-31258r126'></a><span class='ecrm-0500'>126</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-31260r127'></a><span class='ecrm-0500'>127</span><span class='ectt-0800'> </span><span id='textcolor554'><span class='ectt-0800'>/* Number of bytes actually written to the buffer */</span></span>
|
|
<a id='x1-31262r128'></a><span class='ecrm-0500'>128</span><span class='ectt-0800'> </span><span id='textcolor555'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> bytes_read = 0;</span>
|
|
<a id='x1-31264r129'></a><span class='ecrm-0500'>129</span><span class='ectt-0800'> </span><span id='textcolor556'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor557'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *msg_ptr = msg;</span>
|
|
<a id='x1-31266r130'></a><span class='ecrm-0500'>130</span>
|
|
<a id='x1-31268r131'></a><span class='ecrm-0500'>131</span><span class='ectt-0800'> </span><span id='textcolor558'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (!*(msg_ptr + *offset)) { </span><span id='textcolor559'><span class='ectt-0800'>/* we are at the end of message */</span></span>
|
|
<a id='x1-31270r132'></a><span class='ecrm-0500'>132</span><span class='ectt-0800'> *offset = 0; </span><span id='textcolor560'><span class='ectt-0800'>/* reset the offset */</span></span>
|
|
<a id='x1-31272r133'></a><span class='ecrm-0500'>133</span><span class='ectt-0800'> </span><span id='textcolor561'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0; </span><span id='textcolor562'><span class='ectt-0800'>/* signify end of file */</span></span>
|
|
<a id='x1-31274r134'></a><span class='ecrm-0500'>134</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-31276r135'></a><span class='ecrm-0500'>135</span>
|
|
<a id='x1-31278r136'></a><span class='ecrm-0500'>136</span><span class='ectt-0800'> msg_ptr += *offset;</span>
|
|
<a id='x1-31280r137'></a><span class='ecrm-0500'>137</span>
|
|
<a id='x1-31282r138'></a><span class='ecrm-0500'>138</span><span class='ectt-0800'> </span><span id='textcolor563'><span class='ectt-0800'>/* Actually put the data into the buffer */</span></span>
|
|
<a id='x1-31284r139'></a><span class='ecrm-0500'>139</span><span class='ectt-0800'> </span><span id='textcolor564'><span class='ectt-0800'>while</span></span><span class='ectt-0800'> (length && *msg_ptr) {</span>
|
|
<a id='x1-31286r140'></a><span class='ecrm-0500'>140</span><span class='ectt-0800'> </span><span id='textcolor565'><span class='ectt-0800'>/* The buffer is in the user data segment, not the kernel</span></span>
|
|
<a id='x1-31288r141'></a><span class='ecrm-0500'>141</span><span id='textcolor566'><span class='ectt-0800'> * segment so "*" assignment won</span><span class='tctt-0800'>'</span><span class='ectt-0800'>t work. We have to use</span></span>
|
|
<a id='x1-31290r142'></a><span class='ecrm-0500'>142</span><span id='textcolor567'><span class='ectt-0800'> * put_user which copies data from the kernel data segment to</span></span>
|
|
<a id='x1-31292r143'></a><span class='ecrm-0500'>143</span><span id='textcolor568'><span class='ectt-0800'> * the user data segment.</span></span>
|
|
<a id='x1-31294r144'></a><span class='ecrm-0500'>144</span><span id='textcolor569'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-31296r145'></a><span class='ecrm-0500'>145</span><span class='ectt-0800'> put_user(*(msg_ptr++), buffer++);</span>
|
|
<a id='x1-31298r146'></a><span class='ecrm-0500'>146</span><span class='ectt-0800'> length--;</span>
|
|
<a id='x1-31300r147'></a><span class='ecrm-0500'>147</span><span class='ectt-0800'> bytes_read++;</span>
|
|
<a id='x1-31302r148'></a><span class='ecrm-0500'>148</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-31304r149'></a><span class='ecrm-0500'>149</span>
|
|
<a id='x1-31306r150'></a><span class='ecrm-0500'>150</span><span class='ectt-0800'> *offset += bytes_read;</span>
|
|
<a id='x1-31308r151'></a><span class='ecrm-0500'>151</span>
|
|
<a id='x1-31310r152'></a><span class='ecrm-0500'>152</span><span class='ectt-0800'> </span><span id='textcolor570'><span class='ectt-0800'>/* Most read functions return the number of bytes put into the buffer. */</span></span>
|
|
<a id='x1-31312r153'></a><span class='ecrm-0500'>153</span><span class='ectt-0800'> </span><span id='textcolor571'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> bytes_read;</span>
|
|
<a id='x1-31314r154'></a><span class='ecrm-0500'>154</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-31316r155'></a><span class='ecrm-0500'>155</span>
|
|
<a id='x1-31318r156'></a><span class='ecrm-0500'>156</span><span id='textcolor572'><span class='ectt-0800'>/* Called when a process writes to dev file: echo "hi" > /dev/hello */</span></span>
|
|
<a id='x1-31320r157'></a><span class='ecrm-0500'>157</span><span id='textcolor573'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor574'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> device_write(</span><span id='textcolor575'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *filp, </span><span id='textcolor576'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor577'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *buff,</span>
|
|
<a id='x1-31322r158'></a><span class='ecrm-0500'>158</span><span class='ectt-0800'> </span><span id='textcolor578'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'> len, loff_t *off)</span>
|
|
<a id='x1-31324r159'></a><span class='ecrm-0500'>159</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-31326r160'></a><span class='ecrm-0500'>160</span><span class='ectt-0800'> pr_alert(</span><span id='textcolor579'><span class='ectt-0800'>"Sorry, this operation is not supported.</span></span><span id='textcolor580'><span class='ectt-0800'>\n</span></span><span id='textcolor581'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-31328r161'></a><span class='ecrm-0500'>161</span><span class='ectt-0800'> </span><span id='textcolor582'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -EINVAL;</span>
|
|
<a id='x1-31330r162'></a><span class='ecrm-0500'>162</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-31332r163'></a><span class='ecrm-0500'>163</span>
|
|
<a id='x1-31334r164'></a><span class='ecrm-0500'>164</span><span class='ectt-0800'>module_init(chardev_init);</span>
|
|
<a id='x1-31336r165'></a><span class='ecrm-0500'>165</span><span class='ectt-0800'>module_exit(chardev_exit);</span>
|
|
<a id='x1-31338r166'></a><span class='ecrm-0500'>166</span>
|
|
<a id='x1-31340r167'></a><span class='ecrm-0500'>167</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor583'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span></pre>
|
|
<!-- l. 1128 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='writing-modules-for-multiple-kernel-versions'><span class='titlemark'>6.6 </span> <a id='x1-320006.6'></a>Writing Modules for Multiple Kernel Versions</h4>
|
|
<!-- l. 1130 --><p class='noindent'>The system calls, which are the major interface the kernel shows to the processes,
|
|
generally stay the same across versions. A new system call may be added, but
|
|
usually the old ones will behave exactly like they used to. This is necessary for
|
|
backward compatibility – a new kernel version is not supposed to break regular
|
|
processes. In most cases, the device files will also remain the same. On the other
|
|
hand, the internal interfaces within the kernel can and do change between
|
|
versions.
|
|
</p><!-- l. 1135 --><p class='indent'> There are differences between different kernel versions, and if you want
|
|
to support multiple kernel versions, you will find yourself having to code
|
|
conditional compilation directives. The way to do this to compare the macro
|
|
<code> <span class='ectt-1000'>LINUX_VERSION_CODE</span>
|
|
</code> to the macro <code> <span class='ectt-1000'>KERNEL_VERSION</span>
|
|
</code>. In version <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>a.b.c</span></span></span> of the kernel, the value of this macro would be <img alt='216a+ 28b+ c ' class='math' src='lkmpg-for-ht0x.svg' />.
|
|
</p><!-- l. 1139 --><p class='noindent'>
|
|
</p>
|
|
<h3 class='sectionHead' id='the-proc-file-system'><span class='titlemark'>7 </span> <a id='x1-330007'></a>The /proc File System</h3>
|
|
<!-- l. 1141 --><p class='noindent'>In Linux, there is an additional mechanism for the kernel and kernel modules to send
|
|
information to processes — the <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc</span></span></span> file system. Originally designed to allow easy
|
|
access to information about processes (hence the name), it is now used by every bit
|
|
of the kernel which has something interesting to report, such as <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc/modules</span></span></span>
|
|
which provides the list of modules and <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc/meminfo</span></span></span> which gathers memory usage
|
|
statistics.
|
|
</p><!-- l. 1144 --><p class='indent'> The method to use the proc file system is very similar to the one used with device
|
|
drivers — a structure is created with all the information needed for the <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc</span></span></span> file,
|
|
including pointers to any handler functions (in our case there is only one, the
|
|
one called when somebody attempts to read from the <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc</span></span></span> file). Then,
|
|
<code> <span class='ectt-1000'>init_module</span>
|
|
</code> registers the structure with the kernel and
|
|
<code> <span class='ectt-1000'>cleanup_module</span>
|
|
</code> unregisters it.
|
|
|
|
|
|
|
|
</p><!-- l. 1147 --><p class='indent'> Normal file systems are located on a disk, rather than just in memory (which is
|
|
where <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc</span></span></span> is), and in that case the index-node (inode for short) number
|
|
is a pointer to a disk location where the file’s inode is located. The inode
|
|
contains information about the file, for example the file’s permissions, together
|
|
with a pointer to the disk location or locations where the file’s data can be
|
|
found.
|
|
</p><!-- l. 1150 --><p class='indent'> Because we don’t get called when the file is opened or closed, there’s nowhere for
|
|
us to put <code> <span class='ectt-1000'>try_module_get</span>
|
|
</code> and <code> <span class='ectt-1000'>module_put</span>
|
|
</code> in this module, and if the file is opened and then the module is removed, there’s no
|
|
way to avoid the consequences.
|
|
</p><!-- l. 1152 --><p class='indent'> Here a simple example showing how to use a <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc</span></span></span> file. This is the HelloWorld for
|
|
the <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc</span></span></span> filesystem. There are three parts: create the file <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc/helloworld</span></span></span> in the
|
|
function <code> <span class='ectt-1000'>init_module</span>
|
|
</code>, return a value (and a buffer) when the file <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc/helloworld</span></span></span> is read in the callback
|
|
function <code> <span class='ectt-1000'>procfile_read</span>
|
|
</code>, and delete the file <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc/helloworld</span></span></span> in the function
|
|
<code> <span class='ectt-1000'>cleanup_module</span>
|
|
</code>.
|
|
</p><!-- l. 1156 --><p class='indent'> The <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc/helloworld</span></span></span> is created when the module is loaded with the function
|
|
<code> <span class='ectt-1000'>proc_create</span>
|
|
</code>. The return value is a pointer to <code> <span id='textcolor584'><span class='ectt-1000'>struct</span></span><span class='ectt-1000'> proc_dir_entry</span>
|
|
</code>, and it will be used to configure the file <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc/helloworld</span></span></span> (for example, the owner
|
|
of this file). A null return value means that the creation has failed.
|
|
</p><!-- l. 1160 --><p class='indent'> Every time the file <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc/helloworld</span></span></span> is read, the function
|
|
<code> <span class='ectt-1000'>procfile_read</span>
|
|
</code> is called. Two parameters of this function are very important: the buffer
|
|
(the second parameter) and the offset (the fourth one). The content of the
|
|
buffer will be returned to the application which read it (for example the
|
|
<code> <span class='ectt-1000'>cat</span>
|
|
</code> command). The offset is the current position in the file. If the return value of the
|
|
function is not null, then this function is called again. So be careful with this
|
|
function, if it never returns zero, the read function is called endlessly.
|
|
|
|
|
|
|
|
</p>
|
|
<pre class='verbatim' id='verbatim-15'>
|
|
$ cat /proc/helloworld
|
|
HelloWorld!
|
|
</pre>
|
|
<!-- l. 1170 --><p class='nopar'>
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb47'><a id='x1-33013r1'></a><span class='ecrm-0500'>1</span><span id='textcolor585'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-33015r2'></a><span class='ecrm-0500'>2</span><span id='textcolor586'><span class='ectt-0800'> * procfs1.c</span></span>
|
|
<a id='x1-33017r3'></a><span class='ecrm-0500'>3</span><span id='textcolor587'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-33019r4'></a><span class='ecrm-0500'>4</span>
|
|
<a id='x1-33021r5'></a><span class='ecrm-0500'>5</span><span id='textcolor588'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor589'><span class='ectt-0800'><linux/kernel.h></span></span>
|
|
<a id='x1-33023r6'></a><span class='ecrm-0500'>6</span><span id='textcolor590'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor591'><span class='ectt-0800'><linux/module.h></span></span>
|
|
<a id='x1-33025r7'></a><span class='ecrm-0500'>7</span><span id='textcolor592'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor593'><span class='ectt-0800'><linux/proc_fs.h></span></span>
|
|
<a id='x1-33027r8'></a><span class='ecrm-0500'>8</span><span id='textcolor594'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor595'><span class='ectt-0800'><linux/uaccess.h></span></span>
|
|
<a id='x1-33029r9'></a><span class='ecrm-0500'>9</span><span id='textcolor596'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor597'><span class='ectt-0800'><linux/version.h></span></span>
|
|
<a id='x1-33031r10'></a><span class='ecrm-0500'>10</span>
|
|
<a id='x1-33033r11'></a><span class='ecrm-0500'>11</span><span id='textcolor598'><span class='ectt-0800'>#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)</span></span>
|
|
<a id='x1-33035r12'></a><span class='ecrm-0500'>12</span><span id='textcolor599'><span class='ectt-0800'>#define HAVE_PROC_OPS</span></span>
|
|
<a id='x1-33037r13'></a><span class='ecrm-0500'>13</span><span id='textcolor600'><span class='ectt-0800'>#endif</span></span>
|
|
<a id='x1-33039r14'></a><span class='ecrm-0500'>14</span>
|
|
<a id='x1-33041r15'></a><span class='ecrm-0500'>15</span><span id='textcolor601'><span class='ectt-0800'>#define procfs_name "helloworld"</span></span>
|
|
<a id='x1-33043r16'></a><span class='ecrm-0500'>16</span>
|
|
<a id='x1-33045r17'></a><span class='ecrm-0500'>17</span><span id='textcolor602'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor603'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> proc_dir_entry *our_proc_file;</span>
|
|
<a id='x1-33047r18'></a><span class='ecrm-0500'>18</span>
|
|
<a id='x1-33049r19'></a><span class='ecrm-0500'>19</span><span id='textcolor604'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor605'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> procfile_read(</span><span id='textcolor606'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file_pointer, </span><span id='textcolor607'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *buffer,</span>
|
|
<a id='x1-33051r20'></a><span class='ecrm-0500'>20</span><span class='ectt-0800'> </span><span id='textcolor608'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'> buffer_length, loff_t *offset)</span>
|
|
<a id='x1-33053r21'></a><span class='ecrm-0500'>21</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-33055r22'></a><span class='ecrm-0500'>22</span><span class='ectt-0800'> </span><span id='textcolor609'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> s[13] = </span><span id='textcolor610'><span class='ectt-0800'>"HelloWorld!</span></span><span id='textcolor611'><span class='ectt-0800'>\n</span></span><span id='textcolor612'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>;</span>
|
|
<a id='x1-33057r23'></a><span class='ecrm-0500'>23</span><span class='ectt-0800'> </span><span id='textcolor613'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> len = </span><span id='textcolor614'><span class='ectt-0800'>sizeof</span></span><span class='ectt-0800'>(s);</span>
|
|
<a id='x1-33059r24'></a><span class='ecrm-0500'>24</span><span class='ectt-0800'> </span><span id='textcolor615'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> ret = len;</span>
|
|
<a id='x1-33061r25'></a><span class='ecrm-0500'>25</span>
|
|
<a id='x1-33063r26'></a><span class='ecrm-0500'>26</span><span class='ectt-0800'> </span><span id='textcolor616'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (*offset >= len || copy_to_user(buffer, s, len)) {</span>
|
|
<a id='x1-33065r27'></a><span class='ecrm-0500'>27</span><span class='ectt-0800'> pr_info(</span><span id='textcolor617'><span class='ectt-0800'>"copy_to_user failed</span></span><span id='textcolor618'><span class='ectt-0800'>\n</span></span><span id='textcolor619'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-33067r28'></a><span class='ecrm-0500'>28</span><span class='ectt-0800'> ret = 0;</span>
|
|
<a id='x1-33069r29'></a><span class='ecrm-0500'>29</span><span class='ectt-0800'> } </span><span id='textcolor620'><span class='ectt-0800'>else</span></span><span class='ectt-0800'> {</span>
|
|
<a id='x1-33071r30'></a><span class='ecrm-0500'>30</span><span class='ectt-0800'> pr_info(</span><span id='textcolor621'><span class='ectt-0800'>"procfile read %s</span></span><span id='textcolor622'><span class='ectt-0800'>\n</span></span><span id='textcolor623'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, file_pointer->f_path.dentry->d_name.name);</span>
|
|
<a id='x1-33073r31'></a><span class='ecrm-0500'>31</span><span class='ectt-0800'> *offset += len;</span>
|
|
<a id='x1-33075r32'></a><span class='ecrm-0500'>32</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-33077r33'></a><span class='ecrm-0500'>33</span>
|
|
<a id='x1-33079r34'></a><span class='ecrm-0500'>34</span><span class='ectt-0800'> </span><span id='textcolor624'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> ret;</span>
|
|
<a id='x1-33081r35'></a><span class='ecrm-0500'>35</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-33083r36'></a><span class='ecrm-0500'>36</span>
|
|
<a id='x1-33085r37'></a><span class='ecrm-0500'>37</span><span id='textcolor625'><span class='ectt-0800'>#ifdef HAVE_PROC_OPS</span></span>
|
|
<a id='x1-33087r38'></a><span class='ecrm-0500'>38</span><span id='textcolor626'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor627'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor628'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> proc_ops proc_file_fops = {</span>
|
|
<a id='x1-33089r39'></a><span class='ecrm-0500'>39</span><span class='ectt-0800'> .proc_read = procfile_read,</span>
|
|
<a id='x1-33091r40'></a><span class='ecrm-0500'>40</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-33093r41'></a><span class='ecrm-0500'>41</span><span id='textcolor629'><span class='ectt-0800'>#else</span></span>
|
|
<a id='x1-33095r42'></a><span class='ecrm-0500'>42</span><span id='textcolor630'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor631'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor632'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file_operations proc_file_fops = {</span>
|
|
<a id='x1-33097r43'></a><span class='ecrm-0500'>43</span><span class='ectt-0800'> .read = procfile_read,</span>
|
|
<a id='x1-33099r44'></a><span class='ecrm-0500'>44</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-33101r45'></a><span class='ecrm-0500'>45</span><span id='textcolor633'><span class='ectt-0800'>#endif</span></span>
|
|
<a id='x1-33103r46'></a><span class='ecrm-0500'>46</span>
|
|
<a id='x1-33105r47'></a><span class='ecrm-0500'>47</span><span id='textcolor634'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor635'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __init procfs1_init(</span><span id='textcolor636'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-33107r48'></a><span class='ecrm-0500'>48</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-33109r49'></a><span class='ecrm-0500'>49</span><span class='ectt-0800'> our_proc_file = proc_create(procfs_name, 0644, NULL, &proc_file_fops);</span>
|
|
<a id='x1-33111r50'></a><span class='ecrm-0500'>50</span><span class='ectt-0800'> </span><span id='textcolor637'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (NULL == our_proc_file) {</span>
|
|
<a id='x1-33113r51'></a><span class='ecrm-0500'>51</span><span class='ectt-0800'> proc_remove(our_proc_file);</span>
|
|
<a id='x1-33115r52'></a><span class='ecrm-0500'>52</span><span class='ectt-0800'> pr_alert(</span><span id='textcolor638'><span class='ectt-0800'>"Error:Could not initialize /proc/%s</span></span><span id='textcolor639'><span class='ectt-0800'>\n</span></span><span id='textcolor640'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, procfs_name);</span>
|
|
<a id='x1-33117r53'></a><span class='ecrm-0500'>53</span><span class='ectt-0800'> </span><span id='textcolor641'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -ENOMEM;</span>
|
|
<a id='x1-33119r54'></a><span class='ecrm-0500'>54</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-33121r55'></a><span class='ecrm-0500'>55</span>
|
|
<a id='x1-33123r56'></a><span class='ecrm-0500'>56</span><span class='ectt-0800'> pr_info(</span><span id='textcolor642'><span class='ectt-0800'>"/proc/%s created</span></span><span id='textcolor643'><span class='ectt-0800'>\n</span></span><span id='textcolor644'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, procfs_name);</span>
|
|
<a id='x1-33125r57'></a><span class='ecrm-0500'>57</span><span class='ectt-0800'> </span><span id='textcolor645'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-33127r58'></a><span class='ecrm-0500'>58</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-33129r59'></a><span class='ecrm-0500'>59</span>
|
|
<a id='x1-33131r60'></a><span class='ecrm-0500'>60</span><span id='textcolor646'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor647'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> __exit procfs1_exit(</span><span id='textcolor648'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-33133r61'></a><span class='ecrm-0500'>61</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-33135r62'></a><span class='ecrm-0500'>62</span><span class='ectt-0800'> proc_remove(our_proc_file);</span>
|
|
<a id='x1-33137r63'></a><span class='ecrm-0500'>63</span><span class='ectt-0800'> pr_info(</span><span id='textcolor649'><span class='ectt-0800'>"/proc/%s removed</span></span><span id='textcolor650'><span class='ectt-0800'>\n</span></span><span id='textcolor651'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, procfs_name);</span>
|
|
<a id='x1-33139r64'></a><span class='ecrm-0500'>64</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-33141r65'></a><span class='ecrm-0500'>65</span>
|
|
<a id='x1-33143r66'></a><span class='ecrm-0500'>66</span><span class='ectt-0800'>module_init(procfs1_init);</span>
|
|
<a id='x1-33145r67'></a><span class='ecrm-0500'>67</span><span class='ectt-0800'>module_exit(procfs1_exit);</span>
|
|
<a id='x1-33147r68'></a><span class='ecrm-0500'>68</span>
|
|
<a id='x1-33149r69'></a><span class='ecrm-0500'>69</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor652'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span></pre>
|
|
<!-- l. 1174 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='the-procops-structure'><span class='titlemark'>7.1 </span> <a id='x1-340007.1'></a>The proc_ops Structure</h4>
|
|
<!-- l. 1176 --><p class='noindent'>The <code> <span class='ectt-1000'>proc_ops</span>
|
|
</code> structure is defined in <a href='https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/include/linux/proc_fs.h'>include/linux/proc_fs.h</a> in Linux v5.6+. In older kernels, it
|
|
used <code> <span class='ectt-1000'>file_operations</span>
|
|
</code> for custom hooks in <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc</span></span></span> file system, but it contains some
|
|
members that are unnecessary in VFS, and every time VFS expands
|
|
<code> <span class='ectt-1000'>file_operations</span>
|
|
</code> set, <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc</span></span></span> code comes bloated. On the other hand, not only the space,
|
|
but also some operations were saved by this structure to improve its
|
|
performance. For example, the file which never disappears in <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc</span></span></span> can set the
|
|
<code> <span class='ectt-1000'>proc_flag</span>
|
|
</code> as <code> <span class='ectt-1000'>PROC_ENTRY_PERMANENT</span>
|
|
</code> to save 2 atomic ops, 1 allocation, 1 free in per open/read/close sequence.
|
|
</p><!-- l. 1181 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='read-and-write-a-proc-file'><span class='titlemark'>7.2 </span> <a id='x1-350007.2'></a>Read and Write a /proc File</h4>
|
|
<!-- l. 1183 --><p class='noindent'>We have seen a very simple example for a <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc</span></span></span> file where we only read
|
|
the file <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc/helloworld</span></span></span>. It is also possible to write in a <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc</span></span></span> file. It
|
|
works the same way as read, a function is called when the <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc</span></span></span> file
|
|
is written. But there is a little difference with read, data comes from
|
|
user, so you have to import data from user space to kernel space (with
|
|
<code> <span class='ectt-1000'>copy_from_user</span>
|
|
</code> or <code> <span class='ectt-1000'>get_user</span>
|
|
</code>)
|
|
</p><!-- l. 1188 --><p class='indent'> The reason for <code> <span class='ectt-1000'>copy_from_user</span>
|
|
</code> or <code> <span class='ectt-1000'>get_user</span>
|
|
</code> is that Linux memory (on Intel architecture, it may be different under some
|
|
|
|
|
|
|
|
other processors) is segmented. This means that a pointer, by itself, does
|
|
not reference a unique location in memory, only a location in a memory
|
|
segment, and you need to know which memory segment it is to be able to use
|
|
it. There is one memory segment for the kernel, and one for each of the
|
|
processes.
|
|
</p><!-- l. 1192 --><p class='indent'> The only memory segment accessible to a process is its own, so when
|
|
writing regular programs to run as processes, there is no need to worry about
|
|
segments. When you write a kernel module, normally you want to access
|
|
the kernel memory segment, which is handled automatically by the system.
|
|
However, when the content of a memory buffer needs to be passed between
|
|
the currently running process and the kernel, the kernel function receives
|
|
a pointer to the memory buffer which is in the process segment. The
|
|
<code> <span class='ectt-1000'>put_user</span>
|
|
</code> and <code> <span class='ectt-1000'>get_user</span>
|
|
</code> macros allow you to access that memory. These functions handle
|
|
only one character, you can handle several characters with
|
|
<code> <span class='ectt-1000'>copy_to_user</span>
|
|
</code> and <code> <span class='ectt-1000'>copy_from_user</span>
|
|
</code>. As the buffer (in read or write function) is in kernel space, for write function you
|
|
need to import data because it comes from user space, but not for the read function
|
|
because data is already in kernel space.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb48'><a id='x1-35010r1'></a><span class='ecrm-0500'>1</span><span id='textcolor653'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-35012r2'></a><span class='ecrm-0500'>2</span><span id='textcolor654'><span class='ectt-0800'> * procfs2.c - create a "file" in /proc</span></span>
|
|
<a id='x1-35014r3'></a><span class='ecrm-0500'>3</span><span id='textcolor655'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-35016r4'></a><span class='ecrm-0500'>4</span>
|
|
<a id='x1-35018r5'></a><span class='ecrm-0500'>5</span><span id='textcolor656'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor657'><span class='ectt-0800'><linux/kernel.h> /* We</span><span class='tctt-0800'>'</span><span class='ectt-0800'>re doing kernel work */</span></span>
|
|
<a id='x1-35020r6'></a><span class='ecrm-0500'>6</span><span id='textcolor658'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor659'><span class='ectt-0800'><linux/module.h> /* Specifically, a module */</span></span>
|
|
<a id='x1-35022r7'></a><span class='ecrm-0500'>7</span><span id='textcolor660'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor661'><span class='ectt-0800'><linux/proc_fs.h> /* Necessary because we use the proc fs */</span></span>
|
|
<a id='x1-35024r8'></a><span class='ecrm-0500'>8</span><span id='textcolor662'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor663'><span class='ectt-0800'><linux/uaccess.h> /* for copy_from_user */</span></span>
|
|
<a id='x1-35026r9'></a><span class='ecrm-0500'>9</span><span id='textcolor664'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor665'><span class='ectt-0800'><linux/version.h></span></span>
|
|
<a id='x1-35028r10'></a><span class='ecrm-0500'>10</span>
|
|
<a id='x1-35030r11'></a><span class='ecrm-0500'>11</span><span id='textcolor666'><span class='ectt-0800'>#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)</span></span>
|
|
<a id='x1-35032r12'></a><span class='ecrm-0500'>12</span><span id='textcolor667'><span class='ectt-0800'>#define HAVE_PROC_OPS</span></span>
|
|
<a id='x1-35034r13'></a><span class='ecrm-0500'>13</span><span id='textcolor668'><span class='ectt-0800'>#endif</span></span>
|
|
<a id='x1-35036r14'></a><span class='ecrm-0500'>14</span>
|
|
<a id='x1-35038r15'></a><span class='ecrm-0500'>15</span><span id='textcolor669'><span class='ectt-0800'>#define PROCFS_MAX_SIZE 1024</span></span>
|
|
<a id='x1-35040r16'></a><span class='ecrm-0500'>16</span><span id='textcolor670'><span class='ectt-0800'>#define PROCFS_NAME "buffer1k"</span></span>
|
|
<a id='x1-35042r17'></a><span class='ecrm-0500'>17</span>
|
|
<a id='x1-35044r18'></a><span class='ecrm-0500'>18</span><span id='textcolor671'><span class='ectt-0800'>/* This structure hold information about the /proc file */</span></span>
|
|
<a id='x1-35046r19'></a><span class='ecrm-0500'>19</span><span id='textcolor672'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor673'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> proc_dir_entry *our_proc_file;</span>
|
|
<a id='x1-35048r20'></a><span class='ecrm-0500'>20</span>
|
|
<a id='x1-35050r21'></a><span class='ecrm-0500'>21</span><span id='textcolor674'><span class='ectt-0800'>/* The buffer used to store character for this module */</span></span>
|
|
<a id='x1-35052r22'></a><span class='ecrm-0500'>22</span><span id='textcolor675'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor676'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> procfs_buffer[PROCFS_MAX_SIZE];</span>
|
|
<a id='x1-35054r23'></a><span class='ecrm-0500'>23</span>
|
|
<a id='x1-35056r24'></a><span class='ecrm-0500'>24</span><span id='textcolor677'><span class='ectt-0800'>/* The size of the buffer */</span></span>
|
|
<a id='x1-35058r25'></a><span class='ecrm-0500'>25</span><span id='textcolor678'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor679'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor680'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> procfs_buffer_size = 0;</span>
|
|
<a id='x1-35060r26'></a><span class='ecrm-0500'>26</span>
|
|
<a id='x1-35062r27'></a><span class='ecrm-0500'>27</span><span id='textcolor681'><span class='ectt-0800'>/* This function is called then the /proc file is read */</span></span>
|
|
<a id='x1-35064r28'></a><span class='ecrm-0500'>28</span><span id='textcolor682'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor683'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> procfile_read(</span><span id='textcolor684'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file_pointer, </span><span id='textcolor685'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *buffer,</span>
|
|
<a id='x1-35066r29'></a><span class='ecrm-0500'>29</span><span class='ectt-0800'> </span><span id='textcolor686'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'> buffer_length, loff_t *offset)</span>
|
|
<a id='x1-35068r30'></a><span class='ecrm-0500'>30</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-35070r31'></a><span class='ecrm-0500'>31</span><span class='ectt-0800'> </span><span id='textcolor687'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> s[13] = </span><span id='textcolor688'><span class='ectt-0800'>"HelloWorld!</span></span><span id='textcolor689'><span class='ectt-0800'>\n</span></span><span id='textcolor690'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>;</span>
|
|
<a id='x1-35072r32'></a><span class='ecrm-0500'>32</span><span class='ectt-0800'> </span><span id='textcolor691'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> len = </span><span id='textcolor692'><span class='ectt-0800'>sizeof</span></span><span class='ectt-0800'>(s);</span>
|
|
<a id='x1-35074r33'></a><span class='ecrm-0500'>33</span><span class='ectt-0800'> </span><span id='textcolor693'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> ret = len;</span>
|
|
<a id='x1-35076r34'></a><span class='ecrm-0500'>34</span>
|
|
<a id='x1-35078r35'></a><span class='ecrm-0500'>35</span><span class='ectt-0800'> </span><span id='textcolor694'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (*offset >= len || copy_to_user(buffer, s, len)) {</span>
|
|
<a id='x1-35080r36'></a><span class='ecrm-0500'>36</span><span class='ectt-0800'> pr_info(</span><span id='textcolor695'><span class='ectt-0800'>"copy_to_user failed</span></span><span id='textcolor696'><span class='ectt-0800'>\n</span></span><span id='textcolor697'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-35082r37'></a><span class='ecrm-0500'>37</span><span class='ectt-0800'> ret = 0;</span>
|
|
<a id='x1-35084r38'></a><span class='ecrm-0500'>38</span><span class='ectt-0800'> } </span><span id='textcolor698'><span class='ectt-0800'>else</span></span><span class='ectt-0800'> {</span>
|
|
<a id='x1-35086r39'></a><span class='ecrm-0500'>39</span><span class='ectt-0800'> pr_info(</span><span id='textcolor699'><span class='ectt-0800'>"procfile read %s</span></span><span id='textcolor700'><span class='ectt-0800'>\n</span></span><span id='textcolor701'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, file_pointer->f_path.dentry->d_name.name);</span>
|
|
<a id='x1-35088r40'></a><span class='ecrm-0500'>40</span><span class='ectt-0800'> *offset += len;</span>
|
|
<a id='x1-35090r41'></a><span class='ecrm-0500'>41</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-35092r42'></a><span class='ecrm-0500'>42</span>
|
|
<a id='x1-35094r43'></a><span class='ecrm-0500'>43</span><span class='ectt-0800'> </span><span id='textcolor702'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> ret;</span>
|
|
<a id='x1-35096r44'></a><span class='ecrm-0500'>44</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-35098r45'></a><span class='ecrm-0500'>45</span>
|
|
<a id='x1-35100r46'></a><span class='ecrm-0500'>46</span><span id='textcolor703'><span class='ectt-0800'>/* This function is called with the /proc file is written. */</span></span>
|
|
<a id='x1-35102r47'></a><span class='ecrm-0500'>47</span><span id='textcolor704'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor705'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> procfile_write(</span><span id='textcolor706'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file, </span><span id='textcolor707'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor708'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *buff,</span>
|
|
<a id='x1-35104r48'></a><span class='ecrm-0500'>48</span><span class='ectt-0800'> </span><span id='textcolor709'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'> len, loff_t *off)</span>
|
|
<a id='x1-35106r49'></a><span class='ecrm-0500'>49</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-35108r50'></a><span class='ecrm-0500'>50</span><span class='ectt-0800'> procfs_buffer_size = len;</span>
|
|
<a id='x1-35110r51'></a><span class='ecrm-0500'>51</span><span class='ectt-0800'> </span><span id='textcolor710'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (procfs_buffer_size > PROCFS_MAX_SIZE)</span>
|
|
<a id='x1-35112r52'></a><span class='ecrm-0500'>52</span><span class='ectt-0800'> procfs_buffer_size = PROCFS_MAX_SIZE;</span>
|
|
<a id='x1-35114r53'></a><span class='ecrm-0500'>53</span>
|
|
<a id='x1-35116r54'></a><span class='ecrm-0500'>54</span><span class='ectt-0800'> </span><span id='textcolor711'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (copy_from_user(procfs_buffer, buff, procfs_buffer_size))</span>
|
|
<a id='x1-35118r55'></a><span class='ecrm-0500'>55</span><span class='ectt-0800'> </span><span id='textcolor712'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -EFAULT;</span>
|
|
<a id='x1-35120r56'></a><span class='ecrm-0500'>56</span>
|
|
<a id='x1-35122r57'></a><span class='ecrm-0500'>57</span><span class='ectt-0800'> procfs_buffer[procfs_buffer_size & (PROCFS_MAX_SIZE - 1)] = </span><span id='textcolor713'><span class='tctt-0800'>'</span><span class='ectt-0800'>\0</span><span class='tctt-0800'>'</span></span><span class='ectt-0800'>;</span>
|
|
<a id='x1-35124r58'></a><span class='ecrm-0500'>58</span><span class='ectt-0800'> *off += procfs_buffer_size;</span>
|
|
<a id='x1-35126r59'></a><span class='ecrm-0500'>59</span><span class='ectt-0800'> pr_info(</span><span id='textcolor714'><span class='ectt-0800'>"procfile write %s</span></span><span id='textcolor715'><span class='ectt-0800'>\n</span></span><span id='textcolor716'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, procfs_buffer);</span>
|
|
<a id='x1-35128r60'></a><span class='ecrm-0500'>60</span>
|
|
<a id='x1-35130r61'></a><span class='ecrm-0500'>61</span><span class='ectt-0800'> </span><span id='textcolor717'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> procfs_buffer_size;</span>
|
|
<a id='x1-35132r62'></a><span class='ecrm-0500'>62</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-35134r63'></a><span class='ecrm-0500'>63</span>
|
|
<a id='x1-35136r64'></a><span class='ecrm-0500'>64</span><span id='textcolor718'><span class='ectt-0800'>#ifdef HAVE_PROC_OPS</span></span>
|
|
<a id='x1-35138r65'></a><span class='ecrm-0500'>65</span><span id='textcolor719'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor720'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor721'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> proc_ops proc_file_fops = {</span>
|
|
<a id='x1-35140r66'></a><span class='ecrm-0500'>66</span><span class='ectt-0800'> .proc_read = procfile_read,</span>
|
|
<a id='x1-35142r67'></a><span class='ecrm-0500'>67</span><span class='ectt-0800'> .proc_write = procfile_write,</span>
|
|
<a id='x1-35144r68'></a><span class='ecrm-0500'>68</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-35146r69'></a><span class='ecrm-0500'>69</span><span id='textcolor722'><span class='ectt-0800'>#else</span></span>
|
|
<a id='x1-35148r70'></a><span class='ecrm-0500'>70</span><span id='textcolor723'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor724'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor725'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file_operations proc_file_fops = {</span>
|
|
<a id='x1-35150r71'></a><span class='ecrm-0500'>71</span><span class='ectt-0800'> .read = procfile_read,</span>
|
|
<a id='x1-35152r72'></a><span class='ecrm-0500'>72</span><span class='ectt-0800'> .write = procfile_write,</span>
|
|
<a id='x1-35154r73'></a><span class='ecrm-0500'>73</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-35156r74'></a><span class='ecrm-0500'>74</span><span id='textcolor726'><span class='ectt-0800'>#endif</span></span>
|
|
<a id='x1-35158r75'></a><span class='ecrm-0500'>75</span>
|
|
<a id='x1-35160r76'></a><span class='ecrm-0500'>76</span><span id='textcolor727'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor728'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __init procfs2_init(</span><span id='textcolor729'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-35162r77'></a><span class='ecrm-0500'>77</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-35164r78'></a><span class='ecrm-0500'>78</span><span class='ectt-0800'> our_proc_file = proc_create(PROCFS_NAME, 0644, NULL, &proc_file_fops);</span>
|
|
<a id='x1-35166r79'></a><span class='ecrm-0500'>79</span><span class='ectt-0800'> </span><span id='textcolor730'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (NULL == our_proc_file) {</span>
|
|
<a id='x1-35168r80'></a><span class='ecrm-0500'>80</span><span class='ectt-0800'> pr_alert(</span><span id='textcolor731'><span class='ectt-0800'>"Error:Could not initialize /proc/%s</span></span><span id='textcolor732'><span class='ectt-0800'>\n</span></span><span id='textcolor733'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, PROCFS_NAME);</span>
|
|
<a id='x1-35170r81'></a><span class='ecrm-0500'>81</span><span class='ectt-0800'> </span><span id='textcolor734'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -ENOMEM;</span>
|
|
<a id='x1-35172r82'></a><span class='ecrm-0500'>82</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-35174r83'></a><span class='ecrm-0500'>83</span>
|
|
<a id='x1-35176r84'></a><span class='ecrm-0500'>84</span><span class='ectt-0800'> pr_info(</span><span id='textcolor735'><span class='ectt-0800'>"/proc/%s created</span></span><span id='textcolor736'><span class='ectt-0800'>\n</span></span><span id='textcolor737'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, PROCFS_NAME);</span>
|
|
<a id='x1-35178r85'></a><span class='ecrm-0500'>85</span><span class='ectt-0800'> </span><span id='textcolor738'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-35180r86'></a><span class='ecrm-0500'>86</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-35182r87'></a><span class='ecrm-0500'>87</span>
|
|
<a id='x1-35184r88'></a><span class='ecrm-0500'>88</span><span id='textcolor739'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor740'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> __exit procfs2_exit(</span><span id='textcolor741'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-35186r89'></a><span class='ecrm-0500'>89</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-35188r90'></a><span class='ecrm-0500'>90</span><span class='ectt-0800'> proc_remove(our_proc_file);</span>
|
|
<a id='x1-35190r91'></a><span class='ecrm-0500'>91</span><span class='ectt-0800'> pr_info(</span><span id='textcolor742'><span class='ectt-0800'>"/proc/%s removed</span></span><span id='textcolor743'><span class='ectt-0800'>\n</span></span><span id='textcolor744'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, PROCFS_NAME);</span>
|
|
<a id='x1-35192r92'></a><span class='ecrm-0500'>92</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-35194r93'></a><span class='ecrm-0500'>93</span>
|
|
<a id='x1-35196r94'></a><span class='ecrm-0500'>94</span><span class='ectt-0800'>module_init(procfs2_init);</span>
|
|
<a id='x1-35198r95'></a><span class='ecrm-0500'>95</span><span class='ectt-0800'>module_exit(procfs2_exit);</span>
|
|
<a id='x1-35200r96'></a><span class='ecrm-0500'>96</span>
|
|
<a id='x1-35202r97'></a><span class='ecrm-0500'>97</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor745'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span></pre>
|
|
<!-- l. 1201 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='manage-proc-file-with-standard-filesystem'><span class='titlemark'>7.3 </span> <a id='x1-360007.3'></a>Manage /proc file with standard filesystem</h4>
|
|
<!-- l. 1203 --><p class='noindent'>We have seen how to read and write a <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc</span></span></span> file with the <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc</span></span></span> interface. But it is
|
|
also possible to manage <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc</span></span></span> file with inodes. The main concern is to use advanced
|
|
functions, like permissions.
|
|
</p><!-- l. 1207 --><p class='indent'> In Linux, there is a standard mechanism for file system registration.
|
|
Since every file system has to have its own functions to handle inode and file
|
|
operations, there is a special structure to hold pointers to all those functions,
|
|
<code> <span id='textcolor746'><span class='ectt-1000'>struct</span></span><span class='ectt-1000'> inode_operations</span>
|
|
</code>, which includes a pointer to <code> <span id='textcolor747'><span class='ectt-1000'>struct</span></span><span class='ectt-1000'> proc_ops</span>
|
|
</code>.
|
|
</p><!-- l. 1210 --><p class='indent'> The difference between file and inode operations is that file operations deal with
|
|
the file itself whereas inode operations deal with ways of referencing the file, such as
|
|
creating links to it.
|
|
</p><!-- l. 1212 --><p class='indent'> In <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc</span></span></span>, whenever we register a new file, we’re allowed to specify which
|
|
<code> <span id='textcolor748'><span class='ectt-1000'>struct</span></span><span class='ectt-1000'> inode_operations</span>
|
|
</code> will be used to access to it. This is the mechanism we use, a
|
|
<code> <span id='textcolor749'><span class='ectt-1000'>struct</span></span><span class='ectt-1000'> inode_operations</span>
|
|
|
|
|
|
|
|
</code> which includes a pointer to a <code> <span id='textcolor750'><span class='ectt-1000'>struct</span></span><span class='ectt-1000'> proc_ops</span>
|
|
</code> which includes pointers to our <code> <span class='ectt-1000'>procfs_read</span>
|
|
</code> and <code> <span class='ectt-1000'>procfs_write</span>
|
|
</code> functions.
|
|
</p><!-- l. 1215 --><p class='indent'> Another interesting point here is the
|
|
<code> <span class='ectt-1000'>module_permission</span>
|
|
</code> function. This function is called whenever a process tries to do something with the
|
|
<span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc</span></span></span> file, and it can decide whether to allow access or not. Right now it is only
|
|
based on the operation and the uid of the current user (as available in current, a
|
|
pointer to a structure which includes information on the currently running
|
|
process), but it could be based on anything we like, such as what other
|
|
processes are doing with the same file, the time of day, or the last input we
|
|
received.
|
|
</p><!-- l. 1219 --><p class='indent'> It is important to note that the standard roles of read and write are reversed in
|
|
the kernel. Read functions are used for output, whereas write functions are used for
|
|
input. The reason for that is that read and write refer to the user’s point of view — if
|
|
a process reads something from the kernel, then the kernel needs to output it, and
|
|
if a process writes something to the kernel, then the kernel receives it as
|
|
input.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb49'><a id='x1-36010r1'></a><span class='ecrm-0500'>1</span><span id='textcolor751'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-36012r2'></a><span class='ecrm-0500'>2</span><span id='textcolor752'><span class='ectt-0800'> * procfs3.c</span></span>
|
|
<a id='x1-36014r3'></a><span class='ecrm-0500'>3</span><span id='textcolor753'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-36016r4'></a><span class='ecrm-0500'>4</span>
|
|
<a id='x1-36018r5'></a><span class='ecrm-0500'>5</span><span id='textcolor754'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor755'><span class='ectt-0800'><linux/kernel.h></span></span>
|
|
<a id='x1-36020r6'></a><span class='ecrm-0500'>6</span><span id='textcolor756'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor757'><span class='ectt-0800'><linux/module.h></span></span>
|
|
<a id='x1-36022r7'></a><span class='ecrm-0500'>7</span><span id='textcolor758'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor759'><span class='ectt-0800'><linux/proc_fs.h></span></span>
|
|
<a id='x1-36024r8'></a><span class='ecrm-0500'>8</span><span id='textcolor760'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor761'><span class='ectt-0800'><linux/sched.h></span></span>
|
|
<a id='x1-36026r9'></a><span class='ecrm-0500'>9</span><span id='textcolor762'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor763'><span class='ectt-0800'><linux/uaccess.h></span></span>
|
|
<a id='x1-36028r10'></a><span class='ecrm-0500'>10</span><span id='textcolor764'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor765'><span class='ectt-0800'><linux/version.h></span></span>
|
|
<a id='x1-36030r11'></a><span class='ecrm-0500'>11</span><span id='textcolor766'><span class='ectt-0800'>#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)</span></span>
|
|
<a id='x1-36032r12'></a><span class='ecrm-0500'>12</span><span id='textcolor767'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor768'><span class='ectt-0800'><linux/minmax.h></span></span>
|
|
<a id='x1-36034r13'></a><span class='ecrm-0500'>13</span><span id='textcolor769'><span class='ectt-0800'>#endif</span></span>
|
|
<a id='x1-36036r14'></a><span class='ecrm-0500'>14</span>
|
|
<a id='x1-36038r15'></a><span class='ecrm-0500'>15</span><span id='textcolor770'><span class='ectt-0800'>#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)</span></span>
|
|
<a id='x1-36040r16'></a><span class='ecrm-0500'>16</span><span id='textcolor771'><span class='ectt-0800'>#define HAVE_PROC_OPS</span></span>
|
|
<a id='x1-36042r17'></a><span class='ecrm-0500'>17</span><span id='textcolor772'><span class='ectt-0800'>#endif</span></span>
|
|
<a id='x1-36044r18'></a><span class='ecrm-0500'>18</span>
|
|
<a id='x1-36046r19'></a><span class='ecrm-0500'>19</span><span id='textcolor773'><span class='ectt-0800'>#define PROCFS_MAX_SIZE 2048UL</span></span>
|
|
<a id='x1-36048r20'></a><span class='ecrm-0500'>20</span><span id='textcolor774'><span class='ectt-0800'>#define PROCFS_ENTRY_FILENAME "buffer2k"</span></span>
|
|
<a id='x1-36050r21'></a><span class='ecrm-0500'>21</span>
|
|
<a id='x1-36052r22'></a><span class='ecrm-0500'>22</span><span id='textcolor775'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor776'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> proc_dir_entry *our_proc_file;</span>
|
|
<a id='x1-36054r23'></a><span class='ecrm-0500'>23</span><span id='textcolor777'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor778'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> procfs_buffer[PROCFS_MAX_SIZE];</span>
|
|
<a id='x1-36056r24'></a><span class='ecrm-0500'>24</span><span id='textcolor779'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor780'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor781'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> procfs_buffer_size = 0;</span>
|
|
<a id='x1-36058r25'></a><span class='ecrm-0500'>25</span>
|
|
<a id='x1-36060r26'></a><span class='ecrm-0500'>26</span><span id='textcolor782'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor783'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> procfs_read(</span><span id='textcolor784'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *filp, </span><span id='textcolor785'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *buffer,</span>
|
|
<a id='x1-36062r27'></a><span class='ecrm-0500'>27</span><span class='ectt-0800'> </span><span id='textcolor786'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'> length, loff_t *offset)</span>
|
|
<a id='x1-36064r28'></a><span class='ecrm-0500'>28</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-36066r29'></a><span class='ecrm-0500'>29</span><span class='ectt-0800'> </span><span id='textcolor787'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (*offset || procfs_buffer_size == 0) {</span>
|
|
<a id='x1-36068r30'></a><span class='ecrm-0500'>30</span><span class='ectt-0800'> pr_debug(</span><span id='textcolor788'><span class='ectt-0800'>"procfs_read: END</span></span><span id='textcolor789'><span class='ectt-0800'>\n</span></span><span id='textcolor790'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-36070r31'></a><span class='ecrm-0500'>31</span><span class='ectt-0800'> *offset = 0;</span>
|
|
<a id='x1-36072r32'></a><span class='ecrm-0500'>32</span><span class='ectt-0800'> </span><span id='textcolor791'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-36074r33'></a><span class='ecrm-0500'>33</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-36076r34'></a><span class='ecrm-0500'>34</span><span class='ectt-0800'> procfs_buffer_size = min(procfs_buffer_size, length);</span>
|
|
<a id='x1-36078r35'></a><span class='ecrm-0500'>35</span><span class='ectt-0800'> </span><span id='textcolor792'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (copy_to_user(buffer, procfs_buffer, procfs_buffer_size))</span>
|
|
<a id='x1-36080r36'></a><span class='ecrm-0500'>36</span><span class='ectt-0800'> </span><span id='textcolor793'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -EFAULT;</span>
|
|
<a id='x1-36082r37'></a><span class='ecrm-0500'>37</span><span class='ectt-0800'> *offset += procfs_buffer_size;</span>
|
|
<a id='x1-36084r38'></a><span class='ecrm-0500'>38</span>
|
|
<a id='x1-36086r39'></a><span class='ecrm-0500'>39</span><span class='ectt-0800'> pr_debug(</span><span id='textcolor794'><span class='ectt-0800'>"procfs_read: read %lu bytes</span></span><span id='textcolor795'><span class='ectt-0800'>\n</span></span><span id='textcolor796'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, procfs_buffer_size);</span>
|
|
<a id='x1-36088r40'></a><span class='ecrm-0500'>40</span><span class='ectt-0800'> </span><span id='textcolor797'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> procfs_buffer_size;</span>
|
|
<a id='x1-36090r41'></a><span class='ecrm-0500'>41</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-36092r42'></a><span class='ecrm-0500'>42</span><span id='textcolor798'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor799'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> procfs_write(</span><span id='textcolor800'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file, </span><span id='textcolor801'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor802'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *buffer,</span>
|
|
<a id='x1-36094r43'></a><span class='ecrm-0500'>43</span><span class='ectt-0800'> </span><span id='textcolor803'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'> len, loff_t *off)</span>
|
|
<a id='x1-36096r44'></a><span class='ecrm-0500'>44</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-36098r45'></a><span class='ecrm-0500'>45</span><span class='ectt-0800'> procfs_buffer_size = min(PROCFS_MAX_SIZE, len);</span>
|
|
<a id='x1-36100r46'></a><span class='ecrm-0500'>46</span><span class='ectt-0800'> </span><span id='textcolor804'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (copy_from_user(procfs_buffer, buffer, procfs_buffer_size))</span>
|
|
<a id='x1-36102r47'></a><span class='ecrm-0500'>47</span><span class='ectt-0800'> </span><span id='textcolor805'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -EFAULT;</span>
|
|
<a id='x1-36104r48'></a><span class='ecrm-0500'>48</span><span class='ectt-0800'> *off += procfs_buffer_size;</span>
|
|
<a id='x1-36106r49'></a><span class='ecrm-0500'>49</span>
|
|
<a id='x1-36108r50'></a><span class='ecrm-0500'>50</span><span class='ectt-0800'> pr_debug(</span><span id='textcolor806'><span class='ectt-0800'>"procfs_write: write %lu bytes</span></span><span id='textcolor807'><span class='ectt-0800'>\n</span></span><span id='textcolor808'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, procfs_buffer_size);</span>
|
|
<a id='x1-36110r51'></a><span class='ecrm-0500'>51</span><span class='ectt-0800'> </span><span id='textcolor809'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> procfs_buffer_size;</span>
|
|
<a id='x1-36112r52'></a><span class='ecrm-0500'>52</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-36114r53'></a><span class='ecrm-0500'>53</span><span id='textcolor810'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor811'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> procfs_open(</span><span id='textcolor812'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> inode *inode, </span><span id='textcolor813'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file)</span>
|
|
<a id='x1-36116r54'></a><span class='ecrm-0500'>54</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-36118r55'></a><span class='ecrm-0500'>55</span><span class='ectt-0800'> try_module_get(THIS_MODULE);</span>
|
|
<a id='x1-36120r56'></a><span class='ecrm-0500'>56</span><span class='ectt-0800'> </span><span id='textcolor814'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-36122r57'></a><span class='ecrm-0500'>57</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-36124r58'></a><span class='ecrm-0500'>58</span><span id='textcolor815'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor816'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> procfs_close(</span><span id='textcolor817'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> inode *inode, </span><span id='textcolor818'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file)</span>
|
|
<a id='x1-36126r59'></a><span class='ecrm-0500'>59</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-36128r60'></a><span class='ecrm-0500'>60</span><span class='ectt-0800'> module_put(THIS_MODULE);</span>
|
|
<a id='x1-36130r61'></a><span class='ecrm-0500'>61</span><span class='ectt-0800'> </span><span id='textcolor819'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-36132r62'></a><span class='ecrm-0500'>62</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-36134r63'></a><span class='ecrm-0500'>63</span>
|
|
<a id='x1-36136r64'></a><span class='ecrm-0500'>64</span><span id='textcolor820'><span class='ectt-0800'>#ifdef HAVE_PROC_OPS</span></span>
|
|
<a id='x1-36138r65'></a><span class='ecrm-0500'>65</span><span id='textcolor821'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor822'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> proc_ops file_ops_4_our_proc_file = {</span>
|
|
<a id='x1-36140r66'></a><span class='ecrm-0500'>66</span><span class='ectt-0800'> .proc_read = procfs_read,</span>
|
|
<a id='x1-36142r67'></a><span class='ecrm-0500'>67</span><span class='ectt-0800'> .proc_write = procfs_write,</span>
|
|
<a id='x1-36144r68'></a><span class='ecrm-0500'>68</span><span class='ectt-0800'> .proc_open = procfs_open,</span>
|
|
<a id='x1-36146r69'></a><span class='ecrm-0500'>69</span><span class='ectt-0800'> .proc_release = procfs_close,</span>
|
|
<a id='x1-36148r70'></a><span class='ecrm-0500'>70</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-36150r71'></a><span class='ecrm-0500'>71</span><span id='textcolor823'><span class='ectt-0800'>#else</span></span>
|
|
<a id='x1-36152r72'></a><span class='ecrm-0500'>72</span><span id='textcolor824'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor825'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor826'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file_operations file_ops_4_our_proc_file = {</span>
|
|
<a id='x1-36154r73'></a><span class='ecrm-0500'>73</span><span class='ectt-0800'> .read = procfs_read,</span>
|
|
<a id='x1-36156r74'></a><span class='ecrm-0500'>74</span><span class='ectt-0800'> .write = procfs_write,</span>
|
|
<a id='x1-36158r75'></a><span class='ecrm-0500'>75</span><span class='ectt-0800'> .open = procfs_open,</span>
|
|
<a id='x1-36160r76'></a><span class='ecrm-0500'>76</span><span class='ectt-0800'> .release = procfs_close,</span>
|
|
<a id='x1-36162r77'></a><span class='ecrm-0500'>77</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-36164r78'></a><span class='ecrm-0500'>78</span><span id='textcolor827'><span class='ectt-0800'>#endif</span></span>
|
|
<a id='x1-36166r79'></a><span class='ecrm-0500'>79</span>
|
|
<a id='x1-36168r80'></a><span class='ecrm-0500'>80</span><span id='textcolor828'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor829'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __init procfs3_init(</span><span id='textcolor830'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-36170r81'></a><span class='ecrm-0500'>81</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-36172r82'></a><span class='ecrm-0500'>82</span><span class='ectt-0800'> our_proc_file = proc_create(PROCFS_ENTRY_FILENAME, 0644, NULL,</span>
|
|
<a id='x1-36174r83'></a><span class='ecrm-0500'>83</span><span class='ectt-0800'> &file_ops_4_our_proc_file);</span>
|
|
<a id='x1-36176r84'></a><span class='ecrm-0500'>84</span><span class='ectt-0800'> </span><span id='textcolor831'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (our_proc_file == NULL) {</span>
|
|
<a id='x1-36178r85'></a><span class='ecrm-0500'>85</span><span class='ectt-0800'> pr_debug(</span><span id='textcolor832'><span class='ectt-0800'>"Error: Could not initialize /proc/%s</span></span><span id='textcolor833'><span class='ectt-0800'>\n</span></span><span id='textcolor834'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>,</span>
|
|
<a id='x1-36180r86'></a><span class='ecrm-0500'>86</span><span class='ectt-0800'> PROCFS_ENTRY_FILENAME);</span>
|
|
<a id='x1-36182r87'></a><span class='ecrm-0500'>87</span><span class='ectt-0800'> </span><span id='textcolor835'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -ENOMEM;</span>
|
|
<a id='x1-36184r88'></a><span class='ecrm-0500'>88</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-36186r89'></a><span class='ecrm-0500'>89</span><span class='ectt-0800'> proc_set_size(our_proc_file, 80);</span>
|
|
<a id='x1-36188r90'></a><span class='ecrm-0500'>90</span><span class='ectt-0800'> proc_set_user(our_proc_file, GLOBAL_ROOT_UID, GLOBAL_ROOT_GID);</span>
|
|
<a id='x1-36190r91'></a><span class='ecrm-0500'>91</span>
|
|
<a id='x1-36192r92'></a><span class='ecrm-0500'>92</span><span class='ectt-0800'> pr_debug(</span><span id='textcolor836'><span class='ectt-0800'>"/proc/%s created</span></span><span id='textcolor837'><span class='ectt-0800'>\n</span></span><span id='textcolor838'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, PROCFS_ENTRY_FILENAME);</span>
|
|
<a id='x1-36194r93'></a><span class='ecrm-0500'>93</span><span class='ectt-0800'> </span><span id='textcolor839'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-36196r94'></a><span class='ecrm-0500'>94</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-36198r95'></a><span class='ecrm-0500'>95</span>
|
|
<a id='x1-36200r96'></a><span class='ecrm-0500'>96</span><span id='textcolor840'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor841'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> __exit procfs3_exit(</span><span id='textcolor842'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-36202r97'></a><span class='ecrm-0500'>97</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-36204r98'></a><span class='ecrm-0500'>98</span><span class='ectt-0800'> remove_proc_entry(PROCFS_ENTRY_FILENAME, NULL);</span>
|
|
<a id='x1-36206r99'></a><span class='ecrm-0500'>99</span><span class='ectt-0800'> pr_debug(</span><span id='textcolor843'><span class='ectt-0800'>"/proc/%s removed</span></span><span id='textcolor844'><span class='ectt-0800'>\n</span></span><span id='textcolor845'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, PROCFS_ENTRY_FILENAME);</span>
|
|
<a id='x1-36208r100'></a><span class='ecrm-0500'>100</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-36210r101'></a><span class='ecrm-0500'>101</span>
|
|
<a id='x1-36212r102'></a><span class='ecrm-0500'>102</span><span class='ectt-0800'>module_init(procfs3_init);</span>
|
|
<a id='x1-36214r103'></a><span class='ecrm-0500'>103</span><span class='ectt-0800'>module_exit(procfs3_exit);</span>
|
|
<a id='x1-36216r104'></a><span class='ecrm-0500'>104</span>
|
|
<a id='x1-36218r105'></a><span class='ecrm-0500'>105</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor846'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span></pre>
|
|
<!-- l. 1225 --><p class='indent'> Still hungry for procfs examples? Well, first of all keep in mind, there are rumors
|
|
around, claiming that procfs is on its way out, consider using <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>sysfs</span></span></span> instead. Consider
|
|
using this mechanism, in case you want to document something kernel related
|
|
yourself.
|
|
</p><!-- l. 1229 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='manage-proc-file-with-seqfile'><span class='titlemark'>7.4 </span> <a id='x1-370007.4'></a>Manage /proc file with seq_file</h4>
|
|
<!-- l. 1231 --><p class='noindent'>As we have seen, writing a <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc</span></span></span> file may be quite “complex”.
|
|
So to help people writing <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc</span></span></span> file, there is an API named
|
|
<code> <span class='ectt-1000'>seq_file</span>
|
|
</code> that helps formatting a <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc</span></span></span> file for output. It is based on sequence, which is composed of
|
|
3 functions: <code> <span class='ectt-1000'>start()</span>
|
|
</code>, <code> <span class='ectt-1000'>next()</span>
|
|
</code>, and <code> <span class='ectt-1000'>stop()</span>
|
|
</code>. The <code> <span class='ectt-1000'>seq_file</span>
|
|
</code> API starts a sequence when a user read the <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc</span></span></span> file.
|
|
</p><!-- l. 1236 --><p class='indent'> A sequence begins with the call of the function
|
|
<code> <span class='ectt-1000'>start()</span>
|
|
</code>. If the return is a non <code> <span class='ectt-1000'>NULL</span>
|
|
</code> value, the function <code> <span class='ectt-1000'>next()</span>
|
|
</code> is called. This function is an iterator, the goal is to go through all the data. Each
|
|
|
|
|
|
|
|
time <code> <span class='ectt-1000'>next()</span>
|
|
</code> is called, the function <code> <span class='ectt-1000'>show()</span>
|
|
</code> is also called. It writes data values in the buffer read by the user. The function
|
|
<code> <span class='ectt-1000'>next()</span>
|
|
</code> is called until it returns <code> <span class='ectt-1000'>NULL</span>
|
|
</code>. The sequence ends when <code> <span class='ectt-1000'>next()</span>
|
|
</code> returns <code> <span class='ectt-1000'>NULL</span>
|
|
</code>, then the function <code> <span class='ectt-1000'>stop()</span>
|
|
</code> is called.
|
|
</p><!-- l. 1244 --><p class='indent'> BE CAREFUL: when a sequence is finished, another one starts. That means that at the end
|
|
of function <code> <span class='ectt-1000'>stop()</span>
|
|
</code>, the function <code> <span class='ectt-1000'>start()</span>
|
|
</code> is called again. This loop finishes when the function
|
|
<code> <span class='ectt-1000'>start()</span>
|
|
</code> returns <code> <span class='ectt-1000'>NULL</span>
|
|
</code>. You can see a scheme of this in the Figure <a href='#ignorespaces-how-seqfile-works'>1<!-- tex4ht:ref: img:seqfile --></a>.
|
|
</p>
|
|
<figure class='figure' id='ignorespaces-how-seqfile-works'>
|
|
|
|
|
|
|
|
|
|
<a id='x1-37020r1'></a>
|
|
|
|
|
|
|
|
<!-- l. 1251 --><p class='noindent'><img alt='srYrsNNYtaeenetoooertusetupstrxr((ntn))( tis)istrr teeaNreNatUaUtmLtLmeLmLen?e?ntntt ' src='lkmpg-for-ht1x.svg' />
|
|
</p>
|
|
<figcaption class='caption'><span class='id'>Figure 1:</span><span class='content'>How seq_file works</span></figcaption><!-- tex4ht:label?: x1-37020r1 -->
|
|
|
|
|
|
|
|
</figure>
|
|
<!-- l. 1271 --><p class='indent'> The <code> <span class='ectt-1000'>seq_file</span>
|
|
</code> provides basic functions for <code> <span class='ectt-1000'>proc_ops</span>
|
|
</code>, such as <code> <span class='ectt-1000'>seq_read</span>
|
|
</code>, <code> <span class='ectt-1000'>seq_lseek</span>
|
|
</code>, and some others. But nothing to write in the <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc</span></span></span> file. Of course, you can still use
|
|
the same way as in the previous example.
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb50'><a id='x1-37026r1'></a><span class='ecrm-0500'>1</span><span id='textcolor847'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-37028r2'></a><span class='ecrm-0500'>2</span><span id='textcolor848'><span class='ectt-0800'> * procfs4.c - create a "file" in /proc</span></span>
|
|
<a id='x1-37030r3'></a><span class='ecrm-0500'>3</span><span id='textcolor849'><span class='ectt-0800'> * This program uses the seq_file library to manage the /proc file.</span></span>
|
|
<a id='x1-37032r4'></a><span class='ecrm-0500'>4</span><span id='textcolor850'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-37034r5'></a><span class='ecrm-0500'>5</span>
|
|
<a id='x1-37036r6'></a><span class='ecrm-0500'>6</span><span id='textcolor851'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor852'><span class='ectt-0800'><linux/kernel.h> /* We are doing kernel work */</span></span>
|
|
<a id='x1-37038r7'></a><span class='ecrm-0500'>7</span><span id='textcolor853'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor854'><span class='ectt-0800'><linux/module.h> /* Specifically, a module */</span></span>
|
|
<a id='x1-37040r8'></a><span class='ecrm-0500'>8</span><span id='textcolor855'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor856'><span class='ectt-0800'><linux/proc_fs.h> /* Necessary because we use proc fs */</span></span>
|
|
<a id='x1-37042r9'></a><span class='ecrm-0500'>9</span><span id='textcolor857'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor858'><span class='ectt-0800'><linux/seq_file.h> /* for seq_file */</span></span>
|
|
<a id='x1-37044r10'></a><span class='ecrm-0500'>10</span><span id='textcolor859'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor860'><span class='ectt-0800'><linux/version.h></span></span>
|
|
<a id='x1-37046r11'></a><span class='ecrm-0500'>11</span>
|
|
<a id='x1-37048r12'></a><span class='ecrm-0500'>12</span><span id='textcolor861'><span class='ectt-0800'>#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)</span></span>
|
|
<a id='x1-37050r13'></a><span class='ecrm-0500'>13</span><span id='textcolor862'><span class='ectt-0800'>#define HAVE_PROC_OPS</span></span>
|
|
<a id='x1-37052r14'></a><span class='ecrm-0500'>14</span><span id='textcolor863'><span class='ectt-0800'>#endif</span></span>
|
|
<a id='x1-37054r15'></a><span class='ecrm-0500'>15</span>
|
|
<a id='x1-37056r16'></a><span class='ecrm-0500'>16</span><span id='textcolor864'><span class='ectt-0800'>#define PROC_NAME "iter"</span></span>
|
|
<a id='x1-37058r17'></a><span class='ecrm-0500'>17</span>
|
|
<a id='x1-37060r18'></a><span class='ecrm-0500'>18</span><span id='textcolor865'><span class='ectt-0800'>/* This function is called at the beginning of a sequence.</span></span>
|
|
<a id='x1-37062r19'></a><span class='ecrm-0500'>19</span><span id='textcolor866'><span class='ectt-0800'> * ie, when:</span></span>
|
|
<a id='x1-37064r20'></a><span class='ecrm-0500'>20</span><span id='textcolor867'><span class='ectt-0800'> * - the /proc file is read (first time)</span></span>
|
|
<a id='x1-37066r21'></a><span class='ecrm-0500'>21</span><span id='textcolor868'><span class='ectt-0800'> * - after the function stop (end of sequence)</span></span>
|
|
<a id='x1-37068r22'></a><span class='ecrm-0500'>22</span><span id='textcolor869'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-37070r23'></a><span class='ecrm-0500'>23</span><span id='textcolor870'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor871'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> *my_seq_start(</span><span id='textcolor872'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> seq_file *s, loff_t *pos)</span>
|
|
<a id='x1-37072r24'></a><span class='ecrm-0500'>24</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-37074r25'></a><span class='ecrm-0500'>25</span><span class='ectt-0800'> </span><span id='textcolor873'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor874'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor875'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> counter = 0;</span>
|
|
<a id='x1-37076r26'></a><span class='ecrm-0500'>26</span>
|
|
<a id='x1-37078r27'></a><span class='ecrm-0500'>27</span><span class='ectt-0800'> </span><span id='textcolor876'><span class='ectt-0800'>/* beginning a new sequence? */</span></span>
|
|
<a id='x1-37080r28'></a><span class='ecrm-0500'>28</span><span class='ectt-0800'> </span><span id='textcolor877'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (*pos == 0) {</span>
|
|
<a id='x1-37082r29'></a><span class='ecrm-0500'>29</span><span class='ectt-0800'> </span><span id='textcolor878'><span class='ectt-0800'>/* yes => return a non null value to begin the sequence */</span></span>
|
|
<a id='x1-37084r30'></a><span class='ecrm-0500'>30</span><span class='ectt-0800'> </span><span id='textcolor879'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> &counter;</span>
|
|
<a id='x1-37086r31'></a><span class='ecrm-0500'>31</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-37088r32'></a><span class='ecrm-0500'>32</span>
|
|
<a id='x1-37090r33'></a><span class='ecrm-0500'>33</span><span class='ectt-0800'> </span><span id='textcolor880'><span class='ectt-0800'>/* no => it is the end of the sequence, return end to stop reading */</span></span>
|
|
<a id='x1-37092r34'></a><span class='ecrm-0500'>34</span><span class='ectt-0800'> *pos = 0;</span>
|
|
<a id='x1-37094r35'></a><span class='ecrm-0500'>35</span><span class='ectt-0800'> </span><span id='textcolor881'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> NULL;</span>
|
|
<a id='x1-37096r36'></a><span class='ecrm-0500'>36</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-37098r37'></a><span class='ecrm-0500'>37</span>
|
|
<a id='x1-37100r38'></a><span class='ecrm-0500'>38</span><span id='textcolor882'><span class='ectt-0800'>/* This function is called after the beginning of a sequence.</span></span>
|
|
<a id='x1-37102r39'></a><span class='ecrm-0500'>39</span><span id='textcolor883'><span class='ectt-0800'> * It is called until the return is NULL (this ends the sequence).</span></span>
|
|
<a id='x1-37104r40'></a><span class='ecrm-0500'>40</span><span id='textcolor884'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-37106r41'></a><span class='ecrm-0500'>41</span><span id='textcolor885'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor886'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> *my_seq_next(</span><span id='textcolor887'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> seq_file *s, </span><span id='textcolor888'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> *v, loff_t *pos)</span>
|
|
<a id='x1-37108r42'></a><span class='ecrm-0500'>42</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-37110r43'></a><span class='ecrm-0500'>43</span><span class='ectt-0800'> </span><span id='textcolor889'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor890'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> *tmp_v = (</span><span id='textcolor891'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor892'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> *)v;</span>
|
|
<a id='x1-37112r44'></a><span class='ecrm-0500'>44</span><span class='ectt-0800'> (*tmp_v)++;</span>
|
|
<a id='x1-37114r45'></a><span class='ecrm-0500'>45</span><span class='ectt-0800'> (*pos)++;</span>
|
|
<a id='x1-37116r46'></a><span class='ecrm-0500'>46</span><span class='ectt-0800'> </span><span id='textcolor893'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> NULL;</span>
|
|
<a id='x1-37118r47'></a><span class='ecrm-0500'>47</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-37120r48'></a><span class='ecrm-0500'>48</span>
|
|
<a id='x1-37122r49'></a><span class='ecrm-0500'>49</span><span id='textcolor894'><span class='ectt-0800'>/* This function is called at the end of a sequence. */</span></span>
|
|
<a id='x1-37124r50'></a><span class='ecrm-0500'>50</span><span id='textcolor895'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor896'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> my_seq_stop(</span><span id='textcolor897'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> seq_file *s, </span><span id='textcolor898'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> *v)</span>
|
|
<a id='x1-37126r51'></a><span class='ecrm-0500'>51</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-37128r52'></a><span class='ecrm-0500'>52</span><span class='ectt-0800'> </span><span id='textcolor899'><span class='ectt-0800'>/* nothing to do, we use a static value in start() */</span></span>
|
|
<a id='x1-37130r53'></a><span class='ecrm-0500'>53</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-37132r54'></a><span class='ecrm-0500'>54</span>
|
|
<a id='x1-37134r55'></a><span class='ecrm-0500'>55</span><span id='textcolor900'><span class='ectt-0800'>/* This function is called for each "step" of a sequence. */</span></span>
|
|
<a id='x1-37136r56'></a><span class='ecrm-0500'>56</span><span id='textcolor901'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor902'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> my_seq_show(</span><span id='textcolor903'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> seq_file *s, </span><span id='textcolor904'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> *v)</span>
|
|
<a id='x1-37138r57'></a><span class='ecrm-0500'>57</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-37140r58'></a><span class='ecrm-0500'>58</span><span class='ectt-0800'> loff_t *spos = (loff_t *)v;</span>
|
|
<a id='x1-37142r59'></a><span class='ecrm-0500'>59</span>
|
|
<a id='x1-37144r60'></a><span class='ecrm-0500'>60</span><span class='ectt-0800'> seq_printf(s, </span><span id='textcolor905'><span class='ectt-0800'>"%Ld</span></span><span id='textcolor906'><span class='ectt-0800'>\n</span></span><span id='textcolor907'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, *spos);</span>
|
|
<a id='x1-37146r61'></a><span class='ecrm-0500'>61</span><span class='ectt-0800'> </span><span id='textcolor908'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-37148r62'></a><span class='ecrm-0500'>62</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-37150r63'></a><span class='ecrm-0500'>63</span>
|
|
<a id='x1-37152r64'></a><span class='ecrm-0500'>64</span><span id='textcolor909'><span class='ectt-0800'>/* This structure gather "function" to manage the sequence */</span></span>
|
|
<a id='x1-37154r65'></a><span class='ecrm-0500'>65</span><span id='textcolor910'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor911'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> seq_operations my_seq_ops = {</span>
|
|
<a id='x1-37156r66'></a><span class='ecrm-0500'>66</span><span class='ectt-0800'> .start = my_seq_start,</span>
|
|
<a id='x1-37158r67'></a><span class='ecrm-0500'>67</span><span class='ectt-0800'> .next = my_seq_next,</span>
|
|
<a id='x1-37160r68'></a><span class='ecrm-0500'>68</span><span class='ectt-0800'> .stop = my_seq_stop,</span>
|
|
<a id='x1-37162r69'></a><span class='ecrm-0500'>69</span><span class='ectt-0800'> .show = my_seq_show,</span>
|
|
<a id='x1-37164r70'></a><span class='ecrm-0500'>70</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-37166r71'></a><span class='ecrm-0500'>71</span>
|
|
<a id='x1-37168r72'></a><span class='ecrm-0500'>72</span><span id='textcolor912'><span class='ectt-0800'>/* This function is called when the /proc file is open. */</span></span>
|
|
<a id='x1-37170r73'></a><span class='ecrm-0500'>73</span><span id='textcolor913'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor914'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> my_open(</span><span id='textcolor915'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> inode *inode, </span><span id='textcolor916'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file)</span>
|
|
<a id='x1-37172r74'></a><span class='ecrm-0500'>74</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-37174r75'></a><span class='ecrm-0500'>75</span><span class='ectt-0800'> </span><span id='textcolor917'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> seq_open(file, &my_seq_ops);</span>
|
|
<a id='x1-37176r76'></a><span class='ecrm-0500'>76</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-37178r77'></a><span class='ecrm-0500'>77</span>
|
|
<a id='x1-37180r78'></a><span class='ecrm-0500'>78</span><span id='textcolor918'><span class='ectt-0800'>/* This structure gather "function" that manage the /proc file */</span></span>
|
|
<a id='x1-37182r79'></a><span class='ecrm-0500'>79</span><span id='textcolor919'><span class='ectt-0800'>#ifdef HAVE_PROC_OPS</span></span>
|
|
<a id='x1-37184r80'></a><span class='ecrm-0500'>80</span><span id='textcolor920'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor921'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor922'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> proc_ops my_file_ops = {</span>
|
|
<a id='x1-37186r81'></a><span class='ecrm-0500'>81</span><span class='ectt-0800'> .proc_open = my_open,</span>
|
|
<a id='x1-37188r82'></a><span class='ecrm-0500'>82</span><span class='ectt-0800'> .proc_read = seq_read,</span>
|
|
<a id='x1-37190r83'></a><span class='ecrm-0500'>83</span><span class='ectt-0800'> .proc_lseek = seq_lseek,</span>
|
|
<a id='x1-37192r84'></a><span class='ecrm-0500'>84</span><span class='ectt-0800'> .proc_release = seq_release,</span>
|
|
<a id='x1-37194r85'></a><span class='ecrm-0500'>85</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-37196r86'></a><span class='ecrm-0500'>86</span><span id='textcolor923'><span class='ectt-0800'>#else</span></span>
|
|
<a id='x1-37198r87'></a><span class='ecrm-0500'>87</span><span id='textcolor924'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor925'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor926'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file_operations my_file_ops = {</span>
|
|
<a id='x1-37200r88'></a><span class='ecrm-0500'>88</span><span class='ectt-0800'> .open = my_open,</span>
|
|
<a id='x1-37202r89'></a><span class='ecrm-0500'>89</span><span class='ectt-0800'> .read = seq_read,</span>
|
|
<a id='x1-37204r90'></a><span class='ecrm-0500'>90</span><span class='ectt-0800'> .llseek = seq_lseek,</span>
|
|
<a id='x1-37206r91'></a><span class='ecrm-0500'>91</span><span class='ectt-0800'> .release = seq_release,</span>
|
|
<a id='x1-37208r92'></a><span class='ecrm-0500'>92</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-37210r93'></a><span class='ecrm-0500'>93</span><span id='textcolor927'><span class='ectt-0800'>#endif</span></span>
|
|
<a id='x1-37212r94'></a><span class='ecrm-0500'>94</span>
|
|
<a id='x1-37214r95'></a><span class='ecrm-0500'>95</span><span id='textcolor928'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor929'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __init procfs4_init(</span><span id='textcolor930'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-37216r96'></a><span class='ecrm-0500'>96</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-37218r97'></a><span class='ecrm-0500'>97</span><span class='ectt-0800'> </span><span id='textcolor931'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> proc_dir_entry *entry;</span>
|
|
<a id='x1-37220r98'></a><span class='ecrm-0500'>98</span>
|
|
<a id='x1-37222r99'></a><span class='ecrm-0500'>99</span><span class='ectt-0800'> entry = proc_create(PROC_NAME, 0, NULL, &my_file_ops);</span>
|
|
<a id='x1-37224r100'></a><span class='ecrm-0500'>100</span><span class='ectt-0800'> </span><span id='textcolor932'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (entry == NULL) {</span>
|
|
<a id='x1-37226r101'></a><span class='ecrm-0500'>101</span><span class='ectt-0800'> pr_debug(</span><span id='textcolor933'><span class='ectt-0800'>"Error: Could not initialize /proc/%s</span></span><span id='textcolor934'><span class='ectt-0800'>\n</span></span><span id='textcolor935'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, PROC_NAME);</span>
|
|
<a id='x1-37228r102'></a><span class='ecrm-0500'>102</span><span class='ectt-0800'> </span><span id='textcolor936'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -ENOMEM;</span>
|
|
<a id='x1-37230r103'></a><span class='ecrm-0500'>103</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-37232r104'></a><span class='ecrm-0500'>104</span>
|
|
<a id='x1-37234r105'></a><span class='ecrm-0500'>105</span><span class='ectt-0800'> </span><span id='textcolor937'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-37236r106'></a><span class='ecrm-0500'>106</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-37238r107'></a><span class='ecrm-0500'>107</span>
|
|
<a id='x1-37240r108'></a><span class='ecrm-0500'>108</span><span id='textcolor938'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor939'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> __exit procfs4_exit(</span><span id='textcolor940'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-37242r109'></a><span class='ecrm-0500'>109</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-37244r110'></a><span class='ecrm-0500'>110</span><span class='ectt-0800'> remove_proc_entry(PROC_NAME, NULL);</span>
|
|
<a id='x1-37246r111'></a><span class='ecrm-0500'>111</span><span class='ectt-0800'> pr_debug(</span><span id='textcolor941'><span class='ectt-0800'>"/proc/%s removed</span></span><span id='textcolor942'><span class='ectt-0800'>\n</span></span><span id='textcolor943'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, PROC_NAME);</span>
|
|
<a id='x1-37248r112'></a><span class='ecrm-0500'>112</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-37250r113'></a><span class='ecrm-0500'>113</span>
|
|
<a id='x1-37252r114'></a><span class='ecrm-0500'>114</span><span class='ectt-0800'>module_init(procfs4_init);</span>
|
|
<a id='x1-37254r115'></a><span class='ecrm-0500'>115</span><span class='ectt-0800'>module_exit(procfs4_exit);</span>
|
|
<a id='x1-37256r116'></a><span class='ecrm-0500'>116</span>
|
|
<a id='x1-37258r117'></a><span class='ecrm-0500'>117</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor944'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span></pre>
|
|
<!-- l. 1277 --><p class='indent'> If you want more information, you can read this web page:
|
|
</p>
|
|
<ul class='itemize1'>
|
|
<li class='itemize'><a class='url' href='https://lwn.net/Articles/22355/'><span class='ectt-1000'>https://lwn.net/Articles/22355/</span></a>
|
|
</li>
|
|
<li class='itemize'><a class='url' href='https://kernelnewbies.org/Documents/SeqFileHowTo'><span class='ectt-1000'>https://kernelnewbies.org/Documents/SeqFileHowTo</span></a></li></ul>
|
|
<!-- l. 1284 --><p class='indent'> You can also read the code of <a href='https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/fs/seq_file.c'>fs/seq_file.c</a> in the linux kernel.
|
|
</p>
|
|
<h3 class='sectionHead' id='sysfs-interacting-with-your-module'><span class='titlemark'>8 </span> <a id='x1-380008'></a>sysfs: Interacting with your module</h3>
|
|
<!-- l. 1288 --><p class='noindent'><span class='ecti-1000'>sysfs </span>allows you to interact with the running kernel from userspace by reading or
|
|
setting variables inside of modules. This can be useful for debugging purposes, or just
|
|
as an interface for applications or scripts. You can find sysfs directories and files
|
|
under the <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/sys</span></span></span> directory on your system.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb51'><a id='x1-38003r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>ls -l /sys</span></pre>
|
|
<!-- l. 1296 --><p class='indent'> Attributes can be exported for kobjects in the form of regular files in the
|
|
filesystem. Sysfs forwards file I/O operations to methods defined for the attributes,
|
|
providing a means to read and write kernel attributes.
|
|
</p><!-- l. 1299 --><p class='indent'> An attribute definition in simply:
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb52'><a id='x1-38013r1'></a><span class='ecrm-0500'>1</span><span id='textcolor945'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> attribute {</span>
|
|
<a id='x1-38015r2'></a><span class='ecrm-0500'>2</span><span class='ectt-0800'> </span><span id='textcolor946'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *name;</span>
|
|
<a id='x1-38017r3'></a><span class='ecrm-0500'>3</span><span class='ectt-0800'> </span><span id='textcolor947'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> module *owner;</span>
|
|
<a id='x1-38019r4'></a><span class='ecrm-0500'>4</span><span class='ectt-0800'> umode_t mode;</span>
|
|
<a id='x1-38021r5'></a><span class='ecrm-0500'>5</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-38023r6'></a><span class='ecrm-0500'>6</span>
|
|
<a id='x1-38025r7'></a><span class='ecrm-0500'>7</span><span id='textcolor948'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> sysfs_create_file(</span><span id='textcolor949'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> kobject * kobj, </span><span id='textcolor950'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor951'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> attribute * attr);</span>
|
|
<a id='x1-38027r8'></a><span class='ecrm-0500'>8</span><span id='textcolor952'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> sysfs_remove_file(</span><span id='textcolor953'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> kobject * kobj, </span><span id='textcolor954'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor955'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> attribute * attr);</span></pre>
|
|
<!-- l. 1312 --><p class='indent'> For example, the driver model defines
|
|
<code> <span id='textcolor956'><span class='ectt-1000'>struct</span></span><span class='ectt-1000'> device_attribute</span>
|
|
</code> like:
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
|
|
|
|
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb53'><a id='x1-38040r1'></a><span class='ecrm-0500'>1</span><span id='textcolor957'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> device_attribute {</span>
|
|
<a id='x1-38042r2'></a><span class='ecrm-0500'>2</span><span class='ectt-0800'> </span><span id='textcolor958'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> attribute attr;</span>
|
|
<a id='x1-38044r3'></a><span class='ecrm-0500'>3</span><span class='ectt-0800'> </span><span id='textcolor959'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> (*show)(</span><span id='textcolor960'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> device *dev, </span><span id='textcolor961'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> device_attribute *attr,</span>
|
|
<a id='x1-38046r4'></a><span class='ecrm-0500'>4</span><span class='ectt-0800'> </span><span id='textcolor962'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *buf);</span>
|
|
<a id='x1-38048r5'></a><span class='ecrm-0500'>5</span><span class='ectt-0800'> </span><span id='textcolor963'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> (*store)(</span><span id='textcolor964'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> device *dev, </span><span id='textcolor965'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> device_attribute *attr,</span>
|
|
<a id='x1-38050r6'></a><span class='ecrm-0500'>6</span><span class='ectt-0800'> </span><span id='textcolor966'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor967'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *buf, </span><span id='textcolor968'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'> count);</span>
|
|
<a id='x1-38052r7'></a><span class='ecrm-0500'>7</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-38054r8'></a><span class='ecrm-0500'>8</span>
|
|
<a id='x1-38056r9'></a><span class='ecrm-0500'>9</span><span id='textcolor969'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> device_create_file(</span><span id='textcolor970'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> device *, </span><span id='textcolor971'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor972'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> device_attribute *);</span>
|
|
<a id='x1-38058r10'></a><span class='ecrm-0500'>10</span><span id='textcolor973'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> device_remove_file(</span><span id='textcolor974'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> device *, </span><span id='textcolor975'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor976'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> device_attribute *);</span></pre>
|
|
<!-- l. 1327 --><p class='indent'> To read or write attributes, <code> <span class='ectt-1000'>show()</span>
|
|
</code> or <code> <span class='ectt-1000'>store()</span>
|
|
</code> method must be specified when declaring the attribute. For the
|
|
common cases <a href='https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/include/linux/sysfs.h'>include/linux/sysfs.h</a> provides convenience macros
|
|
(<code> <span class='ectt-1000'>__ATTR</span>
|
|
</code>, <code> <span class='ectt-1000'>__ATTR_RO</span>
|
|
</code>, <code> <span class='ectt-1000'>__ATTR_WO</span>
|
|
</code>, etc.) to make defining attributes easier as well as making code more concise and
|
|
readable.
|
|
</p><!-- l. 1330 --><p class='indent'> An example of a hello world module which includes the creation of a variable
|
|
accessible via sysfs is given below.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb54'><a id='x1-38065r1'></a><span class='ecrm-0500'>1</span><span id='textcolor977'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-38067r2'></a><span class='ecrm-0500'>2</span><span id='textcolor978'><span class='ectt-0800'> * hello-sysfs.c sysfs example</span></span>
|
|
<a id='x1-38069r3'></a><span class='ecrm-0500'>3</span><span id='textcolor979'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-38071r4'></a><span class='ecrm-0500'>4</span><span id='textcolor980'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor981'><span class='ectt-0800'><linux/fs.h></span></span>
|
|
<a id='x1-38073r5'></a><span class='ecrm-0500'>5</span><span id='textcolor982'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor983'><span class='ectt-0800'><linux/init.h></span></span>
|
|
<a id='x1-38075r6'></a><span class='ecrm-0500'>6</span><span id='textcolor984'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor985'><span class='ectt-0800'><linux/kobject.h></span></span>
|
|
<a id='x1-38077r7'></a><span class='ecrm-0500'>7</span><span id='textcolor986'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor987'><span class='ectt-0800'><linux/module.h></span></span>
|
|
<a id='x1-38079r8'></a><span class='ecrm-0500'>8</span><span id='textcolor988'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor989'><span class='ectt-0800'><linux/string.h></span></span>
|
|
<a id='x1-38081r9'></a><span class='ecrm-0500'>9</span><span id='textcolor990'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor991'><span class='ectt-0800'><linux/sysfs.h></span></span>
|
|
<a id='x1-38083r10'></a><span class='ecrm-0500'>10</span>
|
|
<a id='x1-38085r11'></a><span class='ecrm-0500'>11</span><span id='textcolor992'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor993'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> kobject *mymodule;</span>
|
|
<a id='x1-38087r12'></a><span class='ecrm-0500'>12</span>
|
|
<a id='x1-38089r13'></a><span class='ecrm-0500'>13</span><span id='textcolor994'><span class='ectt-0800'>/* the variable you want to be able to change */</span></span>
|
|
<a id='x1-38091r14'></a><span class='ecrm-0500'>14</span><span id='textcolor995'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor996'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> myvariable = 0;</span>
|
|
<a id='x1-38093r15'></a><span class='ecrm-0500'>15</span>
|
|
<a id='x1-38095r16'></a><span class='ecrm-0500'>16</span><span id='textcolor997'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor998'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> myvariable_show(</span><span id='textcolor999'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> kobject *kobj,</span>
|
|
<a id='x1-38097r17'></a><span class='ecrm-0500'>17</span><span class='ectt-0800'> </span><span id='textcolor1000'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> kobj_attribute *attr, </span><span id='textcolor1001'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *buf)</span>
|
|
<a id='x1-38099r18'></a><span class='ecrm-0500'>18</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-38101r19'></a><span class='ecrm-0500'>19</span><span class='ectt-0800'> </span><span id='textcolor1002'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> sprintf(buf, </span><span id='textcolor1003'><span class='ectt-0800'>"%d</span></span><span id='textcolor1004'><span class='ectt-0800'>\n</span></span><span id='textcolor1005'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, myvariable);</span>
|
|
<a id='x1-38103r20'></a><span class='ecrm-0500'>20</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-38105r21'></a><span class='ecrm-0500'>21</span>
|
|
<a id='x1-38107r22'></a><span class='ecrm-0500'>22</span><span id='textcolor1006'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1007'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> myvariable_store(</span><span id='textcolor1008'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> kobject *kobj,</span>
|
|
<a id='x1-38109r23'></a><span class='ecrm-0500'>23</span><span class='ectt-0800'> </span><span id='textcolor1009'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> kobj_attribute *attr, </span><span id='textcolor1010'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *buf,</span>
|
|
<a id='x1-38111r24'></a><span class='ecrm-0500'>24</span><span class='ectt-0800'> </span><span id='textcolor1011'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'> count)</span>
|
|
<a id='x1-38113r25'></a><span class='ecrm-0500'>25</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-38115r26'></a><span class='ecrm-0500'>26</span><span class='ectt-0800'> sscanf(buf, </span><span id='textcolor1012'><span class='ectt-0800'>"%du"</span></span><span class='ectt-0800'>, &myvariable);</span>
|
|
<a id='x1-38117r27'></a><span class='ecrm-0500'>27</span><span class='ectt-0800'> </span><span id='textcolor1013'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> count;</span>
|
|
<a id='x1-38119r28'></a><span class='ecrm-0500'>28</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-38121r29'></a><span class='ecrm-0500'>29</span>
|
|
<a id='x1-38123r30'></a><span class='ecrm-0500'>30</span><span id='textcolor1014'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1015'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> kobj_attribute myvariable_attribute =</span>
|
|
<a id='x1-38125r31'></a><span class='ecrm-0500'>31</span><span class='ectt-0800'> __ATTR(myvariable, 0660, myvariable_show, (</span><span id='textcolor1016'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> *)myvariable_store);</span>
|
|
<a id='x1-38127r32'></a><span class='ecrm-0500'>32</span>
|
|
<a id='x1-38129r33'></a><span class='ecrm-0500'>33</span><span id='textcolor1017'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1018'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __init mymodule_init(</span><span id='textcolor1019'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-38131r34'></a><span class='ecrm-0500'>34</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-38133r35'></a><span class='ecrm-0500'>35</span><span class='ectt-0800'> </span><span id='textcolor1020'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> error = 0;</span>
|
|
<a id='x1-38135r36'></a><span class='ecrm-0500'>36</span>
|
|
<a id='x1-38137r37'></a><span class='ecrm-0500'>37</span><span class='ectt-0800'> pr_info(</span><span id='textcolor1021'><span class='ectt-0800'>"mymodule: initialized</span></span><span id='textcolor1022'><span class='ectt-0800'>\n</span></span><span id='textcolor1023'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-38139r38'></a><span class='ecrm-0500'>38</span>
|
|
<a id='x1-38141r39'></a><span class='ecrm-0500'>39</span><span class='ectt-0800'> mymodule = kobject_create_and_add(</span><span id='textcolor1024'><span class='ectt-0800'>"mymodule"</span></span><span class='ectt-0800'>, kernel_kobj);</span>
|
|
<a id='x1-38143r40'></a><span class='ecrm-0500'>40</span><span class='ectt-0800'> </span><span id='textcolor1025'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (!mymodule)</span>
|
|
<a id='x1-38145r41'></a><span class='ecrm-0500'>41</span><span class='ectt-0800'> </span><span id='textcolor1026'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -ENOMEM;</span>
|
|
<a id='x1-38147r42'></a><span class='ecrm-0500'>42</span>
|
|
<a id='x1-38149r43'></a><span class='ecrm-0500'>43</span><span class='ectt-0800'> error = sysfs_create_file(mymodule, &myvariable_attribute.attr);</span>
|
|
<a id='x1-38151r44'></a><span class='ecrm-0500'>44</span><span class='ectt-0800'> </span><span id='textcolor1027'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (error) {</span>
|
|
<a id='x1-38153r45'></a><span class='ecrm-0500'>45</span><span class='ectt-0800'> pr_info(</span><span id='textcolor1028'><span class='ectt-0800'>"failed to create the myvariable file "</span></span>
|
|
<a id='x1-38155r46'></a><span class='ecrm-0500'>46</span><span class='ectt-0800'> </span><span id='textcolor1029'><span class='ectt-0800'>"in /sys/kernel/mymodule</span></span><span id='textcolor1030'><span class='ectt-0800'>\n</span></span><span id='textcolor1031'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-38157r47'></a><span class='ecrm-0500'>47</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-38159r48'></a><span class='ecrm-0500'>48</span>
|
|
<a id='x1-38161r49'></a><span class='ecrm-0500'>49</span><span class='ectt-0800'> </span><span id='textcolor1032'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> error;</span>
|
|
<a id='x1-38163r50'></a><span class='ecrm-0500'>50</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-38165r51'></a><span class='ecrm-0500'>51</span>
|
|
<a id='x1-38167r52'></a><span class='ecrm-0500'>52</span><span id='textcolor1033'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1034'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> __exit mymodule_exit(</span><span id='textcolor1035'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-38169r53'></a><span class='ecrm-0500'>53</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-38171r54'></a><span class='ecrm-0500'>54</span><span class='ectt-0800'> pr_info(</span><span id='textcolor1036'><span class='ectt-0800'>"mymodule: Exit success</span></span><span id='textcolor1037'><span class='ectt-0800'>\n</span></span><span id='textcolor1038'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-38173r55'></a><span class='ecrm-0500'>55</span><span class='ectt-0800'> kobject_put(mymodule);</span>
|
|
<a id='x1-38175r56'></a><span class='ecrm-0500'>56</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-38177r57'></a><span class='ecrm-0500'>57</span>
|
|
<a id='x1-38179r58'></a><span class='ecrm-0500'>58</span><span class='ectt-0800'>module_init(mymodule_init);</span>
|
|
<a id='x1-38181r59'></a><span class='ecrm-0500'>59</span><span class='ectt-0800'>module_exit(mymodule_exit);</span>
|
|
<a id='x1-38183r60'></a><span class='ecrm-0500'>60</span>
|
|
<a id='x1-38185r61'></a><span class='ecrm-0500'>61</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor1039'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span></pre>
|
|
<!-- l. 1334 --><p class='indent'> Make and install the module:
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb55'><a id='x1-38189r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>make</span>
|
|
<a id='x1-38191r2'></a><span class='ecrm-0500'>2</span><span class='ectt-1000'>sudo insmod hello-sysfs.ko</span></pre>
|
|
<!-- l. 1341 --><p class='indent'> Check that it exists:
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb56'><a id='x1-38194r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>sudo lsmod | grep hello_sysfs</span></pre>
|
|
<!-- l. 1347 --><p class='indent'> What is the current value of <code> <span class='ectt-1000'>myvariable</span>
|
|
</code> ?
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb57'><a id='x1-38198r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>cat /sys/kernel/mymodule/myvariable</span></pre>
|
|
<!-- l. 1353 --><p class='indent'> Set the value of <code> <span class='ectt-1000'>myvariable</span>
|
|
</code> and check that it changed.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb58'><a id='x1-38203r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>echo </span><span id='textcolor1040'><span class='ectt-1000'>"32"</span></span><span class='ectt-1000'> > /sys/kernel/mymodule/myvariable</span>
|
|
<a id='x1-38205r2'></a><span class='ecrm-0500'>2</span><span class='ectt-1000'>cat /sys/kernel/mymodule/myvariable</span></pre>
|
|
<!-- l. 1360 --><p class='indent'> Finally, remove the test module:
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb59'><a id='x1-38208r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>sudo rmmod hello_sysfs</span></pre>
|
|
|
|
|
|
|
|
<!-- l. 1366 --><p class='indent'> In the above case, we use a simple kobject to create a directory under
|
|
sysfs, and communicate with its attributes. Since Linux v2.6.0, the
|
|
<code> <span class='ectt-1000'>kobject</span>
|
|
</code> structure made its appearance. It was initially meant as a simple way of
|
|
unifying kernel code which manages reference counted objects. After a
|
|
bit of mission creep, it is now the glue that holds much of the device
|
|
model and its sysfs interface together. For more information about kobject
|
|
and sysfs, see <a href='https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/Documentation/driver-api/driver-model/driver.rst'>Documentation/driver-api/driver-model/driver.rst</a> and
|
|
<a class='url' href='https://lwn.net/Articles/51437/'><span class='ectt-1000'>https://lwn.net/Articles/51437/</span></a>.
|
|
</p><!-- l. 1372 --><p class='noindent'>
|
|
</p>
|
|
<h3 class='sectionHead' id='talking-to-device-files'><span class='titlemark'>9 </span> <a id='x1-390009'></a>Talking To Device Files</h3>
|
|
<!-- l. 1374 --><p class='noindent'>Device files are supposed to represent physical devices. Most physical devices are
|
|
used for output as well as input, so there has to be some mechanism for
|
|
device drivers in the kernel to get the output to send to the device from
|
|
processes. This is done by opening the device file for output and writing to it,
|
|
just like writing to a file. In the following example, this is implemented by
|
|
<code> <span class='ectt-1000'>device_write</span>
|
|
</code>.
|
|
</p><!-- l. 1379 --><p class='indent'> This is not always enough. Imagine you had a serial port connected to a modem
|
|
(even if you have an internal modem, it is still implemented from the CPU’s
|
|
perspective as a serial port connected to a modem, so you don’t have to tax
|
|
your imagination too hard). The natural thing to do would be to use the
|
|
device file to write things to the modem (either modem commands or data to
|
|
be sent through the phone line) and read things from the modem (either
|
|
responses for commands or the data received through the phone line). However,
|
|
this leaves open the question of what to do when you need to talk to the
|
|
serial port itself, for example to configure the rate at which data is sent and
|
|
received.
|
|
</p><!-- l. 1384 --><p class='indent'> The answer in Unix is to use a special function called
|
|
<code> <span class='ectt-1000'>ioctl</span>
|
|
</code> (short for Input Output ConTroL). Every device can have its own
|
|
<code> <span class='ectt-1000'>ioctl</span>
|
|
</code> commands, which can be read ioctl’s (to send information from a process to the
|
|
kernel), write ioctl’s (to return information to a process), both or neither. Notice
|
|
here the roles of read and write are reversed again, so in ioctl’s read is to
|
|
send information to the kernel and write is to receive information from the
|
|
kernel.
|
|
</p><!-- l. 1388 --><p class='indent'> The ioctl function is called with three parameters: the file descriptor of the
|
|
appropriate device file, the ioctl number, and a parameter, which is of type long so
|
|
you can use a cast to use it to pass anything. You will not be able to pass a structure
|
|
this way, but you will be able to pass a pointer to the structure. Here is an
|
|
example:
|
|
|
|
|
|
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb60'><a id='x1-39005r1'></a><span class='ecrm-0500'>1</span><span id='textcolor1041'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-39007r2'></a><span class='ecrm-0500'>2</span><span id='textcolor1042'><span class='ectt-0800'> * ioctl.c</span></span>
|
|
<a id='x1-39009r3'></a><span class='ecrm-0500'>3</span><span id='textcolor1043'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-39011r4'></a><span class='ecrm-0500'>4</span><span id='textcolor1044'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1045'><span class='ectt-0800'><linux/cdev.h></span></span>
|
|
<a id='x1-39013r5'></a><span class='ecrm-0500'>5</span><span id='textcolor1046'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1047'><span class='ectt-0800'><linux/fs.h></span></span>
|
|
<a id='x1-39015r6'></a><span class='ecrm-0500'>6</span><span id='textcolor1048'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1049'><span class='ectt-0800'><linux/init.h></span></span>
|
|
<a id='x1-39017r7'></a><span class='ecrm-0500'>7</span><span id='textcolor1050'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1051'><span class='ectt-0800'><linux/ioctl.h></span></span>
|
|
<a id='x1-39019r8'></a><span class='ecrm-0500'>8</span><span id='textcolor1052'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1053'><span class='ectt-0800'><linux/module.h></span></span>
|
|
<a id='x1-39021r9'></a><span class='ecrm-0500'>9</span><span id='textcolor1054'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1055'><span class='ectt-0800'><linux/slab.h></span></span>
|
|
<a id='x1-39023r10'></a><span class='ecrm-0500'>10</span><span id='textcolor1056'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1057'><span class='ectt-0800'><linux/uaccess.h></span></span>
|
|
<a id='x1-39025r11'></a><span class='ecrm-0500'>11</span><span id='textcolor1058'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1059'><span class='ectt-0800'><linux/version.h></span></span>
|
|
<a id='x1-39027r12'></a><span class='ecrm-0500'>12</span>
|
|
<a id='x1-39029r13'></a><span class='ecrm-0500'>13</span><span id='textcolor1060'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> ioctl_arg {</span>
|
|
<a id='x1-39031r14'></a><span class='ecrm-0500'>14</span><span class='ectt-0800'> </span><span id='textcolor1061'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1062'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> val;</span>
|
|
<a id='x1-39033r15'></a><span class='ecrm-0500'>15</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-39035r16'></a><span class='ecrm-0500'>16</span>
|
|
<a id='x1-39037r17'></a><span class='ecrm-0500'>17</span><span id='textcolor1063'><span class='ectt-0800'>/* Documentation/userspace-api/ioctl/ioctl-number.rst */</span></span>
|
|
<a id='x1-39039r18'></a><span class='ecrm-0500'>18</span><span id='textcolor1064'><span class='ectt-0800'>#define IOC_MAGIC </span><span class='tctt-0800'>'</span><span class='ectt-0800'>\x66</span><span class='tctt-0800'>'</span></span>
|
|
<a id='x1-39041r19'></a><span class='ecrm-0500'>19</span>
|
|
<a id='x1-39043r20'></a><span class='ecrm-0500'>20</span><span id='textcolor1065'><span class='ectt-0800'>#define IOCTL_VALSET _IOW(IOC_MAGIC, 0, struct ioctl_arg)</span></span>
|
|
<a id='x1-39045r21'></a><span class='ecrm-0500'>21</span><span id='textcolor1066'><span class='ectt-0800'>#define IOCTL_VALGET _IOR(IOC_MAGIC, 1, struct ioctl_arg)</span></span>
|
|
<a id='x1-39047r22'></a><span class='ecrm-0500'>22</span><span id='textcolor1067'><span class='ectt-0800'>#define IOCTL_VALGET_NUM _IOR(IOC_MAGIC, 2, int)</span></span>
|
|
<a id='x1-39049r23'></a><span class='ecrm-0500'>23</span><span id='textcolor1068'><span class='ectt-0800'>#define IOCTL_VALSET_NUM _IOW(IOC_MAGIC, 3, int)</span></span>
|
|
<a id='x1-39051r24'></a><span class='ecrm-0500'>24</span>
|
|
<a id='x1-39053r25'></a><span class='ecrm-0500'>25</span><span id='textcolor1069'><span class='ectt-0800'>#define IOCTL_VAL_MAXNR 3</span></span>
|
|
<a id='x1-39055r26'></a><span class='ecrm-0500'>26</span><span id='textcolor1070'><span class='ectt-0800'>#define DRIVER_NAME "ioctltest"</span></span>
|
|
<a id='x1-39057r27'></a><span class='ecrm-0500'>27</span>
|
|
<a id='x1-39059r28'></a><span class='ecrm-0500'>28</span><span id='textcolor1071'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1072'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1073'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> test_ioctl_major = 0;</span>
|
|
<a id='x1-39061r29'></a><span class='ecrm-0500'>29</span><span id='textcolor1074'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1075'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1076'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> num_of_dev = 1;</span>
|
|
<a id='x1-39063r30'></a><span class='ecrm-0500'>30</span><span id='textcolor1077'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1078'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> cdev test_ioctl_cdev;</span>
|
|
<a id='x1-39065r31'></a><span class='ecrm-0500'>31</span><span id='textcolor1079'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1080'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> ioctl_num = 0;</span>
|
|
<a id='x1-39067r32'></a><span class='ecrm-0500'>32</span>
|
|
<a id='x1-39069r33'></a><span class='ecrm-0500'>33</span><span id='textcolor1081'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> test_ioctl_data {</span>
|
|
<a id='x1-39071r34'></a><span class='ecrm-0500'>34</span><span class='ectt-0800'> </span><span id='textcolor1082'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1083'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> val;</span>
|
|
<a id='x1-39073r35'></a><span class='ecrm-0500'>35</span><span class='ectt-0800'> rwlock_t lock;</span>
|
|
<a id='x1-39075r36'></a><span class='ecrm-0500'>36</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-39077r37'></a><span class='ecrm-0500'>37</span>
|
|
<a id='x1-39079r38'></a><span class='ecrm-0500'>38</span><span id='textcolor1084'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1085'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> test_ioctl_ioctl(</span><span id='textcolor1086'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *filp, </span><span id='textcolor1087'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1088'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> cmd,</span>
|
|
<a id='x1-39081r39'></a><span class='ecrm-0500'>39</span><span class='ectt-0800'> </span><span id='textcolor1089'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1090'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> arg)</span>
|
|
<a id='x1-39083r40'></a><span class='ecrm-0500'>40</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-39085r41'></a><span class='ecrm-0500'>41</span><span class='ectt-0800'> </span><span id='textcolor1091'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> test_ioctl_data *ioctl_data = filp->private_data;</span>
|
|
<a id='x1-39087r42'></a><span class='ecrm-0500'>42</span><span class='ectt-0800'> </span><span id='textcolor1092'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> retval = 0;</span>
|
|
<a id='x1-39089r43'></a><span class='ecrm-0500'>43</span><span class='ectt-0800'> </span><span id='textcolor1093'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1094'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> val;</span>
|
|
<a id='x1-39091r44'></a><span class='ecrm-0500'>44</span><span class='ectt-0800'> </span><span id='textcolor1095'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> ioctl_arg data;</span>
|
|
<a id='x1-39093r45'></a><span class='ecrm-0500'>45</span><span class='ectt-0800'> memset(&data, 0, </span><span id='textcolor1096'><span class='ectt-0800'>sizeof</span></span><span class='ectt-0800'>(data));</span>
|
|
<a id='x1-39095r46'></a><span class='ecrm-0500'>46</span>
|
|
<a id='x1-39097r47'></a><span class='ecrm-0500'>47</span><span class='ectt-0800'> </span><span id='textcolor1097'><span class='ectt-0800'>switch</span></span><span class='ectt-0800'> (cmd) {</span>
|
|
<a id='x1-39099r48'></a><span class='ecrm-0500'>48</span><span class='ectt-0800'> </span><span id='textcolor1098'><span class='ectt-0800'>case</span></span><span class='ectt-0800'> IOCTL_VALSET:</span>
|
|
<a id='x1-39101r49'></a><span class='ecrm-0500'>49</span><span class='ectt-0800'> </span><span id='textcolor1099'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (copy_from_user(&data, (</span><span id='textcolor1100'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __user *)arg, </span><span id='textcolor1101'><span class='ectt-0800'>sizeof</span></span><span class='ectt-0800'>(data))) {</span>
|
|
<a id='x1-39103r50'></a><span class='ecrm-0500'>50</span><span class='ectt-0800'> retval = -EFAULT;</span>
|
|
<a id='x1-39105r51'></a><span class='ecrm-0500'>51</span><span class='ectt-0800'> </span><span id='textcolor1102'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> done;</span>
|
|
<a id='x1-39107r52'></a><span class='ecrm-0500'>52</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-39109r53'></a><span class='ecrm-0500'>53</span>
|
|
<a id='x1-39111r54'></a><span class='ecrm-0500'>54</span><span class='ectt-0800'> pr_alert(</span><span id='textcolor1103'><span class='ectt-0800'>"IOCTL set val:%x .</span></span><span id='textcolor1104'><span class='ectt-0800'>\n</span></span><span id='textcolor1105'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, data.val);</span>
|
|
<a id='x1-39113r55'></a><span class='ecrm-0500'>55</span><span class='ectt-0800'> write_lock(&ioctl_data->lock);</span>
|
|
<a id='x1-39115r56'></a><span class='ecrm-0500'>56</span><span class='ectt-0800'> ioctl_data->val = data.val;</span>
|
|
<a id='x1-39117r57'></a><span class='ecrm-0500'>57</span><span class='ectt-0800'> write_unlock(&ioctl_data->lock);</span>
|
|
<a id='x1-39119r58'></a><span class='ecrm-0500'>58</span><span class='ectt-0800'> </span><span id='textcolor1106'><span class='ectt-0800'>break</span></span><span class='ectt-0800'>;</span>
|
|
<a id='x1-39121r59'></a><span class='ecrm-0500'>59</span>
|
|
<a id='x1-39123r60'></a><span class='ecrm-0500'>60</span><span class='ectt-0800'> </span><span id='textcolor1107'><span class='ectt-0800'>case</span></span><span class='ectt-0800'> IOCTL_VALGET:</span>
|
|
<a id='x1-39125r61'></a><span class='ecrm-0500'>61</span><span class='ectt-0800'> read_lock(&ioctl_data->lock);</span>
|
|
<a id='x1-39127r62'></a><span class='ecrm-0500'>62</span><span class='ectt-0800'> val = ioctl_data->val;</span>
|
|
<a id='x1-39129r63'></a><span class='ecrm-0500'>63</span><span class='ectt-0800'> read_unlock(&ioctl_data->lock);</span>
|
|
<a id='x1-39131r64'></a><span class='ecrm-0500'>64</span><span class='ectt-0800'> data.val = val;</span>
|
|
<a id='x1-39133r65'></a><span class='ecrm-0500'>65</span>
|
|
<a id='x1-39135r66'></a><span class='ecrm-0500'>66</span><span class='ectt-0800'> </span><span id='textcolor1108'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (copy_to_user((</span><span id='textcolor1109'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __user *)arg, &data, </span><span id='textcolor1110'><span class='ectt-0800'>sizeof</span></span><span class='ectt-0800'>(data))) {</span>
|
|
<a id='x1-39137r67'></a><span class='ecrm-0500'>67</span><span class='ectt-0800'> retval = -EFAULT;</span>
|
|
<a id='x1-39139r68'></a><span class='ecrm-0500'>68</span><span class='ectt-0800'> </span><span id='textcolor1111'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> done;</span>
|
|
<a id='x1-39141r69'></a><span class='ecrm-0500'>69</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-39143r70'></a><span class='ecrm-0500'>70</span>
|
|
<a id='x1-39145r71'></a><span class='ecrm-0500'>71</span><span class='ectt-0800'> </span><span id='textcolor1112'><span class='ectt-0800'>break</span></span><span class='ectt-0800'>;</span>
|
|
<a id='x1-39147r72'></a><span class='ecrm-0500'>72</span>
|
|
<a id='x1-39149r73'></a><span class='ecrm-0500'>73</span><span class='ectt-0800'> </span><span id='textcolor1113'><span class='ectt-0800'>case</span></span><span class='ectt-0800'> IOCTL_VALGET_NUM:</span>
|
|
<a id='x1-39151r74'></a><span class='ecrm-0500'>74</span><span class='ectt-0800'> retval = __put_user(ioctl_num, (</span><span id='textcolor1114'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __user *)arg);</span>
|
|
<a id='x1-39153r75'></a><span class='ecrm-0500'>75</span><span class='ectt-0800'> </span><span id='textcolor1115'><span class='ectt-0800'>break</span></span><span class='ectt-0800'>;</span>
|
|
<a id='x1-39155r76'></a><span class='ecrm-0500'>76</span>
|
|
<a id='x1-39157r77'></a><span class='ecrm-0500'>77</span><span class='ectt-0800'> </span><span id='textcolor1116'><span class='ectt-0800'>case</span></span><span class='ectt-0800'> IOCTL_VALSET_NUM:</span>
|
|
<a id='x1-39159r78'></a><span class='ecrm-0500'>78</span><span class='ectt-0800'> ioctl_num = arg;</span>
|
|
<a id='x1-39161r79'></a><span class='ecrm-0500'>79</span><span class='ectt-0800'> </span><span id='textcolor1117'><span class='ectt-0800'>break</span></span><span class='ectt-0800'>;</span>
|
|
<a id='x1-39163r80'></a><span class='ecrm-0500'>80</span>
|
|
<a id='x1-39165r81'></a><span class='ecrm-0500'>81</span><span class='ectt-0800'> </span><span id='textcolor1118'><span class='ectt-0800'>default</span></span><span class='ectt-0800'>:</span>
|
|
<a id='x1-39167r82'></a><span class='ecrm-0500'>82</span><span class='ectt-0800'> retval = -ENOTTY;</span>
|
|
<a id='x1-39169r83'></a><span class='ecrm-0500'>83</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-39171r84'></a><span class='ecrm-0500'>84</span>
|
|
<a id='x1-39173r85'></a><span class='ecrm-0500'>85</span><span class='ectt-0800'>done:</span>
|
|
<a id='x1-39175r86'></a><span class='ecrm-0500'>86</span><span class='ectt-0800'> </span><span id='textcolor1119'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> retval;</span>
|
|
<a id='x1-39177r87'></a><span class='ecrm-0500'>87</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-39179r88'></a><span class='ecrm-0500'>88</span>
|
|
<a id='x1-39181r89'></a><span class='ecrm-0500'>89</span><span id='textcolor1120'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1121'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> test_ioctl_read(</span><span id='textcolor1122'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *filp, </span><span id='textcolor1123'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *buf,</span>
|
|
<a id='x1-39183r90'></a><span class='ecrm-0500'>90</span><span class='ectt-0800'> </span><span id='textcolor1124'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'> count, loff_t *f_pos)</span>
|
|
<a id='x1-39185r91'></a><span class='ecrm-0500'>91</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-39187r92'></a><span class='ecrm-0500'>92</span><span class='ectt-0800'> </span><span id='textcolor1125'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> test_ioctl_data *ioctl_data = filp->private_data;</span>
|
|
<a id='x1-39189r93'></a><span class='ecrm-0500'>93</span><span class='ectt-0800'> </span><span id='textcolor1126'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1127'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> val;</span>
|
|
<a id='x1-39191r94'></a><span class='ecrm-0500'>94</span><span class='ectt-0800'> </span><span id='textcolor1128'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> retval;</span>
|
|
<a id='x1-39193r95'></a><span class='ecrm-0500'>95</span><span class='ectt-0800'> </span><span id='textcolor1129'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> i = 0;</span>
|
|
<a id='x1-39195r96'></a><span class='ecrm-0500'>96</span>
|
|
<a id='x1-39197r97'></a><span class='ecrm-0500'>97</span><span class='ectt-0800'> read_lock(&ioctl_data->lock);</span>
|
|
<a id='x1-39199r98'></a><span class='ecrm-0500'>98</span><span class='ectt-0800'> val = ioctl_data->val;</span>
|
|
<a id='x1-39201r99'></a><span class='ecrm-0500'>99</span><span class='ectt-0800'> read_unlock(&ioctl_data->lock);</span>
|
|
<a id='x1-39203r100'></a><span class='ecrm-0500'>100</span>
|
|
<a id='x1-39205r101'></a><span class='ecrm-0500'>101</span><span class='ectt-0800'> </span><span id='textcolor1130'><span class='ectt-0800'>for</span></span><span class='ectt-0800'> (; i < count; i++) {</span>
|
|
<a id='x1-39207r102'></a><span class='ecrm-0500'>102</span><span class='ectt-0800'> </span><span id='textcolor1131'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (copy_to_user(&buf[i], &val, 1)) {</span>
|
|
<a id='x1-39209r103'></a><span class='ecrm-0500'>103</span><span class='ectt-0800'> retval = -EFAULT;</span>
|
|
<a id='x1-39211r104'></a><span class='ecrm-0500'>104</span><span class='ectt-0800'> </span><span id='textcolor1132'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> out;</span>
|
|
<a id='x1-39213r105'></a><span class='ecrm-0500'>105</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-39215r106'></a><span class='ecrm-0500'>106</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-39217r107'></a><span class='ecrm-0500'>107</span>
|
|
<a id='x1-39219r108'></a><span class='ecrm-0500'>108</span><span class='ectt-0800'> retval = count;</span>
|
|
<a id='x1-39221r109'></a><span class='ecrm-0500'>109</span><span class='ectt-0800'>out:</span>
|
|
<a id='x1-39223r110'></a><span class='ecrm-0500'>110</span><span class='ectt-0800'> </span><span id='textcolor1133'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> retval;</span>
|
|
<a id='x1-39225r111'></a><span class='ecrm-0500'>111</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-39227r112'></a><span class='ecrm-0500'>112</span>
|
|
<a id='x1-39229r113'></a><span class='ecrm-0500'>113</span><span id='textcolor1134'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1135'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> test_ioctl_close(</span><span id='textcolor1136'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> inode *inode, </span><span id='textcolor1137'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *filp)</span>
|
|
<a id='x1-39231r114'></a><span class='ecrm-0500'>114</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-39233r115'></a><span class='ecrm-0500'>115</span><span class='ectt-0800'> pr_alert(</span><span id='textcolor1138'><span class='ectt-0800'>"%s call.</span></span><span id='textcolor1139'><span class='ectt-0800'>\n</span></span><span id='textcolor1140'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, __func__);</span>
|
|
<a id='x1-39235r116'></a><span class='ecrm-0500'>116</span>
|
|
<a id='x1-39237r117'></a><span class='ecrm-0500'>117</span><span class='ectt-0800'> </span><span id='textcolor1141'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (filp->private_data) {</span>
|
|
<a id='x1-39239r118'></a><span class='ecrm-0500'>118</span><span class='ectt-0800'> kfree(filp->private_data);</span>
|
|
<a id='x1-39241r119'></a><span class='ecrm-0500'>119</span><span class='ectt-0800'> filp->private_data = NULL;</span>
|
|
<a id='x1-39243r120'></a><span class='ecrm-0500'>120</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-39245r121'></a><span class='ecrm-0500'>121</span>
|
|
<a id='x1-39247r122'></a><span class='ecrm-0500'>122</span><span class='ectt-0800'> </span><span id='textcolor1142'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-39249r123'></a><span class='ecrm-0500'>123</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-39251r124'></a><span class='ecrm-0500'>124</span>
|
|
<a id='x1-39253r125'></a><span class='ecrm-0500'>125</span><span id='textcolor1143'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1144'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> test_ioctl_open(</span><span id='textcolor1145'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> inode *inode, </span><span id='textcolor1146'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *filp)</span>
|
|
<a id='x1-39255r126'></a><span class='ecrm-0500'>126</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-39257r127'></a><span class='ecrm-0500'>127</span><span class='ectt-0800'> </span><span id='textcolor1147'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> test_ioctl_data *ioctl_data;</span>
|
|
<a id='x1-39259r128'></a><span class='ecrm-0500'>128</span>
|
|
<a id='x1-39261r129'></a><span class='ecrm-0500'>129</span><span class='ectt-0800'> pr_alert(</span><span id='textcolor1148'><span class='ectt-0800'>"%s call.</span></span><span id='textcolor1149'><span class='ectt-0800'>\n</span></span><span id='textcolor1150'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, __func__);</span>
|
|
<a id='x1-39263r130'></a><span class='ecrm-0500'>130</span><span class='ectt-0800'> ioctl_data = kmalloc(</span><span id='textcolor1151'><span class='ectt-0800'>sizeof</span></span><span class='ectt-0800'>(</span><span id='textcolor1152'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> test_ioctl_data), GFP_KERNEL);</span>
|
|
<a id='x1-39265r131'></a><span class='ecrm-0500'>131</span>
|
|
<a id='x1-39267r132'></a><span class='ecrm-0500'>132</span><span class='ectt-0800'> </span><span id='textcolor1153'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (ioctl_data == NULL)</span>
|
|
<a id='x1-39269r133'></a><span class='ecrm-0500'>133</span><span class='ectt-0800'> </span><span id='textcolor1154'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -ENOMEM;</span>
|
|
<a id='x1-39271r134'></a><span class='ecrm-0500'>134</span>
|
|
<a id='x1-39273r135'></a><span class='ecrm-0500'>135</span><span class='ectt-0800'> rwlock_init(&ioctl_data->lock);</span>
|
|
<a id='x1-39275r136'></a><span class='ecrm-0500'>136</span><span class='ectt-0800'> ioctl_data->val = 0xFF;</span>
|
|
<a id='x1-39277r137'></a><span class='ecrm-0500'>137</span><span class='ectt-0800'> filp->private_data = ioctl_data;</span>
|
|
<a id='x1-39279r138'></a><span class='ecrm-0500'>138</span>
|
|
<a id='x1-39281r139'></a><span class='ecrm-0500'>139</span><span class='ectt-0800'> </span><span id='textcolor1155'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-39283r140'></a><span class='ecrm-0500'>140</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-39285r141'></a><span class='ecrm-0500'>141</span>
|
|
<a id='x1-39287r142'></a><span class='ecrm-0500'>142</span><span id='textcolor1156'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1157'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file_operations fops = {</span>
|
|
<a id='x1-39289r143'></a><span class='ecrm-0500'>143</span><span id='textcolor1158'><span class='ectt-0800'>#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 0)</span></span>
|
|
<a id='x1-39291r144'></a><span class='ecrm-0500'>144</span><span class='ectt-0800'> .owner = THIS_MODULE,</span>
|
|
<a id='x1-39293r145'></a><span class='ecrm-0500'>145</span><span id='textcolor1159'><span class='ectt-0800'>#endif</span></span>
|
|
<a id='x1-39295r146'></a><span class='ecrm-0500'>146</span><span class='ectt-0800'> .open = test_ioctl_open,</span>
|
|
<a id='x1-39297r147'></a><span class='ecrm-0500'>147</span><span class='ectt-0800'> .release = test_ioctl_close,</span>
|
|
<a id='x1-39299r148'></a><span class='ecrm-0500'>148</span><span class='ectt-0800'> .read = test_ioctl_read,</span>
|
|
<a id='x1-39301r149'></a><span class='ecrm-0500'>149</span><span class='ectt-0800'> .unlocked_ioctl = test_ioctl_ioctl,</span>
|
|
<a id='x1-39303r150'></a><span class='ecrm-0500'>150</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-39305r151'></a><span class='ecrm-0500'>151</span>
|
|
<a id='x1-39307r152'></a><span class='ecrm-0500'>152</span><span id='textcolor1160'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1161'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __init ioctl_init(</span><span id='textcolor1162'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-39309r153'></a><span class='ecrm-0500'>153</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-39311r154'></a><span class='ecrm-0500'>154</span><span class='ectt-0800'> </span><span id='textcolor1163'><span class='ectt-0800'>dev_t</span></span><span class='ectt-0800'> dev;</span>
|
|
<a id='x1-39313r155'></a><span class='ecrm-0500'>155</span><span class='ectt-0800'> </span><span id='textcolor1164'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> alloc_ret = -1;</span>
|
|
<a id='x1-39315r156'></a><span class='ecrm-0500'>156</span><span class='ectt-0800'> </span><span id='textcolor1165'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> cdev_ret = -1;</span>
|
|
<a id='x1-39317r157'></a><span class='ecrm-0500'>157</span><span class='ectt-0800'> alloc_ret = alloc_chrdev_region(&dev, 0, num_of_dev, DRIVER_NAME);</span>
|
|
<a id='x1-39319r158'></a><span class='ecrm-0500'>158</span>
|
|
<a id='x1-39321r159'></a><span class='ecrm-0500'>159</span><span class='ectt-0800'> </span><span id='textcolor1166'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (alloc_ret)</span>
|
|
<a id='x1-39323r160'></a><span class='ecrm-0500'>160</span><span class='ectt-0800'> </span><span id='textcolor1167'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> error;</span>
|
|
<a id='x1-39325r161'></a><span class='ecrm-0500'>161</span>
|
|
<a id='x1-39327r162'></a><span class='ecrm-0500'>162</span><span class='ectt-0800'> test_ioctl_major = MAJOR(dev);</span>
|
|
<a id='x1-39329r163'></a><span class='ecrm-0500'>163</span><span class='ectt-0800'> cdev_init(&test_ioctl_cdev, &fops);</span>
|
|
<a id='x1-39331r164'></a><span class='ecrm-0500'>164</span><span class='ectt-0800'> cdev_ret = cdev_add(&test_ioctl_cdev, dev, num_of_dev);</span>
|
|
<a id='x1-39333r165'></a><span class='ecrm-0500'>165</span>
|
|
<a id='x1-39335r166'></a><span class='ecrm-0500'>166</span><span class='ectt-0800'> </span><span id='textcolor1168'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (cdev_ret)</span>
|
|
<a id='x1-39337r167'></a><span class='ecrm-0500'>167</span><span class='ectt-0800'> </span><span id='textcolor1169'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> error;</span>
|
|
<a id='x1-39339r168'></a><span class='ecrm-0500'>168</span>
|
|
<a id='x1-39341r169'></a><span class='ecrm-0500'>169</span><span class='ectt-0800'> pr_alert(</span><span id='textcolor1170'><span class='ectt-0800'>"%s driver(major: %d) installed.</span></span><span id='textcolor1171'><span class='ectt-0800'>\n</span></span><span id='textcolor1172'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, DRIVER_NAME,</span>
|
|
<a id='x1-39343r170'></a><span class='ecrm-0500'>170</span><span class='ectt-0800'> test_ioctl_major);</span>
|
|
<a id='x1-39345r171'></a><span class='ecrm-0500'>171</span><span class='ectt-0800'> </span><span id='textcolor1173'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-39347r172'></a><span class='ecrm-0500'>172</span><span class='ectt-0800'>error:</span>
|
|
<a id='x1-39349r173'></a><span class='ecrm-0500'>173</span><span class='ectt-0800'> </span><span id='textcolor1174'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (cdev_ret == 0)</span>
|
|
<a id='x1-39351r174'></a><span class='ecrm-0500'>174</span><span class='ectt-0800'> cdev_del(&test_ioctl_cdev);</span>
|
|
<a id='x1-39353r175'></a><span class='ecrm-0500'>175</span><span class='ectt-0800'> </span><span id='textcolor1175'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (alloc_ret == 0)</span>
|
|
<a id='x1-39355r176'></a><span class='ecrm-0500'>176</span><span class='ectt-0800'> unregister_chrdev_region(dev, num_of_dev);</span>
|
|
<a id='x1-39357r177'></a><span class='ecrm-0500'>177</span><span class='ectt-0800'> </span><span id='textcolor1176'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -1;</span>
|
|
<a id='x1-39359r178'></a><span class='ecrm-0500'>178</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-39361r179'></a><span class='ecrm-0500'>179</span>
|
|
<a id='x1-39363r180'></a><span class='ecrm-0500'>180</span><span id='textcolor1177'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1178'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> __exit ioctl_exit(</span><span id='textcolor1179'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-39365r181'></a><span class='ecrm-0500'>181</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-39367r182'></a><span class='ecrm-0500'>182</span><span class='ectt-0800'> </span><span id='textcolor1180'><span class='ectt-0800'>dev_t</span></span><span class='ectt-0800'> dev = MKDEV(test_ioctl_major, 0);</span>
|
|
<a id='x1-39369r183'></a><span class='ecrm-0500'>183</span>
|
|
<a id='x1-39371r184'></a><span class='ecrm-0500'>184</span><span class='ectt-0800'> cdev_del(&test_ioctl_cdev);</span>
|
|
<a id='x1-39373r185'></a><span class='ecrm-0500'>185</span><span class='ectt-0800'> unregister_chrdev_region(dev, num_of_dev);</span>
|
|
<a id='x1-39375r186'></a><span class='ecrm-0500'>186</span><span class='ectt-0800'> pr_alert(</span><span id='textcolor1181'><span class='ectt-0800'>"%s driver removed.</span></span><span id='textcolor1182'><span class='ectt-0800'>\n</span></span><span id='textcolor1183'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, DRIVER_NAME);</span>
|
|
<a id='x1-39377r187'></a><span class='ecrm-0500'>187</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-39379r188'></a><span class='ecrm-0500'>188</span>
|
|
<a id='x1-39381r189'></a><span class='ecrm-0500'>189</span><span class='ectt-0800'>module_init(ioctl_init);</span>
|
|
<a id='x1-39383r190'></a><span class='ecrm-0500'>190</span><span class='ectt-0800'>module_exit(ioctl_exit);</span>
|
|
<a id='x1-39385r191'></a><span class='ecrm-0500'>191</span>
|
|
<a id='x1-39387r192'></a><span class='ecrm-0500'>192</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor1184'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-39389r193'></a><span class='ecrm-0500'>193</span><span class='ectt-0800'>MODULE_DESCRIPTION(</span><span id='textcolor1185'><span class='ectt-0800'>"This is test_ioctl module"</span></span><span class='ectt-0800'>);</span></pre>
|
|
<!-- l. 1394 --><p class='indent'> You can see there is an argument called
|
|
<code> <span class='ectt-1000'>cmd</span>
|
|
</code> in <code> <span class='ectt-1000'>test_ioctl_ioctl()</span>
|
|
</code> function. It is the ioctl number. The ioctl number encodes the major
|
|
device number, the type of the ioctl, the command, and the type of
|
|
the parameter. This ioctl number is usually created by a macro call
|
|
(<code> <span class='ectt-1000'>_IO</span>
|
|
</code>, <code> <span class='ectt-1000'>_IOR</span>
|
|
</code>, <code> <span class='ectt-1000'>_IOW</span>
|
|
</code> or <code> <span class='ectt-1000'>_IOWR</span>
|
|
</code> — depending on the type) in a header file. This header file should then be
|
|
included both by the programs which will use ioctl (so they can generate the
|
|
appropriate ioctl’s) and by the kernel module (so it can understand it). In the
|
|
example below, the header file is <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>chardev.h</span></span></span> and the program which uses it is
|
|
<span class='obeylines-h'><span class='verb'><span class='ectt-1000'>userspace_ioctl.c</span></span></span>.
|
|
</p><!-- l. 1401 --><p class='indent'> If you want to use ioctls in your own kernel modules, it is best to receive an
|
|
official ioctl assignment, so if you accidentally get somebody else’s ioctls, or if they
|
|
get yours, you’ll know something is wrong. For more information, consult the kernel
|
|
source tree at <a href='https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/Documentation/userspace-api/ioctl/ioctl-number.rst'>Documentation/userspace-api/ioctl/ioctl-number.rst</a>.
|
|
</p><!-- l. 1404 --><p class='indent'> Also, we need to be careful that concurrent access to the shared resources will
|
|
lead to the race condition. The solution is using atomic Compare-And-Swap (CAS),
|
|
which we mentioned at <a href='#chardevc'>6.5<!-- tex4ht:ref: sec:chardev_c --></a> section, to enforce the exclusive access.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb61'><a id='x1-39397r1'></a><span class='ecrm-0500'>1</span><span id='textcolor1186'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-39399r2'></a><span class='ecrm-0500'>2</span><span id='textcolor1187'><span class='ectt-0800'> * chardev2.c - Create an input/output character device</span></span>
|
|
<a id='x1-39401r3'></a><span class='ecrm-0500'>3</span><span id='textcolor1188'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-39403r4'></a><span class='ecrm-0500'>4</span>
|
|
<a id='x1-39405r5'></a><span class='ecrm-0500'>5</span><span id='textcolor1189'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1190'><span class='ectt-0800'><linux/atomic.h></span></span>
|
|
<a id='x1-39407r6'></a><span class='ecrm-0500'>6</span><span id='textcolor1191'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1192'><span class='ectt-0800'><linux/cdev.h></span></span>
|
|
<a id='x1-39409r7'></a><span class='ecrm-0500'>7</span><span id='textcolor1193'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1194'><span class='ectt-0800'><linux/delay.h></span></span>
|
|
<a id='x1-39411r8'></a><span class='ecrm-0500'>8</span><span id='textcolor1195'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1196'><span class='ectt-0800'><linux/device.h></span></span>
|
|
<a id='x1-39413r9'></a><span class='ecrm-0500'>9</span><span id='textcolor1197'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1198'><span class='ectt-0800'><linux/fs.h></span></span>
|
|
<a id='x1-39415r10'></a><span class='ecrm-0500'>10</span><span id='textcolor1199'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1200'><span class='ectt-0800'><linux/init.h></span></span>
|
|
<a id='x1-39417r11'></a><span class='ecrm-0500'>11</span><span id='textcolor1201'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1202'><span class='ectt-0800'><linux/module.h> /* Specifically, a module */</span></span>
|
|
<a id='x1-39419r12'></a><span class='ecrm-0500'>12</span><span id='textcolor1203'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1204'><span class='ectt-0800'><linux/printk.h></span></span>
|
|
<a id='x1-39421r13'></a><span class='ecrm-0500'>13</span><span id='textcolor1205'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1206'><span class='ectt-0800'><linux/types.h></span></span>
|
|
<a id='x1-39423r14'></a><span class='ecrm-0500'>14</span><span id='textcolor1207'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1208'><span class='ectt-0800'><linux/uaccess.h> /* for get_user and put_user */</span></span>
|
|
<a id='x1-39425r15'></a><span class='ecrm-0500'>15</span><span id='textcolor1209'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1210'><span class='ectt-0800'><linux/version.h></span></span>
|
|
<a id='x1-39427r16'></a><span class='ecrm-0500'>16</span>
|
|
<a id='x1-39429r17'></a><span class='ecrm-0500'>17</span><span id='textcolor1211'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1212'><span class='ectt-0800'><asm/errno.h></span></span>
|
|
<a id='x1-39431r18'></a><span class='ecrm-0500'>18</span>
|
|
<a id='x1-39433r19'></a><span class='ecrm-0500'>19</span><span id='textcolor1213'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1214'><span class='ectt-0800'>"chardev.h"</span></span>
|
|
<a id='x1-39435r20'></a><span class='ecrm-0500'>20</span><span id='textcolor1215'><span class='ectt-0800'>#define SUCCESS 0</span></span>
|
|
<a id='x1-39437r21'></a><span class='ecrm-0500'>21</span><span id='textcolor1216'><span class='ectt-0800'>#define DEVICE_NAME "char_dev"</span></span>
|
|
<a id='x1-39439r22'></a><span class='ecrm-0500'>22</span><span id='textcolor1217'><span class='ectt-0800'>#define BUF_LEN 80</span></span>
|
|
<a id='x1-39441r23'></a><span class='ecrm-0500'>23</span>
|
|
<a id='x1-39443r24'></a><span class='ecrm-0500'>24</span><span id='textcolor1218'><span class='ectt-0800'>enum</span></span><span class='ectt-0800'> {</span>
|
|
<a id='x1-39445r25'></a><span class='ecrm-0500'>25</span><span class='ectt-0800'> CDEV_NOT_USED = 0,</span>
|
|
<a id='x1-39447r26'></a><span class='ecrm-0500'>26</span><span class='ectt-0800'> CDEV_EXCLUSIVE_OPEN = 1,</span>
|
|
<a id='x1-39449r27'></a><span class='ecrm-0500'>27</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-39451r28'></a><span class='ecrm-0500'>28</span>
|
|
<a id='x1-39453r29'></a><span class='ecrm-0500'>29</span><span id='textcolor1219'><span class='ectt-0800'>/* Is the device open right now? Used to prevent concurrent access into</span></span>
|
|
<a id='x1-39455r30'></a><span class='ecrm-0500'>30</span><span id='textcolor1220'><span class='ectt-0800'> * the same device</span></span>
|
|
<a id='x1-39457r31'></a><span class='ecrm-0500'>31</span><span id='textcolor1221'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-39459r32'></a><span class='ecrm-0500'>32</span><span id='textcolor1222'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> atomic_t already_open = ATOMIC_INIT(CDEV_NOT_USED);</span>
|
|
<a id='x1-39461r33'></a><span class='ecrm-0500'>33</span>
|
|
<a id='x1-39463r34'></a><span class='ecrm-0500'>34</span><span id='textcolor1223'><span class='ectt-0800'>/* The message the device will give when asked */</span></span>
|
|
<a id='x1-39465r35'></a><span class='ecrm-0500'>35</span><span id='textcolor1224'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1225'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> message[BUF_LEN + 1];</span>
|
|
<a id='x1-39467r36'></a><span class='ecrm-0500'>36</span>
|
|
<a id='x1-39469r37'></a><span class='ecrm-0500'>37</span><span id='textcolor1226'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1227'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> class *cls;</span>
|
|
<a id='x1-39471r38'></a><span class='ecrm-0500'>38</span>
|
|
<a id='x1-39473r39'></a><span class='ecrm-0500'>39</span><span id='textcolor1228'><span class='ectt-0800'>/* This is called whenever a process attempts to open the device file */</span></span>
|
|
<a id='x1-39475r40'></a><span class='ecrm-0500'>40</span><span id='textcolor1229'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1230'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> device_open(</span><span id='textcolor1231'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> inode *inode, </span><span id='textcolor1232'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file)</span>
|
|
<a id='x1-39477r41'></a><span class='ecrm-0500'>41</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-39479r42'></a><span class='ecrm-0500'>42</span><span class='ectt-0800'> pr_info(</span><span id='textcolor1233'><span class='ectt-0800'>"device_open(%p)</span></span><span id='textcolor1234'><span class='ectt-0800'>\n</span></span><span id='textcolor1235'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, file);</span>
|
|
<a id='x1-39481r43'></a><span class='ecrm-0500'>43</span>
|
|
<a id='x1-39483r44'></a><span class='ecrm-0500'>44</span><span class='ectt-0800'> try_module_get(THIS_MODULE);</span>
|
|
<a id='x1-39485r45'></a><span class='ecrm-0500'>45</span><span class='ectt-0800'> </span><span id='textcolor1236'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> SUCCESS;</span>
|
|
<a id='x1-39487r46'></a><span class='ecrm-0500'>46</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-39489r47'></a><span class='ecrm-0500'>47</span>
|
|
<a id='x1-39491r48'></a><span class='ecrm-0500'>48</span><span id='textcolor1237'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1238'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> device_release(</span><span id='textcolor1239'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> inode *inode, </span><span id='textcolor1240'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file)</span>
|
|
<a id='x1-39493r49'></a><span class='ecrm-0500'>49</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-39495r50'></a><span class='ecrm-0500'>50</span><span class='ectt-0800'> pr_info(</span><span id='textcolor1241'><span class='ectt-0800'>"device_release(%p,%p)</span></span><span id='textcolor1242'><span class='ectt-0800'>\n</span></span><span id='textcolor1243'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, inode, file);</span>
|
|
<a id='x1-39497r51'></a><span class='ecrm-0500'>51</span>
|
|
<a id='x1-39499r52'></a><span class='ecrm-0500'>52</span><span class='ectt-0800'> module_put(THIS_MODULE);</span>
|
|
<a id='x1-39501r53'></a><span class='ecrm-0500'>53</span><span class='ectt-0800'> </span><span id='textcolor1244'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> SUCCESS;</span>
|
|
<a id='x1-39503r54'></a><span class='ecrm-0500'>54</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-39505r55'></a><span class='ecrm-0500'>55</span>
|
|
<a id='x1-39507r56'></a><span class='ecrm-0500'>56</span><span id='textcolor1245'><span class='ectt-0800'>/* This function is called whenever a process which has already opened the</span></span>
|
|
<a id='x1-39509r57'></a><span class='ecrm-0500'>57</span><span id='textcolor1246'><span class='ectt-0800'> * device file attempts to read from it.</span></span>
|
|
<a id='x1-39511r58'></a><span class='ecrm-0500'>58</span><span id='textcolor1247'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-39513r59'></a><span class='ecrm-0500'>59</span><span id='textcolor1248'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1249'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> device_read(</span><span id='textcolor1250'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file, </span><span id='textcolor1251'><span class='ectt-0800'>/* see include/linux/fs.h */</span></span>
|
|
<a id='x1-39515r60'></a><span class='ecrm-0500'>60</span><span class='ectt-0800'> </span><span id='textcolor1252'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *buffer, </span><span id='textcolor1253'><span class='ectt-0800'>/* buffer to be filled */</span></span>
|
|
<a id='x1-39517r61'></a><span class='ecrm-0500'>61</span><span class='ectt-0800'> </span><span id='textcolor1254'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'> length, </span><span id='textcolor1255'><span class='ectt-0800'>/* length of the buffer */</span></span>
|
|
<a id='x1-39519r62'></a><span class='ecrm-0500'>62</span><span class='ectt-0800'> loff_t *offset)</span>
|
|
<a id='x1-39521r63'></a><span class='ecrm-0500'>63</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-39523r64'></a><span class='ecrm-0500'>64</span><span class='ectt-0800'> </span><span id='textcolor1256'><span class='ectt-0800'>/* Number of bytes actually written to the buffer */</span></span>
|
|
<a id='x1-39525r65'></a><span class='ecrm-0500'>65</span><span class='ectt-0800'> </span><span id='textcolor1257'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> bytes_read = 0;</span>
|
|
<a id='x1-39527r66'></a><span class='ecrm-0500'>66</span><span class='ectt-0800'> </span><span id='textcolor1258'><span class='ectt-0800'>/* How far did the process reading the message get? Useful if the message</span></span>
|
|
<a id='x1-39529r67'></a><span class='ecrm-0500'>67</span><span id='textcolor1259'><span class='ectt-0800'> * is larger than the size of the buffer we get to fill in device_read.</span></span>
|
|
<a id='x1-39531r68'></a><span class='ecrm-0500'>68</span><span id='textcolor1260'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-39533r69'></a><span class='ecrm-0500'>69</span><span class='ectt-0800'> </span><span id='textcolor1261'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor1262'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *message_ptr = message;</span>
|
|
<a id='x1-39535r70'></a><span class='ecrm-0500'>70</span>
|
|
<a id='x1-39537r71'></a><span class='ecrm-0500'>71</span><span class='ectt-0800'> </span><span id='textcolor1263'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (!*(message_ptr + *offset)) { </span><span id='textcolor1264'><span class='ectt-0800'>/* we are at the end of message */</span></span>
|
|
<a id='x1-39539r72'></a><span class='ecrm-0500'>72</span><span class='ectt-0800'> *offset = 0; </span><span id='textcolor1265'><span class='ectt-0800'>/* reset the offset */</span></span>
|
|
<a id='x1-39541r73'></a><span class='ecrm-0500'>73</span><span class='ectt-0800'> </span><span id='textcolor1266'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0; </span><span id='textcolor1267'><span class='ectt-0800'>/* signify end of file */</span></span>
|
|
<a id='x1-39543r74'></a><span class='ecrm-0500'>74</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-39545r75'></a><span class='ecrm-0500'>75</span>
|
|
<a id='x1-39547r76'></a><span class='ecrm-0500'>76</span><span class='ectt-0800'> message_ptr += *offset;</span>
|
|
<a id='x1-39549r77'></a><span class='ecrm-0500'>77</span>
|
|
<a id='x1-39551r78'></a><span class='ecrm-0500'>78</span><span class='ectt-0800'> </span><span id='textcolor1268'><span class='ectt-0800'>/* Actually put the data into the buffer */</span></span>
|
|
<a id='x1-39553r79'></a><span class='ecrm-0500'>79</span><span class='ectt-0800'> </span><span id='textcolor1269'><span class='ectt-0800'>while</span></span><span class='ectt-0800'> (length && *message_ptr) {</span>
|
|
<a id='x1-39555r80'></a><span class='ecrm-0500'>80</span><span class='ectt-0800'> </span><span id='textcolor1270'><span class='ectt-0800'>/* Because the buffer is in the user data segment, not the kernel</span></span>
|
|
<a id='x1-39557r81'></a><span class='ecrm-0500'>81</span><span id='textcolor1271'><span class='ectt-0800'> * data segment, assignment would not work. Instead, we have to</span></span>
|
|
<a id='x1-39559r82'></a><span class='ecrm-0500'>82</span><span id='textcolor1272'><span class='ectt-0800'> * use put_user which copies data from the kernel data segment to</span></span>
|
|
<a id='x1-39561r83'></a><span class='ecrm-0500'>83</span><span id='textcolor1273'><span class='ectt-0800'> * the user data segment.</span></span>
|
|
<a id='x1-39563r84'></a><span class='ecrm-0500'>84</span><span id='textcolor1274'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-39565r85'></a><span class='ecrm-0500'>85</span><span class='ectt-0800'> put_user(*(message_ptr++), buffer++);</span>
|
|
<a id='x1-39567r86'></a><span class='ecrm-0500'>86</span><span class='ectt-0800'> length--;</span>
|
|
<a id='x1-39569r87'></a><span class='ecrm-0500'>87</span><span class='ectt-0800'> bytes_read++;</span>
|
|
<a id='x1-39571r88'></a><span class='ecrm-0500'>88</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-39573r89'></a><span class='ecrm-0500'>89</span>
|
|
<a id='x1-39575r90'></a><span class='ecrm-0500'>90</span><span class='ectt-0800'> pr_info(</span><span id='textcolor1275'><span class='ectt-0800'>"Read %d bytes, %ld left</span></span><span id='textcolor1276'><span class='ectt-0800'>\n</span></span><span id='textcolor1277'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, bytes_read, length);</span>
|
|
<a id='x1-39577r91'></a><span class='ecrm-0500'>91</span>
|
|
<a id='x1-39579r92'></a><span class='ecrm-0500'>92</span><span class='ectt-0800'> *offset += bytes_read;</span>
|
|
<a id='x1-39581r93'></a><span class='ecrm-0500'>93</span>
|
|
<a id='x1-39583r94'></a><span class='ecrm-0500'>94</span><span class='ectt-0800'> </span><span id='textcolor1278'><span class='ectt-0800'>/* Read functions are supposed to return the number of bytes actually</span></span>
|
|
<a id='x1-39585r95'></a><span class='ecrm-0500'>95</span><span id='textcolor1279'><span class='ectt-0800'> * inserted into the buffer.</span></span>
|
|
<a id='x1-39587r96'></a><span class='ecrm-0500'>96</span><span id='textcolor1280'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-39589r97'></a><span class='ecrm-0500'>97</span><span class='ectt-0800'> </span><span id='textcolor1281'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> bytes_read;</span>
|
|
<a id='x1-39591r98'></a><span class='ecrm-0500'>98</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-39593r99'></a><span class='ecrm-0500'>99</span>
|
|
<a id='x1-39595r100'></a><span class='ecrm-0500'>100</span><span id='textcolor1282'><span class='ectt-0800'>/* called when somebody tries to write into our device file. */</span></span>
|
|
<a id='x1-39597r101'></a><span class='ecrm-0500'>101</span><span id='textcolor1283'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1284'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> device_write(</span><span id='textcolor1285'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file, </span><span id='textcolor1286'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor1287'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *buffer,</span>
|
|
<a id='x1-39599r102'></a><span class='ecrm-0500'>102</span><span class='ectt-0800'> </span><span id='textcolor1288'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'> length, loff_t *offset)</span>
|
|
<a id='x1-39601r103'></a><span class='ecrm-0500'>103</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-39603r104'></a><span class='ecrm-0500'>104</span><span class='ectt-0800'> </span><span id='textcolor1289'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> i;</span>
|
|
<a id='x1-39605r105'></a><span class='ecrm-0500'>105</span>
|
|
<a id='x1-39607r106'></a><span class='ecrm-0500'>106</span><span class='ectt-0800'> pr_info(</span><span id='textcolor1290'><span class='ectt-0800'>"device_write(%p,%p,%ld)"</span></span><span class='ectt-0800'>, file, buffer, length);</span>
|
|
<a id='x1-39609r107'></a><span class='ecrm-0500'>107</span>
|
|
<a id='x1-39611r108'></a><span class='ecrm-0500'>108</span><span class='ectt-0800'> </span><span id='textcolor1291'><span class='ectt-0800'>for</span></span><span class='ectt-0800'> (i = 0; i < length && i < BUF_LEN; i++)</span>
|
|
<a id='x1-39613r109'></a><span class='ecrm-0500'>109</span><span class='ectt-0800'> get_user(message[i], buffer + i);</span>
|
|
<a id='x1-39615r110'></a><span class='ecrm-0500'>110</span>
|
|
<a id='x1-39617r111'></a><span class='ecrm-0500'>111</span><span class='ectt-0800'> </span><span id='textcolor1292'><span class='ectt-0800'>/* Again, return the number of input characters used. */</span></span>
|
|
<a id='x1-39619r112'></a><span class='ecrm-0500'>112</span><span class='ectt-0800'> </span><span id='textcolor1293'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> i;</span>
|
|
<a id='x1-39621r113'></a><span class='ecrm-0500'>113</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-39623r114'></a><span class='ecrm-0500'>114</span>
|
|
<a id='x1-39625r115'></a><span class='ecrm-0500'>115</span><span id='textcolor1294'><span class='ectt-0800'>/* This function is called whenever a process tries to do an ioctl on our</span></span>
|
|
<a id='x1-39627r116'></a><span class='ecrm-0500'>116</span><span id='textcolor1295'><span class='ectt-0800'> * device file. We get two extra parameters (additional to the inode and file</span></span>
|
|
<a id='x1-39629r117'></a><span class='ecrm-0500'>117</span><span id='textcolor1296'><span class='ectt-0800'> * structures, which all device functions get): the number of the ioctl called</span></span>
|
|
<a id='x1-39631r118'></a><span class='ecrm-0500'>118</span><span id='textcolor1297'><span class='ectt-0800'> * and the parameter given to the ioctl function.</span></span>
|
|
<a id='x1-39633r119'></a><span class='ecrm-0500'>119</span><span id='textcolor1298'><span class='ectt-0800'> *</span></span>
|
|
<a id='x1-39635r120'></a><span class='ecrm-0500'>120</span><span id='textcolor1299'><span class='ectt-0800'> * If the ioctl is write or read/write (meaning output is returned to the</span></span>
|
|
<a id='x1-39637r121'></a><span class='ecrm-0500'>121</span><span id='textcolor1300'><span class='ectt-0800'> * calling process), the ioctl call returns the output of this function.</span></span>
|
|
<a id='x1-39639r122'></a><span class='ecrm-0500'>122</span><span id='textcolor1301'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-39641r123'></a><span class='ecrm-0500'>123</span><span id='textcolor1302'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1303'><span class='ectt-0800'>long</span></span>
|
|
<a id='x1-39643r124'></a><span class='ecrm-0500'>124</span><span class='ectt-0800'>device_ioctl(</span><span id='textcolor1304'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file, </span><span id='textcolor1305'><span class='ectt-0800'>/* ditto */</span></span>
|
|
<a id='x1-39645r125'></a><span class='ecrm-0500'>125</span><span class='ectt-0800'> </span><span id='textcolor1306'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1307'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> ioctl_num, </span><span id='textcolor1308'><span class='ectt-0800'>/* number and param for ioctl */</span></span>
|
|
<a id='x1-39647r126'></a><span class='ecrm-0500'>126</span><span class='ectt-0800'> </span><span id='textcolor1309'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1310'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> ioctl_param)</span>
|
|
<a id='x1-39649r127'></a><span class='ecrm-0500'>127</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-39651r128'></a><span class='ecrm-0500'>128</span><span class='ectt-0800'> </span><span id='textcolor1311'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> i;</span>
|
|
<a id='x1-39653r129'></a><span class='ecrm-0500'>129</span><span class='ectt-0800'> </span><span id='textcolor1312'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> ret = SUCCESS;</span>
|
|
<a id='x1-39655r130'></a><span class='ecrm-0500'>130</span>
|
|
<a id='x1-39657r131'></a><span class='ecrm-0500'>131</span><span class='ectt-0800'> </span><span id='textcolor1313'><span class='ectt-0800'>/* We don</span><span class='tctt-0800'>'</span><span class='ectt-0800'>t want to talk to two processes at the same time. */</span></span>
|
|
<a id='x1-39659r132'></a><span class='ecrm-0500'>132</span><span class='ectt-0800'> </span><span id='textcolor1314'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (atomic_cmpxchg(&already_open, CDEV_NOT_USED, CDEV_EXCLUSIVE_OPEN))</span>
|
|
<a id='x1-39661r133'></a><span class='ecrm-0500'>133</span><span class='ectt-0800'> </span><span id='textcolor1315'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -EBUSY;</span>
|
|
<a id='x1-39663r134'></a><span class='ecrm-0500'>134</span>
|
|
<a id='x1-39665r135'></a><span class='ecrm-0500'>135</span><span class='ectt-0800'> </span><span id='textcolor1316'><span class='ectt-0800'>/* Switch according to the ioctl called */</span></span>
|
|
<a id='x1-39667r136'></a><span class='ecrm-0500'>136</span><span class='ectt-0800'> </span><span id='textcolor1317'><span class='ectt-0800'>switch</span></span><span class='ectt-0800'> (ioctl_num) {</span>
|
|
<a id='x1-39669r137'></a><span class='ecrm-0500'>137</span><span class='ectt-0800'> </span><span id='textcolor1318'><span class='ectt-0800'>case</span></span><span class='ectt-0800'> IOCTL_SET_MSG: {</span>
|
|
<a id='x1-39671r138'></a><span class='ecrm-0500'>138</span><span class='ectt-0800'> </span><span id='textcolor1319'><span class='ectt-0800'>/* Receive a pointer to a message (in user space) and set that to</span></span>
|
|
<a id='x1-39673r139'></a><span class='ecrm-0500'>139</span><span id='textcolor1320'><span class='ectt-0800'> * be the device</span><span class='tctt-0800'>'</span><span class='ectt-0800'>s message. Get the parameter given to ioctl by</span></span>
|
|
<a id='x1-39675r140'></a><span class='ecrm-0500'>140</span><span id='textcolor1321'><span class='ectt-0800'> * the process.</span></span>
|
|
<a id='x1-39677r141'></a><span class='ecrm-0500'>141</span><span id='textcolor1322'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-39679r142'></a><span class='ecrm-0500'>142</span><span class='ectt-0800'> </span><span id='textcolor1323'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *tmp = (</span><span id='textcolor1324'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *)ioctl_param;</span>
|
|
<a id='x1-39681r143'></a><span class='ecrm-0500'>143</span><span class='ectt-0800'> </span><span id='textcolor1325'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> ch;</span>
|
|
<a id='x1-39683r144'></a><span class='ecrm-0500'>144</span>
|
|
<a id='x1-39685r145'></a><span class='ecrm-0500'>145</span><span class='ectt-0800'> </span><span id='textcolor1326'><span class='ectt-0800'>/* Find the length of the message */</span></span>
|
|
<a id='x1-39687r146'></a><span class='ecrm-0500'>146</span><span class='ectt-0800'> get_user(ch, tmp);</span>
|
|
<a id='x1-39689r147'></a><span class='ecrm-0500'>147</span><span class='ectt-0800'> </span><span id='textcolor1327'><span class='ectt-0800'>for</span></span><span class='ectt-0800'> (i = 0; ch && i < BUF_LEN; i++, tmp++)</span>
|
|
<a id='x1-39691r148'></a><span class='ecrm-0500'>148</span><span class='ectt-0800'> get_user(ch, tmp);</span>
|
|
<a id='x1-39693r149'></a><span class='ecrm-0500'>149</span>
|
|
<a id='x1-39695r150'></a><span class='ecrm-0500'>150</span><span class='ectt-0800'> device_write(file, (</span><span id='textcolor1328'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *)ioctl_param, i, NULL);</span>
|
|
<a id='x1-39697r151'></a><span class='ecrm-0500'>151</span><span class='ectt-0800'> </span><span id='textcolor1329'><span class='ectt-0800'>break</span></span><span class='ectt-0800'>;</span>
|
|
<a id='x1-39699r152'></a><span class='ecrm-0500'>152</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-39701r153'></a><span class='ecrm-0500'>153</span><span class='ectt-0800'> </span><span id='textcolor1330'><span class='ectt-0800'>case</span></span><span class='ectt-0800'> IOCTL_GET_MSG: {</span>
|
|
<a id='x1-39703r154'></a><span class='ecrm-0500'>154</span><span class='ectt-0800'> loff_t offset = 0;</span>
|
|
<a id='x1-39705r155'></a><span class='ecrm-0500'>155</span>
|
|
<a id='x1-39707r156'></a><span class='ecrm-0500'>156</span><span class='ectt-0800'> </span><span id='textcolor1331'><span class='ectt-0800'>/* Give the current message to the calling process - the parameter</span></span>
|
|
<a id='x1-39709r157'></a><span class='ecrm-0500'>157</span><span id='textcolor1332'><span class='ectt-0800'> * we got is a pointer, fill it.</span></span>
|
|
<a id='x1-39711r158'></a><span class='ecrm-0500'>158</span><span id='textcolor1333'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-39713r159'></a><span class='ecrm-0500'>159</span><span class='ectt-0800'> i = device_read(file, (</span><span id='textcolor1334'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *)ioctl_param, 99, &offset);</span>
|
|
<a id='x1-39715r160'></a><span class='ecrm-0500'>160</span>
|
|
<a id='x1-39717r161'></a><span class='ecrm-0500'>161</span><span class='ectt-0800'> </span><span id='textcolor1335'><span class='ectt-0800'>/* Put a zero at the end of the buffer, so it will be properly</span></span>
|
|
<a id='x1-39719r162'></a><span class='ecrm-0500'>162</span><span id='textcolor1336'><span class='ectt-0800'> * terminated.</span></span>
|
|
<a id='x1-39721r163'></a><span class='ecrm-0500'>163</span><span id='textcolor1337'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-39723r164'></a><span class='ecrm-0500'>164</span><span class='ectt-0800'> put_user(</span><span id='textcolor1338'><span class='tctt-0800'>'</span><span class='ectt-0800'>\0</span><span class='tctt-0800'>'</span></span><span class='ectt-0800'>, (</span><span id='textcolor1339'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *)ioctl_param + i);</span>
|
|
<a id='x1-39725r165'></a><span class='ecrm-0500'>165</span><span class='ectt-0800'> </span><span id='textcolor1340'><span class='ectt-0800'>break</span></span><span class='ectt-0800'>;</span>
|
|
<a id='x1-39727r166'></a><span class='ecrm-0500'>166</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-39729r167'></a><span class='ecrm-0500'>167</span><span class='ectt-0800'> </span><span id='textcolor1341'><span class='ectt-0800'>case</span></span><span class='ectt-0800'> IOCTL_GET_NTH_BYTE:</span>
|
|
<a id='x1-39731r168'></a><span class='ecrm-0500'>168</span><span class='ectt-0800'> </span><span id='textcolor1342'><span class='ectt-0800'>/* This ioctl is both input (ioctl_param) and output (the return</span></span>
|
|
<a id='x1-39733r169'></a><span class='ecrm-0500'>169</span><span id='textcolor1343'><span class='ectt-0800'> * value of this function).</span></span>
|
|
<a id='x1-39735r170'></a><span class='ecrm-0500'>170</span><span id='textcolor1344'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-39737r171'></a><span class='ecrm-0500'>171</span><span class='ectt-0800'> ret = (</span><span id='textcolor1345'><span class='ectt-0800'>long</span></span><span class='ectt-0800'>)message[ioctl_param];</span>
|
|
<a id='x1-39739r172'></a><span class='ecrm-0500'>172</span><span class='ectt-0800'> </span><span id='textcolor1346'><span class='ectt-0800'>break</span></span><span class='ectt-0800'>;</span>
|
|
<a id='x1-39741r173'></a><span class='ecrm-0500'>173</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-39743r174'></a><span class='ecrm-0500'>174</span>
|
|
<a id='x1-39745r175'></a><span class='ecrm-0500'>175</span><span class='ectt-0800'> </span><span id='textcolor1347'><span class='ectt-0800'>/* We</span><span class='tctt-0800'>'</span><span class='ectt-0800'>re now ready for our next caller */</span></span>
|
|
<a id='x1-39747r176'></a><span class='ecrm-0500'>176</span><span class='ectt-0800'> atomic_set(&already_open, CDEV_NOT_USED);</span>
|
|
<a id='x1-39749r177'></a><span class='ecrm-0500'>177</span>
|
|
<a id='x1-39751r178'></a><span class='ecrm-0500'>178</span><span class='ectt-0800'> </span><span id='textcolor1348'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> ret;</span>
|
|
<a id='x1-39753r179'></a><span class='ecrm-0500'>179</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-39755r180'></a><span class='ecrm-0500'>180</span>
|
|
<a id='x1-39757r181'></a><span class='ecrm-0500'>181</span><span id='textcolor1349'><span class='ectt-0800'>/* Module Declarations */</span></span>
|
|
<a id='x1-39759r182'></a><span class='ecrm-0500'>182</span>
|
|
<a id='x1-39761r183'></a><span class='ecrm-0500'>183</span><span id='textcolor1350'><span class='ectt-0800'>/* This structure will hold the functions to be called when a process does</span></span>
|
|
<a id='x1-39763r184'></a><span class='ecrm-0500'>184</span><span id='textcolor1351'><span class='ectt-0800'> * something to the device we created. Since a pointer to this structure</span></span>
|
|
<a id='x1-39765r185'></a><span class='ecrm-0500'>185</span><span id='textcolor1352'><span class='ectt-0800'> * is kept in the devices table, it can</span><span class='tctt-0800'>'</span><span class='ectt-0800'>t be local to init_module. NULL is</span></span>
|
|
<a id='x1-39767r186'></a><span class='ecrm-0500'>186</span><span id='textcolor1353'><span class='ectt-0800'> * for unimplemented functions.</span></span>
|
|
<a id='x1-39769r187'></a><span class='ecrm-0500'>187</span><span id='textcolor1354'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-39771r188'></a><span class='ecrm-0500'>188</span><span id='textcolor1355'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1356'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file_operations fops = {</span>
|
|
<a id='x1-39773r189'></a><span class='ecrm-0500'>189</span><span class='ectt-0800'> .read = device_read,</span>
|
|
<a id='x1-39775r190'></a><span class='ecrm-0500'>190</span><span class='ectt-0800'> .write = device_write,</span>
|
|
<a id='x1-39777r191'></a><span class='ecrm-0500'>191</span><span class='ectt-0800'> .unlocked_ioctl = device_ioctl,</span>
|
|
<a id='x1-39779r192'></a><span class='ecrm-0500'>192</span><span class='ectt-0800'> .open = device_open,</span>
|
|
<a id='x1-39781r193'></a><span class='ecrm-0500'>193</span><span class='ectt-0800'> .release = device_release, </span><span id='textcolor1357'><span class='ectt-0800'>/* a.k.a. close */</span></span>
|
|
<a id='x1-39783r194'></a><span class='ecrm-0500'>194</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-39785r195'></a><span class='ecrm-0500'>195</span>
|
|
<a id='x1-39787r196'></a><span class='ecrm-0500'>196</span><span id='textcolor1358'><span class='ectt-0800'>/* Initialize the module - Register the character device */</span></span>
|
|
<a id='x1-39789r197'></a><span class='ecrm-0500'>197</span><span id='textcolor1359'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1360'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __init chardev2_init(</span><span id='textcolor1361'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-39791r198'></a><span class='ecrm-0500'>198</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-39793r199'></a><span class='ecrm-0500'>199</span><span class='ectt-0800'> </span><span id='textcolor1362'><span class='ectt-0800'>/* Register the character device (atleast try) */</span></span>
|
|
<a id='x1-39795r200'></a><span class='ecrm-0500'>200</span><span class='ectt-0800'> </span><span id='textcolor1363'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> ret_val = register_chrdev(MAJOR_NUM, DEVICE_NAME, &fops);</span>
|
|
<a id='x1-39797r201'></a><span class='ecrm-0500'>201</span>
|
|
<a id='x1-39799r202'></a><span class='ecrm-0500'>202</span><span class='ectt-0800'> </span><span id='textcolor1364'><span class='ectt-0800'>/* Negative values signify an error */</span></span>
|
|
<a id='x1-39801r203'></a><span class='ecrm-0500'>203</span><span class='ectt-0800'> </span><span id='textcolor1365'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (ret_val < 0) {</span>
|
|
<a id='x1-39803r204'></a><span class='ecrm-0500'>204</span><span class='ectt-0800'> pr_alert(</span><span id='textcolor1366'><span class='ectt-0800'>"%s failed with %d</span></span><span id='textcolor1367'><span class='ectt-0800'>\n</span></span><span id='textcolor1368'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>,</span>
|
|
<a id='x1-39805r205'></a><span class='ecrm-0500'>205</span><span class='ectt-0800'> </span><span id='textcolor1369'><span class='ectt-0800'>"Sorry, registering the character device "</span></span><span class='ectt-0800'>, ret_val);</span>
|
|
<a id='x1-39807r206'></a><span class='ecrm-0500'>206</span><span class='ectt-0800'> </span><span id='textcolor1370'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> ret_val;</span>
|
|
<a id='x1-39809r207'></a><span class='ecrm-0500'>207</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-39811r208'></a><span class='ecrm-0500'>208</span>
|
|
<a id='x1-39813r209'></a><span class='ecrm-0500'>209</span><span id='textcolor1371'><span class='ectt-0800'>#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0)</span></span>
|
|
<a id='x1-39815r210'></a><span class='ecrm-0500'>210</span><span class='ectt-0800'> cls = class_create(DEVICE_FILE_NAME);</span>
|
|
<a id='x1-39817r211'></a><span class='ecrm-0500'>211</span><span id='textcolor1372'><span class='ectt-0800'>#else</span></span>
|
|
<a id='x1-39819r212'></a><span class='ecrm-0500'>212</span><span class='ectt-0800'> cls = class_create(THIS_MODULE, DEVICE_FILE_NAME);</span>
|
|
<a id='x1-39821r213'></a><span class='ecrm-0500'>213</span><span id='textcolor1373'><span class='ectt-0800'>#endif</span></span>
|
|
<a id='x1-39823r214'></a><span class='ecrm-0500'>214</span><span class='ectt-0800'> device_create(cls, NULL, MKDEV(MAJOR_NUM, 0), NULL, DEVICE_FILE_NAME);</span>
|
|
<a id='x1-39825r215'></a><span class='ecrm-0500'>215</span>
|
|
<a id='x1-39827r216'></a><span class='ecrm-0500'>216</span><span class='ectt-0800'> pr_info(</span><span id='textcolor1374'><span class='ectt-0800'>"Device created on /dev/%s</span></span><span id='textcolor1375'><span class='ectt-0800'>\n</span></span><span id='textcolor1376'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, DEVICE_FILE_NAME);</span>
|
|
<a id='x1-39829r217'></a><span class='ecrm-0500'>217</span>
|
|
<a id='x1-39831r218'></a><span class='ecrm-0500'>218</span><span class='ectt-0800'> </span><span id='textcolor1377'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-39833r219'></a><span class='ecrm-0500'>219</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-39835r220'></a><span class='ecrm-0500'>220</span>
|
|
<a id='x1-39837r221'></a><span class='ecrm-0500'>221</span><span id='textcolor1378'><span class='ectt-0800'>/* Cleanup - unregister the appropriate file from /proc */</span></span>
|
|
<a id='x1-39839r222'></a><span class='ecrm-0500'>222</span><span id='textcolor1379'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1380'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> __exit chardev2_exit(</span><span id='textcolor1381'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-39841r223'></a><span class='ecrm-0500'>223</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-39843r224'></a><span class='ecrm-0500'>224</span><span class='ectt-0800'> device_destroy(cls, MKDEV(MAJOR_NUM, 0));</span>
|
|
<a id='x1-39845r225'></a><span class='ecrm-0500'>225</span><span class='ectt-0800'> class_destroy(cls);</span>
|
|
<a id='x1-39847r226'></a><span class='ecrm-0500'>226</span>
|
|
<a id='x1-39849r227'></a><span class='ecrm-0500'>227</span><span class='ectt-0800'> </span><span id='textcolor1382'><span class='ectt-0800'>/* Unregister the device */</span></span>
|
|
<a id='x1-39851r228'></a><span class='ecrm-0500'>228</span><span class='ectt-0800'> unregister_chrdev(MAJOR_NUM, DEVICE_NAME);</span>
|
|
<a id='x1-39853r229'></a><span class='ecrm-0500'>229</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-39855r230'></a><span class='ecrm-0500'>230</span>
|
|
<a id='x1-39857r231'></a><span class='ecrm-0500'>231</span><span class='ectt-0800'>module_init(chardev2_init);</span>
|
|
<a id='x1-39859r232'></a><span class='ecrm-0500'>232</span><span class='ectt-0800'>module_exit(chardev2_exit);</span>
|
|
<a id='x1-39861r233'></a><span class='ecrm-0500'>233</span>
|
|
<a id='x1-39863r234'></a><span class='ecrm-0500'>234</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor1383'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span></pre>
|
|
|
|
<!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb62'><a id='x1-39865r1'></a><span class='ecrm-0500'>1</span><span id='textcolor1384'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-39867r2'></a><span class='ecrm-0500'>2</span><span id='textcolor1385'><span class='ectt-0800'> * chardev.h - the header file with the ioctl definitions.</span></span>
|
|
<a id='x1-39869r3'></a><span class='ecrm-0500'>3</span><span id='textcolor1386'><span class='ectt-0800'> *</span></span>
|
|
<a id='x1-39871r4'></a><span class='ecrm-0500'>4</span><span id='textcolor1387'><span class='ectt-0800'> * The declarations here have to be in a header file, because they need</span></span>
|
|
<a id='x1-39873r5'></a><span class='ecrm-0500'>5</span><span id='textcolor1388'><span class='ectt-0800'> * to be known both to the kernel module (in chardev2.c) and the process</span></span>
|
|
<a id='x1-39875r6'></a><span class='ecrm-0500'>6</span><span id='textcolor1389'><span class='ectt-0800'> * calling ioctl() (in userspace_ioctl.c).</span></span>
|
|
<a id='x1-39877r7'></a><span class='ecrm-0500'>7</span><span id='textcolor1390'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-39879r8'></a><span class='ecrm-0500'>8</span>
|
|
<a id='x1-39881r9'></a><span class='ecrm-0500'>9</span><span id='textcolor1391'><span class='ectt-0800'>#ifndef CHARDEV_H</span></span>
|
|
<a id='x1-39883r10'></a><span class='ecrm-0500'>10</span><span id='textcolor1392'><span class='ectt-0800'>#define CHARDEV_H</span></span>
|
|
<a id='x1-39885r11'></a><span class='ecrm-0500'>11</span>
|
|
<a id='x1-39887r12'></a><span class='ecrm-0500'>12</span><span id='textcolor1393'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1394'><span class='ectt-0800'><linux/ioctl.h></span></span>
|
|
<a id='x1-39889r13'></a><span class='ecrm-0500'>13</span>
|
|
<a id='x1-39891r14'></a><span class='ecrm-0500'>14</span><span id='textcolor1395'><span class='ectt-0800'>/* The major device number. We can not rely on dynamic registration</span></span>
|
|
<a id='x1-39893r15'></a><span class='ecrm-0500'>15</span><span id='textcolor1396'><span class='ectt-0800'> * any more, because ioctls need to know it.</span></span>
|
|
<a id='x1-39895r16'></a><span class='ecrm-0500'>16</span><span id='textcolor1397'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-39897r17'></a><span class='ecrm-0500'>17</span><span id='textcolor1398'><span class='ectt-0800'>#define MAJOR_NUM 100</span></span>
|
|
<a id='x1-39899r18'></a><span class='ecrm-0500'>18</span>
|
|
<a id='x1-39901r19'></a><span class='ecrm-0500'>19</span><span id='textcolor1399'><span class='ectt-0800'>/* Set the message of the device driver */</span></span>
|
|
<a id='x1-39903r20'></a><span class='ecrm-0500'>20</span><span id='textcolor1400'><span class='ectt-0800'>#define IOCTL_SET_MSG _IOW(MAJOR_NUM, 0, char *)</span></span>
|
|
<a id='x1-39905r21'></a><span class='ecrm-0500'>21</span><span id='textcolor1401'><span class='ectt-0800'>/* _IOW means that we are creating an ioctl command number for passing</span></span>
|
|
<a id='x1-39907r22'></a><span class='ecrm-0500'>22</span><span id='textcolor1402'><span class='ectt-0800'> * information from a user process to the kernel module.</span></span>
|
|
<a id='x1-39909r23'></a><span class='ecrm-0500'>23</span><span id='textcolor1403'><span class='ectt-0800'> *</span></span>
|
|
<a id='x1-39911r24'></a><span class='ecrm-0500'>24</span><span id='textcolor1404'><span class='ectt-0800'> * The first arguments, MAJOR_NUM, is the major device number we are using.</span></span>
|
|
<a id='x1-39913r25'></a><span class='ecrm-0500'>25</span><span id='textcolor1405'><span class='ectt-0800'> *</span></span>
|
|
<a id='x1-39915r26'></a><span class='ecrm-0500'>26</span><span id='textcolor1406'><span class='ectt-0800'> * The second argument is the number of the command (there could be several</span></span>
|
|
<a id='x1-39917r27'></a><span class='ecrm-0500'>27</span><span id='textcolor1407'><span class='ectt-0800'> * with different meanings).</span></span>
|
|
<a id='x1-39919r28'></a><span class='ecrm-0500'>28</span><span id='textcolor1408'><span class='ectt-0800'> *</span></span>
|
|
<a id='x1-39921r29'></a><span class='ecrm-0500'>29</span><span id='textcolor1409'><span class='ectt-0800'> * The third argument is the type we want to get from the process to the</span></span>
|
|
<a id='x1-39923r30'></a><span class='ecrm-0500'>30</span><span id='textcolor1410'><span class='ectt-0800'> * kernel.</span></span>
|
|
<a id='x1-39925r31'></a><span class='ecrm-0500'>31</span><span id='textcolor1411'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-39927r32'></a><span class='ecrm-0500'>32</span>
|
|
<a id='x1-39929r33'></a><span class='ecrm-0500'>33</span><span id='textcolor1412'><span class='ectt-0800'>/* Get the message of the device driver */</span></span>
|
|
<a id='x1-39931r34'></a><span class='ecrm-0500'>34</span><span id='textcolor1413'><span class='ectt-0800'>#define IOCTL_GET_MSG _IOR(MAJOR_NUM, 1, char *)</span></span>
|
|
<a id='x1-39933r35'></a><span class='ecrm-0500'>35</span><span id='textcolor1414'><span class='ectt-0800'>/* This IOCTL is used for output, to get the message of the device driver.</span></span>
|
|
<a id='x1-39935r36'></a><span class='ecrm-0500'>36</span><span id='textcolor1415'><span class='ectt-0800'> * However, we still need the buffer to place the message in to be input,</span></span>
|
|
<a id='x1-39937r37'></a><span class='ecrm-0500'>37</span><span id='textcolor1416'><span class='ectt-0800'> * as it is allocated by the process.</span></span>
|
|
<a id='x1-39939r38'></a><span class='ecrm-0500'>38</span><span id='textcolor1417'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-39941r39'></a><span class='ecrm-0500'>39</span>
|
|
<a id='x1-39943r40'></a><span class='ecrm-0500'>40</span><span id='textcolor1418'><span class='ectt-0800'>/* Get the n</span><span class='tctt-0800'>'</span><span class='ectt-0800'>th byte of the message */</span></span>
|
|
<a id='x1-39945r41'></a><span class='ecrm-0500'>41</span><span id='textcolor1419'><span class='ectt-0800'>#define IOCTL_GET_NTH_BYTE _IOWR(MAJOR_NUM, 2, int)</span></span>
|
|
<a id='x1-39947r42'></a><span class='ecrm-0500'>42</span><span id='textcolor1420'><span class='ectt-0800'>/* The IOCTL is used for both input and output. It receives from the user</span></span>
|
|
<a id='x1-39949r43'></a><span class='ecrm-0500'>43</span><span id='textcolor1421'><span class='ectt-0800'> * a number, n, and returns message[n].</span></span>
|
|
<a id='x1-39951r44'></a><span class='ecrm-0500'>44</span><span id='textcolor1422'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-39953r45'></a><span class='ecrm-0500'>45</span>
|
|
<a id='x1-39955r46'></a><span class='ecrm-0500'>46</span><span id='textcolor1423'><span class='ectt-0800'>/* The name of the device file */</span></span>
|
|
<a id='x1-39957r47'></a><span class='ecrm-0500'>47</span><span id='textcolor1424'><span class='ectt-0800'>#define DEVICE_FILE_NAME "char_dev"</span></span>
|
|
<a id='x1-39959r48'></a><span class='ecrm-0500'>48</span><span id='textcolor1425'><span class='ectt-0800'>#define DEVICE_PATH "/dev/char_dev"</span></span>
|
|
<a id='x1-39961r49'></a><span class='ecrm-0500'>49</span>
|
|
<a id='x1-39963r50'></a><span class='ecrm-0500'>50</span><span id='textcolor1426'><span class='ectt-0800'>#endif</span></span></pre>
|
|
|
|
<!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb63'><a id='x1-39965r1'></a><span class='ecrm-0500'>1</span><span id='textcolor1427'><span class='ectt-0800'>/* userspace_ioctl.c - the process to use ioctl</span><span class='tctt-0800'>'</span><span class='ectt-0800'>s to control the kernel module</span></span>
|
|
<a id='x1-39967r2'></a><span class='ecrm-0500'>2</span><span id='textcolor1428'><span class='ectt-0800'> *</span></span>
|
|
<a id='x1-39969r3'></a><span class='ecrm-0500'>3</span><span id='textcolor1429'><span class='ectt-0800'> * Until now we could have used cat for input and output. But now</span></span>
|
|
<a id='x1-39971r4'></a><span class='ecrm-0500'>4</span><span id='textcolor1430'><span class='ectt-0800'> * we need to do ioctl</span><span class='tctt-0800'>'</span><span class='ectt-0800'>s, which require writing our own process. </span></span>
|
|
<a id='x1-39973r5'></a><span class='ecrm-0500'>5</span><span id='textcolor1431'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-39975r6'></a><span class='ecrm-0500'>6</span>
|
|
<a id='x1-39977r7'></a><span class='ecrm-0500'>7</span><span id='textcolor1432'><span class='ectt-0800'>/* device specifics, such as ioctl numbers and the </span></span>
|
|
<a id='x1-39979r8'></a><span class='ecrm-0500'>8</span><span id='textcolor1433'><span class='ectt-0800'> * major device file. */</span></span>
|
|
<a id='x1-39981r9'></a><span class='ecrm-0500'>9</span><span id='textcolor1434'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1435'><span class='ectt-0800'>"../chardev.h"</span></span>
|
|
<a id='x1-39983r10'></a><span class='ecrm-0500'>10</span>
|
|
<a id='x1-39985r11'></a><span class='ecrm-0500'>11</span><span id='textcolor1436'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1437'><span class='ectt-0800'><stdio.h> /* standard I/O */</span></span>
|
|
<a id='x1-39987r12'></a><span class='ecrm-0500'>12</span><span id='textcolor1438'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1439'><span class='ectt-0800'><fcntl.h> /* open */</span></span>
|
|
<a id='x1-39989r13'></a><span class='ecrm-0500'>13</span><span id='textcolor1440'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1441'><span class='ectt-0800'><unistd.h> /* close */</span></span>
|
|
<a id='x1-39991r14'></a><span class='ecrm-0500'>14</span><span id='textcolor1442'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1443'><span class='ectt-0800'><stdlib.h> /* exit */</span></span>
|
|
<a id='x1-39993r15'></a><span class='ecrm-0500'>15</span><span id='textcolor1444'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1445'><span class='ectt-0800'><sys/ioctl.h> /* ioctl */</span></span>
|
|
<a id='x1-39995r16'></a><span class='ecrm-0500'>16</span>
|
|
<a id='x1-39997r17'></a><span class='ecrm-0500'>17</span><span id='textcolor1446'><span class='ectt-0800'>/* Functions for the ioctl calls */</span></span>
|
|
<a id='x1-39999r18'></a><span class='ecrm-0500'>18</span>
|
|
<a id='x1-40001r19'></a><span class='ecrm-0500'>19</span><span id='textcolor1447'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> ioctl_set_msg(</span><span id='textcolor1448'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> file_desc, </span><span id='textcolor1449'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *message)</span>
|
|
<a id='x1-40003r20'></a><span class='ecrm-0500'>20</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-40005r21'></a><span class='ecrm-0500'>21</span><span class='ectt-0800'> </span><span id='textcolor1450'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> ret_val;</span>
|
|
<a id='x1-40007r22'></a><span class='ecrm-0500'>22</span>
|
|
<a id='x1-40009r23'></a><span class='ecrm-0500'>23</span><span class='ectt-0800'> ret_val = ioctl(file_desc, IOCTL_SET_MSG, message);</span>
|
|
<a id='x1-40011r24'></a><span class='ecrm-0500'>24</span>
|
|
<a id='x1-40013r25'></a><span class='ecrm-0500'>25</span><span class='ectt-0800'> </span><span id='textcolor1451'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (ret_val < 0) {</span>
|
|
<a id='x1-40015r26'></a><span class='ecrm-0500'>26</span><span class='ectt-0800'> printf(</span><span id='textcolor1452'><span class='ectt-0800'>"ioctl_set_msg failed:%d</span></span><span id='textcolor1453'><span class='ectt-0800'>\n</span></span><span id='textcolor1454'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, ret_val);</span>
|
|
<a id='x1-40017r27'></a><span class='ecrm-0500'>27</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-40019r28'></a><span class='ecrm-0500'>28</span>
|
|
<a id='x1-40021r29'></a><span class='ecrm-0500'>29</span><span class='ectt-0800'> </span><span id='textcolor1455'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> ret_val;</span>
|
|
<a id='x1-40023r30'></a><span class='ecrm-0500'>30</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-40025r31'></a><span class='ecrm-0500'>31</span>
|
|
<a id='x1-40027r32'></a><span class='ecrm-0500'>32</span><span id='textcolor1456'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> ioctl_get_msg(</span><span id='textcolor1457'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> file_desc)</span>
|
|
<a id='x1-40029r33'></a><span class='ecrm-0500'>33</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-40031r34'></a><span class='ecrm-0500'>34</span><span class='ectt-0800'> </span><span id='textcolor1458'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> ret_val;</span>
|
|
<a id='x1-40033r35'></a><span class='ecrm-0500'>35</span><span class='ectt-0800'> </span><span id='textcolor1459'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> message[100] = { 0 };</span>
|
|
<a id='x1-40035r36'></a><span class='ecrm-0500'>36</span>
|
|
<a id='x1-40037r37'></a><span class='ecrm-0500'>37</span><span class='ectt-0800'> </span><span id='textcolor1460'><span class='ectt-0800'>/* Warning - this is dangerous because we don</span><span class='tctt-0800'>'</span><span class='ectt-0800'>t tell </span></span>
|
|
<a id='x1-40039r38'></a><span class='ecrm-0500'>38</span><span id='textcolor1461'><span class='ectt-0800'> * the kernel how far it</span><span class='tctt-0800'>'</span><span class='ectt-0800'>s allowed to write, so it </span></span>
|
|
<a id='x1-40041r39'></a><span class='ecrm-0500'>39</span><span id='textcolor1462'><span class='ectt-0800'> * might overflow the buffer. In a real production </span></span>
|
|
<a id='x1-40043r40'></a><span class='ecrm-0500'>40</span><span id='textcolor1463'><span class='ectt-0800'> * program, we would have used two ioctls - one to tell</span></span>
|
|
<a id='x1-40045r41'></a><span class='ecrm-0500'>41</span><span id='textcolor1464'><span class='ectt-0800'> * the kernel the buffer length and another to give </span></span>
|
|
<a id='x1-40047r42'></a><span class='ecrm-0500'>42</span><span id='textcolor1465'><span class='ectt-0800'> * it the buffer to fill</span></span>
|
|
<a id='x1-40049r43'></a><span class='ecrm-0500'>43</span><span id='textcolor1466'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-40051r44'></a><span class='ecrm-0500'>44</span><span class='ectt-0800'> ret_val = ioctl(file_desc, IOCTL_GET_MSG, message);</span>
|
|
<a id='x1-40053r45'></a><span class='ecrm-0500'>45</span>
|
|
<a id='x1-40055r46'></a><span class='ecrm-0500'>46</span><span class='ectt-0800'> </span><span id='textcolor1467'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (ret_val < 0) {</span>
|
|
<a id='x1-40057r47'></a><span class='ecrm-0500'>47</span><span class='ectt-0800'> printf(</span><span id='textcolor1468'><span class='ectt-0800'>"ioctl_get_msg failed:%d</span></span><span id='textcolor1469'><span class='ectt-0800'>\n</span></span><span id='textcolor1470'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, ret_val);</span>
|
|
<a id='x1-40059r48'></a><span class='ecrm-0500'>48</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-40061r49'></a><span class='ecrm-0500'>49</span><span class='ectt-0800'> printf(</span><span id='textcolor1471'><span class='ectt-0800'>"get_msg message:%s"</span></span><span class='ectt-0800'>, message);</span>
|
|
<a id='x1-40063r50'></a><span class='ecrm-0500'>50</span>
|
|
<a id='x1-40065r51'></a><span class='ecrm-0500'>51</span><span class='ectt-0800'> </span><span id='textcolor1472'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> ret_val;</span>
|
|
<a id='x1-40067r52'></a><span class='ecrm-0500'>52</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-40069r53'></a><span class='ecrm-0500'>53</span>
|
|
<a id='x1-40071r54'></a><span class='ecrm-0500'>54</span><span id='textcolor1473'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> ioctl_get_nth_byte(</span><span id='textcolor1474'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> file_desc)</span>
|
|
<a id='x1-40073r55'></a><span class='ecrm-0500'>55</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-40075r56'></a><span class='ecrm-0500'>56</span><span class='ectt-0800'> </span><span id='textcolor1475'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> i, c;</span>
|
|
<a id='x1-40077r57'></a><span class='ecrm-0500'>57</span>
|
|
<a id='x1-40079r58'></a><span class='ecrm-0500'>58</span><span class='ectt-0800'> printf(</span><span id='textcolor1476'><span class='ectt-0800'>"get_nth_byte message:"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-40081r59'></a><span class='ecrm-0500'>59</span>
|
|
<a id='x1-40083r60'></a><span class='ecrm-0500'>60</span><span class='ectt-0800'> i = 0;</span>
|
|
<a id='x1-40085r61'></a><span class='ecrm-0500'>61</span><span class='ectt-0800'> </span><span id='textcolor1477'><span class='ectt-0800'>do</span></span><span class='ectt-0800'> {</span>
|
|
<a id='x1-40087r62'></a><span class='ecrm-0500'>62</span><span class='ectt-0800'> c = ioctl(file_desc, IOCTL_GET_NTH_BYTE, i++);</span>
|
|
<a id='x1-40089r63'></a><span class='ecrm-0500'>63</span>
|
|
<a id='x1-40091r64'></a><span class='ecrm-0500'>64</span><span class='ectt-0800'> </span><span id='textcolor1478'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (c < 0) {</span>
|
|
<a id='x1-40093r65'></a><span class='ecrm-0500'>65</span><span class='ectt-0800'> printf(</span><span id='textcolor1479'><span class='ectt-0800'>"</span></span><span id='textcolor1480'><span class='ectt-0800'>\n</span></span><span id='textcolor1481'><span class='ectt-0800'>ioctl_get_nth_byte failed at the %d</span><span class='tctt-0800'>'</span><span class='ectt-0800'>th byte:</span></span><span id='textcolor1482'><span class='ectt-0800'>\n</span></span><span id='textcolor1483'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, i);</span>
|
|
<a id='x1-40095r66'></a><span class='ecrm-0500'>66</span><span class='ectt-0800'> </span><span id='textcolor1484'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> c;</span>
|
|
<a id='x1-40097r67'></a><span class='ecrm-0500'>67</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-40099r68'></a><span class='ecrm-0500'>68</span>
|
|
<a id='x1-40101r69'></a><span class='ecrm-0500'>69</span><span class='ectt-0800'> putchar(c);</span>
|
|
<a id='x1-40103r70'></a><span class='ecrm-0500'>70</span><span class='ectt-0800'> } </span><span id='textcolor1485'><span class='ectt-0800'>while</span></span><span class='ectt-0800'> (c != 0);</span>
|
|
<a id='x1-40105r71'></a><span class='ecrm-0500'>71</span>
|
|
<a id='x1-40107r72'></a><span class='ecrm-0500'>72</span><span class='ectt-0800'> </span><span id='textcolor1486'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-40109r73'></a><span class='ecrm-0500'>73</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-40111r74'></a><span class='ecrm-0500'>74</span>
|
|
<a id='x1-40113r75'></a><span class='ecrm-0500'>75</span><span id='textcolor1487'><span class='ectt-0800'>/* Main - Call the ioctl functions */</span></span>
|
|
<a id='x1-40115r76'></a><span class='ecrm-0500'>76</span><span id='textcolor1488'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> main(</span><span id='textcolor1489'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-40117r77'></a><span class='ecrm-0500'>77</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-40119r78'></a><span class='ecrm-0500'>78</span><span class='ectt-0800'> </span><span id='textcolor1490'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> file_desc, ret_val;</span>
|
|
<a id='x1-40121r79'></a><span class='ecrm-0500'>79</span><span class='ectt-0800'> </span><span id='textcolor1491'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *msg = </span><span id='textcolor1492'><span class='ectt-0800'>"Message passed by ioctl</span></span><span id='textcolor1493'><span class='ectt-0800'>\n</span></span><span id='textcolor1494'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>;</span>
|
|
<a id='x1-40123r80'></a><span class='ecrm-0500'>80</span>
|
|
<a id='x1-40125r81'></a><span class='ecrm-0500'>81</span><span class='ectt-0800'> file_desc = open(DEVICE_PATH, O_RDWR);</span>
|
|
<a id='x1-40127r82'></a><span class='ecrm-0500'>82</span><span class='ectt-0800'> </span><span id='textcolor1495'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (file_desc < 0) {</span>
|
|
<a id='x1-40129r83'></a><span class='ecrm-0500'>83</span><span class='ectt-0800'> printf(</span><span id='textcolor1496'><span class='ectt-0800'>"Can</span><span class='tctt-0800'>'</span><span class='ectt-0800'>t open device file: %s, error:%d</span></span><span id='textcolor1497'><span class='ectt-0800'>\n</span></span><span id='textcolor1498'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, DEVICE_PATH,</span>
|
|
<a id='x1-40131r84'></a><span class='ecrm-0500'>84</span><span class='ectt-0800'> file_desc);</span>
|
|
<a id='x1-40133r85'></a><span class='ecrm-0500'>85</span><span class='ectt-0800'> exit(EXIT_FAILURE);</span>
|
|
<a id='x1-40135r86'></a><span class='ecrm-0500'>86</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-40137r87'></a><span class='ecrm-0500'>87</span>
|
|
<a id='x1-40139r88'></a><span class='ecrm-0500'>88</span><span class='ectt-0800'> ret_val = ioctl_set_msg(file_desc, msg);</span>
|
|
<a id='x1-40141r89'></a><span class='ecrm-0500'>89</span><span class='ectt-0800'> </span><span id='textcolor1499'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (ret_val)</span>
|
|
<a id='x1-40143r90'></a><span class='ecrm-0500'>90</span><span class='ectt-0800'> </span><span id='textcolor1500'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> error;</span>
|
|
<a id='x1-40145r91'></a><span class='ecrm-0500'>91</span><span class='ectt-0800'> ret_val = ioctl_get_nth_byte(file_desc);</span>
|
|
<a id='x1-40147r92'></a><span class='ecrm-0500'>92</span><span class='ectt-0800'> </span><span id='textcolor1501'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (ret_val)</span>
|
|
<a id='x1-40149r93'></a><span class='ecrm-0500'>93</span><span class='ectt-0800'> </span><span id='textcolor1502'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> error;</span>
|
|
<a id='x1-40151r94'></a><span class='ecrm-0500'>94</span><span class='ectt-0800'> ret_val = ioctl_get_msg(file_desc);</span>
|
|
<a id='x1-40153r95'></a><span class='ecrm-0500'>95</span><span class='ectt-0800'> </span><span id='textcolor1503'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (ret_val)</span>
|
|
<a id='x1-40155r96'></a><span class='ecrm-0500'>96</span><span class='ectt-0800'> </span><span id='textcolor1504'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> error;</span>
|
|
<a id='x1-40157r97'></a><span class='ecrm-0500'>97</span>
|
|
<a id='x1-40159r98'></a><span class='ecrm-0500'>98</span><span class='ectt-0800'> close(file_desc);</span>
|
|
<a id='x1-40161r99'></a><span class='ecrm-0500'>99</span><span class='ectt-0800'> </span><span id='textcolor1505'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-40163r100'></a><span class='ecrm-0500'>100</span><span class='ectt-0800'>error:</span>
|
|
<a id='x1-40165r101'></a><span class='ecrm-0500'>101</span><span class='ectt-0800'> close(file_desc);</span>
|
|
<a id='x1-40167r102'></a><span class='ecrm-0500'>102</span><span class='ectt-0800'> exit(EXIT_FAILURE);</span>
|
|
<a id='x1-40169r103'></a><span class='ecrm-0500'>103</span><span class='ectt-0800'>}</span></pre>
|
|
<!-- l. 1413 --><p class='noindent'>
|
|
</p>
|
|
<h3 class='sectionHead' id='system-calls'><span class='titlemark'>10 </span> <a id='x1-4100010'></a>System Calls</h3>
|
|
<!-- l. 1415 --><p class='noindent'>So far, the only thing we’ve done was to use well defined kernel mechanisms to
|
|
register <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc</span></span></span> files and device handlers. This is fine if you want to do something the
|
|
kernel programmers thought you’d want, such as write a device driver. But what if
|
|
|
|
|
|
|
|
you want to do something unusual, to change the behavior of the system in some
|
|
way? Then, you are mostly on your own.
|
|
</p><!-- l. 1420 --><p class='indent'> Should one choose not to use a virtual machine, kernel programming
|
|
can become risky. For example, while writing the code below, the
|
|
<code> <span class='ectt-1000'>open()</span>
|
|
</code> system call was inadvertently disrupted. This resulted in an inability to open any
|
|
files, run programs, or shut down the system, necessitating a restart of the virtual
|
|
machine. Fortunately, no critical files were lost in this instance. However, if such
|
|
modifications were made on a live, mission-critical system, the consequences could be
|
|
severe. To mitigate the risk of file loss, even in a test environment, it is advised to
|
|
execute <code> <span class='ectt-1000'>sync</span>
|
|
</code> right before using <code> <span class='ectt-1000'>insmod</span>
|
|
</code> and <code> <span class='ectt-1000'>rmmod</span>
|
|
</code>.
|
|
</p><!-- l. 1427 --><p class='indent'> Forget about <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc</span></span></span> files, forget about device files. They are just minor details.
|
|
Minutiae in the vast expanse of the universe. The real process to kernel
|
|
communication mechanism, the one used by all processes, is <span class='ecti-1000'>system calls</span>. When a
|
|
process requests a service from the kernel (such as opening a file, forking to a new
|
|
process, or requesting more memory), this is the mechanism used. If you want to
|
|
change the behaviour of the kernel in interesting ways, this is the place to do
|
|
it. By the way, if you want to see which system calls a program uses, run
|
|
<code> <span class='ectt-1000'>strace <arguments></span>
|
|
</code>.
|
|
</p><!-- l. 1435 --><p class='indent'> In general, a process is not supposed to be able to access the kernel. It can not
|
|
access kernel memory and it can’t call kernel functions. The hardware of the CPU
|
|
enforces this (that is the reason why it is called “protected mode” or “page
|
|
protection”).
|
|
</p><!-- l. 1439 --><p class='indent'> System calls are an exception to this general rule. What happens is that the
|
|
process fills the registers with the appropriate values and then calls a special
|
|
instruction which jumps to a previously defined location in the kernel (of course, that
|
|
location is readable by user processes, it is not writable by them). Under Intel CPUs,
|
|
this is done by means of interrupt 0x80. The hardware knows that once you jump to
|
|
this location, you are no longer running in restricted user mode, but as the
|
|
operating system kernel — and therefore you’re allowed to do whatever you
|
|
want.
|
|
</p><!-- l. 1444 --><p class='indent'> The location in the kernel a process can jump to is called <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>system_call</span></span></span>. The
|
|
procedure at that location checks the system call number, which tells the kernel what
|
|
service the process requested. Then, it looks at the table of system calls
|
|
(<code> <span class='ectt-1000'>sys_call_table</span>
|
|
</code>) to see the address of the kernel function to call. Then it calls the function, and after
|
|
it returns, does a few system checks and then return back to the process (or to a
|
|
different process, if the process time ran out). If you want to read this code, it is
|
|
at the source file <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>arch/$(architecture)/kernel/entry.S</span></span></span>, after the line
|
|
<code> <span class='ectt-1000'>ENTRY(system_call)</span>
|
|
</code>.
|
|
</p><!-- l. 1450 --><p class='indent'> So, if we want to change the way a certain system call works, what we need to do
|
|
|
|
|
|
|
|
is to write our own function to implement it (usually by adding a bit of our own
|
|
code, and then calling the original function) and then change the pointer at
|
|
<code> <span class='ectt-1000'>sys_call_table</span>
|
|
</code> to point to our function. Because we might be removed later and we
|
|
don’t want to leave the system in an unstable state, it’s important for
|
|
<code> <span class='ectt-1000'>cleanup_module</span>
|
|
</code> to restore the table to its original state.
|
|
</p><!-- l. 1453 --><p class='indent'> To modify the content of <code> <span class='ectt-1000'>sys_call_table</span>
|
|
</code>, we need to consider the control register. A control register is a processor
|
|
register that changes or controls the general behavior of the CPU. For x86
|
|
architecture, the <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>cr0</span></span></span> register has various control flags that modify the basic
|
|
operation of the processor. The <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>WP</span></span></span> flag in <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>cr0</span></span></span> stands for write protection.
|
|
Once the <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>WP</span></span></span> flag is set, the processor disallows further write attempts to the
|
|
read-only sections Therefore, we must disable the <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>WP</span></span></span> flag before modifying
|
|
<code> <span class='ectt-1000'>sys_call_table</span>
|
|
</code>. Since Linux v5.3, the <code> <span class='ectt-1000'>write_cr0</span>
|
|
</code> function cannot be used because of the sensitive <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>cr0</span></span></span> bits pinned by the security
|
|
issue, the attacker may write into CPU control registers to disable CPU protections
|
|
like write protection. As a result, we have to provide the custom assembly routine to
|
|
bypass it.
|
|
</p><!-- l. 1462 --><p class='indent'> However, <code> <span class='ectt-1000'>sys_call_table</span>
|
|
</code> symbol is unexported to prevent misuse. But there have few ways to get the symbol, manual
|
|
symbol lookup and <code> <span class='ectt-1000'>kallsyms_lookup_name</span>
|
|
</code>. Here we use both depend on the kernel version.
|
|
</p><!-- l. 1466 --><p class='indent'> Because of the <span class='ecti-1000'>control-flow integrity</span>, which is a technique to prevent the redirect
|
|
execution code from the attacker, for making sure that the indirect calls go to the
|
|
expected addresses and the return addresses are not changed. Since Linux v5.7, the
|
|
kernel patched the series of <span class='ecti-1000'>control-flow enforcement </span>(CET) for x86, and some
|
|
configurations of GCC, like GCC versions 9 and 10 in Ubuntu Linux, will add with
|
|
CET (the <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>-fcf-protection</span></span></span> option) in the kernel by default. Using that GCC to
|
|
compile the kernel with retpoline off may result in CET being enabled in the kernel.
|
|
You can use the following command to check out the <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>-fcf-protection</span></span></span> option is
|
|
enabled or not:
|
|
|
|
|
|
|
|
</p>
|
|
<pre class='verbatim' id='verbatim-16'>
|
|
$ gcc -v -Q -O2 --help=target | grep protection
|
|
Using built-in specs.
|
|
COLLECT_GCC=gcc
|
|
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/9/lto-wrapper
|
|
...
|
|
gcc version 9.3.0 (Ubuntu 9.3.0-17ubuntu1~20.04)
|
|
COLLECT_GCC_OPTIONS='-v' '-Q' '-O2' '--help=target' '-mtune=generic' '-march=x86-64'
|
|
/usr/lib/gcc/x86_64-linux-gnu/9/cc1 -v ... -fcf-protection ...
|
|
GNU C17 (Ubuntu 9.3.0-17ubuntu1~20.04) version 9.3.0 (x86_64-linux-gnu)
|
|
...
|
|
</pre>
|
|
<!-- l. 1483 --><p class='nopar'>But CET should not be enabled in the kernel, it may break the Kprobes and bpf.
|
|
Consequently, CET is disabled since v5.11. To guarantee the manual symbol lookup
|
|
worked, we only use up to v5.4.
|
|
</p><!-- l. 1488 --><p class='indent'> Unfortunately, since Linux v5.7 <code> <span class='ectt-1000'>kallsyms_lookup_name</span>
|
|
</code> is also unexported, it needs certain trick to get the address of
|
|
<code> <span class='ectt-1000'>kallsyms_lookup_name</span>
|
|
</code>. If <code> <span class='ectt-1000'>CONFIG_KPROBES</span>
|
|
</code> is enabled, we can facilitate the retrieval of function addresses by means of Kprobes
|
|
to dynamically break into the specific kernel routine. Kprobes inserts a breakpoint at
|
|
the entry of function by replacing the first bytes of the probed instruction. When a
|
|
CPU hits the breakpoint, registers are stored, and the control will pass to Kprobes. It
|
|
passes the addresses of the saved registers and the Kprobe struct to the handler
|
|
you defined, then executes it. Kprobes can be registered by symbol name
|
|
or address. Within the symbol name, the address will be handled by the
|
|
kernel.
|
|
</p><!-- l. 1496 --><p class='indent'> Otherwise, specify the address of <code> <span class='ectt-1000'>sys_call_table</span>
|
|
</code> from <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc/kallsyms</span></span></span> and <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/boot/System.map</span></span></span> into
|
|
<code> <span class='ectt-1000'>sym</span>
|
|
</code> parameter. Following is the sample usage for <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc/kallsyms</span></span></span>:
|
|
|
|
|
|
|
|
</p>
|
|
<pre class='verbatim' id='verbatim-17'>
|
|
$ sudo grep sys_call_table /proc/kallsyms
|
|
ffffffff82000280 R x32_sys_call_table
|
|
ffffffff820013a0 R sys_call_table
|
|
ffffffff820023e0 R ia32_sys_call_table
|
|
$ sudo insmod syscall-steal.ko sym=0xffffffff820013a0
|
|
</pre>
|
|
<!-- l. 1504 --><p class='nopar'>
|
|
</p><!-- l. 1506 --><p class='indent'> Using the address from <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/boot/System.map</span></span></span>, be careful about <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>KASLR</span></span></span> (Kernel
|
|
Address Space Layout Randomization). <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>KASLR</span></span></span> may randomize the address of
|
|
kernel code and data at every boot time, such as the static address listed in
|
|
<span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/boot/System.map</span></span></span> will offset by some entropy. The purpose of <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>KASLR</span></span></span> is to protect
|
|
the kernel space from the attacker. Without <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>KASLR</span></span></span>, the attacker may find the target
|
|
address in the fixed address easily. Then the attacker can use return-oriented
|
|
programming to insert some malicious codes to execute or receive the target data by
|
|
a tampered pointer. <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>KASLR</span></span></span> mitigates these kinds of attacks because the attacker
|
|
cannot immediately know the target address, but a brute-force attack can still work.
|
|
If the address of a symbol in <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc/kallsyms</span></span></span> is different from the address in
|
|
<span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/boot/System.map</span></span></span>, <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>KASLR</span></span></span> is enabled with the kernel, which your system running
|
|
on.
|
|
|
|
|
|
|
|
</p>
|
|
<pre class='verbatim' id='verbatim-18'>
|
|
$ grep GRUB_CMDLINE_LINUX_DEFAULT /etc/default/grub
|
|
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"
|
|
$ sudo grep sys_call_table /boot/System.map-$(uname -r)
|
|
ffffffff82000300 R sys_call_table
|
|
$ sudo grep sys_call_table /proc/kallsyms
|
|
ffffffff820013a0 R sys_call_table
|
|
# Reboot
|
|
$ sudo grep sys_call_table /boot/System.map-$(uname -r)
|
|
ffffffff82000300 R sys_call_table
|
|
$ sudo grep sys_call_table /proc/kallsyms
|
|
ffffffff86400300 R sys_call_table
|
|
</pre>
|
|
<!-- l. 1525 --><p class='nopar'>If <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>KASLR</span></span></span> is enabled, we have to take care of the address from <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc/kallsyms</span></span></span> each
|
|
time we reboot the machine. In order to use the address from <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/boot/System.map</span></span></span>,
|
|
make sure that <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>KASLR</span></span></span> is disabled. You can add the <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>nokaslr</span></span></span> for disabling <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>KASLR</span></span></span> in
|
|
next booting time:
|
|
|
|
|
|
|
|
</p>
|
|
<pre class='verbatim' id='verbatim-19'>
|
|
$ grep GRUB_CMDLINE_LINUX_DEFAULT /etc/default/grub
|
|
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"
|
|
$ sudo perl -i -pe 'm/quiet/ and s//quiet nokaslr/' /etc/default/grub
|
|
$ grep quiet /etc/default/grub
|
|
GRUB_CMDLINE_LINUX_DEFAULT="quiet nokaslr splash"
|
|
$ sudo update-grub
|
|
</pre>
|
|
<!-- l. 1536 --><p class='nopar'>
|
|
</p><!-- l. 1538 --><p class='indent'> For more information, check out the following:
|
|
</p>
|
|
<ul class='itemize1'>
|
|
<li class='itemize'><a href='https://lwn.net/Articles/804849/'>Cook: Security things in Linux v5.3</a>
|
|
</li>
|
|
<li class='itemize'><a href='https://lwn.net/Articles/12211/'>Unexporting the system call table</a>
|
|
</li>
|
|
<li class='itemize'><a href='https://lwn.net/Articles/810077/'>Control-flow integrity for the kernel</a>
|
|
</li>
|
|
<li class='itemize'><a href='https://lwn.net/Articles/813350/'>Unexporting kallsyms_lookup_name()</a>
|
|
</li>
|
|
<li class='itemize'><a href='https://www.kernel.org/doc/Documentation/kprobes.txt'>Kernel Probes (Kprobes)</a>
|
|
</li>
|
|
<li class='itemize'><a href='https://lwn.net/Articles/569635/'>Kernel address space layout randomization</a></li></ul>
|
|
<!-- l. 1549 --><p class='indent'> The source code here is an example of such a kernel module. We want to “spy” on a certain
|
|
user, and to <code> <span class='ectt-1000'>pr_info()</span>
|
|
</code> a message whenever that user opens a file. Towards this end, we
|
|
replace the system call to open a file with our own function, called
|
|
<code> <span class='ectt-1000'>our_sys_openat</span>
|
|
</code>. This function checks the uid (user’s id) of the current process, and if it is equal to the uid we
|
|
|
|
|
|
|
|
spy on, it calls <code> <span class='ectt-1000'>pr_info()</span>
|
|
</code> to display the name of the file to be opened. Then, either way, it calls the original
|
|
<code> <span class='ectt-1000'>openat()</span>
|
|
</code> function with the same parameters, to actually open the file.
|
|
</p><!-- l. 1555 --><p class='indent'> The <code> <span class='ectt-1000'>init_module</span>
|
|
</code> function replaces the appropriate location in
|
|
<code> <span class='ectt-1000'>sys_call_table</span>
|
|
</code> and keeps the original pointer in a variable. The
|
|
<code> <span class='ectt-1000'>cleanup_module</span>
|
|
</code> function uses that variable to restore everything back to normal. This approach is
|
|
dangerous, because of the possibility of two kernel modules changing the same system
|
|
call. Imagine we have two kernel modules, A and B. A’s openat system call will be
|
|
<code> <span class='ectt-1000'>A_openat</span>
|
|
</code> and B’s will be <code> <span class='ectt-1000'>B_openat</span>
|
|
</code>. Now, when A is inserted into the kernel, the system call is replaced with
|
|
<code> <span class='ectt-1000'>A_openat</span>
|
|
</code>, which will call the original <code> <span class='ectt-1000'>sys_openat</span>
|
|
</code> when it is done. Next, B is inserted into the kernel, which replaces the system call
|
|
with <code> <span class='ectt-1000'>B_openat</span>
|
|
</code>, which will call what it thinks is the original system call,
|
|
<code> <span class='ectt-1000'>A_openat</span>
|
|
</code>, when it’s done.
|
|
</p><!-- l. 1562 --><p class='indent'> Now, if B is removed first, everything will be well — it will simply restore the system
|
|
call to <code> <span class='ectt-1000'>A_openat</span>
|
|
</code>, which calls the original. However, if A is removed and then B is removed, the
|
|
system will crash. A’s removal will restore the system call to the original,
|
|
<code> <span class='ectt-1000'>sys_openat</span>
|
|
</code>, cutting B out of the loop. Then, when B is removed, it will restore the system call to what it thinks
|
|
is the original, <code> <span class='ectt-1000'>A_openat</span>
|
|
</code>, which is no longer in memory. At first glance, it appears we could solve
|
|
this particular problem by checking if the system call is equal to our
|
|
open function and if so not changing it at all (so that B won’t change
|
|
the system call when it is removed), but that will cause an even worse
|
|
problem. When A is removed, it sees that the system call was changed to
|
|
<code> <span class='ectt-1000'>B_openat</span>
|
|
</code> so that it is no longer pointing to <code> <span class='ectt-1000'>A_openat</span>
|
|
</code>, so it will not restore it to <code> <span class='ectt-1000'>sys_openat</span>
|
|
</code> before it is removed from memory. Unfortunately,
|
|
<code> <span class='ectt-1000'>B_openat</span>
|
|
</code> will still try to call <code> <span class='ectt-1000'>A_openat</span>
|
|
</code> which is no longer there, so that even without removing B the system would
|
|
crash.
|
|
</p><!-- l. 1570 --><p class='indent'> Note that all the related problems make syscall stealing unfeasible for
|
|
production use. In order to keep people from doing potential harmful things
|
|
<code> <span class='ectt-1000'>sys_call_table</span>
|
|
</code> is no longer exported. This means, if you want to do something more than a mere
|
|
|
|
|
|
|
|
dry run of this example, you will have to patch your current kernel in order to have
|
|
<code> <span class='ectt-1000'>sys_call_table</span>
|
|
</code> exported.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb64'><a id='x1-41044r1'></a><span class='ecrm-0500'>1</span><span id='textcolor1506'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-41046r2'></a><span class='ecrm-0500'>2</span><span id='textcolor1507'><span class='ectt-0800'> * syscall-steal.c</span></span>
|
|
<a id='x1-41048r3'></a><span class='ecrm-0500'>3</span><span id='textcolor1508'><span class='ectt-0800'> *</span></span>
|
|
<a id='x1-41050r4'></a><span class='ecrm-0500'>4</span><span id='textcolor1509'><span class='ectt-0800'> * System call "stealing" sample.</span></span>
|
|
<a id='x1-41052r5'></a><span class='ecrm-0500'>5</span><span id='textcolor1510'><span class='ectt-0800'> *</span></span>
|
|
<a id='x1-41054r6'></a><span class='ecrm-0500'>6</span><span id='textcolor1511'><span class='ectt-0800'> * Disables page protection at a processor level by changing the 16th bit</span></span>
|
|
<a id='x1-41056r7'></a><span class='ecrm-0500'>7</span><span id='textcolor1512'><span class='ectt-0800'> * in the cr0 register (could be Intel specific).</span></span>
|
|
<a id='x1-41058r8'></a><span class='ecrm-0500'>8</span><span id='textcolor1513'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-41060r9'></a><span class='ecrm-0500'>9</span>
|
|
<a id='x1-41062r10'></a><span class='ecrm-0500'>10</span><span id='textcolor1514'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1515'><span class='ectt-0800'><linux/delay.h></span></span>
|
|
<a id='x1-41064r11'></a><span class='ecrm-0500'>11</span><span id='textcolor1516'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1517'><span class='ectt-0800'><linux/kernel.h></span></span>
|
|
<a id='x1-41066r12'></a><span class='ecrm-0500'>12</span><span id='textcolor1518'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1519'><span class='ectt-0800'><linux/module.h></span></span>
|
|
<a id='x1-41068r13'></a><span class='ecrm-0500'>13</span><span id='textcolor1520'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1521'><span class='ectt-0800'><linux/moduleparam.h> /* which will have params */</span></span>
|
|
<a id='x1-41070r14'></a><span class='ecrm-0500'>14</span><span id='textcolor1522'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1523'><span class='ectt-0800'><linux/unistd.h> /* The list of system calls */</span></span>
|
|
<a id='x1-41072r15'></a><span class='ecrm-0500'>15</span><span id='textcolor1524'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1525'><span class='ectt-0800'><linux/cred.h> /* For current_uid() */</span></span>
|
|
<a id='x1-41074r16'></a><span class='ecrm-0500'>16</span><span id='textcolor1526'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1527'><span class='ectt-0800'><linux/uidgid.h> /* For __kuid_val() */</span></span>
|
|
<a id='x1-41076r17'></a><span class='ecrm-0500'>17</span><span id='textcolor1528'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1529'><span class='ectt-0800'><linux/version.h></span></span>
|
|
<a id='x1-41078r18'></a><span class='ecrm-0500'>18</span>
|
|
<a id='x1-41080r19'></a><span class='ecrm-0500'>19</span><span id='textcolor1530'><span class='ectt-0800'>/* For the current (process) structure, we need this to know who the</span></span>
|
|
<a id='x1-41082r20'></a><span class='ecrm-0500'>20</span><span id='textcolor1531'><span class='ectt-0800'> * current user is.</span></span>
|
|
<a id='x1-41084r21'></a><span class='ecrm-0500'>21</span><span id='textcolor1532'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-41086r22'></a><span class='ecrm-0500'>22</span><span id='textcolor1533'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1534'><span class='ectt-0800'><linux/sched.h></span></span>
|
|
<a id='x1-41088r23'></a><span class='ecrm-0500'>23</span><span id='textcolor1535'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1536'><span class='ectt-0800'><linux/uaccess.h></span></span>
|
|
<a id='x1-41090r24'></a><span class='ecrm-0500'>24</span>
|
|
<a id='x1-41092r25'></a><span class='ecrm-0500'>25</span><span id='textcolor1537'><span class='ectt-0800'>/* The way we access "sys_call_table" varies as kernel internal changes.</span></span>
|
|
<a id='x1-41094r26'></a><span class='ecrm-0500'>26</span><span id='textcolor1538'><span class='ectt-0800'> * - Prior to v5.4 : manual symbol lookup</span></span>
|
|
<a id='x1-41096r27'></a><span class='ecrm-0500'>27</span><span id='textcolor1539'><span class='ectt-0800'> * - v5.5 to v5.6 : use kallsyms_lookup_name()</span></span>
|
|
<a id='x1-41098r28'></a><span class='ecrm-0500'>28</span><span id='textcolor1540'><span class='ectt-0800'> * - v5.7+ : Kprobes or specific kernel module parameter</span></span>
|
|
<a id='x1-41100r29'></a><span class='ecrm-0500'>29</span><span id='textcolor1541'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-41102r30'></a><span class='ecrm-0500'>30</span>
|
|
<a id='x1-41104r31'></a><span class='ecrm-0500'>31</span><span id='textcolor1542'><span class='ectt-0800'>/* The in-kernel calls to the ksys_close() syscall were removed in Linux v5.11+.</span></span>
|
|
<a id='x1-41106r32'></a><span class='ecrm-0500'>32</span><span id='textcolor1543'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-41108r33'></a><span class='ecrm-0500'>33</span><span id='textcolor1544'><span class='ectt-0800'>#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 7, 0))</span></span>
|
|
<a id='x1-41110r34'></a><span class='ecrm-0500'>34</span>
|
|
<a id='x1-41112r35'></a><span class='ecrm-0500'>35</span><span id='textcolor1545'><span class='ectt-0800'>#if LINUX_VERSION_CODE <= KERNEL_VERSION(5, 4, 0)</span></span>
|
|
<a id='x1-41114r36'></a><span class='ecrm-0500'>36</span><span id='textcolor1546'><span class='ectt-0800'>#define HAVE_KSYS_CLOSE 1</span></span>
|
|
<a id='x1-41116r37'></a><span class='ecrm-0500'>37</span><span id='textcolor1547'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1548'><span class='ectt-0800'><linux/syscalls.h> /* For ksys_close() */</span></span>
|
|
<a id='x1-41118r38'></a><span class='ecrm-0500'>38</span><span id='textcolor1549'><span class='ectt-0800'>#else</span></span>
|
|
<a id='x1-41120r39'></a><span class='ecrm-0500'>39</span><span id='textcolor1550'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1551'><span class='ectt-0800'><linux/kallsyms.h> /* For kallsyms_lookup_name */</span></span>
|
|
<a id='x1-41122r40'></a><span class='ecrm-0500'>40</span><span id='textcolor1552'><span class='ectt-0800'>#endif</span></span>
|
|
<a id='x1-41124r41'></a><span class='ecrm-0500'>41</span>
|
|
<a id='x1-41126r42'></a><span class='ecrm-0500'>42</span><span id='textcolor1553'><span class='ectt-0800'>#else</span></span>
|
|
<a id='x1-41128r43'></a><span class='ecrm-0500'>43</span>
|
|
<a id='x1-41130r44'></a><span class='ecrm-0500'>44</span><span id='textcolor1554'><span class='ectt-0800'>#if defined(CONFIG_KPROBES)</span></span>
|
|
<a id='x1-41132r45'></a><span class='ecrm-0500'>45</span><span id='textcolor1555'><span class='ectt-0800'>#define HAVE_KPROBES 1</span></span>
|
|
<a id='x1-41134r46'></a><span class='ecrm-0500'>46</span><span id='textcolor1556'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1557'><span class='ectt-0800'><linux/kprobes.h></span></span>
|
|
<a id='x1-41136r47'></a><span class='ecrm-0500'>47</span><span id='textcolor1558'><span class='ectt-0800'>#else</span></span>
|
|
<a id='x1-41138r48'></a><span class='ecrm-0500'>48</span><span id='textcolor1559'><span class='ectt-0800'>#define HAVE_PARAM 1</span></span>
|
|
<a id='x1-41140r49'></a><span class='ecrm-0500'>49</span><span id='textcolor1560'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1561'><span class='ectt-0800'><linux/kallsyms.h> /* For sprint_symbol */</span></span>
|
|
<a id='x1-41142r50'></a><span class='ecrm-0500'>50</span><span id='textcolor1562'><span class='ectt-0800'>/* The address of the sys_call_table, which can be obtained with looking up</span></span>
|
|
<a id='x1-41144r51'></a><span class='ecrm-0500'>51</span><span id='textcolor1563'><span class='ectt-0800'> * "/boot/System.map" or "/proc/kallsyms". When the kernel version is v5.7+,</span></span>
|
|
<a id='x1-41146r52'></a><span class='ecrm-0500'>52</span><span id='textcolor1564'><span class='ectt-0800'> * without CONFIG_KPROBES, you can input the parameter or the module will look</span></span>
|
|
<a id='x1-41148r53'></a><span class='ecrm-0500'>53</span><span id='textcolor1565'><span class='ectt-0800'> * up all the memory.</span></span>
|
|
<a id='x1-41150r54'></a><span class='ecrm-0500'>54</span><span id='textcolor1566'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-41152r55'></a><span class='ecrm-0500'>55</span><span id='textcolor1567'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1568'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1569'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> sym = 0;</span>
|
|
<a id='x1-41154r56'></a><span class='ecrm-0500'>56</span><span class='ectt-0800'>module_param(sym, ulong, 0644);</span>
|
|
<a id='x1-41156r57'></a><span class='ecrm-0500'>57</span><span id='textcolor1570'><span class='ectt-0800'>#endif </span></span><span id='textcolor1571'><span class='ectt-0800'>/* CONFIG_KPROBES */</span></span>
|
|
<a id='x1-41158r58'></a><span class='ecrm-0500'>58</span>
|
|
<a id='x1-41160r59'></a><span class='ecrm-0500'>59</span><span id='textcolor1572'><span class='ectt-0800'>#endif </span></span><span id='textcolor1573'><span class='ectt-0800'>/* Version < v5.7 */</span></span>
|
|
<a id='x1-41162r60'></a><span class='ecrm-0500'>60</span>
|
|
<a id='x1-41164r61'></a><span class='ecrm-0500'>61</span><span id='textcolor1574'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1575'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1576'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> **sys_call_table_stolen;</span>
|
|
<a id='x1-41166r62'></a><span class='ecrm-0500'>62</span>
|
|
<a id='x1-41168r63'></a><span class='ecrm-0500'>63</span><span id='textcolor1577'><span class='ectt-0800'>/* UID we want to spy on - will be filled from the command line. */</span></span>
|
|
<a id='x1-41170r64'></a><span class='ecrm-0500'>64</span><span id='textcolor1578'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1579'><span class='ectt-0800'>uid_t</span></span><span class='ectt-0800'> uid = -1;</span>
|
|
<a id='x1-41172r65'></a><span class='ecrm-0500'>65</span><span class='ectt-0800'>module_param(uid, </span><span id='textcolor1580'><span class='ectt-0800'>int</span></span><span class='ectt-0800'>, 0644);</span>
|
|
<a id='x1-41174r66'></a><span class='ecrm-0500'>66</span>
|
|
<a id='x1-41176r67'></a><span class='ecrm-0500'>67</span><span id='textcolor1581'><span class='ectt-0800'>/* A pointer to the original system call. The reason we keep this, rather</span></span>
|
|
<a id='x1-41178r68'></a><span class='ecrm-0500'>68</span><span id='textcolor1582'><span class='ectt-0800'> * than call the original function (sys_openat), is because somebody else</span></span>
|
|
<a id='x1-41180r69'></a><span class='ecrm-0500'>69</span><span id='textcolor1583'><span class='ectt-0800'> * might have replaced the system call before us. Note that this is not</span></span>
|
|
<a id='x1-41182r70'></a><span class='ecrm-0500'>70</span><span id='textcolor1584'><span class='ectt-0800'> * 100% safe, because if another module replaced sys_openat before us,</span></span>
|
|
<a id='x1-41184r71'></a><span class='ecrm-0500'>71</span><span id='textcolor1585'><span class='ectt-0800'> * then when we are inserted, we will call the function in that module -</span></span>
|
|
<a id='x1-41186r72'></a><span class='ecrm-0500'>72</span><span id='textcolor1586'><span class='ectt-0800'> * and it might be removed before we are.</span></span>
|
|
<a id='x1-41188r73'></a><span class='ecrm-0500'>73</span><span id='textcolor1587'><span class='ectt-0800'> *</span></span>
|
|
<a id='x1-41190r74'></a><span class='ecrm-0500'>74</span><span id='textcolor1588'><span class='ectt-0800'> * Another reason for this is that we can not get sys_openat.</span></span>
|
|
<a id='x1-41192r75'></a><span class='ecrm-0500'>75</span><span id='textcolor1589'><span class='ectt-0800'> * It is a static variable, so it is not exported.</span></span>
|
|
<a id='x1-41194r76'></a><span class='ecrm-0500'>76</span><span id='textcolor1590'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-41196r77'></a><span class='ecrm-0500'>77</span><span id='textcolor1591'><span class='ectt-0800'>#ifdef CONFIG_ARCH_HAS_SYSCALL_WRAPPER</span></span>
|
|
<a id='x1-41198r78'></a><span class='ecrm-0500'>78</span><span id='textcolor1592'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> asmlinkage long (*original_call)(</span><span id='textcolor1593'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor1594'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> pt_regs *);</span>
|
|
<a id='x1-41200r79'></a><span class='ecrm-0500'>79</span><span id='textcolor1595'><span class='ectt-0800'>#else</span></span>
|
|
<a id='x1-41202r80'></a><span class='ecrm-0500'>80</span><span id='textcolor1596'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> asmlinkage long (*original_call)(</span><span id='textcolor1597'><span class='ectt-0800'>int</span></span><span class='ectt-0800'>, </span><span id='textcolor1598'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor1599'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *, </span><span id='textcolor1600'><span class='ectt-0800'>int</span></span><span class='ectt-0800'>, umode_t);</span>
|
|
<a id='x1-41204r81'></a><span class='ecrm-0500'>81</span><span id='textcolor1601'><span class='ectt-0800'>#endif</span></span>
|
|
<a id='x1-41206r82'></a><span class='ecrm-0500'>82</span>
|
|
<a id='x1-41208r83'></a><span class='ecrm-0500'>83</span><span id='textcolor1602'><span class='ectt-0800'>/* The function we will replace sys_openat (the function called when you</span></span>
|
|
<a id='x1-41210r84'></a><span class='ecrm-0500'>84</span><span id='textcolor1603'><span class='ectt-0800'> * call the open system call) with. To find the exact prototype, with</span></span>
|
|
<a id='x1-41212r85'></a><span class='ecrm-0500'>85</span><span id='textcolor1604'><span class='ectt-0800'> * the number and type of arguments, we find the original function first</span></span>
|
|
<a id='x1-41214r86'></a><span class='ecrm-0500'>86</span><span id='textcolor1605'><span class='ectt-0800'> * (it is at fs/open.c).</span></span>
|
|
<a id='x1-41216r87'></a><span class='ecrm-0500'>87</span><span id='textcolor1606'><span class='ectt-0800'> *</span></span>
|
|
<a id='x1-41218r88'></a><span class='ecrm-0500'>88</span><span id='textcolor1607'><span class='ectt-0800'> * In theory, this means that we are tied to the current version of the</span></span>
|
|
<a id='x1-41220r89'></a><span class='ecrm-0500'>89</span><span id='textcolor1608'><span class='ectt-0800'> * kernel. In practice, the system calls almost never change (it would</span></span>
|
|
<a id='x1-41222r90'></a><span class='ecrm-0500'>90</span><span id='textcolor1609'><span class='ectt-0800'> * wreck havoc and require programs to be recompiled, since the system</span></span>
|
|
<a id='x1-41224r91'></a><span class='ecrm-0500'>91</span><span id='textcolor1610'><span class='ectt-0800'> * calls are the interface between the kernel and the processes).</span></span>
|
|
<a id='x1-41226r92'></a><span class='ecrm-0500'>92</span><span id='textcolor1611'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-41228r93'></a><span class='ecrm-0500'>93</span><span id='textcolor1612'><span class='ectt-0800'>#ifdef CONFIG_ARCH_HAS_SYSCALL_WRAPPER</span></span>
|
|
<a id='x1-41230r94'></a><span class='ecrm-0500'>94</span><span id='textcolor1613'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> asmlinkage </span><span id='textcolor1614'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> our_sys_openat(</span><span id='textcolor1615'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor1616'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> pt_regs *regs)</span>
|
|
<a id='x1-41232r95'></a><span class='ecrm-0500'>95</span><span id='textcolor1617'><span class='ectt-0800'>#else</span></span>
|
|
<a id='x1-41234r96'></a><span class='ecrm-0500'>96</span><span id='textcolor1618'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> asmlinkage </span><span id='textcolor1619'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> our_sys_openat(</span><span id='textcolor1620'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> dfd, </span><span id='textcolor1621'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor1622'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *filename,</span>
|
|
<a id='x1-41236r97'></a><span class='ecrm-0500'>97</span><span class='ectt-0800'> </span><span id='textcolor1623'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> flags, umode_t mode)</span>
|
|
<a id='x1-41238r98'></a><span class='ecrm-0500'>98</span><span id='textcolor1624'><span class='ectt-0800'>#endif</span></span>
|
|
<a id='x1-41240r99'></a><span class='ecrm-0500'>99</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-41242r100'></a><span class='ecrm-0500'>100</span><span class='ectt-0800'> </span><span id='textcolor1625'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> i = 0;</span>
|
|
<a id='x1-41244r101'></a><span class='ecrm-0500'>101</span><span class='ectt-0800'> </span><span id='textcolor1626'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> ch;</span>
|
|
<a id='x1-41246r102'></a><span class='ecrm-0500'>102</span>
|
|
<a id='x1-41248r103'></a><span class='ecrm-0500'>103</span><span class='ectt-0800'> </span><span id='textcolor1627'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (__kuid_val(current_uid()) != uid)</span>
|
|
<a id='x1-41250r104'></a><span class='ecrm-0500'>104</span><span class='ectt-0800'> </span><span id='textcolor1628'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> orig_call;</span>
|
|
<a id='x1-41252r105'></a><span class='ecrm-0500'>105</span>
|
|
<a id='x1-41254r106'></a><span class='ecrm-0500'>106</span><span class='ectt-0800'> </span><span id='textcolor1629'><span class='ectt-0800'>/* Report the file, if relevant */</span></span>
|
|
<a id='x1-41256r107'></a><span class='ecrm-0500'>107</span><span class='ectt-0800'> pr_info(</span><span id='textcolor1630'><span class='ectt-0800'>"Opened file by %d: "</span></span><span class='ectt-0800'>, uid);</span>
|
|
<a id='x1-41258r108'></a><span class='ecrm-0500'>108</span><span class='ectt-0800'> </span><span id='textcolor1631'><span class='ectt-0800'>do</span></span><span class='ectt-0800'> {</span>
|
|
<a id='x1-41260r109'></a><span class='ecrm-0500'>109</span><span id='textcolor1632'><span class='ectt-0800'>#ifdef CONFIG_ARCH_HAS_SYSCALL_WRAPPER</span></span>
|
|
<a id='x1-41262r110'></a><span class='ecrm-0500'>110</span><span class='ectt-0800'> get_user(ch, (</span><span id='textcolor1633'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *)regs->si + i);</span>
|
|
<a id='x1-41264r111'></a><span class='ecrm-0500'>111</span><span id='textcolor1634'><span class='ectt-0800'>#else</span></span>
|
|
<a id='x1-41266r112'></a><span class='ecrm-0500'>112</span><span class='ectt-0800'> get_user(ch, (</span><span id='textcolor1635'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *)filename + i);</span>
|
|
<a id='x1-41268r113'></a><span class='ecrm-0500'>113</span><span id='textcolor1636'><span class='ectt-0800'>#endif</span></span>
|
|
<a id='x1-41270r114'></a><span class='ecrm-0500'>114</span><span class='ectt-0800'> i++;</span>
|
|
<a id='x1-41272r115'></a><span class='ecrm-0500'>115</span><span class='ectt-0800'> pr_info(</span><span id='textcolor1637'><span class='ectt-0800'>"%c"</span></span><span class='ectt-0800'>, ch);</span>
|
|
<a id='x1-41274r116'></a><span class='ecrm-0500'>116</span><span class='ectt-0800'> } </span><span id='textcolor1638'><span class='ectt-0800'>while</span></span><span class='ectt-0800'> (ch != 0);</span>
|
|
<a id='x1-41276r117'></a><span class='ecrm-0500'>117</span><span class='ectt-0800'> pr_info(</span><span id='textcolor1639'><span class='ectt-0800'>"</span></span><span id='textcolor1640'><span class='ectt-0800'>\n</span></span><span id='textcolor1641'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-41278r118'></a><span class='ecrm-0500'>118</span>
|
|
<a id='x1-41280r119'></a><span class='ecrm-0500'>119</span><span class='ectt-0800'>orig_call:</span>
|
|
<a id='x1-41282r120'></a><span class='ecrm-0500'>120</span><span class='ectt-0800'> </span><span id='textcolor1642'><span class='ectt-0800'>/* Call the original sys_openat - otherwise, we lose the ability to</span></span>
|
|
<a id='x1-41284r121'></a><span class='ecrm-0500'>121</span><span id='textcolor1643'><span class='ectt-0800'> * open files.</span></span>
|
|
<a id='x1-41286r122'></a><span class='ecrm-0500'>122</span><span id='textcolor1644'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-41288r123'></a><span class='ecrm-0500'>123</span><span id='textcolor1645'><span class='ectt-0800'>#ifdef CONFIG_ARCH_HAS_SYSCALL_WRAPPER</span></span>
|
|
<a id='x1-41290r124'></a><span class='ecrm-0500'>124</span><span class='ectt-0800'> </span><span id='textcolor1646'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> original_call(regs);</span>
|
|
<a id='x1-41292r125'></a><span class='ecrm-0500'>125</span><span id='textcolor1647'><span class='ectt-0800'>#else</span></span>
|
|
<a id='x1-41294r126'></a><span class='ecrm-0500'>126</span><span class='ectt-0800'> </span><span id='textcolor1648'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> original_call(dfd, filename, flags, mode);</span>
|
|
<a id='x1-41296r127'></a><span class='ecrm-0500'>127</span><span id='textcolor1649'><span class='ectt-0800'>#endif</span></span>
|
|
<a id='x1-41298r128'></a><span class='ecrm-0500'>128</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-41300r129'></a><span class='ecrm-0500'>129</span>
|
|
<a id='x1-41302r130'></a><span class='ecrm-0500'>130</span><span id='textcolor1650'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1651'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1652'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> **acquire_sys_call_table(</span><span id='textcolor1653'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-41304r131'></a><span class='ecrm-0500'>131</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-41306r132'></a><span class='ecrm-0500'>132</span><span id='textcolor1654'><span class='ectt-0800'>#ifdef HAVE_KSYS_CLOSE</span></span>
|
|
<a id='x1-41308r133'></a><span class='ecrm-0500'>133</span><span class='ectt-0800'> </span><span id='textcolor1655'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1656'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> </span><span id='textcolor1657'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> offset = PAGE_OFFSET;</span>
|
|
<a id='x1-41310r134'></a><span class='ecrm-0500'>134</span><span class='ectt-0800'> </span><span id='textcolor1658'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1659'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> **sct;</span>
|
|
<a id='x1-41312r135'></a><span class='ecrm-0500'>135</span>
|
|
<a id='x1-41314r136'></a><span class='ecrm-0500'>136</span><span class='ectt-0800'> </span><span id='textcolor1660'><span class='ectt-0800'>while</span></span><span class='ectt-0800'> (offset < ULLONG_MAX) {</span>
|
|
<a id='x1-41316r137'></a><span class='ecrm-0500'>137</span><span class='ectt-0800'> sct = (</span><span id='textcolor1661'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1662'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> **)offset;</span>
|
|
<a id='x1-41318r138'></a><span class='ecrm-0500'>138</span>
|
|
<a id='x1-41320r139'></a><span class='ecrm-0500'>139</span><span class='ectt-0800'> </span><span id='textcolor1663'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (sct[__NR_close] == (</span><span id='textcolor1664'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1665'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> *)ksys_close)</span>
|
|
<a id='x1-41322r140'></a><span class='ecrm-0500'>140</span><span class='ectt-0800'> </span><span id='textcolor1666'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> sct;</span>
|
|
<a id='x1-41324r141'></a><span class='ecrm-0500'>141</span>
|
|
<a id='x1-41326r142'></a><span class='ecrm-0500'>142</span><span class='ectt-0800'> offset += </span><span id='textcolor1667'><span class='ectt-0800'>sizeof</span></span><span class='ectt-0800'>(</span><span id='textcolor1668'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> *);</span>
|
|
<a id='x1-41328r143'></a><span class='ecrm-0500'>143</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-41330r144'></a><span class='ecrm-0500'>144</span>
|
|
<a id='x1-41332r145'></a><span class='ecrm-0500'>145</span><span class='ectt-0800'> </span><span id='textcolor1669'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> NULL;</span>
|
|
<a id='x1-41334r146'></a><span class='ecrm-0500'>146</span><span id='textcolor1670'><span class='ectt-0800'>#endif</span></span>
|
|
<a id='x1-41336r147'></a><span class='ecrm-0500'>147</span>
|
|
<a id='x1-41338r148'></a><span class='ecrm-0500'>148</span><span id='textcolor1671'><span class='ectt-0800'>#ifdef HAVE_PARAM</span></span>
|
|
<a id='x1-41340r149'></a><span class='ecrm-0500'>149</span><span class='ectt-0800'> </span><span id='textcolor1672'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor1673'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> sct_name[15] = </span><span id='textcolor1674'><span class='ectt-0800'>"sys_call_table"</span></span><span class='ectt-0800'>;</span>
|
|
<a id='x1-41342r150'></a><span class='ecrm-0500'>150</span><span class='ectt-0800'> </span><span id='textcolor1675'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> symbol[40] = { 0 };</span>
|
|
<a id='x1-41344r151'></a><span class='ecrm-0500'>151</span>
|
|
<a id='x1-41346r152'></a><span class='ecrm-0500'>152</span><span class='ectt-0800'> </span><span id='textcolor1676'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (sym == 0) {</span>
|
|
<a id='x1-41348r153'></a><span class='ecrm-0500'>153</span><span class='ectt-0800'> pr_alert(</span><span id='textcolor1677'><span class='ectt-0800'>"For Linux v5.7+, Kprobes is the preferable way to get "</span></span>
|
|
<a id='x1-41350r154'></a><span class='ecrm-0500'>154</span><span class='ectt-0800'> </span><span id='textcolor1678'><span class='ectt-0800'>"symbol.</span></span><span id='textcolor1679'><span class='ectt-0800'>\n</span></span><span id='textcolor1680'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-41352r155'></a><span class='ecrm-0500'>155</span><span class='ectt-0800'> pr_info(</span><span id='textcolor1681'><span class='ectt-0800'>"If Kprobes is absent, you have to specify the address of "</span></span>
|
|
<a id='x1-41354r156'></a><span class='ecrm-0500'>156</span><span class='ectt-0800'> </span><span id='textcolor1682'><span class='ectt-0800'>"sys_call_table symbol</span></span><span id='textcolor1683'><span class='ectt-0800'>\n</span></span><span id='textcolor1684'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-41356r157'></a><span class='ecrm-0500'>157</span><span class='ectt-0800'> pr_info(</span><span id='textcolor1685'><span class='ectt-0800'>"by /boot/System.map or /proc/kallsyms, which contains all the "</span></span>
|
|
<a id='x1-41358r158'></a><span class='ecrm-0500'>158</span><span class='ectt-0800'> </span><span id='textcolor1686'><span class='ectt-0800'>"symbol addresses, into sym parameter.</span></span><span id='textcolor1687'><span class='ectt-0800'>\n</span></span><span id='textcolor1688'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-41360r159'></a><span class='ecrm-0500'>159</span><span class='ectt-0800'> </span><span id='textcolor1689'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> NULL;</span>
|
|
<a id='x1-41362r160'></a><span class='ecrm-0500'>160</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-41364r161'></a><span class='ecrm-0500'>161</span><span class='ectt-0800'> sprint_symbol(symbol, sym);</span>
|
|
<a id='x1-41366r162'></a><span class='ecrm-0500'>162</span><span class='ectt-0800'> </span><span id='textcolor1690'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (!strncmp(sct_name, symbol, </span><span id='textcolor1691'><span class='ectt-0800'>sizeof</span></span><span class='ectt-0800'>(sct_name) - 1))</span>
|
|
<a id='x1-41368r163'></a><span class='ecrm-0500'>163</span><span class='ectt-0800'> </span><span id='textcolor1692'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> (</span><span id='textcolor1693'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1694'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> **)sym;</span>
|
|
<a id='x1-41370r164'></a><span class='ecrm-0500'>164</span>
|
|
<a id='x1-41372r165'></a><span class='ecrm-0500'>165</span><span class='ectt-0800'> </span><span id='textcolor1695'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> NULL;</span>
|
|
<a id='x1-41374r166'></a><span class='ecrm-0500'>166</span><span id='textcolor1696'><span class='ectt-0800'>#endif</span></span>
|
|
<a id='x1-41376r167'></a><span class='ecrm-0500'>167</span>
|
|
<a id='x1-41378r168'></a><span class='ecrm-0500'>168</span><span id='textcolor1697'><span class='ectt-0800'>#ifdef HAVE_KPROBES</span></span>
|
|
<a id='x1-41380r169'></a><span class='ecrm-0500'>169</span><span class='ectt-0800'> </span><span id='textcolor1698'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1699'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> (*kallsyms_lookup_name)(</span><span id='textcolor1700'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor1701'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *name);</span>
|
|
<a id='x1-41382r170'></a><span class='ecrm-0500'>170</span><span class='ectt-0800'> </span><span id='textcolor1702'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> kprobe kp = {</span>
|
|
<a id='x1-41384r171'></a><span class='ecrm-0500'>171</span><span class='ectt-0800'> .symbol_name = </span><span id='textcolor1703'><span class='ectt-0800'>"kallsyms_lookup_name"</span></span><span class='ectt-0800'>,</span>
|
|
<a id='x1-41386r172'></a><span class='ecrm-0500'>172</span><span class='ectt-0800'> };</span>
|
|
<a id='x1-41388r173'></a><span class='ecrm-0500'>173</span>
|
|
<a id='x1-41390r174'></a><span class='ecrm-0500'>174</span><span class='ectt-0800'> </span><span id='textcolor1704'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (register_kprobe(&kp) < 0)</span>
|
|
<a id='x1-41392r175'></a><span class='ecrm-0500'>175</span><span class='ectt-0800'> </span><span id='textcolor1705'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> NULL;</span>
|
|
<a id='x1-41394r176'></a><span class='ecrm-0500'>176</span><span class='ectt-0800'> kallsyms_lookup_name = (</span><span id='textcolor1706'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1707'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> (*)(</span><span id='textcolor1708'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor1709'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *name))kp.addr;</span>
|
|
<a id='x1-41396r177'></a><span class='ecrm-0500'>177</span><span class='ectt-0800'> unregister_kprobe(&kp);</span>
|
|
<a id='x1-41398r178'></a><span class='ecrm-0500'>178</span><span id='textcolor1710'><span class='ectt-0800'>#endif</span></span>
|
|
<a id='x1-41400r179'></a><span class='ecrm-0500'>179</span>
|
|
<a id='x1-41402r180'></a><span class='ecrm-0500'>180</span><span class='ectt-0800'> </span><span id='textcolor1711'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> (</span><span id='textcolor1712'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1713'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> **)kallsyms_lookup_name(</span><span id='textcolor1714'><span class='ectt-0800'>"sys_call_table"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-41404r181'></a><span class='ecrm-0500'>181</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-41406r182'></a><span class='ecrm-0500'>182</span>
|
|
<a id='x1-41408r183'></a><span class='ecrm-0500'>183</span><span id='textcolor1715'><span class='ectt-0800'>#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)</span></span>
|
|
<a id='x1-41410r184'></a><span class='ecrm-0500'>184</span><span id='textcolor1716'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1717'><span class='ectt-0800'>inline</span></span><span class='ectt-0800'> </span><span id='textcolor1718'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> __write_cr0(</span><span id='textcolor1719'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1720'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> cr0)</span>
|
|
<a id='x1-41412r185'></a><span class='ecrm-0500'>185</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-41414r186'></a><span class='ecrm-0500'>186</span><span class='ectt-0800'> </span><span id='textcolor1721'><span class='ectt-0800'>asm</span></span><span class='ectt-0800'> </span><span id='textcolor1722'><span class='ectt-0800'>volatile</span></span><span class='ectt-0800'>(</span><span id='textcolor1723'><span class='ectt-0800'>"mov %0,%%cr0"</span></span><span class='ectt-0800'> : </span><span id='textcolor1724'><span class='ectt-0800'>"+r"</span></span><span class='ectt-0800'>(cr0) : : </span><span id='textcolor1725'><span class='ectt-0800'>"memory"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-41416r187'></a><span class='ecrm-0500'>187</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-41418r188'></a><span class='ecrm-0500'>188</span><span id='textcolor1726'><span class='ectt-0800'>#else</span></span>
|
|
<a id='x1-41420r189'></a><span class='ecrm-0500'>189</span><span id='textcolor1727'><span class='ectt-0800'>#define __write_cr0 write_cr0</span></span>
|
|
<a id='x1-41422r190'></a><span class='ecrm-0500'>190</span><span id='textcolor1728'><span class='ectt-0800'>#endif</span></span>
|
|
<a id='x1-41424r191'></a><span class='ecrm-0500'>191</span>
|
|
<a id='x1-41426r192'></a><span class='ecrm-0500'>192</span><span id='textcolor1729'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1730'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> enable_write_protection(</span><span id='textcolor1731'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-41428r193'></a><span class='ecrm-0500'>193</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-41430r194'></a><span class='ecrm-0500'>194</span><span class='ectt-0800'> </span><span id='textcolor1732'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1733'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> cr0 = read_cr0();</span>
|
|
<a id='x1-41432r195'></a><span class='ecrm-0500'>195</span><span class='ectt-0800'> set_bit(16, &cr0);</span>
|
|
<a id='x1-41434r196'></a><span class='ecrm-0500'>196</span><span class='ectt-0800'> __write_cr0(cr0);</span>
|
|
<a id='x1-41436r197'></a><span class='ecrm-0500'>197</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-41438r198'></a><span class='ecrm-0500'>198</span>
|
|
<a id='x1-41440r199'></a><span class='ecrm-0500'>199</span><span id='textcolor1734'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1735'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> disable_write_protection(</span><span id='textcolor1736'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-41442r200'></a><span class='ecrm-0500'>200</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-41444r201'></a><span class='ecrm-0500'>201</span><span class='ectt-0800'> </span><span id='textcolor1737'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1738'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> cr0 = read_cr0();</span>
|
|
<a id='x1-41446r202'></a><span class='ecrm-0500'>202</span><span class='ectt-0800'> clear_bit(16, &cr0);</span>
|
|
<a id='x1-41448r203'></a><span class='ecrm-0500'>203</span><span class='ectt-0800'> __write_cr0(cr0);</span>
|
|
<a id='x1-41450r204'></a><span class='ecrm-0500'>204</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-41452r205'></a><span class='ecrm-0500'>205</span>
|
|
<a id='x1-41454r206'></a><span class='ecrm-0500'>206</span><span id='textcolor1739'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1740'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __init syscall_steal_start(</span><span id='textcolor1741'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-41456r207'></a><span class='ecrm-0500'>207</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-41458r208'></a><span class='ecrm-0500'>208</span><span class='ectt-0800'> </span><span id='textcolor1742'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (!(sys_call_table_stolen = acquire_sys_call_table()))</span>
|
|
<a id='x1-41460r209'></a><span class='ecrm-0500'>209</span><span class='ectt-0800'> </span><span id='textcolor1743'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -1;</span>
|
|
<a id='x1-41462r210'></a><span class='ecrm-0500'>210</span>
|
|
<a id='x1-41464r211'></a><span class='ecrm-0500'>211</span><span class='ectt-0800'> disable_write_protection();</span>
|
|
<a id='x1-41466r212'></a><span class='ecrm-0500'>212</span>
|
|
<a id='x1-41468r213'></a><span class='ecrm-0500'>213</span><span class='ectt-0800'> </span><span id='textcolor1744'><span class='ectt-0800'>/* keep track of the original open function */</span></span>
|
|
<a id='x1-41470r214'></a><span class='ecrm-0500'>214</span><span class='ectt-0800'> original_call = (</span><span id='textcolor1745'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> *)sys_call_table_stolen[__NR_openat];</span>
|
|
<a id='x1-41472r215'></a><span class='ecrm-0500'>215</span>
|
|
<a id='x1-41474r216'></a><span class='ecrm-0500'>216</span><span class='ectt-0800'> </span><span id='textcolor1746'><span class='ectt-0800'>/* use our openat function instead */</span></span>
|
|
<a id='x1-41476r217'></a><span class='ecrm-0500'>217</span><span class='ectt-0800'> sys_call_table_stolen[__NR_openat] = (</span><span id='textcolor1747'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1748'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> *)our_sys_openat;</span>
|
|
<a id='x1-41478r218'></a><span class='ecrm-0500'>218</span>
|
|
<a id='x1-41480r219'></a><span class='ecrm-0500'>219</span><span class='ectt-0800'> enable_write_protection();</span>
|
|
<a id='x1-41482r220'></a><span class='ecrm-0500'>220</span>
|
|
<a id='x1-41484r221'></a><span class='ecrm-0500'>221</span><span class='ectt-0800'> pr_info(</span><span id='textcolor1749'><span class='ectt-0800'>"Spying on UID:%d</span></span><span id='textcolor1750'><span class='ectt-0800'>\n</span></span><span id='textcolor1751'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, uid);</span>
|
|
<a id='x1-41486r222'></a><span class='ecrm-0500'>222</span>
|
|
<a id='x1-41488r223'></a><span class='ecrm-0500'>223</span><span class='ectt-0800'> </span><span id='textcolor1752'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-41490r224'></a><span class='ecrm-0500'>224</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-41492r225'></a><span class='ecrm-0500'>225</span>
|
|
<a id='x1-41494r226'></a><span class='ecrm-0500'>226</span><span id='textcolor1753'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1754'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> __exit syscall_steal_end(</span><span id='textcolor1755'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-41496r227'></a><span class='ecrm-0500'>227</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-41498r228'></a><span class='ecrm-0500'>228</span><span class='ectt-0800'> </span><span id='textcolor1756'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (!sys_call_table_stolen)</span>
|
|
<a id='x1-41500r229'></a><span class='ecrm-0500'>229</span><span class='ectt-0800'> </span><span id='textcolor1757'><span class='ectt-0800'>return</span></span><span class='ectt-0800'>;</span>
|
|
<a id='x1-41502r230'></a><span class='ecrm-0500'>230</span>
|
|
<a id='x1-41504r231'></a><span class='ecrm-0500'>231</span><span class='ectt-0800'> </span><span id='textcolor1758'><span class='ectt-0800'>/* Return the system call back to normal */</span></span>
|
|
<a id='x1-41506r232'></a><span class='ecrm-0500'>232</span><span class='ectt-0800'> </span><span id='textcolor1759'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (sys_call_table_stolen[__NR_openat] != (</span><span id='textcolor1760'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1761'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> *)our_sys_openat) {</span>
|
|
<a id='x1-41508r233'></a><span class='ecrm-0500'>233</span><span class='ectt-0800'> pr_alert(</span><span id='textcolor1762'><span class='ectt-0800'>"Somebody else also played with the "</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-41510r234'></a><span class='ecrm-0500'>234</span><span class='ectt-0800'> pr_alert(</span><span id='textcolor1763'><span class='ectt-0800'>"open system call</span></span><span id='textcolor1764'><span class='ectt-0800'>\n</span></span><span id='textcolor1765'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-41512r235'></a><span class='ecrm-0500'>235</span><span class='ectt-0800'> pr_alert(</span><span id='textcolor1766'><span class='ectt-0800'>"The system may be left in "</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-41514r236'></a><span class='ecrm-0500'>236</span><span class='ectt-0800'> pr_alert(</span><span id='textcolor1767'><span class='ectt-0800'>"an unstable state.</span></span><span id='textcolor1768'><span class='ectt-0800'>\n</span></span><span id='textcolor1769'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-41516r237'></a><span class='ecrm-0500'>237</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-41518r238'></a><span class='ecrm-0500'>238</span>
|
|
<a id='x1-41520r239'></a><span class='ecrm-0500'>239</span><span class='ectt-0800'> disable_write_protection();</span>
|
|
<a id='x1-41522r240'></a><span class='ecrm-0500'>240</span><span class='ectt-0800'> sys_call_table_stolen[__NR_openat] = (</span><span id='textcolor1770'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor1771'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> *)original_call;</span>
|
|
<a id='x1-41524r241'></a><span class='ecrm-0500'>241</span><span class='ectt-0800'> enable_write_protection();</span>
|
|
<a id='x1-41526r242'></a><span class='ecrm-0500'>242</span>
|
|
<a id='x1-41528r243'></a><span class='ecrm-0500'>243</span><span class='ectt-0800'> msleep(2000);</span>
|
|
<a id='x1-41530r244'></a><span class='ecrm-0500'>244</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-41532r245'></a><span class='ecrm-0500'>245</span>
|
|
<a id='x1-41534r246'></a><span class='ecrm-0500'>246</span><span class='ectt-0800'>module_init(syscall_steal_start);</span>
|
|
<a id='x1-41536r247'></a><span class='ecrm-0500'>247</span><span class='ectt-0800'>module_exit(syscall_steal_end);</span>
|
|
<a id='x1-41538r248'></a><span class='ecrm-0500'>248</span>
|
|
<a id='x1-41540r249'></a><span class='ecrm-0500'>249</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor1772'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span></pre>
|
|
<!-- l. 1576 --><p class='noindent'>
|
|
</p>
|
|
<h3 class='sectionHead' id='blocking-processes-and-threads'><span class='titlemark'>11 </span> <a id='x1-4200011'></a>Blocking Processes and threads</h3>
|
|
<!-- l. 1578 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='sleep'><span class='titlemark'>11.1 </span> <a id='x1-4300011.1'></a>Sleep</h4>
|
|
<!-- l. 1580 --><p class='noindent'>What do you do when somebody asks you for something you can not do right
|
|
away? If you are a human being and you are bothered by a human being, the
|
|
only thing you can say is: "<span class='ecti-1000'>Not right now, I’m busy. Go away!</span>". But if you
|
|
are a kernel module and you are bothered by a process, you have another
|
|
possibility. You can put the process to sleep until you can service it. After all,
|
|
processes are being put to sleep by the kernel and woken up all the time (that
|
|
is the way multiple processes appear to run on the same time on a single
|
|
CPU).
|
|
</p><!-- l. 1586 --><p class='indent'> This kernel module is an example of this. The file (called <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc/sleep</span></span></span>) can only
|
|
be opened by a single process at a time. If the file is already open, the kernel module
|
|
calls <code> <span class='ectt-1000'>wait_event_interruptible</span>
|
|
</code>. The easiest way to keep a file open is to open it with:
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb65'><a id='x1-43004r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>tail -f</span></pre>
|
|
<!-- l. 1595 --><p class='indent'> This function changes the status of the task (a task is the kernel data structure
|
|
which holds information about a process and the system call it is in, if any) to
|
|
<code> <span class='ectt-1000'>TASK_INTERRUPTIBLE</span>
|
|
</code>, which means that the task will not run until it is woken up somehow, and adds it to
|
|
WaitQ, the queue of tasks waiting to access the file. Then, the function calls the
|
|
scheduler to context switch to a different process, one which has some use for the
|
|
CPU.
|
|
</p><!-- l. 1599 --><p class='indent'> When a process is done with the file, it closes it, and
|
|
<code> <span class='ectt-1000'>module_close</span>
|
|
</code> is called. That function wakes up all the processes in the queue (there’s no
|
|
mechanism to only wake up one of them). It then returns and the process which just
|
|
|
|
|
|
|
|
closed the file can continue to run. In time, the scheduler decides that that
|
|
process has had enough and gives control of the CPU to another process.
|
|
Eventually, one of the processes which was in the queue will be given control
|
|
of the CPU by the scheduler. It starts at the point right after the call to
|
|
<code> <span class='ectt-1000'>wait_event_interruptible</span>
|
|
</code>.
|
|
</p><!-- l. 1606 --><p class='indent'> This means that the process is still in kernel mode - as far as the process
|
|
is concerned, it issued the open system call and the system call has not
|
|
returned yet. The process does not know somebody else used the CPU for
|
|
most of the time between the moment it issued the call and the moment it
|
|
returned.
|
|
</p><!-- l. 1609 --><p class='indent'> It can then proceed to set a global variable to tell all the other processes that the
|
|
file is still open and go on with its life. When the other processes get a piece of the
|
|
CPU, they’ll see that global variable and go back to sleep.
|
|
</p><!-- l. 1612 --><p class='indent'> So we will use <code> <span class='ectt-1000'>tail -f</span>
|
|
</code> to keep the file open in the background, while trying to access it with another
|
|
process (again in the background, so that we need not switch to a different vt). As
|
|
soon as the first background process is killed with kill %1 , the second is woken up, is
|
|
able to access the file and finally terminates.
|
|
</p><!-- l. 1615 --><p class='indent'> To make our life more interesting, <code> <span class='ectt-1000'>module_close</span>
|
|
</code> does not have a monopoly on waking up the processes which wait to access the file.
|
|
A signal, such as <span class='ecti-1000'>Ctrl +c </span>(<span class='ecbx-1000'>SIGINT</span>) can also wake up a process. This is because we
|
|
used <code> <span class='ectt-1000'>wait_event_interruptible</span>
|
|
</code>. We could have used <code> <span class='ectt-1000'>wait_event</span>
|
|
</code> instead, but that would have resulted in extremely angry users whose <span class='ecti-1000'>Ctrl+c</span>’s are
|
|
ignored.
|
|
</p><!-- l. 1619 --><p class='indent'> In that case, we want to return with
|
|
<code> <span class='ectt-1000'>-EINTR</span>
|
|
</code> immediately. This is important so users can, for example, kill the process before it
|
|
receives the file.
|
|
</p><!-- l. 1621 --><p class='indent'> There is one more point to remember. Some times processes don’t want to sleep, they want
|
|
either to get what they want immediately, or to be told it cannot be done. Such processes
|
|
use the <code> <span class='ectt-1000'>O_NONBLOCK</span>
|
|
</code> flag when opening the file. The kernel is supposed to respond by returning with the error
|
|
code <code> <span class='ectt-1000'>-EAGAIN</span>
|
|
</code> from operations which would otherwise block, such as opening the file in this example. The
|
|
program <code> <span class='ectt-1000'>cat_nonblock</span>
|
|
</code>, available in the <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>examples/other</span></span></span> directory, can be used to open a file with
|
|
<code> <span class='ectt-1000'>O_NONBLOCK</span>
|
|
</code>.
|
|
|
|
|
|
|
|
</p>
|
|
<pre class='verbatim' id='verbatim-20'>
|
|
$ sudo insmod sleep.ko
|
|
$ cat_nonblock /proc/sleep
|
|
Last input:
|
|
$ tail -f /proc/sleep &
|
|
Last input:
|
|
Last input:
|
|
Last input:
|
|
Last input:
|
|
Last input:
|
|
Last input:
|
|
Last input:
|
|
tail: /proc/sleep: file truncated
|
|
[1] 6540
|
|
$ cat_nonblock /proc/sleep
|
|
Open would block
|
|
$ kill %1
|
|
[1]+ Terminated tail -f /proc/sleep
|
|
$ cat_nonblock /proc/sleep
|
|
Last input:
|
|
$
|
|
</pre>
|
|
<!-- l. 1646 --><p class='nopar'>
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb66'><a id='x1-43018r1'></a><span class='ecrm-0500'>1</span><span id='textcolor1773'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-43020r2'></a><span class='ecrm-0500'>2</span><span id='textcolor1774'><span class='ectt-0800'> * sleep.c - create a /proc file, and if several processes try to open it</span></span>
|
|
<a id='x1-43022r3'></a><span class='ecrm-0500'>3</span><span id='textcolor1775'><span class='ectt-0800'> * at the same time, put all but one to sleep.</span></span>
|
|
<a id='x1-43024r4'></a><span class='ecrm-0500'>4</span><span id='textcolor1776'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-43026r5'></a><span class='ecrm-0500'>5</span>
|
|
<a id='x1-43028r6'></a><span class='ecrm-0500'>6</span><span id='textcolor1777'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1778'><span class='ectt-0800'><linux/atomic.h></span></span>
|
|
<a id='x1-43030r7'></a><span class='ecrm-0500'>7</span><span id='textcolor1779'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1780'><span class='ectt-0800'><linux/fs.h></span></span>
|
|
<a id='x1-43032r8'></a><span class='ecrm-0500'>8</span><span id='textcolor1781'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1782'><span class='ectt-0800'><linux/kernel.h> /* for sprintf() */</span></span>
|
|
<a id='x1-43034r9'></a><span class='ecrm-0500'>9</span><span id='textcolor1783'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1784'><span class='ectt-0800'><linux/module.h> /* Specifically, a module */</span></span>
|
|
<a id='x1-43036r10'></a><span class='ecrm-0500'>10</span><span id='textcolor1785'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1786'><span class='ectt-0800'><linux/printk.h></span></span>
|
|
<a id='x1-43038r11'></a><span class='ecrm-0500'>11</span><span id='textcolor1787'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1788'><span class='ectt-0800'><linux/proc_fs.h> /* Necessary because we use proc fs */</span></span>
|
|
<a id='x1-43040r12'></a><span class='ecrm-0500'>12</span><span id='textcolor1789'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1790'><span class='ectt-0800'><linux/types.h></span></span>
|
|
<a id='x1-43042r13'></a><span class='ecrm-0500'>13</span><span id='textcolor1791'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1792'><span class='ectt-0800'><linux/uaccess.h> /* for get_user and put_user */</span></span>
|
|
<a id='x1-43044r14'></a><span class='ecrm-0500'>14</span><span id='textcolor1793'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1794'><span class='ectt-0800'><linux/version.h></span></span>
|
|
<a id='x1-43046r15'></a><span class='ecrm-0500'>15</span><span id='textcolor1795'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1796'><span class='ectt-0800'><linux/wait.h> /* For putting processes to sleep and</span></span>
|
|
<a id='x1-43048r16'></a><span class='ecrm-0500'>16</span><span class='ectt-0800'> waking them up </span><span class='colorbox' id='colorbox1797'><span class='ectt-0800'>*/</span></span>
|
|
<a id='x1-43050r17'></a><span class='ecrm-0500'>17</span>
|
|
<a id='x1-43052r18'></a><span class='ecrm-0500'>18</span><span id='textcolor1798'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1799'><span class='ectt-0800'><asm/current.h></span></span>
|
|
<a id='x1-43054r19'></a><span class='ecrm-0500'>19</span><span id='textcolor1800'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1801'><span class='ectt-0800'><asm/errno.h></span></span>
|
|
<a id='x1-43056r20'></a><span class='ecrm-0500'>20</span>
|
|
<a id='x1-43058r21'></a><span class='ecrm-0500'>21</span><span id='textcolor1802'><span class='ectt-0800'>#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)</span></span>
|
|
<a id='x1-43060r22'></a><span class='ecrm-0500'>22</span><span id='textcolor1803'><span class='ectt-0800'>#define HAVE_PROC_OPS</span></span>
|
|
<a id='x1-43062r23'></a><span class='ecrm-0500'>23</span><span id='textcolor1804'><span class='ectt-0800'>#endif</span></span>
|
|
<a id='x1-43064r24'></a><span class='ecrm-0500'>24</span>
|
|
<a id='x1-43066r25'></a><span class='ecrm-0500'>25</span><span id='textcolor1805'><span class='ectt-0800'>/* Here we keep the last message received, to prove that we can process our</span></span>
|
|
<a id='x1-43068r26'></a><span class='ecrm-0500'>26</span><span id='textcolor1806'><span class='ectt-0800'> * input.</span></span>
|
|
<a id='x1-43070r27'></a><span class='ecrm-0500'>27</span><span id='textcolor1807'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-43072r28'></a><span class='ecrm-0500'>28</span><span id='textcolor1808'><span class='ectt-0800'>#define MESSAGE_LENGTH 80</span></span>
|
|
<a id='x1-43074r29'></a><span class='ecrm-0500'>29</span><span id='textcolor1809'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1810'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> message[MESSAGE_LENGTH];</span>
|
|
<a id='x1-43076r30'></a><span class='ecrm-0500'>30</span>
|
|
<a id='x1-43078r31'></a><span class='ecrm-0500'>31</span><span id='textcolor1811'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1812'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> proc_dir_entry *our_proc_file;</span>
|
|
<a id='x1-43080r32'></a><span class='ecrm-0500'>32</span><span id='textcolor1813'><span class='ectt-0800'>#define PROC_ENTRY_FILENAME "sleep"</span></span>
|
|
<a id='x1-43082r33'></a><span class='ecrm-0500'>33</span>
|
|
<a id='x1-43084r34'></a><span class='ecrm-0500'>34</span><span id='textcolor1814'><span class='ectt-0800'>/* Since we use the file operations struct, we can</span><span class='tctt-0800'>'</span><span class='ectt-0800'>t use the special proc</span></span>
|
|
<a id='x1-43086r35'></a><span class='ecrm-0500'>35</span><span id='textcolor1815'><span class='ectt-0800'> * output provisions - we have to use a standard read function, which is this</span></span>
|
|
<a id='x1-43088r36'></a><span class='ecrm-0500'>36</span><span id='textcolor1816'><span class='ectt-0800'> * function.</span></span>
|
|
<a id='x1-43090r37'></a><span class='ecrm-0500'>37</span><span id='textcolor1817'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-43092r38'></a><span class='ecrm-0500'>38</span><span id='textcolor1818'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1819'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> module_output(</span><span id='textcolor1820'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file, </span><span id='textcolor1821'><span class='ectt-0800'>/* see include/linux/fs.h */</span></span>
|
|
<a id='x1-43094r39'></a><span class='ecrm-0500'>39</span><span class='ectt-0800'> </span><span id='textcolor1822'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *buf, </span><span id='textcolor1823'><span class='ectt-0800'>/* The buffer to put data to</span></span>
|
|
<a id='x1-43096r40'></a><span class='ecrm-0500'>40</span><span id='textcolor1824'><span class='ectt-0800'> (in the user segment)</span></span><span class='ectt-0800'> </span><span class='colorbox' id='colorbox1825'><span class='ectt-0800'>*/</span></span>
|
|
<a id='x1-43098r41'></a><span class='ecrm-0500'>41</span><span class='ectt-0800'> </span><span id='textcolor1826'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'> len, </span><span id='textcolor1827'><span class='ectt-0800'>/* The length of the buffer */</span></span>
|
|
<a id='x1-43100r42'></a><span class='ecrm-0500'>42</span><span class='ectt-0800'> loff_t *offset)</span>
|
|
<a id='x1-43102r43'></a><span class='ecrm-0500'>43</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-43104r44'></a><span class='ecrm-0500'>44</span><span class='ectt-0800'> </span><span id='textcolor1828'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1829'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> finished = 0;</span>
|
|
<a id='x1-43106r45'></a><span class='ecrm-0500'>45</span><span class='ectt-0800'> </span><span id='textcolor1830'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> i;</span>
|
|
<a id='x1-43108r46'></a><span class='ecrm-0500'>46</span><span class='ectt-0800'> </span><span id='textcolor1831'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> output_msg[MESSAGE_LENGTH + 30];</span>
|
|
<a id='x1-43110r47'></a><span class='ecrm-0500'>47</span>
|
|
<a id='x1-43112r48'></a><span class='ecrm-0500'>48</span><span class='ectt-0800'> </span><span id='textcolor1832'><span class='ectt-0800'>/* Return 0 to signify end of file - that we have nothing more to say</span></span>
|
|
<a id='x1-43114r49'></a><span class='ecrm-0500'>49</span><span id='textcolor1833'><span class='ectt-0800'> * at this point.</span></span>
|
|
<a id='x1-43116r50'></a><span class='ecrm-0500'>50</span><span id='textcolor1834'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-43118r51'></a><span class='ecrm-0500'>51</span><span class='ectt-0800'> </span><span id='textcolor1835'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (finished) {</span>
|
|
<a id='x1-43120r52'></a><span class='ecrm-0500'>52</span><span class='ectt-0800'> finished = 0;</span>
|
|
<a id='x1-43122r53'></a><span class='ecrm-0500'>53</span><span class='ectt-0800'> </span><span id='textcolor1836'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-43124r54'></a><span class='ecrm-0500'>54</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-43126r55'></a><span class='ecrm-0500'>55</span>
|
|
<a id='x1-43128r56'></a><span class='ecrm-0500'>56</span><span class='ectt-0800'> sprintf(output_msg, </span><span id='textcolor1837'><span class='ectt-0800'>"Last input:%s</span></span><span id='textcolor1838'><span class='ectt-0800'>\n</span></span><span id='textcolor1839'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, message);</span>
|
|
<a id='x1-43130r57'></a><span class='ecrm-0500'>57</span><span class='ectt-0800'> </span><span id='textcolor1840'><span class='ectt-0800'>for</span></span><span class='ectt-0800'> (i = 0; i < len && output_msg[i]; i++)</span>
|
|
<a id='x1-43132r58'></a><span class='ecrm-0500'>58</span><span class='ectt-0800'> put_user(output_msg[i], buf + i);</span>
|
|
<a id='x1-43134r59'></a><span class='ecrm-0500'>59</span>
|
|
<a id='x1-43136r60'></a><span class='ecrm-0500'>60</span><span class='ectt-0800'> finished = 1;</span>
|
|
<a id='x1-43138r61'></a><span class='ecrm-0500'>61</span><span class='ectt-0800'> </span><span id='textcolor1841'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> i; </span><span id='textcolor1842'><span class='ectt-0800'>/* Return the number of bytes "read" */</span></span>
|
|
<a id='x1-43140r62'></a><span class='ecrm-0500'>62</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-43142r63'></a><span class='ecrm-0500'>63</span>
|
|
<a id='x1-43144r64'></a><span class='ecrm-0500'>64</span><span id='textcolor1843'><span class='ectt-0800'>/* This function receives input from the user when the user writes to the</span></span>
|
|
<a id='x1-43146r65'></a><span class='ecrm-0500'>65</span><span id='textcolor1844'><span class='ectt-0800'> * /proc file.</span></span>
|
|
<a id='x1-43148r66'></a><span class='ecrm-0500'>66</span><span id='textcolor1845'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-43150r67'></a><span class='ecrm-0500'>67</span><span id='textcolor1846'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1847'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> module_input(</span><span id='textcolor1848'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file, </span><span id='textcolor1849'><span class='ectt-0800'>/* The file itself */</span></span>
|
|
<a id='x1-43152r68'></a><span class='ecrm-0500'>68</span><span class='ectt-0800'> </span><span id='textcolor1850'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor1851'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *buf, </span><span id='textcolor1852'><span class='ectt-0800'>/* The buffer with input */</span></span>
|
|
<a id='x1-43154r69'></a><span class='ecrm-0500'>69</span><span class='ectt-0800'> </span><span id='textcolor1853'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'> length, </span><span id='textcolor1854'><span class='ectt-0800'>/* The buffer</span><span class='tctt-0800'>'</span><span class='ectt-0800'>s length */</span></span>
|
|
<a id='x1-43156r70'></a><span class='ecrm-0500'>70</span><span class='ectt-0800'> loff_t *offset) </span><span id='textcolor1855'><span class='ectt-0800'>/* offset to file - ignore */</span></span>
|
|
<a id='x1-43158r71'></a><span class='ecrm-0500'>71</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-43160r72'></a><span class='ecrm-0500'>72</span><span class='ectt-0800'> </span><span id='textcolor1856'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> i;</span>
|
|
<a id='x1-43162r73'></a><span class='ecrm-0500'>73</span>
|
|
<a id='x1-43164r74'></a><span class='ecrm-0500'>74</span><span class='ectt-0800'> </span><span id='textcolor1857'><span class='ectt-0800'>/* Put the input into Message, where module_output will later be able</span></span>
|
|
<a id='x1-43166r75'></a><span class='ecrm-0500'>75</span><span id='textcolor1858'><span class='ectt-0800'> * to use it.</span></span>
|
|
<a id='x1-43168r76'></a><span class='ecrm-0500'>76</span><span id='textcolor1859'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-43170r77'></a><span class='ecrm-0500'>77</span><span class='ectt-0800'> </span><span id='textcolor1860'><span class='ectt-0800'>for</span></span><span class='ectt-0800'> (i = 0; i < MESSAGE_LENGTH - 1 && i < length; i++)</span>
|
|
<a id='x1-43172r78'></a><span class='ecrm-0500'>78</span><span class='ectt-0800'> get_user(message[i], buf + i);</span>
|
|
<a id='x1-43174r79'></a><span class='ecrm-0500'>79</span><span class='ectt-0800'> </span><span id='textcolor1861'><span class='ectt-0800'>/* we want a standard, zero terminated string */</span></span>
|
|
<a id='x1-43176r80'></a><span class='ecrm-0500'>80</span><span class='ectt-0800'> message[i] = </span><span id='textcolor1862'><span class='tctt-0800'>'</span><span class='ectt-0800'>\0</span><span class='tctt-0800'>'</span></span><span class='ectt-0800'>;</span>
|
|
<a id='x1-43178r81'></a><span class='ecrm-0500'>81</span>
|
|
<a id='x1-43180r82'></a><span class='ecrm-0500'>82</span><span class='ectt-0800'> </span><span id='textcolor1863'><span class='ectt-0800'>/* We need to return the number of input characters used */</span></span>
|
|
<a id='x1-43182r83'></a><span class='ecrm-0500'>83</span><span class='ectt-0800'> </span><span id='textcolor1864'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> i;</span>
|
|
<a id='x1-43184r84'></a><span class='ecrm-0500'>84</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-43186r85'></a><span class='ecrm-0500'>85</span>
|
|
<a id='x1-43188r86'></a><span class='ecrm-0500'>86</span><span id='textcolor1865'><span class='ectt-0800'>/* 1 if the file is currently open by somebody */</span></span>
|
|
<a id='x1-43190r87'></a><span class='ecrm-0500'>87</span><span id='textcolor1866'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> atomic_t already_open = ATOMIC_INIT(0);</span>
|
|
<a id='x1-43192r88'></a><span class='ecrm-0500'>88</span>
|
|
<a id='x1-43194r89'></a><span class='ecrm-0500'>89</span><span id='textcolor1867'><span class='ectt-0800'>/* Queue of processes who want our file */</span></span>
|
|
<a id='x1-43196r90'></a><span class='ecrm-0500'>90</span><span id='textcolor1868'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> DECLARE_WAIT_QUEUE_HEAD(waitq);</span>
|
|
<a id='x1-43198r91'></a><span class='ecrm-0500'>91</span>
|
|
<a id='x1-43200r92'></a><span class='ecrm-0500'>92</span><span id='textcolor1869'><span class='ectt-0800'>/* Called when the /proc file is opened */</span></span>
|
|
<a id='x1-43202r93'></a><span class='ecrm-0500'>93</span><span id='textcolor1870'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1871'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> module_open(</span><span id='textcolor1872'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> inode *inode, </span><span id='textcolor1873'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file)</span>
|
|
<a id='x1-43204r94'></a><span class='ecrm-0500'>94</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-43206r95'></a><span class='ecrm-0500'>95</span><span class='ectt-0800'> </span><span id='textcolor1874'><span class='ectt-0800'>/* If the file</span><span class='tctt-0800'>'</span><span class='ectt-0800'>s flags include O_NONBLOCK, it means the process does not</span></span>
|
|
<a id='x1-43208r96'></a><span class='ecrm-0500'>96</span><span id='textcolor1875'><span class='ectt-0800'> * want to wait for the file. In this case, if the file is already open,</span></span>
|
|
<a id='x1-43210r97'></a><span class='ecrm-0500'>97</span><span id='textcolor1876'><span class='ectt-0800'> * we should fail with -EAGAIN, meaning "you will have to try again",</span></span>
|
|
<a id='x1-43212r98'></a><span class='ecrm-0500'>98</span><span id='textcolor1877'><span class='ectt-0800'> * instead of blocking a process which would rather stay awake.</span></span>
|
|
<a id='x1-43214r99'></a><span class='ecrm-0500'>99</span><span id='textcolor1878'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-43216r100'></a><span class='ecrm-0500'>100</span><span class='ectt-0800'> </span><span id='textcolor1879'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> ((file->f_flags & O_NONBLOCK) && atomic_read(&already_open))</span>
|
|
<a id='x1-43218r101'></a><span class='ecrm-0500'>101</span><span class='ectt-0800'> </span><span id='textcolor1880'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -EAGAIN;</span>
|
|
<a id='x1-43220r102'></a><span class='ecrm-0500'>102</span>
|
|
<a id='x1-43222r103'></a><span class='ecrm-0500'>103</span><span class='ectt-0800'> </span><span id='textcolor1881'><span class='ectt-0800'>/* This is the correct place for try_module_get(THIS_MODULE) because if</span></span>
|
|
<a id='x1-43224r104'></a><span class='ecrm-0500'>104</span><span id='textcolor1882'><span class='ectt-0800'> * a process is in the loop, which is within the kernel module,</span></span>
|
|
<a id='x1-43226r105'></a><span class='ecrm-0500'>105</span><span id='textcolor1883'><span class='ectt-0800'> * the kernel module must not be removed.</span></span>
|
|
<a id='x1-43228r106'></a><span class='ecrm-0500'>106</span><span id='textcolor1884'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-43230r107'></a><span class='ecrm-0500'>107</span><span class='ectt-0800'> try_module_get(THIS_MODULE);</span>
|
|
<a id='x1-43232r108'></a><span class='ecrm-0500'>108</span>
|
|
<a id='x1-43234r109'></a><span class='ecrm-0500'>109</span><span class='ectt-0800'> </span><span id='textcolor1885'><span class='ectt-0800'>while</span></span><span class='ectt-0800'> (atomic_cmpxchg(&already_open, 0, 1)) {</span>
|
|
<a id='x1-43236r110'></a><span class='ecrm-0500'>110</span><span class='ectt-0800'> </span><span id='textcolor1886'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> i, is_sig = 0;</span>
|
|
<a id='x1-43238r111'></a><span class='ecrm-0500'>111</span>
|
|
<a id='x1-43240r112'></a><span class='ecrm-0500'>112</span><span class='ectt-0800'> </span><span id='textcolor1887'><span class='ectt-0800'>/* This function puts the current process, including any system</span></span>
|
|
<a id='x1-43242r113'></a><span class='ecrm-0500'>113</span><span id='textcolor1888'><span class='ectt-0800'> * calls, such as us, to sleep. Execution will be resumed right</span></span>
|
|
<a id='x1-43244r114'></a><span class='ecrm-0500'>114</span><span id='textcolor1889'><span class='ectt-0800'> * after the function call, either because somebody called</span></span>
|
|
<a id='x1-43246r115'></a><span class='ecrm-0500'>115</span><span id='textcolor1890'><span class='ectt-0800'> * wake_up(&waitq) (only module_close does that, when the file</span></span>
|
|
<a id='x1-43248r116'></a><span class='ecrm-0500'>116</span><span id='textcolor1891'><span class='ectt-0800'> * is closed) or when a signal, such as Ctrl-C, is sent</span></span>
|
|
<a id='x1-43250r117'></a><span class='ecrm-0500'>117</span><span id='textcolor1892'><span class='ectt-0800'> * to the process</span></span>
|
|
<a id='x1-43252r118'></a><span class='ecrm-0500'>118</span><span id='textcolor1893'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-43254r119'></a><span class='ecrm-0500'>119</span><span class='ectt-0800'> wait_event_interruptible(waitq, !atomic_read(&already_open));</span>
|
|
<a id='x1-43256r120'></a><span class='ecrm-0500'>120</span>
|
|
<a id='x1-43258r121'></a><span class='ecrm-0500'>121</span><span class='ectt-0800'> </span><span id='textcolor1894'><span class='ectt-0800'>/* If we woke up because we got a signal we</span><span class='tctt-0800'>'</span><span class='ectt-0800'>re not blocking,</span></span>
|
|
<a id='x1-43260r122'></a><span class='ecrm-0500'>122</span><span id='textcolor1895'><span class='ectt-0800'> * return -EINTR (fail the system call). This allows processes</span></span>
|
|
<a id='x1-43262r123'></a><span class='ecrm-0500'>123</span><span id='textcolor1896'><span class='ectt-0800'> * to be killed or stopped.</span></span>
|
|
<a id='x1-43264r124'></a><span class='ecrm-0500'>124</span><span id='textcolor1897'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-43266r125'></a><span class='ecrm-0500'>125</span><span class='ectt-0800'> </span><span id='textcolor1898'><span class='ectt-0800'>for</span></span><span class='ectt-0800'> (i = 0; i < _NSIG_WORDS && !is_sig; i++)</span>
|
|
<a id='x1-43268r126'></a><span class='ecrm-0500'>126</span><span class='ectt-0800'> is_sig = current->pending.signal.sig[i] & ~current->blocked.sig[i];</span>
|
|
<a id='x1-43270r127'></a><span class='ecrm-0500'>127</span>
|
|
<a id='x1-43272r128'></a><span class='ecrm-0500'>128</span><span class='ectt-0800'> </span><span id='textcolor1899'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (is_sig) {</span>
|
|
<a id='x1-43274r129'></a><span class='ecrm-0500'>129</span><span class='ectt-0800'> </span><span id='textcolor1900'><span class='ectt-0800'>/* It is important to put module_put(THIS_MODULE) here, because</span></span>
|
|
<a id='x1-43276r130'></a><span class='ecrm-0500'>130</span><span id='textcolor1901'><span class='ectt-0800'> * for processes where the open is interrupted there will never</span></span>
|
|
<a id='x1-43278r131'></a><span class='ecrm-0500'>131</span><span id='textcolor1902'><span class='ectt-0800'> * be a corresponding close. If we do not decrement the usage</span></span>
|
|
<a id='x1-43280r132'></a><span class='ecrm-0500'>132</span><span id='textcolor1903'><span class='ectt-0800'> * count here, we will be left with a positive usage count</span></span>
|
|
<a id='x1-43282r133'></a><span class='ecrm-0500'>133</span><span id='textcolor1904'><span class='ectt-0800'> * which we will have no way to bring down to zero, giving us</span></span>
|
|
<a id='x1-43284r134'></a><span class='ecrm-0500'>134</span><span id='textcolor1905'><span class='ectt-0800'> * an immortal module, which can only be killed by rebooting</span></span>
|
|
<a id='x1-43286r135'></a><span class='ecrm-0500'>135</span><span id='textcolor1906'><span class='ectt-0800'> * the machine.</span></span>
|
|
<a id='x1-43288r136'></a><span class='ecrm-0500'>136</span><span id='textcolor1907'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-43290r137'></a><span class='ecrm-0500'>137</span><span class='ectt-0800'> module_put(THIS_MODULE);</span>
|
|
<a id='x1-43292r138'></a><span class='ecrm-0500'>138</span><span class='ectt-0800'> </span><span id='textcolor1908'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -EINTR;</span>
|
|
<a id='x1-43294r139'></a><span class='ecrm-0500'>139</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-43296r140'></a><span class='ecrm-0500'>140</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-43298r141'></a><span class='ecrm-0500'>141</span>
|
|
<a id='x1-43300r142'></a><span class='ecrm-0500'>142</span><span class='ectt-0800'> </span><span id='textcolor1909'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0; </span><span id='textcolor1910'><span class='ectt-0800'>/* Allow the access */</span></span>
|
|
<a id='x1-43302r143'></a><span class='ecrm-0500'>143</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-43304r144'></a><span class='ecrm-0500'>144</span>
|
|
<a id='x1-43306r145'></a><span class='ecrm-0500'>145</span><span id='textcolor1911'><span class='ectt-0800'>/* Called when the /proc file is closed */</span></span>
|
|
<a id='x1-43308r146'></a><span class='ecrm-0500'>146</span><span id='textcolor1912'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1913'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> module_close(</span><span id='textcolor1914'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> inode *inode, </span><span id='textcolor1915'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file)</span>
|
|
<a id='x1-43310r147'></a><span class='ecrm-0500'>147</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-43312r148'></a><span class='ecrm-0500'>148</span><span class='ectt-0800'> </span><span id='textcolor1916'><span class='ectt-0800'>/* Set already_open to zero, so one of the processes in the waitq will</span></span>
|
|
<a id='x1-43314r149'></a><span class='ecrm-0500'>149</span><span id='textcolor1917'><span class='ectt-0800'> * be able to set already_open back to one and to open the file. All</span></span>
|
|
<a id='x1-43316r150'></a><span class='ecrm-0500'>150</span><span id='textcolor1918'><span class='ectt-0800'> * the other processes will be called when already_open is back to one,</span></span>
|
|
<a id='x1-43318r151'></a><span class='ecrm-0500'>151</span><span id='textcolor1919'><span class='ectt-0800'> * so they</span><span class='tctt-0800'>'</span><span class='ectt-0800'>ll go back to sleep.</span></span>
|
|
<a id='x1-43320r152'></a><span class='ecrm-0500'>152</span><span id='textcolor1920'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-43322r153'></a><span class='ecrm-0500'>153</span><span class='ectt-0800'> atomic_set(&already_open, 0);</span>
|
|
<a id='x1-43324r154'></a><span class='ecrm-0500'>154</span>
|
|
<a id='x1-43326r155'></a><span class='ecrm-0500'>155</span><span class='ectt-0800'> </span><span id='textcolor1921'><span class='ectt-0800'>/* Wake up all the processes in waitq, so if anybody is waiting for the</span></span>
|
|
<a id='x1-43328r156'></a><span class='ecrm-0500'>156</span><span id='textcolor1922'><span class='ectt-0800'> * file, they can have it.</span></span>
|
|
<a id='x1-43330r157'></a><span class='ecrm-0500'>157</span><span id='textcolor1923'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-43332r158'></a><span class='ecrm-0500'>158</span><span class='ectt-0800'> wake_up(&waitq);</span>
|
|
<a id='x1-43334r159'></a><span class='ecrm-0500'>159</span>
|
|
<a id='x1-43336r160'></a><span class='ecrm-0500'>160</span><span class='ectt-0800'> module_put(THIS_MODULE);</span>
|
|
<a id='x1-43338r161'></a><span class='ecrm-0500'>161</span>
|
|
<a id='x1-43340r162'></a><span class='ecrm-0500'>162</span><span class='ectt-0800'> </span><span id='textcolor1924'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0; </span><span id='textcolor1925'><span class='ectt-0800'>/* success */</span></span>
|
|
<a id='x1-43342r163'></a><span class='ecrm-0500'>163</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-43344r164'></a><span class='ecrm-0500'>164</span>
|
|
<a id='x1-43346r165'></a><span class='ecrm-0500'>165</span><span id='textcolor1926'><span class='ectt-0800'>/* Structures to register as the /proc file, with pointers to all the relevant</span></span>
|
|
<a id='x1-43348r166'></a><span class='ecrm-0500'>166</span><span id='textcolor1927'><span class='ectt-0800'> * functions.</span></span>
|
|
<a id='x1-43350r167'></a><span class='ecrm-0500'>167</span><span id='textcolor1928'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-43352r168'></a><span class='ecrm-0500'>168</span>
|
|
<a id='x1-43354r169'></a><span class='ecrm-0500'>169</span><span id='textcolor1929'><span class='ectt-0800'>/* File operations for our proc file. This is where we place pointers to all</span></span>
|
|
<a id='x1-43356r170'></a><span class='ecrm-0500'>170</span><span id='textcolor1930'><span class='ectt-0800'> * the functions called when somebody tries to do something to our file. NULL</span></span>
|
|
<a id='x1-43358r171'></a><span class='ecrm-0500'>171</span><span id='textcolor1931'><span class='ectt-0800'> * means we don</span><span class='tctt-0800'>'</span><span class='ectt-0800'>t want to deal with something.</span></span>
|
|
<a id='x1-43360r172'></a><span class='ecrm-0500'>172</span><span id='textcolor1932'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-43362r173'></a><span class='ecrm-0500'>173</span><span id='textcolor1933'><span class='ectt-0800'>#ifdef HAVE_PROC_OPS</span></span>
|
|
<a id='x1-43364r174'></a><span class='ecrm-0500'>174</span><span id='textcolor1934'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1935'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor1936'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> proc_ops file_ops_4_our_proc_file = {</span>
|
|
<a id='x1-43366r175'></a><span class='ecrm-0500'>175</span><span class='ectt-0800'> .proc_read = module_output, </span><span id='textcolor1937'><span class='ectt-0800'>/* "read" from the file */</span></span>
|
|
<a id='x1-43368r176'></a><span class='ecrm-0500'>176</span><span class='ectt-0800'> .proc_write = module_input, </span><span id='textcolor1938'><span class='ectt-0800'>/* "write" to the file */</span></span>
|
|
<a id='x1-43370r177'></a><span class='ecrm-0500'>177</span><span class='ectt-0800'> .proc_open = module_open, </span><span id='textcolor1939'><span class='ectt-0800'>/* called when the /proc file is opened */</span></span>
|
|
<a id='x1-43372r178'></a><span class='ecrm-0500'>178</span><span class='ectt-0800'> .proc_release = module_close, </span><span id='textcolor1940'><span class='ectt-0800'>/* called when it</span><span class='tctt-0800'>'</span><span class='ectt-0800'>s closed */</span></span>
|
|
<a id='x1-43374r179'></a><span class='ecrm-0500'>179</span><span class='ectt-0800'> .proc_lseek = noop_llseek, </span><span id='textcolor1941'><span class='ectt-0800'>/* return file->f_pos */</span></span>
|
|
<a id='x1-43376r180'></a><span class='ecrm-0500'>180</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-43378r181'></a><span class='ecrm-0500'>181</span><span id='textcolor1942'><span class='ectt-0800'>#else</span></span>
|
|
<a id='x1-43380r182'></a><span class='ecrm-0500'>182</span><span id='textcolor1943'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1944'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor1945'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file_operations file_ops_4_our_proc_file = {</span>
|
|
<a id='x1-43382r183'></a><span class='ecrm-0500'>183</span><span class='ectt-0800'> .read = module_output,</span>
|
|
<a id='x1-43384r184'></a><span class='ecrm-0500'>184</span><span class='ectt-0800'> .write = module_input,</span>
|
|
<a id='x1-43386r185'></a><span class='ecrm-0500'>185</span><span class='ectt-0800'> .open = module_open,</span>
|
|
<a id='x1-43388r186'></a><span class='ecrm-0500'>186</span><span class='ectt-0800'> .release = module_close,</span>
|
|
<a id='x1-43390r187'></a><span class='ecrm-0500'>187</span><span class='ectt-0800'> .llseek = noop_llseek,</span>
|
|
<a id='x1-43392r188'></a><span class='ecrm-0500'>188</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-43394r189'></a><span class='ecrm-0500'>189</span><span id='textcolor1946'><span class='ectt-0800'>#endif</span></span>
|
|
<a id='x1-43396r190'></a><span class='ecrm-0500'>190</span>
|
|
<a id='x1-43398r191'></a><span class='ecrm-0500'>191</span><span id='textcolor1947'><span class='ectt-0800'>/* Initialize the module - register the proc file */</span></span>
|
|
<a id='x1-43400r192'></a><span class='ecrm-0500'>192</span><span id='textcolor1948'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1949'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __init sleep_init(</span><span id='textcolor1950'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-43402r193'></a><span class='ecrm-0500'>193</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-43404r194'></a><span class='ecrm-0500'>194</span><span class='ectt-0800'> our_proc_file =</span>
|
|
<a id='x1-43406r195'></a><span class='ecrm-0500'>195</span><span class='ectt-0800'> proc_create(PROC_ENTRY_FILENAME, 0644, NULL, &file_ops_4_our_proc_file);</span>
|
|
<a id='x1-43408r196'></a><span class='ecrm-0500'>196</span><span class='ectt-0800'> </span><span id='textcolor1951'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (our_proc_file == NULL) {</span>
|
|
<a id='x1-43410r197'></a><span class='ecrm-0500'>197</span><span class='ectt-0800'> pr_debug(</span><span id='textcolor1952'><span class='ectt-0800'>"Error: Could not initialize /proc/%s</span></span><span id='textcolor1953'><span class='ectt-0800'>\n</span></span><span id='textcolor1954'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, PROC_ENTRY_FILENAME);</span>
|
|
<a id='x1-43412r198'></a><span class='ecrm-0500'>198</span><span class='ectt-0800'> </span><span id='textcolor1955'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -ENOMEM;</span>
|
|
<a id='x1-43414r199'></a><span class='ecrm-0500'>199</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-43416r200'></a><span class='ecrm-0500'>200</span><span class='ectt-0800'> proc_set_size(our_proc_file, 80);</span>
|
|
<a id='x1-43418r201'></a><span class='ecrm-0500'>201</span><span class='ectt-0800'> proc_set_user(our_proc_file, GLOBAL_ROOT_UID, GLOBAL_ROOT_GID);</span>
|
|
<a id='x1-43420r202'></a><span class='ecrm-0500'>202</span>
|
|
<a id='x1-43422r203'></a><span class='ecrm-0500'>203</span><span class='ectt-0800'> pr_info(</span><span id='textcolor1956'><span class='ectt-0800'>"/proc/%s created</span></span><span id='textcolor1957'><span class='ectt-0800'>\n</span></span><span id='textcolor1958'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, PROC_ENTRY_FILENAME);</span>
|
|
<a id='x1-43424r204'></a><span class='ecrm-0500'>204</span>
|
|
<a id='x1-43426r205'></a><span class='ecrm-0500'>205</span><span class='ectt-0800'> </span><span id='textcolor1959'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-43428r206'></a><span class='ecrm-0500'>206</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-43430r207'></a><span class='ecrm-0500'>207</span>
|
|
<a id='x1-43432r208'></a><span class='ecrm-0500'>208</span><span id='textcolor1960'><span class='ectt-0800'>/* Cleanup - unregister our file from /proc. This could get dangerous if</span></span>
|
|
<a id='x1-43434r209'></a><span class='ecrm-0500'>209</span><span id='textcolor1961'><span class='ectt-0800'> * there are still processes waiting in waitq, because they are inside our</span></span>
|
|
<a id='x1-43436r210'></a><span class='ecrm-0500'>210</span><span id='textcolor1962'><span class='ectt-0800'> * open function, which will get unloaded. I</span><span class='tctt-0800'>'</span><span class='ectt-0800'>ll explain how to avoid removal</span></span>
|
|
<a id='x1-43438r211'></a><span class='ecrm-0500'>211</span><span id='textcolor1963'><span class='ectt-0800'> * of a kernel module in such a case in chapter 10.</span></span>
|
|
<a id='x1-43440r212'></a><span class='ecrm-0500'>212</span><span id='textcolor1964'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-43442r213'></a><span class='ecrm-0500'>213</span><span id='textcolor1965'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor1966'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> __exit sleep_exit(</span><span id='textcolor1967'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-43444r214'></a><span class='ecrm-0500'>214</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-43446r215'></a><span class='ecrm-0500'>215</span><span class='ectt-0800'> remove_proc_entry(PROC_ENTRY_FILENAME, NULL);</span>
|
|
<a id='x1-43448r216'></a><span class='ecrm-0500'>216</span><span class='ectt-0800'> pr_debug(</span><span id='textcolor1968'><span class='ectt-0800'>"/proc/%s removed</span></span><span id='textcolor1969'><span class='ectt-0800'>\n</span></span><span id='textcolor1970'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, PROC_ENTRY_FILENAME);</span>
|
|
<a id='x1-43450r217'></a><span class='ecrm-0500'>217</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-43452r218'></a><span class='ecrm-0500'>218</span>
|
|
<a id='x1-43454r219'></a><span class='ecrm-0500'>219</span><span class='ectt-0800'>module_init(sleep_init);</span>
|
|
<a id='x1-43456r220'></a><span class='ecrm-0500'>220</span><span class='ectt-0800'>module_exit(sleep_exit);</span>
|
|
<a id='x1-43458r221'></a><span class='ecrm-0500'>221</span>
|
|
<a id='x1-43460r222'></a><span class='ecrm-0500'>222</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor1971'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span></pre>
|
|
|
|
<!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb67'><a id='x1-43462r1'></a><span class='ecrm-0500'>1</span><span id='textcolor1972'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-43464r2'></a><span class='ecrm-0500'>2</span><span id='textcolor1973'><span class='ectt-0800'> * cat_nonblock.c - open a file and display its contents, but exit rather than</span></span>
|
|
<a id='x1-43466r3'></a><span class='ecrm-0500'>3</span><span id='textcolor1974'><span class='ectt-0800'> * wait for input.</span></span>
|
|
<a id='x1-43468r4'></a><span class='ecrm-0500'>4</span><span id='textcolor1975'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-43470r5'></a><span class='ecrm-0500'>5</span><span id='textcolor1976'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1977'><span class='ectt-0800'><errno.h> /* for errno */</span></span>
|
|
<a id='x1-43472r6'></a><span class='ecrm-0500'>6</span><span id='textcolor1978'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1979'><span class='ectt-0800'><fcntl.h> /* for open */</span></span>
|
|
<a id='x1-43474r7'></a><span class='ecrm-0500'>7</span><span id='textcolor1980'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1981'><span class='ectt-0800'><stdio.h> /* standard I/O */</span></span>
|
|
<a id='x1-43476r8'></a><span class='ecrm-0500'>8</span><span id='textcolor1982'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1983'><span class='ectt-0800'><stdlib.h> /* for exit */</span></span>
|
|
<a id='x1-43478r9'></a><span class='ecrm-0500'>9</span><span id='textcolor1984'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor1985'><span class='ectt-0800'><unistd.h> /* for read */</span></span>
|
|
<a id='x1-43480r10'></a><span class='ecrm-0500'>10</span>
|
|
<a id='x1-43482r11'></a><span class='ecrm-0500'>11</span><span id='textcolor1986'><span class='ectt-0800'>#define MAX_BYTES 1024 * 4</span></span>
|
|
<a id='x1-43484r12'></a><span class='ecrm-0500'>12</span>
|
|
<a id='x1-43486r13'></a><span class='ecrm-0500'>13</span><span id='textcolor1987'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> main(</span><span id='textcolor1988'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> argc, </span><span id='textcolor1989'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *argv[])</span>
|
|
<a id='x1-43488r14'></a><span class='ecrm-0500'>14</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-43490r15'></a><span class='ecrm-0500'>15</span><span class='ectt-0800'> </span><span id='textcolor1990'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> fd; </span><span id='textcolor1991'><span class='ectt-0800'>/* The file descriptor for the file to read */</span></span>
|
|
<a id='x1-43492r16'></a><span class='ecrm-0500'>16</span><span class='ectt-0800'> </span><span id='textcolor1992'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'> bytes; </span><span id='textcolor1993'><span class='ectt-0800'>/* The number of bytes read */</span></span>
|
|
<a id='x1-43494r17'></a><span class='ecrm-0500'>17</span><span class='ectt-0800'> </span><span id='textcolor1994'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> buffer[MAX_BYTES]; </span><span id='textcolor1995'><span class='ectt-0800'>/* The buffer for the bytes */</span></span>
|
|
<a id='x1-43496r18'></a><span class='ecrm-0500'>18</span>
|
|
<a id='x1-43498r19'></a><span class='ecrm-0500'>19</span><span class='ectt-0800'> </span><span id='textcolor1996'><span class='ectt-0800'>/* Usage */</span></span>
|
|
<a id='x1-43500r20'></a><span class='ecrm-0500'>20</span><span class='ectt-0800'> </span><span id='textcolor1997'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (argc != 2) {</span>
|
|
<a id='x1-43502r21'></a><span class='ecrm-0500'>21</span><span class='ectt-0800'> printf(</span><span id='textcolor1998'><span class='ectt-0800'>"Usage: %s <filename></span></span><span id='textcolor1999'><span class='ectt-0800'>\n</span></span><span id='textcolor2000'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, argv[0]);</span>
|
|
<a id='x1-43504r22'></a><span class='ecrm-0500'>22</span><span class='ectt-0800'> puts(</span><span id='textcolor2001'><span class='ectt-0800'>"Reads the content of a file, but doesn</span><span class='tctt-0800'>'</span><span class='ectt-0800'>t wait for input"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-43506r23'></a><span class='ecrm-0500'>23</span><span class='ectt-0800'> exit(-1);</span>
|
|
<a id='x1-43508r24'></a><span class='ecrm-0500'>24</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-43510r25'></a><span class='ecrm-0500'>25</span>
|
|
<a id='x1-43512r26'></a><span class='ecrm-0500'>26</span><span class='ectt-0800'> </span><span id='textcolor2002'><span class='ectt-0800'>/* Open the file for reading in non blocking mode */</span></span>
|
|
<a id='x1-43514r27'></a><span class='ecrm-0500'>27</span><span class='ectt-0800'> fd = open(argv[1], O_RDONLY | O_NONBLOCK);</span>
|
|
<a id='x1-43516r28'></a><span class='ecrm-0500'>28</span>
|
|
<a id='x1-43518r29'></a><span class='ecrm-0500'>29</span><span class='ectt-0800'> </span><span id='textcolor2003'><span class='ectt-0800'>/* If open failed */</span></span>
|
|
<a id='x1-43520r30'></a><span class='ecrm-0500'>30</span><span class='ectt-0800'> </span><span id='textcolor2004'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (fd == -1) {</span>
|
|
<a id='x1-43522r31'></a><span class='ecrm-0500'>31</span><span class='ectt-0800'> puts(errno == EAGAIN ? </span><span id='textcolor2005'><span class='ectt-0800'>"Open would block"</span></span><span class='ectt-0800'> : </span><span id='textcolor2006'><span class='ectt-0800'>"Open failed"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-43524r32'></a><span class='ecrm-0500'>32</span><span class='ectt-0800'> exit(-1);</span>
|
|
<a id='x1-43526r33'></a><span class='ecrm-0500'>33</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-43528r34'></a><span class='ecrm-0500'>34</span>
|
|
<a id='x1-43530r35'></a><span class='ecrm-0500'>35</span><span class='ectt-0800'> </span><span id='textcolor2007'><span class='ectt-0800'>/* Read the file and output its contents */</span></span>
|
|
<a id='x1-43532r36'></a><span class='ecrm-0500'>36</span><span class='ectt-0800'> </span><span id='textcolor2008'><span class='ectt-0800'>do</span></span><span class='ectt-0800'> {</span>
|
|
<a id='x1-43534r37'></a><span class='ecrm-0500'>37</span><span class='ectt-0800'> </span><span id='textcolor2009'><span class='ectt-0800'>/* Read characters from the file */</span></span>
|
|
<a id='x1-43536r38'></a><span class='ecrm-0500'>38</span><span class='ectt-0800'> bytes = read(fd, buffer, MAX_BYTES);</span>
|
|
<a id='x1-43538r39'></a><span class='ecrm-0500'>39</span>
|
|
<a id='x1-43540r40'></a><span class='ecrm-0500'>40</span><span class='ectt-0800'> </span><span id='textcolor2010'><span class='ectt-0800'>/* If there</span><span class='tctt-0800'>'</span><span class='ectt-0800'>s an error, report it and die */</span></span>
|
|
<a id='x1-43542r41'></a><span class='ecrm-0500'>41</span><span class='ectt-0800'> </span><span id='textcolor2011'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (bytes == -1) {</span>
|
|
<a id='x1-43544r42'></a><span class='ecrm-0500'>42</span><span class='ectt-0800'> </span><span id='textcolor2012'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (errno == EAGAIN)</span>
|
|
<a id='x1-43546r43'></a><span class='ecrm-0500'>43</span><span class='ectt-0800'> puts(</span><span id='textcolor2013'><span class='ectt-0800'>"Normally I</span><span class='tctt-0800'>'</span><span class='ectt-0800'>d block, but you told me not to"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-43548r44'></a><span class='ecrm-0500'>44</span><span class='ectt-0800'> </span><span id='textcolor2014'><span class='ectt-0800'>else</span></span>
|
|
<a id='x1-43550r45'></a><span class='ecrm-0500'>45</span><span class='ectt-0800'> puts(</span><span id='textcolor2015'><span class='ectt-0800'>"Another read error"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-43552r46'></a><span class='ecrm-0500'>46</span><span class='ectt-0800'> exit(-1);</span>
|
|
<a id='x1-43554r47'></a><span class='ecrm-0500'>47</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-43556r48'></a><span class='ecrm-0500'>48</span>
|
|
<a id='x1-43558r49'></a><span class='ecrm-0500'>49</span><span class='ectt-0800'> </span><span id='textcolor2016'><span class='ectt-0800'>/* Print the characters */</span></span>
|
|
<a id='x1-43560r50'></a><span class='ecrm-0500'>50</span><span class='ectt-0800'> </span><span id='textcolor2017'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (bytes > 0) {</span>
|
|
<a id='x1-43562r51'></a><span class='ecrm-0500'>51</span><span class='ectt-0800'> </span><span id='textcolor2018'><span class='ectt-0800'>for</span></span><span class='ectt-0800'> (</span><span id='textcolor2019'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> i = 0; i < bytes; i++)</span>
|
|
<a id='x1-43564r52'></a><span class='ecrm-0500'>52</span><span class='ectt-0800'> putchar(buffer[i]);</span>
|
|
<a id='x1-43566r53'></a><span class='ecrm-0500'>53</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-43568r54'></a><span class='ecrm-0500'>54</span>
|
|
<a id='x1-43570r55'></a><span class='ecrm-0500'>55</span><span class='ectt-0800'> </span><span id='textcolor2020'><span class='ectt-0800'>/* While there are no errors and the file isn</span><span class='tctt-0800'>'</span><span class='ectt-0800'>t over */</span></span>
|
|
<a id='x1-43572r56'></a><span class='ecrm-0500'>56</span><span class='ectt-0800'> } </span><span id='textcolor2021'><span class='ectt-0800'>while</span></span><span class='ectt-0800'> (bytes > 0);</span>
|
|
<a id='x1-43574r57'></a><span class='ecrm-0500'>57</span>
|
|
<a id='x1-43576r58'></a><span class='ecrm-0500'>58</span><span class='ectt-0800'> </span><span id='textcolor2022'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-43578r59'></a><span class='ecrm-0500'>59</span><span class='ectt-0800'>}</span></pre>
|
|
<!-- l. 1652 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='completions'><span class='titlemark'>11.2 </span> <a id='x1-4400011.2'></a>Completions</h4>
|
|
<!-- l. 1654 --><p class='noindent'>Sometimes one thing should happen before another within a module having multiple threads.
|
|
Rather than using <code> <span class='ectt-1000'>/bin/sleep</span>
|
|
</code> commands, the kernel has another way to do this which allows timeouts or
|
|
interrupts to also happen.
|
|
</p><!-- l. 1657 --><p class='indent'> Completions as code synchronization mechanism have three main parts, initialization
|
|
of struct completion synchronization object, the waiting or barrier part through
|
|
<code> <span class='ectt-1000'>wait_for_completion()</span>
|
|
|
|
|
|
|
|
</code>, and the signalling side through a call to
|
|
<code> <span class='ectt-1000'>complete()</span>
|
|
</code>.
|
|
</p><!-- l. 1659 --><p class='indent'> In the subsequent example, two threads are initiated: crank and flywheel. It
|
|
is imperative that the crank thread starts before the flywheel thread. A
|
|
completion state is established for each of these threads, with a distinct
|
|
completion defined for both the crank and flywheel threads. At the exit
|
|
point of each thread the respective completion state is updated, and
|
|
<code> <span class='ectt-1000'>wait_for_completion</span>
|
|
</code> is used by the flywheel thread to ensure that it does not begin prematurely. The crank thread
|
|
uses the <code> <span class='ectt-1000'>complete_all()</span>
|
|
</code> function to update the completion, which lets the flywheel thread continue.
|
|
</p><!-- l. 1665 --><p class='indent'> So even though <code> <span class='ectt-1000'>flywheel_thread</span>
|
|
</code> is started first you should notice when you load this module and run
|
|
<code> <span class='ectt-1000'>dmesg</span>
|
|
</code>, that turning the crank always happens first because the flywheel thread waits for
|
|
the crank thread to complete.
|
|
</p><!-- l. 1667 --><p class='indent'> There are other variations of the <code> <span class='ectt-1000'>wait_for_completion</span>
|
|
</code> function, which include timeouts or being interrupted, but this basic mechanism is
|
|
enough for many common situations without adding a lot of complexity.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb68'><a id='x1-44010r1'></a><span class='ecrm-0500'>1</span><span id='textcolor2023'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-44012r2'></a><span class='ecrm-0500'>2</span><span id='textcolor2024'><span class='ectt-0800'> * completions.c</span></span>
|
|
<a id='x1-44014r3'></a><span class='ecrm-0500'>3</span><span id='textcolor2025'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-44016r4'></a><span class='ecrm-0500'>4</span><span id='textcolor2026'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2027'><span class='ectt-0800'><linux/completion.h></span></span>
|
|
<a id='x1-44018r5'></a><span class='ecrm-0500'>5</span><span id='textcolor2028'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2029'><span class='ectt-0800'><linux/err.h> /* for IS_ERR() */</span></span>
|
|
<a id='x1-44020r6'></a><span class='ecrm-0500'>6</span><span id='textcolor2030'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2031'><span class='ectt-0800'><linux/init.h></span></span>
|
|
<a id='x1-44022r7'></a><span class='ecrm-0500'>7</span><span id='textcolor2032'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2033'><span class='ectt-0800'><linux/kthread.h></span></span>
|
|
<a id='x1-44024r8'></a><span class='ecrm-0500'>8</span><span id='textcolor2034'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2035'><span class='ectt-0800'><linux/module.h></span></span>
|
|
<a id='x1-44026r9'></a><span class='ecrm-0500'>9</span><span id='textcolor2036'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2037'><span class='ectt-0800'><linux/printk.h></span></span>
|
|
<a id='x1-44028r10'></a><span class='ecrm-0500'>10</span><span id='textcolor2038'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2039'><span class='ectt-0800'><linux/version.h></span></span>
|
|
<a id='x1-44030r11'></a><span class='ecrm-0500'>11</span>
|
|
<a id='x1-44032r12'></a><span class='ecrm-0500'>12</span><span id='textcolor2040'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2041'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> completion crank_comp;</span>
|
|
<a id='x1-44034r13'></a><span class='ecrm-0500'>13</span><span id='textcolor2042'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2043'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> completion flywheel_comp;</span>
|
|
<a id='x1-44036r14'></a><span class='ecrm-0500'>14</span>
|
|
<a id='x1-44038r15'></a><span class='ecrm-0500'>15</span><span id='textcolor2044'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2045'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> machine_crank_thread(</span><span id='textcolor2046'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> *arg)</span>
|
|
<a id='x1-44040r16'></a><span class='ecrm-0500'>16</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-44042r17'></a><span class='ecrm-0500'>17</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2047'><span class='ectt-0800'>"Turn the crank</span></span><span id='textcolor2048'><span class='ectt-0800'>\n</span></span><span id='textcolor2049'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-44044r18'></a><span class='ecrm-0500'>18</span>
|
|
<a id='x1-44046r19'></a><span class='ecrm-0500'>19</span><span class='ectt-0800'> complete_all(&crank_comp);</span>
|
|
<a id='x1-44048r20'></a><span class='ecrm-0500'>20</span><span id='textcolor2050'><span class='ectt-0800'>#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 17, 0)</span></span>
|
|
<a id='x1-44050r21'></a><span class='ecrm-0500'>21</span><span class='ectt-0800'> kthread_complete_and_exit(&crank_comp, 0);</span>
|
|
<a id='x1-44052r22'></a><span class='ecrm-0500'>22</span><span id='textcolor2051'><span class='ectt-0800'>#else</span></span>
|
|
<a id='x1-44054r23'></a><span class='ecrm-0500'>23</span><span class='ectt-0800'> complete_and_exit(&crank_comp, 0);</span>
|
|
<a id='x1-44056r24'></a><span class='ecrm-0500'>24</span><span id='textcolor2052'><span class='ectt-0800'>#endif</span></span>
|
|
<a id='x1-44058r25'></a><span class='ecrm-0500'>25</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-44060r26'></a><span class='ecrm-0500'>26</span>
|
|
<a id='x1-44062r27'></a><span class='ecrm-0500'>27</span><span id='textcolor2053'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2054'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> machine_flywheel_spinup_thread(</span><span id='textcolor2055'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> *arg)</span>
|
|
<a id='x1-44064r28'></a><span class='ecrm-0500'>28</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-44066r29'></a><span class='ecrm-0500'>29</span><span class='ectt-0800'> wait_for_completion(&crank_comp);</span>
|
|
<a id='x1-44068r30'></a><span class='ecrm-0500'>30</span>
|
|
<a id='x1-44070r31'></a><span class='ecrm-0500'>31</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2056'><span class='ectt-0800'>"Flywheel spins up</span></span><span id='textcolor2057'><span class='ectt-0800'>\n</span></span><span id='textcolor2058'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-44072r32'></a><span class='ecrm-0500'>32</span>
|
|
<a id='x1-44074r33'></a><span class='ecrm-0500'>33</span><span class='ectt-0800'> complete_all(&flywheel_comp);</span>
|
|
<a id='x1-44076r34'></a><span class='ecrm-0500'>34</span><span id='textcolor2059'><span class='ectt-0800'>#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 17, 0)</span></span>
|
|
<a id='x1-44078r35'></a><span class='ecrm-0500'>35</span><span class='ectt-0800'> kthread_complete_and_exit(&flywheel_comp, 0);</span>
|
|
<a id='x1-44080r36'></a><span class='ecrm-0500'>36</span><span id='textcolor2060'><span class='ectt-0800'>#else</span></span>
|
|
<a id='x1-44082r37'></a><span class='ecrm-0500'>37</span><span class='ectt-0800'> complete_and_exit(&flywheel_comp, 0);</span>
|
|
<a id='x1-44084r38'></a><span class='ecrm-0500'>38</span><span id='textcolor2061'><span class='ectt-0800'>#endif</span></span>
|
|
<a id='x1-44086r39'></a><span class='ecrm-0500'>39</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-44088r40'></a><span class='ecrm-0500'>40</span>
|
|
<a id='x1-44090r41'></a><span class='ecrm-0500'>41</span><span id='textcolor2062'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2063'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __init completions_init(</span><span id='textcolor2064'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-44092r42'></a><span class='ecrm-0500'>42</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-44094r43'></a><span class='ecrm-0500'>43</span><span class='ectt-0800'> </span><span id='textcolor2065'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> task_struct *crank_thread;</span>
|
|
<a id='x1-44096r44'></a><span class='ecrm-0500'>44</span><span class='ectt-0800'> </span><span id='textcolor2066'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> task_struct *flywheel_thread;</span>
|
|
<a id='x1-44098r45'></a><span class='ecrm-0500'>45</span>
|
|
<a id='x1-44100r46'></a><span class='ecrm-0500'>46</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2067'><span class='ectt-0800'>"completions example</span></span><span id='textcolor2068'><span class='ectt-0800'>\n</span></span><span id='textcolor2069'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-44102r47'></a><span class='ecrm-0500'>47</span>
|
|
<a id='x1-44104r48'></a><span class='ecrm-0500'>48</span><span class='ectt-0800'> init_completion(&crank_comp);</span>
|
|
<a id='x1-44106r49'></a><span class='ecrm-0500'>49</span><span class='ectt-0800'> init_completion(&flywheel_comp);</span>
|
|
<a id='x1-44108r50'></a><span class='ecrm-0500'>50</span>
|
|
<a id='x1-44110r51'></a><span class='ecrm-0500'>51</span><span class='ectt-0800'> crank_thread = kthread_create(machine_crank_thread, NULL, </span><span id='textcolor2070'><span class='ectt-0800'>"KThread Crank"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-44112r52'></a><span class='ecrm-0500'>52</span><span class='ectt-0800'> </span><span id='textcolor2071'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (IS_ERR(crank_thread))</span>
|
|
<a id='x1-44114r53'></a><span class='ecrm-0500'>53</span><span class='ectt-0800'> </span><span id='textcolor2072'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> ERROR_THREAD_1;</span>
|
|
<a id='x1-44116r54'></a><span class='ecrm-0500'>54</span>
|
|
<a id='x1-44118r55'></a><span class='ecrm-0500'>55</span><span class='ectt-0800'> flywheel_thread = kthread_create(machine_flywheel_spinup_thread, NULL,</span>
|
|
<a id='x1-44120r56'></a><span class='ecrm-0500'>56</span><span class='ectt-0800'> </span><span id='textcolor2073'><span class='ectt-0800'>"KThread Flywheel"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-44122r57'></a><span class='ecrm-0500'>57</span><span class='ectt-0800'> </span><span id='textcolor2074'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (IS_ERR(flywheel_thread))</span>
|
|
<a id='x1-44124r58'></a><span class='ecrm-0500'>58</span><span class='ectt-0800'> </span><span id='textcolor2075'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> ERROR_THREAD_2;</span>
|
|
<a id='x1-44126r59'></a><span class='ecrm-0500'>59</span>
|
|
<a id='x1-44128r60'></a><span class='ecrm-0500'>60</span><span class='ectt-0800'> wake_up_process(flywheel_thread);</span>
|
|
<a id='x1-44130r61'></a><span class='ecrm-0500'>61</span><span class='ectt-0800'> wake_up_process(crank_thread);</span>
|
|
<a id='x1-44132r62'></a><span class='ecrm-0500'>62</span>
|
|
<a id='x1-44134r63'></a><span class='ecrm-0500'>63</span><span class='ectt-0800'> </span><span id='textcolor2076'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-44136r64'></a><span class='ecrm-0500'>64</span>
|
|
<a id='x1-44138r65'></a><span class='ecrm-0500'>65</span><span class='ectt-0800'>ERROR_THREAD_2:</span>
|
|
<a id='x1-44140r66'></a><span class='ecrm-0500'>66</span><span class='ectt-0800'> kthread_stop(crank_thread);</span>
|
|
<a id='x1-44142r67'></a><span class='ecrm-0500'>67</span><span class='ectt-0800'>ERROR_THREAD_1:</span>
|
|
<a id='x1-44144r68'></a><span class='ecrm-0500'>68</span>
|
|
<a id='x1-44146r69'></a><span class='ecrm-0500'>69</span><span class='ectt-0800'> </span><span id='textcolor2077'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -1;</span>
|
|
<a id='x1-44148r70'></a><span class='ecrm-0500'>70</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-44150r71'></a><span class='ecrm-0500'>71</span>
|
|
<a id='x1-44152r72'></a><span class='ecrm-0500'>72</span><span id='textcolor2078'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2079'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> __exit completions_exit(</span><span id='textcolor2080'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-44154r73'></a><span class='ecrm-0500'>73</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-44156r74'></a><span class='ecrm-0500'>74</span><span class='ectt-0800'> wait_for_completion(&crank_comp);</span>
|
|
<a id='x1-44158r75'></a><span class='ecrm-0500'>75</span><span class='ectt-0800'> wait_for_completion(&flywheel_comp);</span>
|
|
<a id='x1-44160r76'></a><span class='ecrm-0500'>76</span>
|
|
<a id='x1-44162r77'></a><span class='ecrm-0500'>77</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2081'><span class='ectt-0800'>"completions exit</span></span><span id='textcolor2082'><span class='ectt-0800'>\n</span></span><span id='textcolor2083'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-44164r78'></a><span class='ecrm-0500'>78</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-44166r79'></a><span class='ecrm-0500'>79</span>
|
|
<a id='x1-44168r80'></a><span class='ecrm-0500'>80</span><span class='ectt-0800'>module_init(completions_init);</span>
|
|
<a id='x1-44170r81'></a><span class='ecrm-0500'>81</span><span class='ectt-0800'>module_exit(completions_exit);</span>
|
|
<a id='x1-44172r82'></a><span class='ecrm-0500'>82</span>
|
|
<a id='x1-44174r83'></a><span class='ecrm-0500'>83</span><span class='ectt-0800'>MODULE_DESCRIPTION(</span><span id='textcolor2084'><span class='ectt-0800'>"Completions example"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-44176r84'></a><span class='ecrm-0500'>84</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor2085'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span></pre>
|
|
<!-- l. 1671 --><p class='noindent'>
|
|
</p>
|
|
<h3 class='sectionHead' id='avoiding-collisions-and-deadlocks'><span class='titlemark'>12 </span> <a id='x1-4500012'></a>Avoiding Collisions and Deadlocks</h3>
|
|
<!-- l. 1673 --><p class='noindent'>If processes running on different CPUs or in different threads try to access the same
|
|
memory, then it is possible that strange things can happen or your system can lock
|
|
up. To avoid this, various types of mutual exclusion kernel functions are available.
|
|
These indicate if a section of code is "locked" or "unlocked" so that simultaneous
|
|
attempts to run it can not happen.
|
|
</p>
|
|
<h4 class='subsectionHead' id='mutex'><span class='titlemark'>12.1 </span> <a id='x1-4600012.1'></a>Mutex</h4>
|
|
<!-- l. 1678 --><p class='noindent'>You can use kernel mutexes (mutual exclusions) in much the same manner that you
|
|
might deploy them in userland. This may be all that is needed to avoid collisions in
|
|
most cases.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb69'><a id='x1-46002r1'></a><span class='ecrm-0500'>1</span><span id='textcolor2086'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-46004r2'></a><span class='ecrm-0500'>2</span><span id='textcolor2087'><span class='ectt-0800'> * example_mutex.c</span></span>
|
|
<a id='x1-46006r3'></a><span class='ecrm-0500'>3</span><span id='textcolor2088'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-46008r4'></a><span class='ecrm-0500'>4</span><span id='textcolor2089'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2090'><span class='ectt-0800'><linux/module.h></span></span>
|
|
<a id='x1-46010r5'></a><span class='ecrm-0500'>5</span><span id='textcolor2091'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2092'><span class='ectt-0800'><linux/mutex.h></span></span>
|
|
<a id='x1-46012r6'></a><span class='ecrm-0500'>6</span><span id='textcolor2093'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2094'><span class='ectt-0800'><linux/printk.h></span></span>
|
|
<a id='x1-46014r7'></a><span class='ecrm-0500'>7</span>
|
|
<a id='x1-46016r8'></a><span class='ecrm-0500'>8</span><span id='textcolor2095'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> DEFINE_MUTEX(mymutex);</span>
|
|
<a id='x1-46018r9'></a><span class='ecrm-0500'>9</span>
|
|
<a id='x1-46020r10'></a><span class='ecrm-0500'>10</span><span id='textcolor2096'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2097'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __init example_mutex_init(</span><span id='textcolor2098'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-46022r11'></a><span class='ecrm-0500'>11</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-46024r12'></a><span class='ecrm-0500'>12</span><span class='ectt-0800'> </span><span id='textcolor2099'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> ret;</span>
|
|
<a id='x1-46026r13'></a><span class='ecrm-0500'>13</span>
|
|
<a id='x1-46028r14'></a><span class='ecrm-0500'>14</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2100'><span class='ectt-0800'>"example_mutex init</span></span><span id='textcolor2101'><span class='ectt-0800'>\n</span></span><span id='textcolor2102'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-46030r15'></a><span class='ecrm-0500'>15</span>
|
|
<a id='x1-46032r16'></a><span class='ecrm-0500'>16</span><span class='ectt-0800'> ret = mutex_trylock(&mymutex);</span>
|
|
<a id='x1-46034r17'></a><span class='ecrm-0500'>17</span><span class='ectt-0800'> </span><span id='textcolor2103'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (ret != 0) {</span>
|
|
<a id='x1-46036r18'></a><span class='ecrm-0500'>18</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2104'><span class='ectt-0800'>"mutex is locked</span></span><span id='textcolor2105'><span class='ectt-0800'>\n</span></span><span id='textcolor2106'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-46038r19'></a><span class='ecrm-0500'>19</span>
|
|
<a id='x1-46040r20'></a><span class='ecrm-0500'>20</span><span class='ectt-0800'> </span><span id='textcolor2107'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (mutex_is_locked(&mymutex) == 0)</span>
|
|
<a id='x1-46042r21'></a><span class='ecrm-0500'>21</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2108'><span class='ectt-0800'>"The mutex failed to lock!</span></span><span id='textcolor2109'><span class='ectt-0800'>\n</span></span><span id='textcolor2110'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-46044r22'></a><span class='ecrm-0500'>22</span>
|
|
<a id='x1-46046r23'></a><span class='ecrm-0500'>23</span><span class='ectt-0800'> mutex_unlock(&mymutex);</span>
|
|
<a id='x1-46048r24'></a><span class='ecrm-0500'>24</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2111'><span class='ectt-0800'>"mutex is unlocked</span></span><span id='textcolor2112'><span class='ectt-0800'>\n</span></span><span id='textcolor2113'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-46050r25'></a><span class='ecrm-0500'>25</span><span class='ectt-0800'> } </span><span id='textcolor2114'><span class='ectt-0800'>else</span></span>
|
|
<a id='x1-46052r26'></a><span class='ecrm-0500'>26</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2115'><span class='ectt-0800'>"Failed to lock</span></span><span id='textcolor2116'><span class='ectt-0800'>\n</span></span><span id='textcolor2117'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-46054r27'></a><span class='ecrm-0500'>27</span>
|
|
<a id='x1-46056r28'></a><span class='ecrm-0500'>28</span><span class='ectt-0800'> </span><span id='textcolor2118'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-46058r29'></a><span class='ecrm-0500'>29</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-46060r30'></a><span class='ecrm-0500'>30</span>
|
|
<a id='x1-46062r31'></a><span class='ecrm-0500'>31</span><span id='textcolor2119'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2120'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> __exit example_mutex_exit(</span><span id='textcolor2121'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-46064r32'></a><span class='ecrm-0500'>32</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-46066r33'></a><span class='ecrm-0500'>33</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2122'><span class='ectt-0800'>"example_mutex exit</span></span><span id='textcolor2123'><span class='ectt-0800'>\n</span></span><span id='textcolor2124'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-46068r34'></a><span class='ecrm-0500'>34</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-46070r35'></a><span class='ecrm-0500'>35</span>
|
|
<a id='x1-46072r36'></a><span class='ecrm-0500'>36</span><span class='ectt-0800'>module_init(example_mutex_init);</span>
|
|
<a id='x1-46074r37'></a><span class='ecrm-0500'>37</span><span class='ectt-0800'>module_exit(example_mutex_exit);</span>
|
|
<a id='x1-46076r38'></a><span class='ecrm-0500'>38</span>
|
|
<a id='x1-46078r39'></a><span class='ecrm-0500'>39</span><span class='ectt-0800'>MODULE_DESCRIPTION(</span><span id='textcolor2125'><span class='ectt-0800'>"Mutex example"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-46080r40'></a><span class='ecrm-0500'>40</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor2126'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span></pre>
|
|
|
|
|
|
|
|
<!-- l. 1683 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='spinlocks'><span class='titlemark'>12.2 </span> <a id='x1-4700012.2'></a>Spinlocks</h4>
|
|
<!-- l. 1685 --><p class='noindent'>As the name suggests, spinlocks lock up the CPU that the code is running on,
|
|
taking 100% of its resources. Because of this you should only use the spinlock
|
|
mechanism around code which is likely to take no more than a few milliseconds to
|
|
run and so will not noticeably slow anything down from the user’s point of
|
|
view.
|
|
</p><!-- l. 1688 --><p class='indent'> The example here is <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>"irq safe"</span></span></span> in that if interrupts happen during the lock then
|
|
they will not be forgotten and will activate when the unlock happens, using the
|
|
<code> <span class='ectt-1000'>flags</span>
|
|
</code> variable to retain their state.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb70'><a id='x1-47003r1'></a><span class='ecrm-0500'>1</span><span id='textcolor2127'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-47005r2'></a><span class='ecrm-0500'>2</span><span id='textcolor2128'><span class='ectt-0800'> * example_spinlock.c</span></span>
|
|
<a id='x1-47007r3'></a><span class='ecrm-0500'>3</span><span id='textcolor2129'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-47009r4'></a><span class='ecrm-0500'>4</span><span id='textcolor2130'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2131'><span class='ectt-0800'><linux/init.h></span></span>
|
|
<a id='x1-47011r5'></a><span class='ecrm-0500'>5</span><span id='textcolor2132'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2133'><span class='ectt-0800'><linux/module.h></span></span>
|
|
<a id='x1-47013r6'></a><span class='ecrm-0500'>6</span><span id='textcolor2134'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2135'><span class='ectt-0800'><linux/printk.h></span></span>
|
|
<a id='x1-47015r7'></a><span class='ecrm-0500'>7</span><span id='textcolor2136'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2137'><span class='ectt-0800'><linux/spinlock.h></span></span>
|
|
<a id='x1-47017r8'></a><span class='ecrm-0500'>8</span>
|
|
<a id='x1-47019r9'></a><span class='ecrm-0500'>9</span><span id='textcolor2138'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> DEFINE_SPINLOCK(sl_static);</span>
|
|
<a id='x1-47021r10'></a><span class='ecrm-0500'>10</span><span id='textcolor2139'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> spinlock_t sl_dynamic;</span>
|
|
<a id='x1-47023r11'></a><span class='ecrm-0500'>11</span>
|
|
<a id='x1-47025r12'></a><span class='ecrm-0500'>12</span><span id='textcolor2140'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2141'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> example_spinlock_static(</span><span id='textcolor2142'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-47027r13'></a><span class='ecrm-0500'>13</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-47029r14'></a><span class='ecrm-0500'>14</span><span class='ectt-0800'> </span><span id='textcolor2143'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor2144'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> flags;</span>
|
|
<a id='x1-47031r15'></a><span class='ecrm-0500'>15</span>
|
|
<a id='x1-47033r16'></a><span class='ecrm-0500'>16</span><span class='ectt-0800'> spin_lock_irqsave(&sl_static, flags);</span>
|
|
<a id='x1-47035r17'></a><span class='ecrm-0500'>17</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2145'><span class='ectt-0800'>"Locked static spinlock</span></span><span id='textcolor2146'><span class='ectt-0800'>\n</span></span><span id='textcolor2147'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-47037r18'></a><span class='ecrm-0500'>18</span>
|
|
<a id='x1-47039r19'></a><span class='ecrm-0500'>19</span><span class='ectt-0800'> </span><span id='textcolor2148'><span class='ectt-0800'>/* Do something or other safely. Because this uses 100% CPU time, this</span></span>
|
|
<a id='x1-47041r20'></a><span class='ecrm-0500'>20</span><span id='textcolor2149'><span class='ectt-0800'> * code should take no more than a few milliseconds to run.</span></span>
|
|
<a id='x1-47043r21'></a><span class='ecrm-0500'>21</span><span id='textcolor2150'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-47045r22'></a><span class='ecrm-0500'>22</span>
|
|
<a id='x1-47047r23'></a><span class='ecrm-0500'>23</span><span class='ectt-0800'> spin_unlock_irqrestore(&sl_static, flags);</span>
|
|
<a id='x1-47049r24'></a><span class='ecrm-0500'>24</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2151'><span class='ectt-0800'>"Unlocked static spinlock</span></span><span id='textcolor2152'><span class='ectt-0800'>\n</span></span><span id='textcolor2153'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-47051r25'></a><span class='ecrm-0500'>25</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-47053r26'></a><span class='ecrm-0500'>26</span>
|
|
<a id='x1-47055r27'></a><span class='ecrm-0500'>27</span><span id='textcolor2154'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2155'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> example_spinlock_dynamic(</span><span id='textcolor2156'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-47057r28'></a><span class='ecrm-0500'>28</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-47059r29'></a><span class='ecrm-0500'>29</span><span class='ectt-0800'> </span><span id='textcolor2157'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor2158'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> flags;</span>
|
|
<a id='x1-47061r30'></a><span class='ecrm-0500'>30</span>
|
|
<a id='x1-47063r31'></a><span class='ecrm-0500'>31</span><span class='ectt-0800'> spin_lock_init(&sl_dynamic);</span>
|
|
<a id='x1-47065r32'></a><span class='ecrm-0500'>32</span><span class='ectt-0800'> spin_lock_irqsave(&sl_dynamic, flags);</span>
|
|
<a id='x1-47067r33'></a><span class='ecrm-0500'>33</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2159'><span class='ectt-0800'>"Locked dynamic spinlock</span></span><span id='textcolor2160'><span class='ectt-0800'>\n</span></span><span id='textcolor2161'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-47069r34'></a><span class='ecrm-0500'>34</span>
|
|
<a id='x1-47071r35'></a><span class='ecrm-0500'>35</span><span class='ectt-0800'> </span><span id='textcolor2162'><span class='ectt-0800'>/* Do something or other safely. Because this uses 100% CPU time, this</span></span>
|
|
<a id='x1-47073r36'></a><span class='ecrm-0500'>36</span><span id='textcolor2163'><span class='ectt-0800'> * code should take no more than a few milliseconds to run.</span></span>
|
|
<a id='x1-47075r37'></a><span class='ecrm-0500'>37</span><span id='textcolor2164'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-47077r38'></a><span class='ecrm-0500'>38</span>
|
|
<a id='x1-47079r39'></a><span class='ecrm-0500'>39</span><span class='ectt-0800'> spin_unlock_irqrestore(&sl_dynamic, flags);</span>
|
|
<a id='x1-47081r40'></a><span class='ecrm-0500'>40</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2165'><span class='ectt-0800'>"Unlocked dynamic spinlock</span></span><span id='textcolor2166'><span class='ectt-0800'>\n</span></span><span id='textcolor2167'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-47083r41'></a><span class='ecrm-0500'>41</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-47085r42'></a><span class='ecrm-0500'>42</span>
|
|
<a id='x1-47087r43'></a><span class='ecrm-0500'>43</span><span id='textcolor2168'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2169'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __init example_spinlock_init(</span><span id='textcolor2170'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-47089r44'></a><span class='ecrm-0500'>44</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-47091r45'></a><span class='ecrm-0500'>45</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2171'><span class='ectt-0800'>"example spinlock started</span></span><span id='textcolor2172'><span class='ectt-0800'>\n</span></span><span id='textcolor2173'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-47093r46'></a><span class='ecrm-0500'>46</span>
|
|
<a id='x1-47095r47'></a><span class='ecrm-0500'>47</span><span class='ectt-0800'> example_spinlock_static();</span>
|
|
<a id='x1-47097r48'></a><span class='ecrm-0500'>48</span><span class='ectt-0800'> example_spinlock_dynamic();</span>
|
|
<a id='x1-47099r49'></a><span class='ecrm-0500'>49</span>
|
|
<a id='x1-47101r50'></a><span class='ecrm-0500'>50</span><span class='ectt-0800'> </span><span id='textcolor2174'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-47103r51'></a><span class='ecrm-0500'>51</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-47105r52'></a><span class='ecrm-0500'>52</span>
|
|
<a id='x1-47107r53'></a><span class='ecrm-0500'>53</span><span id='textcolor2175'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2176'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> __exit example_spinlock_exit(</span><span id='textcolor2177'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-47109r54'></a><span class='ecrm-0500'>54</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-47111r55'></a><span class='ecrm-0500'>55</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2178'><span class='ectt-0800'>"example spinlock exit</span></span><span id='textcolor2179'><span class='ectt-0800'>\n</span></span><span id='textcolor2180'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-47113r56'></a><span class='ecrm-0500'>56</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-47115r57'></a><span class='ecrm-0500'>57</span>
|
|
<a id='x1-47117r58'></a><span class='ecrm-0500'>58</span><span class='ectt-0800'>module_init(example_spinlock_init);</span>
|
|
<a id='x1-47119r59'></a><span class='ecrm-0500'>59</span><span class='ectt-0800'>module_exit(example_spinlock_exit);</span>
|
|
<a id='x1-47121r60'></a><span class='ecrm-0500'>60</span>
|
|
<a id='x1-47123r61'></a><span class='ecrm-0500'>61</span><span class='ectt-0800'>MODULE_DESCRIPTION(</span><span id='textcolor2181'><span class='ectt-0800'>"Spinlock example"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-47125r62'></a><span class='ecrm-0500'>62</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor2182'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span></pre>
|
|
<!-- l. 1692 --><p class='indent'> Taking 100% of a CPU’s resources comes with greater responsibility. Situations
|
|
where the kernel code monopolizes a CPU are called <span class='ecbx-1000'>atomic contexts</span>. Holding a
|
|
spinlock is one of those situations. Sleeping in atomic contexts may leave the system
|
|
hanging, as the occupied CPU devotes 100% of its resources doing nothing
|
|
but sleeping. In some worse cases the system may crash. Thus, sleeping in
|
|
atomic contexts is considered a bug in the kernel. They are sometimes called
|
|
“sleep-in-atomic-context” in some materials.
|
|
</p><!-- l. 1700 --><p class='indent'> Note that sleeping here is not limited to calling the sleep functions explicitly.
|
|
If subsequent function calls eventually invoke a function that sleeps, it is
|
|
also considered sleeping. Thus, it is important to pay attention to functions
|
|
being used in atomic context. There’s no documentation recording all such
|
|
functions, but code comments may help. Sometimes you may find comments in
|
|
kernel source code stating that a function “may sleep”, “might sleep”, or
|
|
more explicitly “the caller should not hold a spinlock”. Those comments are
|
|
hints that a function may implicitly sleep and must not be called in atomic
|
|
contexts.
|
|
</p><!-- l. 1707 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='read-and-write-locks'><span class='titlemark'>12.3 </span> <a id='x1-4800012.3'></a>Read and write locks</h4>
|
|
<!-- l. 1709 --><p class='noindent'>Read and write locks are specialised kinds of spinlocks so that you can exclusively
|
|
read from something or write to something. Like the earlier spinlocks example, the
|
|
one below shows an "irq safe" situation in which if other functions were triggered
|
|
from irqs which might also read and write to whatever you are concerned with
|
|
then they would not disrupt the logic. As before it is a good idea to keep
|
|
anything done within the lock as short as possible so that it does not hang up
|
|
the system and cause users to start revolting against the tyranny of your
|
|
module.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
|
|
|
|
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb71'><a id='x1-48002r1'></a><span class='ecrm-0500'>1</span><span id='textcolor2183'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-48004r2'></a><span class='ecrm-0500'>2</span><span id='textcolor2184'><span class='ectt-0800'> * example_rwlock.c</span></span>
|
|
<a id='x1-48006r3'></a><span class='ecrm-0500'>3</span><span id='textcolor2185'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-48008r4'></a><span class='ecrm-0500'>4</span><span id='textcolor2186'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2187'><span class='ectt-0800'><linux/module.h></span></span>
|
|
<a id='x1-48010r5'></a><span class='ecrm-0500'>5</span><span id='textcolor2188'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2189'><span class='ectt-0800'><linux/printk.h></span></span>
|
|
<a id='x1-48012r6'></a><span class='ecrm-0500'>6</span><span id='textcolor2190'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2191'><span class='ectt-0800'><linux/rwlock.h></span></span>
|
|
<a id='x1-48014r7'></a><span class='ecrm-0500'>7</span>
|
|
<a id='x1-48016r8'></a><span class='ecrm-0500'>8</span><span id='textcolor2192'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> DEFINE_RWLOCK(myrwlock);</span>
|
|
<a id='x1-48018r9'></a><span class='ecrm-0500'>9</span>
|
|
<a id='x1-48020r10'></a><span class='ecrm-0500'>10</span><span id='textcolor2193'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2194'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> example_read_lock(</span><span id='textcolor2195'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-48022r11'></a><span class='ecrm-0500'>11</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-48024r12'></a><span class='ecrm-0500'>12</span><span class='ectt-0800'> </span><span id='textcolor2196'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor2197'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> flags;</span>
|
|
<a id='x1-48026r13'></a><span class='ecrm-0500'>13</span>
|
|
<a id='x1-48028r14'></a><span class='ecrm-0500'>14</span><span class='ectt-0800'> read_lock_irqsave(&myrwlock, flags);</span>
|
|
<a id='x1-48030r15'></a><span class='ecrm-0500'>15</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2198'><span class='ectt-0800'>"Read Locked</span></span><span id='textcolor2199'><span class='ectt-0800'>\n</span></span><span id='textcolor2200'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-48032r16'></a><span class='ecrm-0500'>16</span>
|
|
<a id='x1-48034r17'></a><span class='ecrm-0500'>17</span><span class='ectt-0800'> </span><span id='textcolor2201'><span class='ectt-0800'>/* Read from something */</span></span>
|
|
<a id='x1-48036r18'></a><span class='ecrm-0500'>18</span>
|
|
<a id='x1-48038r19'></a><span class='ecrm-0500'>19</span><span class='ectt-0800'> read_unlock_irqrestore(&myrwlock, flags);</span>
|
|
<a id='x1-48040r20'></a><span class='ecrm-0500'>20</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2202'><span class='ectt-0800'>"Read Unlocked</span></span><span id='textcolor2203'><span class='ectt-0800'>\n</span></span><span id='textcolor2204'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-48042r21'></a><span class='ecrm-0500'>21</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-48044r22'></a><span class='ecrm-0500'>22</span>
|
|
<a id='x1-48046r23'></a><span class='ecrm-0500'>23</span><span id='textcolor2205'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2206'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> example_write_lock(</span><span id='textcolor2207'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-48048r24'></a><span class='ecrm-0500'>24</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-48050r25'></a><span class='ecrm-0500'>25</span><span class='ectt-0800'> </span><span id='textcolor2208'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor2209'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> flags;</span>
|
|
<a id='x1-48052r26'></a><span class='ecrm-0500'>26</span>
|
|
<a id='x1-48054r27'></a><span class='ecrm-0500'>27</span><span class='ectt-0800'> write_lock_irqsave(&myrwlock, flags);</span>
|
|
<a id='x1-48056r28'></a><span class='ecrm-0500'>28</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2210'><span class='ectt-0800'>"Write Locked</span></span><span id='textcolor2211'><span class='ectt-0800'>\n</span></span><span id='textcolor2212'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-48058r29'></a><span class='ecrm-0500'>29</span>
|
|
<a id='x1-48060r30'></a><span class='ecrm-0500'>30</span><span class='ectt-0800'> </span><span id='textcolor2213'><span class='ectt-0800'>/* Write to something */</span></span>
|
|
<a id='x1-48062r31'></a><span class='ecrm-0500'>31</span>
|
|
<a id='x1-48064r32'></a><span class='ecrm-0500'>32</span><span class='ectt-0800'> write_unlock_irqrestore(&myrwlock, flags);</span>
|
|
<a id='x1-48066r33'></a><span class='ecrm-0500'>33</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2214'><span class='ectt-0800'>"Write Unlocked</span></span><span id='textcolor2215'><span class='ectt-0800'>\n</span></span><span id='textcolor2216'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-48068r34'></a><span class='ecrm-0500'>34</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-48070r35'></a><span class='ecrm-0500'>35</span>
|
|
<a id='x1-48072r36'></a><span class='ecrm-0500'>36</span><span id='textcolor2217'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2218'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __init example_rwlock_init(</span><span id='textcolor2219'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-48074r37'></a><span class='ecrm-0500'>37</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-48076r38'></a><span class='ecrm-0500'>38</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2220'><span class='ectt-0800'>"example_rwlock started</span></span><span id='textcolor2221'><span class='ectt-0800'>\n</span></span><span id='textcolor2222'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-48078r39'></a><span class='ecrm-0500'>39</span>
|
|
<a id='x1-48080r40'></a><span class='ecrm-0500'>40</span><span class='ectt-0800'> example_read_lock();</span>
|
|
<a id='x1-48082r41'></a><span class='ecrm-0500'>41</span><span class='ectt-0800'> example_write_lock();</span>
|
|
<a id='x1-48084r42'></a><span class='ecrm-0500'>42</span>
|
|
<a id='x1-48086r43'></a><span class='ecrm-0500'>43</span><span class='ectt-0800'> </span><span id='textcolor2223'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-48088r44'></a><span class='ecrm-0500'>44</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-48090r45'></a><span class='ecrm-0500'>45</span>
|
|
<a id='x1-48092r46'></a><span class='ecrm-0500'>46</span><span id='textcolor2224'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2225'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> __exit example_rwlock_exit(</span><span id='textcolor2226'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-48094r47'></a><span class='ecrm-0500'>47</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-48096r48'></a><span class='ecrm-0500'>48</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2227'><span class='ectt-0800'>"example_rwlock exit</span></span><span id='textcolor2228'><span class='ectt-0800'>\n</span></span><span id='textcolor2229'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-48098r49'></a><span class='ecrm-0500'>49</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-48100r50'></a><span class='ecrm-0500'>50</span>
|
|
<a id='x1-48102r51'></a><span class='ecrm-0500'>51</span><span class='ectt-0800'>module_init(example_rwlock_init);</span>
|
|
<a id='x1-48104r52'></a><span class='ecrm-0500'>52</span><span class='ectt-0800'>module_exit(example_rwlock_exit);</span>
|
|
<a id='x1-48106r53'></a><span class='ecrm-0500'>53</span>
|
|
<a id='x1-48108r54'></a><span class='ecrm-0500'>54</span><span class='ectt-0800'>MODULE_DESCRIPTION(</span><span id='textcolor2230'><span class='ectt-0800'>"Read/Write locks example"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-48110r55'></a><span class='ecrm-0500'>55</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor2231'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span></pre>
|
|
<!-- l. 1715 --><p class='indent'> Of course, if you know for sure that there are no functions triggered by irqs
|
|
which could possibly interfere with your logic then you can use the simpler
|
|
<code> <span class='ectt-1000'>read_lock(&myrwlock)</span>
|
|
</code> and <code> <span class='ectt-1000'>read_unlock(&myrwlock)</span>
|
|
</code> or the corresponding write functions.
|
|
</p>
|
|
<h4 class='subsectionHead' id='atomic-operations'><span class='titlemark'>12.4 </span> <a id='x1-4900012.4'></a>Atomic operations</h4>
|
|
<!-- l. 1718 --><p class='noindent'>If you are doing simple arithmetic: adding, subtracting or bitwise operations, then
|
|
there is another way in the multi-CPU and multi-hyperthreaded world to stop other
|
|
parts of the system from messing with your mojo. By using atomic operations you
|
|
can be confident that your addition, subtraction or bit flip did actually happen
|
|
and was not overwritten by some other shenanigans. An example is shown
|
|
below.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb72'><a id='x1-49002r1'></a><span class='ecrm-0500'>1</span><span id='textcolor2232'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-49004r2'></a><span class='ecrm-0500'>2</span><span id='textcolor2233'><span class='ectt-0800'> * example_atomic.c</span></span>
|
|
<a id='x1-49006r3'></a><span class='ecrm-0500'>3</span><span id='textcolor2234'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-49008r4'></a><span class='ecrm-0500'>4</span><span id='textcolor2235'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2236'><span class='ectt-0800'><linux/atomic.h></span></span>
|
|
<a id='x1-49010r5'></a><span class='ecrm-0500'>5</span><span id='textcolor2237'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2238'><span class='ectt-0800'><linux/bitops.h></span></span>
|
|
<a id='x1-49012r6'></a><span class='ecrm-0500'>6</span><span id='textcolor2239'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2240'><span class='ectt-0800'><linux/module.h></span></span>
|
|
<a id='x1-49014r7'></a><span class='ecrm-0500'>7</span><span id='textcolor2241'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2242'><span class='ectt-0800'><linux/printk.h></span></span>
|
|
<a id='x1-49016r8'></a><span class='ecrm-0500'>8</span>
|
|
<a id='x1-49018r9'></a><span class='ecrm-0500'>9</span><span id='textcolor2243'><span class='ectt-0800'>#define BYTE_TO_BINARY_PATTERN "%c%c%c%c%c%c%c%c"</span></span>
|
|
<a id='x1-49020r10'></a><span class='ecrm-0500'>10</span><span id='textcolor2244'><span class='ectt-0800'>#define BYTE_TO_BINARY(byte) \</span></span>
|
|
<a id='x1-49022r11'></a><span class='ecrm-0500'>11</span><span id='textcolor2245'><span class='ectt-0800'> ((byte & 0x80) ? </span><span class='tctt-0800'>'</span><span class='ectt-0800'>1</span><span class='tctt-0800'>'</span><span class='ectt-0800'> : </span><span class='tctt-0800'>'</span><span class='ectt-0800'>0</span><span class='tctt-0800'>'</span><span class='ectt-0800'>), ((byte & 0x40) ? </span><span class='tctt-0800'>'</span><span class='ectt-0800'>1</span><span class='tctt-0800'>'</span><span class='ectt-0800'> : </span><span class='tctt-0800'>'</span><span class='ectt-0800'>0</span><span class='tctt-0800'>'</span><span class='ectt-0800'>), \</span></span>
|
|
<a id='x1-49024r12'></a><span class='ecrm-0500'>12</span><span id='textcolor2246'><span class='ectt-0800'> ((byte & 0x20) ? </span><span class='tctt-0800'>'</span><span class='ectt-0800'>1</span><span class='tctt-0800'>'</span><span class='ectt-0800'> : </span><span class='tctt-0800'>'</span><span class='ectt-0800'>0</span><span class='tctt-0800'>'</span><span class='ectt-0800'>), ((byte & 0x10) ? </span><span class='tctt-0800'>'</span><span class='ectt-0800'>1</span><span class='tctt-0800'>'</span><span class='ectt-0800'> : </span><span class='tctt-0800'>'</span><span class='ectt-0800'>0</span><span class='tctt-0800'>'</span><span class='ectt-0800'>), \</span></span>
|
|
<a id='x1-49026r13'></a><span class='ecrm-0500'>13</span><span id='textcolor2247'><span class='ectt-0800'> ((byte & 0x08) ? </span><span class='tctt-0800'>'</span><span class='ectt-0800'>1</span><span class='tctt-0800'>'</span><span class='ectt-0800'> : </span><span class='tctt-0800'>'</span><span class='ectt-0800'>0</span><span class='tctt-0800'>'</span><span class='ectt-0800'>), ((byte & 0x04) ? </span><span class='tctt-0800'>'</span><span class='ectt-0800'>1</span><span class='tctt-0800'>'</span><span class='ectt-0800'> : </span><span class='tctt-0800'>'</span><span class='ectt-0800'>0</span><span class='tctt-0800'>'</span><span class='ectt-0800'>), \</span></span>
|
|
<a id='x1-49028r14'></a><span class='ecrm-0500'>14</span><span id='textcolor2248'><span class='ectt-0800'> ((byte & 0x02) ? </span><span class='tctt-0800'>'</span><span class='ectt-0800'>1</span><span class='tctt-0800'>'</span><span class='ectt-0800'> : </span><span class='tctt-0800'>'</span><span class='ectt-0800'>0</span><span class='tctt-0800'>'</span><span class='ectt-0800'>), ((byte & 0x01) ? </span><span class='tctt-0800'>'</span><span class='ectt-0800'>1</span><span class='tctt-0800'>'</span><span class='ectt-0800'> : </span><span class='tctt-0800'>'</span><span class='ectt-0800'>0</span><span class='tctt-0800'>'</span><span class='ectt-0800'>)</span></span>
|
|
<a id='x1-49030r15'></a><span class='ecrm-0500'>15</span>
|
|
<a id='x1-49032r16'></a><span class='ecrm-0500'>16</span><span id='textcolor2249'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2250'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> atomic_add_subtract(</span><span id='textcolor2251'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-49034r17'></a><span class='ecrm-0500'>17</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-49036r18'></a><span class='ecrm-0500'>18</span><span class='ectt-0800'> atomic_t debbie;</span>
|
|
<a id='x1-49038r19'></a><span class='ecrm-0500'>19</span><span class='ectt-0800'> atomic_t chris = ATOMIC_INIT(50);</span>
|
|
<a id='x1-49040r20'></a><span class='ecrm-0500'>20</span>
|
|
<a id='x1-49042r21'></a><span class='ecrm-0500'>21</span><span class='ectt-0800'> atomic_set(&debbie, 45);</span>
|
|
<a id='x1-49044r22'></a><span class='ecrm-0500'>22</span>
|
|
<a id='x1-49046r23'></a><span class='ecrm-0500'>23</span><span class='ectt-0800'> </span><span id='textcolor2252'><span class='ectt-0800'>/* subtract one */</span></span>
|
|
<a id='x1-49048r24'></a><span class='ecrm-0500'>24</span><span class='ectt-0800'> atomic_dec(&debbie);</span>
|
|
<a id='x1-49050r25'></a><span class='ecrm-0500'>25</span>
|
|
<a id='x1-49052r26'></a><span class='ecrm-0500'>26</span><span class='ectt-0800'> atomic_add(7, &debbie);</span>
|
|
<a id='x1-49054r27'></a><span class='ecrm-0500'>27</span>
|
|
<a id='x1-49056r28'></a><span class='ecrm-0500'>28</span><span class='ectt-0800'> </span><span id='textcolor2253'><span class='ectt-0800'>/* add one */</span></span>
|
|
<a id='x1-49058r29'></a><span class='ecrm-0500'>29</span><span class='ectt-0800'> atomic_inc(&debbie);</span>
|
|
<a id='x1-49060r30'></a><span class='ecrm-0500'>30</span>
|
|
<a id='x1-49062r31'></a><span class='ecrm-0500'>31</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2254'><span class='ectt-0800'>"chris: %d, debbie: %d</span></span><span id='textcolor2255'><span class='ectt-0800'>\n</span></span><span id='textcolor2256'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, atomic_read(&chris),</span>
|
|
<a id='x1-49064r32'></a><span class='ecrm-0500'>32</span><span class='ectt-0800'> atomic_read(&debbie));</span>
|
|
<a id='x1-49066r33'></a><span class='ecrm-0500'>33</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-49068r34'></a><span class='ecrm-0500'>34</span>
|
|
<a id='x1-49070r35'></a><span class='ecrm-0500'>35</span><span id='textcolor2257'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2258'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> atomic_bitwise(</span><span id='textcolor2259'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-49072r36'></a><span class='ecrm-0500'>36</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-49074r37'></a><span class='ecrm-0500'>37</span><span class='ectt-0800'> </span><span id='textcolor2260'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor2261'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> word = 0;</span>
|
|
<a id='x1-49076r38'></a><span class='ecrm-0500'>38</span>
|
|
<a id='x1-49078r39'></a><span class='ecrm-0500'>39</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2262'><span class='ectt-0800'>"Bits 0: "</span></span><span class='ectt-0800'> BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(word));</span>
|
|
<a id='x1-49080r40'></a><span class='ecrm-0500'>40</span><span class='ectt-0800'> set_bit(3, &word);</span>
|
|
<a id='x1-49082r41'></a><span class='ecrm-0500'>41</span><span class='ectt-0800'> set_bit(5, &word);</span>
|
|
<a id='x1-49084r42'></a><span class='ecrm-0500'>42</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2263'><span class='ectt-0800'>"Bits 1: "</span></span><span class='ectt-0800'> BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(word));</span>
|
|
<a id='x1-49086r43'></a><span class='ecrm-0500'>43</span><span class='ectt-0800'> clear_bit(5, &word);</span>
|
|
<a id='x1-49088r44'></a><span class='ecrm-0500'>44</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2264'><span class='ectt-0800'>"Bits 2: "</span></span><span class='ectt-0800'> BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(word));</span>
|
|
<a id='x1-49090r45'></a><span class='ecrm-0500'>45</span><span class='ectt-0800'> change_bit(3, &word);</span>
|
|
<a id='x1-49092r46'></a><span class='ecrm-0500'>46</span>
|
|
<a id='x1-49094r47'></a><span class='ecrm-0500'>47</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2265'><span class='ectt-0800'>"Bits 3: "</span></span><span class='ectt-0800'> BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(word));</span>
|
|
<a id='x1-49096r48'></a><span class='ecrm-0500'>48</span><span class='ectt-0800'> </span><span id='textcolor2266'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (test_and_set_bit(3, &word))</span>
|
|
<a id='x1-49098r49'></a><span class='ecrm-0500'>49</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2267'><span class='ectt-0800'>"wrong</span></span><span id='textcolor2268'><span class='ectt-0800'>\n</span></span><span id='textcolor2269'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-49100r50'></a><span class='ecrm-0500'>50</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2270'><span class='ectt-0800'>"Bits 4: "</span></span><span class='ectt-0800'> BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(word));</span>
|
|
<a id='x1-49102r51'></a><span class='ecrm-0500'>51</span>
|
|
<a id='x1-49104r52'></a><span class='ecrm-0500'>52</span><span class='ectt-0800'> word = 255;</span>
|
|
<a id='x1-49106r53'></a><span class='ecrm-0500'>53</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2271'><span class='ectt-0800'>"Bits 5: "</span></span><span class='ectt-0800'> BYTE_TO_BINARY_PATTERN </span><span id='textcolor2272'><span class='ectt-0800'>"</span></span><span id='textcolor2273'><span class='ectt-0800'>\n</span></span><span id='textcolor2274'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, BYTE_TO_BINARY(word));</span>
|
|
<a id='x1-49108r54'></a><span class='ecrm-0500'>54</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-49110r55'></a><span class='ecrm-0500'>55</span>
|
|
<a id='x1-49112r56'></a><span class='ecrm-0500'>56</span><span id='textcolor2275'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2276'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __init example_atomic_init(</span><span id='textcolor2277'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-49114r57'></a><span class='ecrm-0500'>57</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-49116r58'></a><span class='ecrm-0500'>58</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2278'><span class='ectt-0800'>"example_atomic started</span></span><span id='textcolor2279'><span class='ectt-0800'>\n</span></span><span id='textcolor2280'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-49118r59'></a><span class='ecrm-0500'>59</span>
|
|
<a id='x1-49120r60'></a><span class='ecrm-0500'>60</span><span class='ectt-0800'> atomic_add_subtract();</span>
|
|
<a id='x1-49122r61'></a><span class='ecrm-0500'>61</span><span class='ectt-0800'> atomic_bitwise();</span>
|
|
<a id='x1-49124r62'></a><span class='ecrm-0500'>62</span>
|
|
<a id='x1-49126r63'></a><span class='ecrm-0500'>63</span><span class='ectt-0800'> </span><span id='textcolor2281'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-49128r64'></a><span class='ecrm-0500'>64</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-49130r65'></a><span class='ecrm-0500'>65</span>
|
|
<a id='x1-49132r66'></a><span class='ecrm-0500'>66</span><span id='textcolor2282'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2283'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> __exit example_atomic_exit(</span><span id='textcolor2284'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-49134r67'></a><span class='ecrm-0500'>67</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-49136r68'></a><span class='ecrm-0500'>68</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2285'><span class='ectt-0800'>"example_atomic exit</span></span><span id='textcolor2286'><span class='ectt-0800'>\n</span></span><span id='textcolor2287'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-49138r69'></a><span class='ecrm-0500'>69</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-49140r70'></a><span class='ecrm-0500'>70</span>
|
|
<a id='x1-49142r71'></a><span class='ecrm-0500'>71</span><span class='ectt-0800'>module_init(example_atomic_init);</span>
|
|
<a id='x1-49144r72'></a><span class='ecrm-0500'>72</span><span class='ectt-0800'>module_exit(example_atomic_exit);</span>
|
|
<a id='x1-49146r73'></a><span class='ecrm-0500'>73</span>
|
|
<a id='x1-49148r74'></a><span class='ecrm-0500'>74</span><span class='ectt-0800'>MODULE_DESCRIPTION(</span><span id='textcolor2288'><span class='ectt-0800'>"Atomic operations example"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-49150r75'></a><span class='ecrm-0500'>75</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor2289'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span></pre>
|
|
<!-- l. 1724 --><p class='indent'> Before the C11 standard adopts the built-in atomic types, the kernel already
|
|
provided a small set of atomic types by using a bunch of tricky architecture-specific
|
|
codes. Implementing the atomic types by C11 atomics may allow the kernel to throw
|
|
away the architecture-specific codes and letting the kernel code be more friendly to
|
|
the people who understand the standard. But there are some problems, such as the
|
|
memory model of the kernel doesn’t match the model formed by the C11 atomics.
|
|
For further details, see: </p>
|
|
<ul class='itemize1'>
|
|
<li class='itemize'><a href='https://www.kernel.org/doc/Documentation/atomic_t.txt'>kernel documentation of atomic types</a>
|
|
</li>
|
|
<li class='itemize'><a href='https://lwn.net/Articles/691128/'>Time to move to C11 atomics?</a>
|
|
</li>
|
|
<li class='itemize'><a href='https://lwn.net/Articles/698315/'>Atomic usage patterns in the kernel</a></li></ul>
|
|
<!-- l. 1735 --><p class='noindent'>
|
|
</p>
|
|
<h3 class='sectionHead' id='replacing-print-macros'><span class='titlemark'>13 </span> <a id='x1-5000013'></a>Replacing Print Macros</h3>
|
|
|
|
|
|
|
|
<!-- l. 1737 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='replacement'><span class='titlemark'>13.1 </span> <a id='x1-5100013.1'></a>Replacement</h4>
|
|
<!-- l. 1739 --><p class='noindent'>In Section <a href='#before-we-begin'>1.7<!-- tex4ht:ref: sec:preparation --></a>, it was noted that the X Window System and kernel module
|
|
programming are not conducive to integration. This remains valid during the
|
|
development of kernel modules. However, in practical scenarios, the necessity
|
|
emerges to relay messages to the tty (teletype) originating the module load
|
|
command.
|
|
</p><!-- l. 1743 --><p class='indent'> The term “tty” originates from <span class='ecti-1000'>teletype</span>, which initially referred to a combined
|
|
keyboard-printer for Unix system communication. Today, it signifies a text stream
|
|
abstraction employed by Unix programs, encompassing physical terminals, xterms in
|
|
X displays, and network connections like SSH.
|
|
</p><!-- l. 1747 --><p class='indent'> To achieve this, the “current” pointer is leveraged to access the active task’s tty
|
|
structure. Within this structure lies a pointer to a string write function, facilitating
|
|
the string’s transmission to the tty.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb73'><a id='x1-51002r1'></a><span class='ecrm-0500'>1</span><span id='textcolor2290'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-51004r2'></a><span class='ecrm-0500'>2</span><span id='textcolor2291'><span class='ectt-0800'> * print_string.c - Send output to the tty we</span><span class='tctt-0800'>'</span><span class='ectt-0800'>re running on, regardless if</span></span>
|
|
<a id='x1-51006r3'></a><span class='ecrm-0500'>3</span><span id='textcolor2292'><span class='ectt-0800'> * it is through X11, telnet, etc. We do this by printing the string to the</span></span>
|
|
<a id='x1-51008r4'></a><span class='ecrm-0500'>4</span><span id='textcolor2293'><span class='ectt-0800'> * tty associated with the current task.</span></span>
|
|
<a id='x1-51010r5'></a><span class='ecrm-0500'>5</span><span id='textcolor2294'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-51012r6'></a><span class='ecrm-0500'>6</span><span id='textcolor2295'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2296'><span class='ectt-0800'><linux/init.h></span></span>
|
|
<a id='x1-51014r7'></a><span class='ecrm-0500'>7</span><span id='textcolor2297'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2298'><span class='ectt-0800'><linux/kernel.h></span></span>
|
|
<a id='x1-51016r8'></a><span class='ecrm-0500'>8</span><span id='textcolor2299'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2300'><span class='ectt-0800'><linux/module.h></span></span>
|
|
<a id='x1-51018r9'></a><span class='ecrm-0500'>9</span><span id='textcolor2301'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2302'><span class='ectt-0800'><linux/sched.h> /* For current */</span></span>
|
|
<a id='x1-51020r10'></a><span class='ecrm-0500'>10</span><span id='textcolor2303'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2304'><span class='ectt-0800'><linux/tty.h> /* For the tty declarations */</span></span>
|
|
<a id='x1-51022r11'></a><span class='ecrm-0500'>11</span>
|
|
<a id='x1-51024r12'></a><span class='ecrm-0500'>12</span><span id='textcolor2305'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2306'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> print_string(</span><span id='textcolor2307'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *str)</span>
|
|
<a id='x1-51026r13'></a><span class='ecrm-0500'>13</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-51028r14'></a><span class='ecrm-0500'>14</span><span class='ectt-0800'> </span><span id='textcolor2308'><span class='ectt-0800'>/* The tty for the current task */</span></span>
|
|
<a id='x1-51030r15'></a><span class='ecrm-0500'>15</span><span class='ectt-0800'> </span><span id='textcolor2309'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> tty_struct *my_tty = get_current_tty();</span>
|
|
<a id='x1-51032r16'></a><span class='ecrm-0500'>16</span>
|
|
<a id='x1-51034r17'></a><span class='ecrm-0500'>17</span><span class='ectt-0800'> </span><span id='textcolor2310'><span class='ectt-0800'>/* If my_tty is NULL, the current task has no tty you can print to (i.e.,</span></span>
|
|
<a id='x1-51036r18'></a><span class='ecrm-0500'>18</span><span id='textcolor2311'><span class='ectt-0800'> * if it is a daemon). If so, there is nothing we can do.</span></span>
|
|
<a id='x1-51038r19'></a><span class='ecrm-0500'>19</span><span id='textcolor2312'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-51040r20'></a><span class='ecrm-0500'>20</span><span class='ectt-0800'> </span><span id='textcolor2313'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (my_tty) {</span>
|
|
<a id='x1-51042r21'></a><span class='ecrm-0500'>21</span><span class='ectt-0800'> </span><span id='textcolor2314'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor2315'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> tty_operations *ttyops = my_tty->driver->ops;</span>
|
|
<a id='x1-51044r22'></a><span class='ecrm-0500'>22</span><span class='ectt-0800'> </span><span id='textcolor2316'><span class='ectt-0800'>/* my_tty->driver is a struct which holds the tty</span><span class='tctt-0800'>'</span><span class='ectt-0800'>s functions,</span></span>
|
|
<a id='x1-51046r23'></a><span class='ecrm-0500'>23</span><span id='textcolor2317'><span class='ectt-0800'> * one of which (write) is used to write strings to the tty.</span></span>
|
|
<a id='x1-51048r24'></a><span class='ecrm-0500'>24</span><span id='textcolor2318'><span class='ectt-0800'> * It can be used to take a string either from the user</span><span class='tctt-0800'>'</span><span class='ectt-0800'>s or</span></span>
|
|
<a id='x1-51050r25'></a><span class='ecrm-0500'>25</span><span id='textcolor2319'><span class='ectt-0800'> * kernel</span><span class='tctt-0800'>'</span><span class='ectt-0800'>s memory segment.</span></span>
|
|
<a id='x1-51052r26'></a><span class='ecrm-0500'>26</span><span id='textcolor2320'><span class='ectt-0800'> *</span></span>
|
|
<a id='x1-51054r27'></a><span class='ecrm-0500'>27</span><span id='textcolor2321'><span class='ectt-0800'> * The function</span><span class='tctt-0800'>'</span><span class='ectt-0800'>s 1st parameter is the tty to write to, because the</span></span>
|
|
<a id='x1-51056r28'></a><span class='ecrm-0500'>28</span><span id='textcolor2322'><span class='ectt-0800'> * same function would normally be used for all tty</span><span class='tctt-0800'>'</span><span class='ectt-0800'>s of a certain</span></span>
|
|
<a id='x1-51058r29'></a><span class='ecrm-0500'>29</span><span id='textcolor2323'><span class='ectt-0800'> * type.</span></span>
|
|
<a id='x1-51060r30'></a><span class='ecrm-0500'>30</span><span id='textcolor2324'><span class='ectt-0800'> * The 2nd parameter is a pointer to a string.</span></span>
|
|
<a id='x1-51062r31'></a><span class='ecrm-0500'>31</span><span id='textcolor2325'><span class='ectt-0800'> * The 3rd parameter is the length of the string.</span></span>
|
|
<a id='x1-51064r32'></a><span class='ecrm-0500'>32</span><span id='textcolor2326'><span class='ectt-0800'> *</span></span>
|
|
<a id='x1-51066r33'></a><span class='ecrm-0500'>33</span><span id='textcolor2327'><span class='ectt-0800'> * As you will see below, sometimes it</span><span class='tctt-0800'>'</span><span class='ectt-0800'>s necessary to use</span></span>
|
|
<a id='x1-51068r34'></a><span class='ecrm-0500'>34</span><span id='textcolor2328'><span class='ectt-0800'> * preprocessor stuff to create code that works for different</span></span>
|
|
<a id='x1-51070r35'></a><span class='ecrm-0500'>35</span><span id='textcolor2329'><span class='ectt-0800'> * kernel versions. The (naive) approach we</span><span class='tctt-0800'>'</span><span class='ectt-0800'>ve taken here does not</span></span>
|
|
<a id='x1-51072r36'></a><span class='ecrm-0500'>36</span><span id='textcolor2330'><span class='ectt-0800'> * scale well. The right way to deal with this is described in</span></span>
|
|
<a id='x1-51074r37'></a><span class='ecrm-0500'>37</span><span id='textcolor2331'><span class='ectt-0800'> * section 2 of</span></span>
|
|
<a id='x1-51076r38'></a><span class='ecrm-0500'>38</span><span id='textcolor2332'><span class='ectt-0800'> * linux/Documentation/SubmittingPatches</span></span>
|
|
<a id='x1-51078r39'></a><span class='ecrm-0500'>39</span><span id='textcolor2333'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-51080r40'></a><span class='ecrm-0500'>40</span><span class='ectt-0800'> (ttyops->write)(my_tty, </span><span id='textcolor2334'><span class='ectt-0800'>/* The tty itself */</span></span>
|
|
<a id='x1-51082r41'></a><span class='ecrm-0500'>41</span><span class='ectt-0800'> str, </span><span id='textcolor2335'><span class='ectt-0800'>/* String */</span></span>
|
|
<a id='x1-51084r42'></a><span class='ecrm-0500'>42</span><span class='ectt-0800'> strlen(str)); </span><span id='textcolor2336'><span class='ectt-0800'>/* Length */</span></span>
|
|
<a id='x1-51086r43'></a><span class='ecrm-0500'>43</span>
|
|
<a id='x1-51088r44'></a><span class='ecrm-0500'>44</span><span class='ectt-0800'> </span><span id='textcolor2337'><span class='ectt-0800'>/* ttys were originally hardware devices, which (usually) strictly</span></span>
|
|
<a id='x1-51090r45'></a><span class='ecrm-0500'>45</span><span id='textcolor2338'><span class='ectt-0800'> * followed the ASCII standard. In ASCII, to move to a new line you</span></span>
|
|
<a id='x1-51092r46'></a><span class='ecrm-0500'>46</span><span id='textcolor2339'><span class='ectt-0800'> * need two characters, a carriage return and a line feed. On Unix,</span></span>
|
|
<a id='x1-51094r47'></a><span class='ecrm-0500'>47</span><span id='textcolor2340'><span class='ectt-0800'> * the ASCII line feed is used for both purposes - so we can not</span></span>
|
|
<a id='x1-51096r48'></a><span class='ecrm-0500'>48</span><span id='textcolor2341'><span class='ectt-0800'> * just use \n, because it would not have a carriage return and the</span></span>
|
|
<a id='x1-51098r49'></a><span class='ecrm-0500'>49</span><span id='textcolor2342'><span class='ectt-0800'> * next line will start at the column right after the line feed.</span></span>
|
|
<a id='x1-51100r50'></a><span class='ecrm-0500'>50</span><span id='textcolor2343'><span class='ectt-0800'> *</span></span>
|
|
<a id='x1-51102r51'></a><span class='ecrm-0500'>51</span><span id='textcolor2344'><span class='ectt-0800'> * This is why text files are different between Unix and MS Windows.</span></span>
|
|
<a id='x1-51104r52'></a><span class='ecrm-0500'>52</span><span id='textcolor2345'><span class='ectt-0800'> * In CP/M and derivatives, like MS-DOS and MS Windows, the ASCII</span></span>
|
|
<a id='x1-51106r53'></a><span class='ecrm-0500'>53</span><span id='textcolor2346'><span class='ectt-0800'> * standard was strictly adhered to, and therefore a newline requires</span></span>
|
|
<a id='x1-51108r54'></a><span class='ecrm-0500'>54</span><span id='textcolor2347'><span class='ectt-0800'> * both a LF and a CR.</span></span>
|
|
<a id='x1-51110r55'></a><span class='ecrm-0500'>55</span><span id='textcolor2348'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-51112r56'></a><span class='ecrm-0500'>56</span><span class='ectt-0800'> (ttyops->write)(my_tty, </span><span id='textcolor2349'><span class='ectt-0800'>"</span></span><span id='textcolor2350'><span class='ectt-0800'>\015\012</span></span><span id='textcolor2351'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, 2);</span>
|
|
<a id='x1-51114r57'></a><span class='ecrm-0500'>57</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-51116r58'></a><span class='ecrm-0500'>58</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-51118r59'></a><span class='ecrm-0500'>59</span>
|
|
<a id='x1-51120r60'></a><span class='ecrm-0500'>60</span><span id='textcolor2352'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2353'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __init print_string_init(</span><span id='textcolor2354'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-51122r61'></a><span class='ecrm-0500'>61</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-51124r62'></a><span class='ecrm-0500'>62</span><span class='ectt-0800'> print_string(</span><span id='textcolor2355'><span class='ectt-0800'>"The module has been inserted. Hello world!"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-51126r63'></a><span class='ecrm-0500'>63</span><span class='ectt-0800'> </span><span id='textcolor2356'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-51128r64'></a><span class='ecrm-0500'>64</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-51130r65'></a><span class='ecrm-0500'>65</span>
|
|
<a id='x1-51132r66'></a><span class='ecrm-0500'>66</span><span id='textcolor2357'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2358'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> __exit print_string_exit(</span><span id='textcolor2359'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-51134r67'></a><span class='ecrm-0500'>67</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-51136r68'></a><span class='ecrm-0500'>68</span><span class='ectt-0800'> print_string(</span><span id='textcolor2360'><span class='ectt-0800'>"The module has been removed. Farewell world!"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-51138r69'></a><span class='ecrm-0500'>69</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-51140r70'></a><span class='ecrm-0500'>70</span>
|
|
<a id='x1-51142r71'></a><span class='ecrm-0500'>71</span><span class='ectt-0800'>module_init(print_string_init);</span>
|
|
<a id='x1-51144r72'></a><span class='ecrm-0500'>72</span><span class='ectt-0800'>module_exit(print_string_exit);</span>
|
|
<a id='x1-51146r73'></a><span class='ecrm-0500'>73</span>
|
|
<a id='x1-51148r74'></a><span class='ecrm-0500'>74</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor2361'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span></pre>
|
|
<!-- l. 1752 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='flashing-keyboard-leds'><span class='titlemark'>13.2 </span> <a id='x1-5200013.2'></a>Flashing keyboard LEDs</h4>
|
|
<!-- l. 1754 --><p class='noindent'>In certain conditions, you may desire a simpler and more direct way to communicate
|
|
to the external world. Flashing keyboard LEDs can be such a solution: It is an
|
|
immediate way to attract attention or to display a status condition. Keyboard LEDs
|
|
are present on every hardware, they are always visible, they do not need any setup,
|
|
and their use is rather simple and non-intrusive, compared to writing to a tty or a
|
|
file.
|
|
</p><!-- l. 1758 --><p class='indent'> From v4.14 to v4.15, the timer API made a series of changes
|
|
to improve memory safety. A buffer overflow in the area of a
|
|
<code> <span class='ectt-1000'>timer_list</span>
|
|
</code> structure may be able to overwrite the
|
|
<code> <span class='ectt-1000'>function</span>
|
|
</code> and <code> <span class='ectt-1000'>data</span>
|
|
</code> fields, providing the attacker with a way to use return-object programming (ROP)
|
|
to call arbitrary functions within the kernel. Also, the function prototype of the callback,
|
|
containing a <code> <span id='textcolor2362'><span class='ectt-1000'>unsigned</span></span><span class='ectt-1000'> </span><span id='textcolor2363'><span class='ectt-1000'>long</span></span>
|
|
</code> argument, will prevent work from any type checking. Furthermore, the function prototype
|
|
with <code> <span id='textcolor2364'><span class='ectt-1000'>unsigned</span></span><span class='ectt-1000'> </span><span id='textcolor2365'><span class='ectt-1000'>long</span></span>
|
|
</code> argument may be an obstacle to the forward-edge protection of <span class='ecti-1000'>control-flow integrity</span>.
|
|
Thus, it is better to use a unique prototype to separate from the cluster that takes an
|
|
<code> <span id='textcolor2366'><span class='ectt-1000'>unsigned</span></span><span class='ectt-1000'> </span><span id='textcolor2367'><span class='ectt-1000'>long</span></span>
|
|
</code> argument. The timer callback should be passed a pointer to the
|
|
<code> <span class='ectt-1000'>timer_list</span>
|
|
|
|
|
|
|
|
</code> structure rather than an <code> <span id='textcolor2368'><span class='ectt-1000'>unsigned</span></span><span class='ectt-1000'> </span><span id='textcolor2369'><span class='ectt-1000'>long</span></span>
|
|
</code> argument. Then, it wraps all the information the callback needs, including the
|
|
<code> <span class='ectt-1000'>timer_list</span>
|
|
</code> structure, into a larger structure, and it can use the
|
|
<code> <span class='ectt-1000'>container_of</span>
|
|
</code> macro instead of the <code> <span id='textcolor2370'><span class='ectt-1000'>unsigned</span></span><span class='ectt-1000'> </span><span id='textcolor2371'><span class='ectt-1000'>long</span></span>
|
|
</code> value. For more information see: <a href='https://lwn.net/Articles/735887/'>Improving the kernel timers API</a>.
|
|
</p><!-- l. 1767 --><p class='indent'> Before Linux v4.14, <code> <span class='ectt-1000'>setup_timer</span>
|
|
</code> was used to initialize the timer and the
|
|
<code> <span class='ectt-1000'>timer_list</span>
|
|
</code> structure looked like:
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb74'><a id='x1-52025r1'></a><span class='ecrm-0500'>1</span><span id='textcolor2372'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> timer_list {</span>
|
|
<a id='x1-52027r2'></a><span class='ecrm-0500'>2</span><span class='ectt-0800'> </span><span id='textcolor2373'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor2374'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> expires;</span>
|
|
<a id='x1-52029r3'></a><span class='ecrm-0500'>3</span><span class='ectt-0800'> </span><span id='textcolor2375'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> (*function)(</span><span id='textcolor2376'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor2377'><span class='ectt-0800'>long</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-52031r4'></a><span class='ecrm-0500'>4</span><span class='ectt-0800'> </span><span id='textcolor2378'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor2379'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> data;</span>
|
|
<a id='x1-52033r5'></a><span class='ecrm-0500'>5</span><span class='ectt-0800'> u32 flags;</span>
|
|
<a id='x1-52035r6'></a><span class='ecrm-0500'>6</span><span class='ectt-0800'> </span><span id='textcolor2380'><span class='ectt-0800'>/* ... */</span></span>
|
|
<a id='x1-52037r7'></a><span class='ecrm-0500'>7</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-52039r8'></a><span class='ecrm-0500'>8</span>
|
|
<a id='x1-52041r9'></a><span class='ecrm-0500'>9</span><span id='textcolor2381'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> setup_timer(</span><span id='textcolor2382'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> timer_list *timer, </span><span id='textcolor2383'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> (*callback)(</span><span id='textcolor2384'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor2385'><span class='ectt-0800'>long</span></span><span class='ectt-0800'>),</span>
|
|
<a id='x1-52043r10'></a><span class='ecrm-0500'>10</span><span class='ectt-0800'> </span><span id='textcolor2386'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor2387'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> data);</span></pre>
|
|
<!-- l. 1781 --><p class='indent'> Since Linux v4.14, <code> <span class='ectt-1000'>timer_setup</span>
|
|
</code> is adopted and the kernel step by step converting to
|
|
<code> <span class='ectt-1000'>timer_setup</span>
|
|
</code> from <code> <span class='ectt-1000'>setup_timer</span>
|
|
</code>. One of the reasons why API was changed is it need to coexist with the old version interface.
|
|
Moreover, the <code> <span class='ectt-1000'>timer_setup</span>
|
|
</code> was implemented by <code> <span class='ectt-1000'>setup_timer</span>
|
|
</code> at first.
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb75'><a id='x1-52052r1'></a><span class='ecrm-0500'>1</span><span id='textcolor2388'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> timer_setup(</span><span id='textcolor2389'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> timer_list *timer,</span>
|
|
<a id='x1-52054r2'></a><span class='ecrm-0500'>2</span><span class='ectt-0800'> </span><span id='textcolor2390'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> (*callback)(</span><span id='textcolor2391'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> timer_list *), </span><span id='textcolor2392'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor2393'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> flags);</span></pre>
|
|
<!-- l. 1789 --><p class='indent'> The <code> <span class='ectt-1000'>setup_timer</span>
|
|
</code> was then removed since v4.15. As a result, the
|
|
<code> <span class='ectt-1000'>timer_list</span>
|
|
</code> structure had changed to the following.
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb76'><a id='x1-52064r1'></a><span class='ecrm-0500'>1</span><span id='textcolor2394'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> timer_list {</span>
|
|
<a id='x1-52066r2'></a><span class='ecrm-0500'>2</span><span class='ectt-0800'> </span><span id='textcolor2395'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor2396'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> expires;</span>
|
|
<a id='x1-52068r3'></a><span class='ecrm-0500'>3</span><span class='ectt-0800'> </span><span id='textcolor2397'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> (*function)(</span><span id='textcolor2398'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> timer_list *);</span>
|
|
<a id='x1-52070r4'></a><span class='ecrm-0500'>4</span><span class='ectt-0800'> u32 flags;</span>
|
|
<a id='x1-52072r5'></a><span class='ecrm-0500'>5</span><span class='ectt-0800'> </span><span id='textcolor2399'><span class='ectt-0800'>/* ... */</span></span>
|
|
<a id='x1-52074r6'></a><span class='ecrm-0500'>6</span><span class='ectt-0800'>};</span></pre>
|
|
<!-- l. 1800 --><p class='indent'> The following source code illustrates a minimal kernel module which, when
|
|
loaded, starts blinking the keyboard LEDs until it is unloaded.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb77'><a id='x1-52076r1'></a><span class='ecrm-0500'>1</span><span id='textcolor2400'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-52078r2'></a><span class='ecrm-0500'>2</span><span id='textcolor2401'><span class='ectt-0800'> * kbleds.c - Blink keyboard leds until the module is unloaded.</span></span>
|
|
<a id='x1-52080r3'></a><span class='ecrm-0500'>3</span><span id='textcolor2402'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-52082r4'></a><span class='ecrm-0500'>4</span>
|
|
<a id='x1-52084r5'></a><span class='ecrm-0500'>5</span><span id='textcolor2403'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2404'><span class='ectt-0800'><linux/init.h></span></span>
|
|
<a id='x1-52086r6'></a><span class='ecrm-0500'>6</span><span id='textcolor2405'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2406'><span class='ectt-0800'><linux/kd.h> /* For KDSETLED */</span></span>
|
|
<a id='x1-52088r7'></a><span class='ecrm-0500'>7</span><span id='textcolor2407'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2408'><span class='ectt-0800'><linux/module.h></span></span>
|
|
<a id='x1-52090r8'></a><span class='ecrm-0500'>8</span><span id='textcolor2409'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2410'><span class='ectt-0800'><linux/tty.h> /* For tty_struct */</span></span>
|
|
<a id='x1-52092r9'></a><span class='ecrm-0500'>9</span><span id='textcolor2411'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2412'><span class='ectt-0800'><linux/vt.h> /* For MAX_NR_CONSOLES */</span></span>
|
|
<a id='x1-52094r10'></a><span class='ecrm-0500'>10</span><span id='textcolor2413'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2414'><span class='ectt-0800'><linux/vt_kern.h> /* for fg_console */</span></span>
|
|
<a id='x1-52096r11'></a><span class='ecrm-0500'>11</span><span id='textcolor2415'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2416'><span class='ectt-0800'><linux/console_struct.h> /* For vc_cons */</span></span>
|
|
<a id='x1-52098r12'></a><span class='ecrm-0500'>12</span>
|
|
<a id='x1-52100r13'></a><span class='ecrm-0500'>13</span><span class='ectt-0800'>MODULE_DESCRIPTION(</span><span id='textcolor2417'><span class='ectt-0800'>"Example module illustrating the use of Keyboard LEDs."</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-52102r14'></a><span class='ecrm-0500'>14</span>
|
|
<a id='x1-52104r15'></a><span class='ecrm-0500'>15</span><span id='textcolor2418'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2419'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> timer_list my_timer;</span>
|
|
<a id='x1-52106r16'></a><span class='ecrm-0500'>16</span><span id='textcolor2420'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2421'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> tty_driver *my_driver;</span>
|
|
<a id='x1-52108r17'></a><span class='ecrm-0500'>17</span><span id='textcolor2422'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2423'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor2424'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> kbledstatus = 0;</span>
|
|
<a id='x1-52110r18'></a><span class='ecrm-0500'>18</span>
|
|
<a id='x1-52112r19'></a><span class='ecrm-0500'>19</span><span id='textcolor2425'><span class='ectt-0800'>#define BLINK_DELAY HZ / 5</span></span>
|
|
<a id='x1-52114r20'></a><span class='ecrm-0500'>20</span><span id='textcolor2426'><span class='ectt-0800'>#define ALL_LEDS_ON 0x07</span></span>
|
|
<a id='x1-52116r21'></a><span class='ecrm-0500'>21</span><span id='textcolor2427'><span class='ectt-0800'>#define RESTORE_LEDS 0xFF</span></span>
|
|
<a id='x1-52118r22'></a><span class='ecrm-0500'>22</span>
|
|
<a id='x1-52120r23'></a><span class='ecrm-0500'>23</span><span id='textcolor2428'><span class='ectt-0800'>/* Function my_timer_func blinks the keyboard LEDs periodically by invoking</span></span>
|
|
<a id='x1-52122r24'></a><span class='ecrm-0500'>24</span><span id='textcolor2429'><span class='ectt-0800'> * command KDSETLED of ioctl() on the keyboard driver. To learn more on virtual</span></span>
|
|
<a id='x1-52124r25'></a><span class='ecrm-0500'>25</span><span id='textcolor2430'><span class='ectt-0800'> * terminal ioctl operations, please see file:</span></span>
|
|
<a id='x1-52126r26'></a><span class='ecrm-0500'>26</span><span id='textcolor2431'><span class='ectt-0800'> * drivers/tty/vt/vt_ioctl.c, function vt_ioctl().</span></span>
|
|
<a id='x1-52128r27'></a><span class='ecrm-0500'>27</span><span id='textcolor2432'><span class='ectt-0800'> *</span></span>
|
|
<a id='x1-52130r28'></a><span class='ecrm-0500'>28</span><span id='textcolor2433'><span class='ectt-0800'> * The argument to KDSETLED is alternatively set to 7 (thus causing the led</span></span>
|
|
<a id='x1-52132r29'></a><span class='ecrm-0500'>29</span><span id='textcolor2434'><span class='ectt-0800'> * mode to be set to LED_SHOW_IOCTL, and all the leds are lit) and to 0xFF</span></span>
|
|
<a id='x1-52134r30'></a><span class='ecrm-0500'>30</span><span id='textcolor2435'><span class='ectt-0800'> * (any value above 7 switches back the led mode to LED_SHOW_FLAGS, thus</span></span>
|
|
<a id='x1-52136r31'></a><span class='ecrm-0500'>31</span><span id='textcolor2436'><span class='ectt-0800'> * the LEDs reflect the actual keyboard status). To learn more on this,</span></span>
|
|
<a id='x1-52138r32'></a><span class='ecrm-0500'>32</span><span id='textcolor2437'><span class='ectt-0800'> * please see file: drivers/tty/vt/keyboard.c, function setledstate().</span></span>
|
|
<a id='x1-52140r33'></a><span class='ecrm-0500'>33</span><span id='textcolor2438'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-52142r34'></a><span class='ecrm-0500'>34</span><span id='textcolor2439'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2440'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> my_timer_func(</span><span id='textcolor2441'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> timer_list *unused)</span>
|
|
<a id='x1-52144r35'></a><span class='ecrm-0500'>35</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-52146r36'></a><span class='ecrm-0500'>36</span><span class='ectt-0800'> </span><span id='textcolor2442'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> tty_struct *t = vc_cons[fg_console].d->port.tty;</span>
|
|
<a id='x1-52148r37'></a><span class='ecrm-0500'>37</span>
|
|
<a id='x1-52150r38'></a><span class='ecrm-0500'>38</span><span class='ectt-0800'> </span><span id='textcolor2443'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (kbledstatus == ALL_LEDS_ON)</span>
|
|
<a id='x1-52152r39'></a><span class='ecrm-0500'>39</span><span class='ectt-0800'> kbledstatus = RESTORE_LEDS;</span>
|
|
<a id='x1-52154r40'></a><span class='ecrm-0500'>40</span><span class='ectt-0800'> </span><span id='textcolor2444'><span class='ectt-0800'>else</span></span>
|
|
<a id='x1-52156r41'></a><span class='ecrm-0500'>41</span><span class='ectt-0800'> kbledstatus = ALL_LEDS_ON;</span>
|
|
<a id='x1-52158r42'></a><span class='ecrm-0500'>42</span>
|
|
<a id='x1-52160r43'></a><span class='ecrm-0500'>43</span><span class='ectt-0800'> (my_driver->ops->ioctl)(t, KDSETLED, kbledstatus);</span>
|
|
<a id='x1-52162r44'></a><span class='ecrm-0500'>44</span>
|
|
<a id='x1-52164r45'></a><span class='ecrm-0500'>45</span><span class='ectt-0800'> my_timer.expires = jiffies + BLINK_DELAY;</span>
|
|
<a id='x1-52166r46'></a><span class='ecrm-0500'>46</span><span class='ectt-0800'> add_timer(&my_timer);</span>
|
|
<a id='x1-52168r47'></a><span class='ecrm-0500'>47</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-52170r48'></a><span class='ecrm-0500'>48</span>
|
|
<a id='x1-52172r49'></a><span class='ecrm-0500'>49</span><span id='textcolor2445'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2446'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __init kbleds_init(</span><span id='textcolor2447'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-52174r50'></a><span class='ecrm-0500'>50</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-52176r51'></a><span class='ecrm-0500'>51</span><span class='ectt-0800'> </span><span id='textcolor2448'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> i;</span>
|
|
<a id='x1-52178r52'></a><span class='ecrm-0500'>52</span>
|
|
<a id='x1-52180r53'></a><span class='ecrm-0500'>53</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2449'><span class='ectt-0800'>"kbleds: loading</span></span><span id='textcolor2450'><span class='ectt-0800'>\n</span></span><span id='textcolor2451'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-52182r54'></a><span class='ecrm-0500'>54</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2452'><span class='ectt-0800'>"kbleds: fgconsole is %x</span></span><span id='textcolor2453'><span class='ectt-0800'>\n</span></span><span id='textcolor2454'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, fg_console);</span>
|
|
<a id='x1-52184r55'></a><span class='ecrm-0500'>55</span><span class='ectt-0800'> </span><span id='textcolor2455'><span class='ectt-0800'>for</span></span><span class='ectt-0800'> (i = 0; i < MAX_NR_CONSOLES; i++) {</span>
|
|
<a id='x1-52186r56'></a><span class='ecrm-0500'>56</span><span class='ectt-0800'> </span><span id='textcolor2456'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (!vc_cons[i].d)</span>
|
|
<a id='x1-52188r57'></a><span class='ecrm-0500'>57</span><span class='ectt-0800'> </span><span id='textcolor2457'><span class='ectt-0800'>break</span></span><span class='ectt-0800'>;</span>
|
|
<a id='x1-52190r58'></a><span class='ecrm-0500'>58</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2458'><span class='ectt-0800'>"poet_atkm: console[%i/%i] #%i, tty %p</span></span><span id='textcolor2459'><span class='ectt-0800'>\n</span></span><span id='textcolor2460'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, i, MAX_NR_CONSOLES,</span>
|
|
<a id='x1-52192r59'></a><span class='ecrm-0500'>59</span><span class='ectt-0800'> vc_cons[i].d->vc_num, (</span><span id='textcolor2461'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> *)vc_cons[i].d->port.tty);</span>
|
|
<a id='x1-52194r60'></a><span class='ecrm-0500'>60</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-52196r61'></a><span class='ecrm-0500'>61</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2462'><span class='ectt-0800'>"kbleds: finished scanning consoles</span></span><span id='textcolor2463'><span class='ectt-0800'>\n</span></span><span id='textcolor2464'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-52198r62'></a><span class='ecrm-0500'>62</span>
|
|
<a id='x1-52200r63'></a><span class='ecrm-0500'>63</span><span class='ectt-0800'> my_driver = vc_cons[fg_console].d->port.tty->driver;</span>
|
|
<a id='x1-52202r64'></a><span class='ecrm-0500'>64</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2465'><span class='ectt-0800'>"kbleds: tty driver name %s</span></span><span id='textcolor2466'><span class='ectt-0800'>\n</span></span><span id='textcolor2467'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, my_driver->driver_name);</span>
|
|
<a id='x1-52204r65'></a><span class='ecrm-0500'>65</span>
|
|
<a id='x1-52206r66'></a><span class='ecrm-0500'>66</span><span class='ectt-0800'> </span><span id='textcolor2468'><span class='ectt-0800'>/* Set up the LED blink timer the first time. */</span></span>
|
|
<a id='x1-52208r67'></a><span class='ecrm-0500'>67</span><span class='ectt-0800'> timer_setup(&my_timer, my_timer_func, 0);</span>
|
|
<a id='x1-52210r68'></a><span class='ecrm-0500'>68</span><span class='ectt-0800'> my_timer.expires = jiffies + BLINK_DELAY;</span>
|
|
<a id='x1-52212r69'></a><span class='ecrm-0500'>69</span><span class='ectt-0800'> add_timer(&my_timer);</span>
|
|
<a id='x1-52214r70'></a><span class='ecrm-0500'>70</span>
|
|
<a id='x1-52216r71'></a><span class='ecrm-0500'>71</span><span class='ectt-0800'> </span><span id='textcolor2469'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-52218r72'></a><span class='ecrm-0500'>72</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-52220r73'></a><span class='ecrm-0500'>73</span>
|
|
<a id='x1-52222r74'></a><span class='ecrm-0500'>74</span><span id='textcolor2470'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2471'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> __exit kbleds_cleanup(</span><span id='textcolor2472'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-52224r75'></a><span class='ecrm-0500'>75</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-52226r76'></a><span class='ecrm-0500'>76</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2473'><span class='ectt-0800'>"kbleds: unloading...</span></span><span id='textcolor2474'><span class='ectt-0800'>\n</span></span><span id='textcolor2475'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-52228r77'></a><span class='ecrm-0500'>77</span><span class='ectt-0800'> del_timer(&my_timer);</span>
|
|
<a id='x1-52230r78'></a><span class='ecrm-0500'>78</span><span class='ectt-0800'> (my_driver->ops->ioctl)(vc_cons[fg_console].d->port.tty, KDSETLED,</span>
|
|
<a id='x1-52232r79'></a><span class='ecrm-0500'>79</span><span class='ectt-0800'> RESTORE_LEDS);</span>
|
|
<a id='x1-52234r80'></a><span class='ecrm-0500'>80</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-52236r81'></a><span class='ecrm-0500'>81</span>
|
|
<a id='x1-52238r82'></a><span class='ecrm-0500'>82</span><span class='ectt-0800'>module_init(kbleds_init);</span>
|
|
<a id='x1-52240r83'></a><span class='ecrm-0500'>83</span><span class='ectt-0800'>module_exit(kbleds_cleanup);</span>
|
|
<a id='x1-52242r84'></a><span class='ecrm-0500'>84</span>
|
|
<a id='x1-52244r85'></a><span class='ecrm-0500'>85</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor2476'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span></pre>
|
|
<!-- l. 1804 --><p class='indent'> If none of the examples in this chapter fit your debugging needs,
|
|
there might yet be some other tricks to try. Ever wondered what
|
|
<code> <span class='ectt-1000'>CONFIG_LL_DEBUG</span>
|
|
</code> in <code> <span class='ectt-1000'>make menuconfig</span>
|
|
</code> is good for? If you activate that you get low level access to the serial port. While this
|
|
|
|
|
|
|
|
might not sound very powerful by itself, you can patch <a href='https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/kernel/printk.c'>kernel/printk.c</a> or any other
|
|
essential syscall to print ASCII characters, thus making it possible to trace virtually
|
|
everything what your code does over a serial line. If you find yourself porting the
|
|
kernel to some new and former unsupported architecture, this is usually amongst the
|
|
first things that should be implemented. Logging over a netconsole might also be
|
|
worth a try.
|
|
</p><!-- l. 1811 --><p class='indent'> While you have seen lots of stuff that can be used to aid debugging here, there are
|
|
some things to be aware of. Debugging is almost always intrusive. Adding debug code
|
|
can change the situation enough to make the bug seem to disappear. Thus, you
|
|
should keep debug code to a minimum and make sure it does not show up in
|
|
production code.
|
|
</p><!-- l. 1815 --><p class='noindent'>
|
|
</p>
|
|
<h3 class='sectionHead' id='scheduling-tasks'><span class='titlemark'>14 </span> <a id='x1-5300014'></a>Scheduling Tasks</h3>
|
|
<!-- l. 1817 --><p class='noindent'>There are two main ways of running tasks: tasklets and work queues. Tasklets are a
|
|
quick and easy way of scheduling a single function to be run. For example, when
|
|
triggered from an interrupt, whereas work queues are more complicated but also
|
|
better suited to running multiple things in a sequence.
|
|
</p><!-- l. 1821 --><p class='indent'> It is possible that in future tasklets may be replaced by <span class='ecti-1000'>threaded irqs</span>. However,
|
|
discussion about that has been ongoing since 2007 (<a href='https://lwn.net/Articles/239633'>Eliminating tasklets</a>), so do
|
|
not hold your breath. See the section <a href='#interrupt-handlers1'>15.1<!-- tex4ht:ref: sec:irq --></a> if you wish to avoid the tasklet
|
|
debate.
|
|
</p><!-- l. 1825 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='tasklets'><span class='titlemark'>14.1 </span> <a id='x1-5400014.1'></a>Tasklets</h4>
|
|
<!-- l. 1827 --><p class='noindent'>Here is an example tasklet module. The
|
|
<code> <span class='ectt-1000'>tasklet_fn</span>
|
|
</code> function runs for a few seconds. In the meantime, execution of the
|
|
<code> <span class='ectt-1000'>example_tasklet_init</span>
|
|
</code> function may continue to the exit point, depending on whether it is interrupted by
|
|
<span class='ecbx-1000'>softirq</span>.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb78'><a id='x1-54004r1'></a><span class='ecrm-0500'>1</span><span id='textcolor2477'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-54006r2'></a><span class='ecrm-0500'>2</span><span id='textcolor2478'><span class='ectt-0800'> * example_tasklet.c</span></span>
|
|
<a id='x1-54008r3'></a><span class='ecrm-0500'>3</span><span id='textcolor2479'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-54010r4'></a><span class='ecrm-0500'>4</span><span id='textcolor2480'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2481'><span class='ectt-0800'><linux/delay.h></span></span>
|
|
<a id='x1-54012r5'></a><span class='ecrm-0500'>5</span><span id='textcolor2482'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2483'><span class='ectt-0800'><linux/interrupt.h></span></span>
|
|
<a id='x1-54014r6'></a><span class='ecrm-0500'>6</span><span id='textcolor2484'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2485'><span class='ectt-0800'><linux/module.h></span></span>
|
|
<a id='x1-54016r7'></a><span class='ecrm-0500'>7</span><span id='textcolor2486'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2487'><span class='ectt-0800'><linux/printk.h></span></span>
|
|
<a id='x1-54018r8'></a><span class='ecrm-0500'>8</span>
|
|
<a id='x1-54020r9'></a><span class='ecrm-0500'>9</span><span id='textcolor2488'><span class='ectt-0800'>/* Macro DECLARE_TASKLET_OLD exists for compatibility.</span></span>
|
|
<a id='x1-54022r10'></a><span class='ecrm-0500'>10</span><span id='textcolor2489'><span class='ectt-0800'> * See https://lwn.net/Articles/830964/</span></span>
|
|
<a id='x1-54024r11'></a><span class='ecrm-0500'>11</span><span id='textcolor2490'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-54026r12'></a><span class='ecrm-0500'>12</span><span id='textcolor2491'><span class='ectt-0800'>#ifndef DECLARE_TASKLET_OLD</span></span>
|
|
<a id='x1-54028r13'></a><span class='ecrm-0500'>13</span><span id='textcolor2492'><span class='ectt-0800'>#define DECLARE_TASKLET_OLD(arg1, arg2) DECLARE_TASKLET(arg1, arg2, 0L)</span></span>
|
|
<a id='x1-54030r14'></a><span class='ecrm-0500'>14</span><span id='textcolor2493'><span class='ectt-0800'>#endif</span></span>
|
|
<a id='x1-54032r15'></a><span class='ecrm-0500'>15</span>
|
|
<a id='x1-54034r16'></a><span class='ecrm-0500'>16</span><span id='textcolor2494'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2495'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> tasklet_fn(</span><span id='textcolor2496'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor2497'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> data)</span>
|
|
<a id='x1-54036r17'></a><span class='ecrm-0500'>17</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-54038r18'></a><span class='ecrm-0500'>18</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2498'><span class='ectt-0800'>"Example tasklet starts</span></span><span id='textcolor2499'><span class='ectt-0800'>\n</span></span><span id='textcolor2500'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-54040r19'></a><span class='ecrm-0500'>19</span><span class='ectt-0800'> mdelay(5000);</span>
|
|
<a id='x1-54042r20'></a><span class='ecrm-0500'>20</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2501'><span class='ectt-0800'>"Example tasklet ends</span></span><span id='textcolor2502'><span class='ectt-0800'>\n</span></span><span id='textcolor2503'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-54044r21'></a><span class='ecrm-0500'>21</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-54046r22'></a><span class='ecrm-0500'>22</span>
|
|
<a id='x1-54048r23'></a><span class='ecrm-0500'>23</span><span id='textcolor2504'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> DECLARE_TASKLET_OLD(mytask, tasklet_fn);</span>
|
|
<a id='x1-54050r24'></a><span class='ecrm-0500'>24</span>
|
|
<a id='x1-54052r25'></a><span class='ecrm-0500'>25</span><span id='textcolor2505'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2506'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __init example_tasklet_init(</span><span id='textcolor2507'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-54054r26'></a><span class='ecrm-0500'>26</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-54056r27'></a><span class='ecrm-0500'>27</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2508'><span class='ectt-0800'>"tasklet example init</span></span><span id='textcolor2509'><span class='ectt-0800'>\n</span></span><span id='textcolor2510'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-54058r28'></a><span class='ecrm-0500'>28</span><span class='ectt-0800'> tasklet_schedule(&mytask);</span>
|
|
<a id='x1-54060r29'></a><span class='ecrm-0500'>29</span><span class='ectt-0800'> mdelay(200);</span>
|
|
<a id='x1-54062r30'></a><span class='ecrm-0500'>30</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2511'><span class='ectt-0800'>"Example tasklet init continues...</span></span><span id='textcolor2512'><span class='ectt-0800'>\n</span></span><span id='textcolor2513'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-54064r31'></a><span class='ecrm-0500'>31</span><span class='ectt-0800'> </span><span id='textcolor2514'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-54066r32'></a><span class='ecrm-0500'>32</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-54068r33'></a><span class='ecrm-0500'>33</span>
|
|
<a id='x1-54070r34'></a><span class='ecrm-0500'>34</span><span id='textcolor2515'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2516'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> __exit example_tasklet_exit(</span><span id='textcolor2517'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-54072r35'></a><span class='ecrm-0500'>35</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-54074r36'></a><span class='ecrm-0500'>36</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2518'><span class='ectt-0800'>"tasklet example exit</span></span><span id='textcolor2519'><span class='ectt-0800'>\n</span></span><span id='textcolor2520'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-54076r37'></a><span class='ecrm-0500'>37</span><span class='ectt-0800'> tasklet_kill(&mytask);</span>
|
|
<a id='x1-54078r38'></a><span class='ecrm-0500'>38</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-54080r39'></a><span class='ecrm-0500'>39</span>
|
|
<a id='x1-54082r40'></a><span class='ecrm-0500'>40</span><span class='ectt-0800'>module_init(example_tasklet_init);</span>
|
|
<a id='x1-54084r41'></a><span class='ecrm-0500'>41</span><span class='ectt-0800'>module_exit(example_tasklet_exit);</span>
|
|
<a id='x1-54086r42'></a><span class='ecrm-0500'>42</span>
|
|
<a id='x1-54088r43'></a><span class='ecrm-0500'>43</span><span class='ectt-0800'>MODULE_DESCRIPTION(</span><span id='textcolor2521'><span class='ectt-0800'>"Tasklet example"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-54090r44'></a><span class='ecrm-0500'>44</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor2522'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span></pre>
|
|
<!-- l. 1833 --><p class='indent'> So with this example loaded <code> <span class='ectt-1000'>dmesg</span>
|
|
</code> should show:
|
|
|
|
|
|
|
|
</p>
|
|
<pre class='verbatim' id='verbatim-21'>
|
|
tasklet example init
|
|
Example tasklet starts
|
|
Example tasklet init continues...
|
|
Example tasklet ends
|
|
</pre>
|
|
<!-- l. 1840 --><p class='nopar'>Although tasklet is easy to use, it comes with several drawbacks, and developers are
|
|
discussing about getting rid of tasklet in linux kernel. The tasklet callback
|
|
runs in atomic context, inside a software interrupt, meaning that it cannot
|
|
sleep or access user-space data, so not all work can be done in a tasklet
|
|
handler. Also, the kernel only allows one instance of any given tasklet to be
|
|
running at any given time; multiple different tasklet callbacks can run in
|
|
parallel.
|
|
</p><!-- l. 1845 --><p class='indent'> In recent kernels, tasklets can be replaced by workqueues, timers, or threaded
|
|
interrupts.<span class='footnote-mark'><a href='#fn1x0' id='fn1x0-bk'><sup class='textsuperscript'>1</sup></a></span><a id='x1-54092f1'></a>
|
|
While the removal of tasklets remains a longer-term goal, the current kernel contains more
|
|
than a hundred uses of tasklets. Now developers are proceeding with the API changes and
|
|
the macro <code> <span class='ectt-1000'>DECLARE_TASKLET_OLD</span>
|
|
</code> exists for compatibility. For further information, see <a class='url' href='https://lwn.net/Articles/830964/'><span class='ectt-1000'>https://lwn.net/Articles/830964/</span></a>.
|
|
</p><!-- l. 1851 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='work-queues'><span class='titlemark'>14.2 </span> <a id='x1-5500014.2'></a>Work queues</h4>
|
|
<!-- l. 1853 --><p class='noindent'>To add a task to the scheduler we can use a workqueue. The kernel then uses the
|
|
Completely Fair Scheduler (CFS) to execute work within the queue.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb79'><a id='x1-55002r1'></a><span class='ecrm-0500'>1</span><span id='textcolor2523'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-55004r2'></a><span class='ecrm-0500'>2</span><span id='textcolor2524'><span class='ectt-0800'> * sched.c</span></span>
|
|
<a id='x1-55006r3'></a><span class='ecrm-0500'>3</span><span id='textcolor2525'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-55008r4'></a><span class='ecrm-0500'>4</span><span id='textcolor2526'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2527'><span class='ectt-0800'><linux/init.h></span></span>
|
|
<a id='x1-55010r5'></a><span class='ecrm-0500'>5</span><span id='textcolor2528'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2529'><span class='ectt-0800'><linux/module.h></span></span>
|
|
<a id='x1-55012r6'></a><span class='ecrm-0500'>6</span><span id='textcolor2530'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2531'><span class='ectt-0800'><linux/workqueue.h></span></span>
|
|
<a id='x1-55014r7'></a><span class='ecrm-0500'>7</span>
|
|
<a id='x1-55016r8'></a><span class='ecrm-0500'>8</span><span id='textcolor2532'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2533'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> workqueue_struct *queue = NULL;</span>
|
|
<a id='x1-55018r9'></a><span class='ecrm-0500'>9</span><span id='textcolor2534'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2535'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> work_struct work;</span>
|
|
<a id='x1-55020r10'></a><span class='ecrm-0500'>10</span>
|
|
<a id='x1-55022r11'></a><span class='ecrm-0500'>11</span><span id='textcolor2536'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2537'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> work_handler(</span><span id='textcolor2538'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> work_struct *data)</span>
|
|
<a id='x1-55024r12'></a><span class='ecrm-0500'>12</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-55026r13'></a><span class='ecrm-0500'>13</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2539'><span class='ectt-0800'>"work handler function.</span></span><span id='textcolor2540'><span class='ectt-0800'>\n</span></span><span id='textcolor2541'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-55028r14'></a><span class='ecrm-0500'>14</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-55030r15'></a><span class='ecrm-0500'>15</span>
|
|
<a id='x1-55032r16'></a><span class='ecrm-0500'>16</span><span id='textcolor2542'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2543'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __init sched_init(</span><span id='textcolor2544'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-55034r17'></a><span class='ecrm-0500'>17</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-55036r18'></a><span class='ecrm-0500'>18</span><span class='ectt-0800'> queue = alloc_workqueue(</span><span id='textcolor2545'><span class='ectt-0800'>"HELLOWORLD"</span></span><span class='ectt-0800'>, WQ_UNBOUND, 1);</span>
|
|
<a id='x1-55038r19'></a><span class='ecrm-0500'>19</span><span class='ectt-0800'> INIT_WORK(&work, work_handler);</span>
|
|
<a id='x1-55040r20'></a><span class='ecrm-0500'>20</span><span class='ectt-0800'> queue_work(queue, &work);</span>
|
|
<a id='x1-55042r21'></a><span class='ecrm-0500'>21</span><span class='ectt-0800'> </span><span id='textcolor2546'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-55044r22'></a><span class='ecrm-0500'>22</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-55046r23'></a><span class='ecrm-0500'>23</span>
|
|
<a id='x1-55048r24'></a><span class='ecrm-0500'>24</span><span id='textcolor2547'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2548'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> __exit sched_exit(</span><span id='textcolor2549'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-55050r25'></a><span class='ecrm-0500'>25</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-55052r26'></a><span class='ecrm-0500'>26</span><span class='ectt-0800'> destroy_workqueue(queue);</span>
|
|
<a id='x1-55054r27'></a><span class='ecrm-0500'>27</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-55056r28'></a><span class='ecrm-0500'>28</span>
|
|
<a id='x1-55058r29'></a><span class='ecrm-0500'>29</span><span class='ectt-0800'>module_init(sched_init);</span>
|
|
<a id='x1-55060r30'></a><span class='ecrm-0500'>30</span><span class='ectt-0800'>module_exit(sched_exit);</span>
|
|
<a id='x1-55062r31'></a><span class='ecrm-0500'>31</span>
|
|
<a id='x1-55064r32'></a><span class='ecrm-0500'>32</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor2550'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-55066r33'></a><span class='ecrm-0500'>33</span><span class='ectt-0800'>MODULE_DESCRIPTION(</span><span id='textcolor2551'><span class='ectt-0800'>"Workqueue example"</span></span><span class='ectt-0800'>);</span></pre>
|
|
<!-- l. 1858 --><p class='noindent'>
|
|
</p>
|
|
<h3 class='sectionHead' id='interrupt-handlers'><span class='titlemark'>15 </span> <a id='x1-5600015'></a>Interrupt Handlers</h3>
|
|
<!-- l. 1860 --><p class='noindent'>
|
|
</p>
|
|
|
|
|
|
|
|
<h4 class='subsectionHead' id='interrupt-handlers1'><span class='titlemark'>15.1 </span> <a id='x1-5700015.1'></a>Interrupt Handlers</h4>
|
|
<!-- l. 1862 --><p class='noindent'>Except for the last chapter, everything we did in the kernel so far we have done as a
|
|
response to a process asking for it, either by dealing with a special file, sending an
|
|
<code> <span class='ectt-1000'>ioctl()</span>
|
|
</code>, or issuing a system call. But the job of the kernel is not just to respond to process
|
|
requests. Another job, which is every bit as important, is to speak to the hardware
|
|
connected to the machine.
|
|
</p><!-- l. 1866 --><p class='indent'> There are two types of interaction between the CPU and the rest of the
|
|
computer’s hardware. The first type is when the CPU gives orders to the hardware,
|
|
the other is when the hardware needs to tell the CPU something. The second, called
|
|
interrupts, is much harder to implement because it has to be dealt with when
|
|
convenient for the hardware, not the CPU. Hardware devices typically have a very
|
|
small amount of RAM, and if you do not read their information when available, it is
|
|
lost.
|
|
</p><!-- l. 1871 --><p class='indent'> Under Linux, hardware interrupts are called IRQ’s (Interrupt ReQuests). There
|
|
are two types of IRQ’s, short and long. A short IRQ is one which is expected to take
|
|
a very short period of time, during which the rest of the machine will be blocked and
|
|
no other interrupts will be handled. A long IRQ is one which can take longer, and
|
|
during which other interrupts may occur (but not interrupts from the same
|
|
device). If at all possible, it is better to declare an interrupt handler to be
|
|
long.
|
|
</p><!-- l. 1877 --><p class='indent'> When the CPU receives an interrupt, it stops whatever it is doing (unless it is
|
|
processing a more important interrupt, in which case it will deal with this one only
|
|
when the more important one is done), saves certain parameters on the stack and
|
|
calls the interrupt handler. This means that certain things are not allowed in the
|
|
interrupt handler itself, because the system is in an unknown state. Linux kernel
|
|
solves the problem by splitting interrupt handling into two parts. The first part
|
|
executes right away and masks the interrupt line. Hardware interrupts must be
|
|
handled quickly, and that is why we need the second part to handle the
|
|
heavy work deferred from an interrupt handler. Historically, BH (Linux
|
|
naming for <span class='ecti-1000'>Bottom Halves</span>) statistically book-keeps the deferred functions.
|
|
<span class='ecbx-1000'>Softirq </span>and its higher level abstraction, <span class='ecbx-1000'>Tasklet</span>, replace BH since Linux
|
|
2.3.
|
|
</p><!-- l. 1887 --><p class='indent'> The way to implement this is to call
|
|
<code> <span class='ectt-1000'>request_irq()</span>
|
|
</code> to get your interrupt handler called when the relevant IRQ is received.
|
|
</p><!-- l. 1889 --><p class='indent'> In practice IRQ handling can be a bit more complex. Hardware is often designed
|
|
in a way that chains two interrupt controllers, so that all the IRQs from
|
|
interrupt controller B are cascaded to a certain IRQ from interrupt controller A.
|
|
Of course, that requires that the kernel finds out which IRQ it really was
|
|
afterwards and that adds overhead. Other architectures offer some special,
|
|
very low overhead, so called "fast IRQ" or FIQs. To take advantage of them
|
|
requires handlers to be written in assembly language, so they do not really
|
|
fit into the kernel. They can be made to work similar to the others, but
|
|
after that procedure, they are no longer any faster than "common" IRQs.
|
|
SMP enabled kernels running on systems with more than one processor
|
|
|
|
|
|
|
|
need to solve another truckload of problems. It is not enough to know if a
|
|
certain IRQs has happened, it’s also important to know what CPU(s) it was
|
|
for. People still interested in more details, might want to refer to "APIC"
|
|
now.
|
|
</p><!-- l. 1898 --><p class='indent'> This function receives the IRQ number, the name of the function, flags, a name
|
|
for <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc/interrupts</span></span></span> and a parameter to be passed to the interrupt handler.
|
|
Usually there is a certain number of IRQs available. How many IRQs there are is
|
|
hardware-dependent.
|
|
</p><!-- l. 1902 --><p class='indent'> The flags can be used for specify behaviors of the IRQ. For example, use
|
|
<code> <span class='ectt-1000'>IRQF_SHARED</span>
|
|
</code> to indicate you are willing to share the IRQ with other interrupt handlers
|
|
(usually because a number of hardware devices sit on the same IRQ); use the
|
|
<code> <span class='ectt-1000'>IRQF_ONESHOT</span>
|
|
</code> to indicate that the IRQ is not reenabled after the handler finished. It should be
|
|
noted that in some materials, you may encouter another set of IRQ flags named with
|
|
the <code> <span class='ectt-1000'>SA</span>
|
|
</code> prefix. For example, the <code> <span class='ectt-1000'>SA_SHIRQ</span>
|
|
</code> and the <code> <span class='ectt-1000'>SA_INTERRUPT</span>
|
|
</code>. Those are the the IRQ flags in the older kernels. They have been removed completely. Today
|
|
only the <code> <span class='ectt-1000'>IRQF</span>
|
|
</code> flags are in use. This function will only succeed if there is not already a handler on
|
|
this IRQ, or if you are both willing to share.
|
|
</p><!-- l. 1911 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='detecting-button-presses'><span class='titlemark'>15.2 </span> <a id='x1-5800015.2'></a>Detecting button presses</h4>
|
|
<!-- l. 1913 --><p class='noindent'>Many popular single board computers, such as Raspberry Pi or Beagleboards, have a
|
|
bunch of GPIO pins. Attaching buttons to those and then having a button press do
|
|
something is a classic case in which you might need to use interrupts, so that instead
|
|
of having the CPU waste time and battery power polling for a change in input state,
|
|
it is better for the input to trigger the CPU to then run a particular handling
|
|
function.
|
|
</p><!-- l. 1917 --><p class='indent'> Here is an example where buttons are connected to GPIO numbers 17 and 18 and
|
|
an LED is connected to GPIO 4. You can change those numbers to whatever is
|
|
appropriate for your board.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb80'><a id='x1-58002r1'></a><span class='ecrm-0500'>1</span><span id='textcolor2552'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-58004r2'></a><span class='ecrm-0500'>2</span><span id='textcolor2553'><span class='ectt-0800'> * intrpt.c - Handling GPIO with interrupts</span></span>
|
|
<a id='x1-58006r3'></a><span class='ecrm-0500'>3</span><span id='textcolor2554'><span class='ectt-0800'> *</span></span>
|
|
<a id='x1-58008r4'></a><span class='ecrm-0500'>4</span><span id='textcolor2555'><span class='ectt-0800'> * Based upon the RPi example by Stefan Wendler (devnull@kaltpost.de)</span></span>
|
|
<a id='x1-58010r5'></a><span class='ecrm-0500'>5</span><span id='textcolor2556'><span class='ectt-0800'> * from:</span></span>
|
|
<a id='x1-58012r6'></a><span class='ecrm-0500'>6</span><span id='textcolor2557'><span class='ectt-0800'> * https://github.com/wendlers/rpi-kmod-samples</span></span>
|
|
<a id='x1-58014r7'></a><span class='ecrm-0500'>7</span><span id='textcolor2558'><span class='ectt-0800'> *</span></span>
|
|
<a id='x1-58016r8'></a><span class='ecrm-0500'>8</span><span id='textcolor2559'><span class='ectt-0800'> * Press one button to turn on a LED and another to turn it off.</span></span>
|
|
<a id='x1-58018r9'></a><span class='ecrm-0500'>9</span><span id='textcolor2560'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-58020r10'></a><span class='ecrm-0500'>10</span>
|
|
<a id='x1-58022r11'></a><span class='ecrm-0500'>11</span><span id='textcolor2561'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2562'><span class='ectt-0800'><linux/gpio.h></span></span>
|
|
<a id='x1-58024r12'></a><span class='ecrm-0500'>12</span><span id='textcolor2563'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2564'><span class='ectt-0800'><linux/interrupt.h></span></span>
|
|
<a id='x1-58026r13'></a><span class='ecrm-0500'>13</span><span id='textcolor2565'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2566'><span class='ectt-0800'><linux/kernel.h> /* for ARRAY_SIZE() */</span></span>
|
|
<a id='x1-58028r14'></a><span class='ecrm-0500'>14</span><span id='textcolor2567'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2568'><span class='ectt-0800'><linux/module.h></span></span>
|
|
<a id='x1-58030r15'></a><span class='ecrm-0500'>15</span><span id='textcolor2569'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2570'><span class='ectt-0800'><linux/printk.h></span></span>
|
|
<a id='x1-58032r16'></a><span class='ecrm-0500'>16</span>
|
|
<a id='x1-58034r17'></a><span class='ecrm-0500'>17</span><span id='textcolor2571'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2572'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> button_irqs[] = { -1, -1 };</span>
|
|
<a id='x1-58036r18'></a><span class='ecrm-0500'>18</span>
|
|
<a id='x1-58038r19'></a><span class='ecrm-0500'>19</span><span id='textcolor2573'><span class='ectt-0800'>/* Define GPIOs for LEDs.</span></span>
|
|
<a id='x1-58040r20'></a><span class='ecrm-0500'>20</span><span id='textcolor2574'><span class='ectt-0800'> * TODO: Change the numbers for the GPIO on your board.</span></span>
|
|
<a id='x1-58042r21'></a><span class='ecrm-0500'>21</span><span id='textcolor2575'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-58044r22'></a><span class='ecrm-0500'>22</span><span id='textcolor2576'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2577'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> gpio leds[] = { { 4, GPIOF_OUT_INIT_LOW, </span><span id='textcolor2578'><span class='ectt-0800'>"LED 1"</span></span><span class='ectt-0800'> } };</span>
|
|
<a id='x1-58046r23'></a><span class='ecrm-0500'>23</span>
|
|
<a id='x1-58048r24'></a><span class='ecrm-0500'>24</span><span id='textcolor2579'><span class='ectt-0800'>/* Define GPIOs for BUTTONS</span></span>
|
|
<a id='x1-58050r25'></a><span class='ecrm-0500'>25</span><span id='textcolor2580'><span class='ectt-0800'> * TODO: Change the numbers for the GPIO on your board.</span></span>
|
|
<a id='x1-58052r26'></a><span class='ecrm-0500'>26</span><span id='textcolor2581'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-58054r27'></a><span class='ecrm-0500'>27</span><span id='textcolor2582'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2583'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> gpio buttons[] = { { 17, GPIOF_IN, </span><span id='textcolor2584'><span class='ectt-0800'>"LED 1 ON BUTTON"</span></span><span class='ectt-0800'> },</span>
|
|
<a id='x1-58056r28'></a><span class='ecrm-0500'>28</span><span class='ectt-0800'> { 18, GPIOF_IN, </span><span id='textcolor2585'><span class='ectt-0800'>"LED 1 OFF BUTTON"</span></span><span class='ectt-0800'> } };</span>
|
|
<a id='x1-58058r29'></a><span class='ecrm-0500'>29</span>
|
|
<a id='x1-58060r30'></a><span class='ecrm-0500'>30</span><span id='textcolor2586'><span class='ectt-0800'>/* interrupt function triggered when a button is pressed. */</span></span>
|
|
<a id='x1-58062r31'></a><span class='ecrm-0500'>31</span><span id='textcolor2587'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> irqreturn_t button_isr(</span><span id='textcolor2588'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> irq, </span><span id='textcolor2589'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> *data)</span>
|
|
<a id='x1-58064r32'></a><span class='ecrm-0500'>32</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-58066r33'></a><span class='ecrm-0500'>33</span><span class='ectt-0800'> </span><span id='textcolor2590'><span class='ectt-0800'>/* first button */</span></span>
|
|
<a id='x1-58068r34'></a><span class='ecrm-0500'>34</span><span class='ectt-0800'> </span><span id='textcolor2591'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (irq == button_irqs[0] && !gpio_get_value(leds[0].gpio))</span>
|
|
<a id='x1-58070r35'></a><span class='ecrm-0500'>35</span><span class='ectt-0800'> gpio_set_value(leds[0].gpio, 1);</span>
|
|
<a id='x1-58072r36'></a><span class='ecrm-0500'>36</span><span class='ectt-0800'> </span><span id='textcolor2592'><span class='ectt-0800'>/* second button */</span></span>
|
|
<a id='x1-58074r37'></a><span class='ecrm-0500'>37</span><span class='ectt-0800'> </span><span id='textcolor2593'><span class='ectt-0800'>else</span></span><span class='ectt-0800'> </span><span id='textcolor2594'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (irq == button_irqs[1] && gpio_get_value(leds[0].gpio))</span>
|
|
<a id='x1-58076r38'></a><span class='ecrm-0500'>38</span><span class='ectt-0800'> gpio_set_value(leds[0].gpio, 0);</span>
|
|
<a id='x1-58078r39'></a><span class='ecrm-0500'>39</span>
|
|
<a id='x1-58080r40'></a><span class='ecrm-0500'>40</span><span class='ectt-0800'> </span><span id='textcolor2595'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> IRQ_HANDLED;</span>
|
|
<a id='x1-58082r41'></a><span class='ecrm-0500'>41</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-58084r42'></a><span class='ecrm-0500'>42</span>
|
|
<a id='x1-58086r43'></a><span class='ecrm-0500'>43</span><span id='textcolor2596'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2597'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __init intrpt_init(</span><span id='textcolor2598'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-58088r44'></a><span class='ecrm-0500'>44</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-58090r45'></a><span class='ecrm-0500'>45</span><span class='ectt-0800'> </span><span id='textcolor2599'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> ret = 0;</span>
|
|
<a id='x1-58092r46'></a><span class='ecrm-0500'>46</span>
|
|
<a id='x1-58094r47'></a><span class='ecrm-0500'>47</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2600'><span class='ectt-0800'>"%s</span></span><span id='textcolor2601'><span class='ectt-0800'>\n</span></span><span id='textcolor2602'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, __func__);</span>
|
|
<a id='x1-58096r48'></a><span class='ecrm-0500'>48</span>
|
|
<a id='x1-58098r49'></a><span class='ecrm-0500'>49</span><span class='ectt-0800'> </span><span id='textcolor2603'><span class='ectt-0800'>/* register LED gpios */</span></span>
|
|
<a id='x1-58100r50'></a><span class='ecrm-0500'>50</span><span class='ectt-0800'> ret = gpio_request_array(leds, ARRAY_SIZE(leds));</span>
|
|
<a id='x1-58102r51'></a><span class='ecrm-0500'>51</span>
|
|
<a id='x1-58104r52'></a><span class='ecrm-0500'>52</span><span class='ectt-0800'> </span><span id='textcolor2604'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (ret) {</span>
|
|
<a id='x1-58106r53'></a><span class='ecrm-0500'>53</span><span class='ectt-0800'> pr_err(</span><span id='textcolor2605'><span class='ectt-0800'>"Unable to request GPIOs for LEDs: %d</span></span><span id='textcolor2606'><span class='ectt-0800'>\n</span></span><span id='textcolor2607'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, ret);</span>
|
|
<a id='x1-58108r54'></a><span class='ecrm-0500'>54</span><span class='ectt-0800'> </span><span id='textcolor2608'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> ret;</span>
|
|
<a id='x1-58110r55'></a><span class='ecrm-0500'>55</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-58112r56'></a><span class='ecrm-0500'>56</span>
|
|
<a id='x1-58114r57'></a><span class='ecrm-0500'>57</span><span class='ectt-0800'> </span><span id='textcolor2609'><span class='ectt-0800'>/* register BUTTON gpios */</span></span>
|
|
<a id='x1-58116r58'></a><span class='ecrm-0500'>58</span><span class='ectt-0800'> ret = gpio_request_array(buttons, ARRAY_SIZE(buttons));</span>
|
|
<a id='x1-58118r59'></a><span class='ecrm-0500'>59</span>
|
|
<a id='x1-58120r60'></a><span class='ecrm-0500'>60</span><span class='ectt-0800'> </span><span id='textcolor2610'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (ret) {</span>
|
|
<a id='x1-58122r61'></a><span class='ecrm-0500'>61</span><span class='ectt-0800'> pr_err(</span><span id='textcolor2611'><span class='ectt-0800'>"Unable to request GPIOs for BUTTONs: %d</span></span><span id='textcolor2612'><span class='ectt-0800'>\n</span></span><span id='textcolor2613'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, ret);</span>
|
|
<a id='x1-58124r62'></a><span class='ecrm-0500'>62</span><span class='ectt-0800'> </span><span id='textcolor2614'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> fail1;</span>
|
|
<a id='x1-58126r63'></a><span class='ecrm-0500'>63</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-58128r64'></a><span class='ecrm-0500'>64</span>
|
|
<a id='x1-58130r65'></a><span class='ecrm-0500'>65</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2615'><span class='ectt-0800'>"Current button1 value: %d</span></span><span id='textcolor2616'><span class='ectt-0800'>\n</span></span><span id='textcolor2617'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, gpio_get_value(buttons[0].gpio));</span>
|
|
<a id='x1-58132r66'></a><span class='ecrm-0500'>66</span>
|
|
<a id='x1-58134r67'></a><span class='ecrm-0500'>67</span><span class='ectt-0800'> ret = gpio_to_irq(buttons[0].gpio);</span>
|
|
<a id='x1-58136r68'></a><span class='ecrm-0500'>68</span>
|
|
<a id='x1-58138r69'></a><span class='ecrm-0500'>69</span><span class='ectt-0800'> </span><span id='textcolor2618'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (ret < 0) {</span>
|
|
<a id='x1-58140r70'></a><span class='ecrm-0500'>70</span><span class='ectt-0800'> pr_err(</span><span id='textcolor2619'><span class='ectt-0800'>"Unable to request IRQ: %d</span></span><span id='textcolor2620'><span class='ectt-0800'>\n</span></span><span id='textcolor2621'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, ret);</span>
|
|
<a id='x1-58142r71'></a><span class='ecrm-0500'>71</span><span class='ectt-0800'> </span><span id='textcolor2622'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> fail2;</span>
|
|
<a id='x1-58144r72'></a><span class='ecrm-0500'>72</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-58146r73'></a><span class='ecrm-0500'>73</span>
|
|
<a id='x1-58148r74'></a><span class='ecrm-0500'>74</span><span class='ectt-0800'> button_irqs[0] = ret;</span>
|
|
<a id='x1-58150r75'></a><span class='ecrm-0500'>75</span>
|
|
<a id='x1-58152r76'></a><span class='ecrm-0500'>76</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2623'><span class='ectt-0800'>"Successfully requested BUTTON1 IRQ # %d</span></span><span id='textcolor2624'><span class='ectt-0800'>\n</span></span><span id='textcolor2625'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, button_irqs[0]);</span>
|
|
<a id='x1-58154r77'></a><span class='ecrm-0500'>77</span>
|
|
<a id='x1-58156r78'></a><span class='ecrm-0500'>78</span><span class='ectt-0800'> ret = request_irq(button_irqs[0], button_isr,</span>
|
|
<a id='x1-58158r79'></a><span class='ecrm-0500'>79</span><span class='ectt-0800'> IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,</span>
|
|
<a id='x1-58160r80'></a><span class='ecrm-0500'>80</span><span class='ectt-0800'> </span><span id='textcolor2626'><span class='ectt-0800'>"gpiomod#button1"</span></span><span class='ectt-0800'>, NULL);</span>
|
|
<a id='x1-58162r81'></a><span class='ecrm-0500'>81</span>
|
|
<a id='x1-58164r82'></a><span class='ecrm-0500'>82</span><span class='ectt-0800'> </span><span id='textcolor2627'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (ret) {</span>
|
|
<a id='x1-58166r83'></a><span class='ecrm-0500'>83</span><span class='ectt-0800'> pr_err(</span><span id='textcolor2628'><span class='ectt-0800'>"Unable to request IRQ: %d</span></span><span id='textcolor2629'><span class='ectt-0800'>\n</span></span><span id='textcolor2630'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, ret);</span>
|
|
<a id='x1-58168r84'></a><span class='ecrm-0500'>84</span><span class='ectt-0800'> </span><span id='textcolor2631'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> fail2;</span>
|
|
<a id='x1-58170r85'></a><span class='ecrm-0500'>85</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-58172r86'></a><span class='ecrm-0500'>86</span>
|
|
<a id='x1-58174r87'></a><span class='ecrm-0500'>87</span><span class='ectt-0800'> ret = gpio_to_irq(buttons[1].gpio);</span>
|
|
<a id='x1-58176r88'></a><span class='ecrm-0500'>88</span>
|
|
<a id='x1-58178r89'></a><span class='ecrm-0500'>89</span><span class='ectt-0800'> </span><span id='textcolor2632'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (ret < 0) {</span>
|
|
<a id='x1-58180r90'></a><span class='ecrm-0500'>90</span><span class='ectt-0800'> pr_err(</span><span id='textcolor2633'><span class='ectt-0800'>"Unable to request IRQ: %d</span></span><span id='textcolor2634'><span class='ectt-0800'>\n</span></span><span id='textcolor2635'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, ret);</span>
|
|
<a id='x1-58182r91'></a><span class='ecrm-0500'>91</span><span class='ectt-0800'> </span><span id='textcolor2636'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> fail2;</span>
|
|
<a id='x1-58184r92'></a><span class='ecrm-0500'>92</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-58186r93'></a><span class='ecrm-0500'>93</span>
|
|
<a id='x1-58188r94'></a><span class='ecrm-0500'>94</span><span class='ectt-0800'> button_irqs[1] = ret;</span>
|
|
<a id='x1-58190r95'></a><span class='ecrm-0500'>95</span>
|
|
<a id='x1-58192r96'></a><span class='ecrm-0500'>96</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2637'><span class='ectt-0800'>"Successfully requested BUTTON2 IRQ # %d</span></span><span id='textcolor2638'><span class='ectt-0800'>\n</span></span><span id='textcolor2639'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, button_irqs[1]);</span>
|
|
<a id='x1-58194r97'></a><span class='ecrm-0500'>97</span>
|
|
<a id='x1-58196r98'></a><span class='ecrm-0500'>98</span><span class='ectt-0800'> ret = request_irq(button_irqs[1], button_isr,</span>
|
|
<a id='x1-58198r99'></a><span class='ecrm-0500'>99</span><span class='ectt-0800'> IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,</span>
|
|
<a id='x1-58200r100'></a><span class='ecrm-0500'>100</span><span class='ectt-0800'> </span><span id='textcolor2640'><span class='ectt-0800'>"gpiomod#button2"</span></span><span class='ectt-0800'>, NULL);</span>
|
|
<a id='x1-58202r101'></a><span class='ecrm-0500'>101</span>
|
|
<a id='x1-58204r102'></a><span class='ecrm-0500'>102</span><span class='ectt-0800'> </span><span id='textcolor2641'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (ret) {</span>
|
|
<a id='x1-58206r103'></a><span class='ecrm-0500'>103</span><span class='ectt-0800'> pr_err(</span><span id='textcolor2642'><span class='ectt-0800'>"Unable to request IRQ: %d</span></span><span id='textcolor2643'><span class='ectt-0800'>\n</span></span><span id='textcolor2644'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, ret);</span>
|
|
<a id='x1-58208r104'></a><span class='ecrm-0500'>104</span><span class='ectt-0800'> </span><span id='textcolor2645'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> fail3;</span>
|
|
<a id='x1-58210r105'></a><span class='ecrm-0500'>105</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-58212r106'></a><span class='ecrm-0500'>106</span>
|
|
<a id='x1-58214r107'></a><span class='ecrm-0500'>107</span><span class='ectt-0800'> </span><span id='textcolor2646'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-58216r108'></a><span class='ecrm-0500'>108</span>
|
|
<a id='x1-58218r109'></a><span class='ecrm-0500'>109</span><span id='textcolor2647'><span class='ectt-0800'>/* cleanup what has been setup so far */</span></span>
|
|
<a id='x1-58220r110'></a><span class='ecrm-0500'>110</span><span class='ectt-0800'>fail3:</span>
|
|
<a id='x1-58222r111'></a><span class='ecrm-0500'>111</span><span class='ectt-0800'> free_irq(button_irqs[0], NULL);</span>
|
|
<a id='x1-58224r112'></a><span class='ecrm-0500'>112</span>
|
|
<a id='x1-58226r113'></a><span class='ecrm-0500'>113</span><span class='ectt-0800'>fail2:</span>
|
|
<a id='x1-58228r114'></a><span class='ecrm-0500'>114</span><span class='ectt-0800'> gpio_free_array(buttons, ARRAY_SIZE(leds));</span>
|
|
<a id='x1-58230r115'></a><span class='ecrm-0500'>115</span>
|
|
<a id='x1-58232r116'></a><span class='ecrm-0500'>116</span><span class='ectt-0800'>fail1:</span>
|
|
<a id='x1-58234r117'></a><span class='ecrm-0500'>117</span><span class='ectt-0800'> gpio_free_array(leds, ARRAY_SIZE(leds));</span>
|
|
<a id='x1-58236r118'></a><span class='ecrm-0500'>118</span>
|
|
<a id='x1-58238r119'></a><span class='ecrm-0500'>119</span><span class='ectt-0800'> </span><span id='textcolor2648'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> ret;</span>
|
|
<a id='x1-58240r120'></a><span class='ecrm-0500'>120</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-58242r121'></a><span class='ecrm-0500'>121</span>
|
|
<a id='x1-58244r122'></a><span class='ecrm-0500'>122</span><span id='textcolor2649'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2650'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> __exit intrpt_exit(</span><span id='textcolor2651'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-58246r123'></a><span class='ecrm-0500'>123</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-58248r124'></a><span class='ecrm-0500'>124</span><span class='ectt-0800'> </span><span id='textcolor2652'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> i;</span>
|
|
<a id='x1-58250r125'></a><span class='ecrm-0500'>125</span>
|
|
<a id='x1-58252r126'></a><span class='ecrm-0500'>126</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2653'><span class='ectt-0800'>"%s</span></span><span id='textcolor2654'><span class='ectt-0800'>\n</span></span><span id='textcolor2655'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, __func__);</span>
|
|
<a id='x1-58254r127'></a><span class='ecrm-0500'>127</span>
|
|
<a id='x1-58256r128'></a><span class='ecrm-0500'>128</span><span class='ectt-0800'> </span><span id='textcolor2656'><span class='ectt-0800'>/* free irqs */</span></span>
|
|
<a id='x1-58258r129'></a><span class='ecrm-0500'>129</span><span class='ectt-0800'> free_irq(button_irqs[0], NULL);</span>
|
|
<a id='x1-58260r130'></a><span class='ecrm-0500'>130</span><span class='ectt-0800'> free_irq(button_irqs[1], NULL);</span>
|
|
<a id='x1-58262r131'></a><span class='ecrm-0500'>131</span>
|
|
<a id='x1-58264r132'></a><span class='ecrm-0500'>132</span><span class='ectt-0800'> </span><span id='textcolor2657'><span class='ectt-0800'>/* turn all LEDs off */</span></span>
|
|
<a id='x1-58266r133'></a><span class='ecrm-0500'>133</span><span class='ectt-0800'> </span><span id='textcolor2658'><span class='ectt-0800'>for</span></span><span class='ectt-0800'> (i = 0; i < ARRAY_SIZE(leds); i++)</span>
|
|
<a id='x1-58268r134'></a><span class='ecrm-0500'>134</span><span class='ectt-0800'> gpio_set_value(leds[i].gpio, 0);</span>
|
|
<a id='x1-58270r135'></a><span class='ecrm-0500'>135</span>
|
|
<a id='x1-58272r136'></a><span class='ecrm-0500'>136</span><span class='ectt-0800'> </span><span id='textcolor2659'><span class='ectt-0800'>/* unregister */</span></span>
|
|
<a id='x1-58274r137'></a><span class='ecrm-0500'>137</span><span class='ectt-0800'> gpio_free_array(leds, ARRAY_SIZE(leds));</span>
|
|
<a id='x1-58276r138'></a><span class='ecrm-0500'>138</span><span class='ectt-0800'> gpio_free_array(buttons, ARRAY_SIZE(buttons));</span>
|
|
<a id='x1-58278r139'></a><span class='ecrm-0500'>139</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-58280r140'></a><span class='ecrm-0500'>140</span>
|
|
<a id='x1-58282r141'></a><span class='ecrm-0500'>141</span><span class='ectt-0800'>module_init(intrpt_init);</span>
|
|
<a id='x1-58284r142'></a><span class='ecrm-0500'>142</span><span class='ectt-0800'>module_exit(intrpt_exit);</span>
|
|
<a id='x1-58286r143'></a><span class='ecrm-0500'>143</span>
|
|
<a id='x1-58288r144'></a><span class='ecrm-0500'>144</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor2660'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-58290r145'></a><span class='ecrm-0500'>145</span><span class='ectt-0800'>MODULE_DESCRIPTION(</span><span id='textcolor2661'><span class='ectt-0800'>"Handle some GPIO interrupts"</span></span><span class='ectt-0800'>);</span></pre>
|
|
<!-- l. 1922 --><p class='noindent'>
|
|
</p>
|
|
|
|
|
|
|
|
<h4 class='subsectionHead' id='bottom-half'><span class='titlemark'>15.3 </span> <a id='x1-5900015.3'></a>Bottom Half</h4>
|
|
<!-- l. 1924 --><p class='noindent'>Suppose you want to do a bunch of stuff inside of an interrupt routine. A common
|
|
way to do that without rendering the interrupt unavailable for a significant duration
|
|
is to combine it with a tasklet. This pushes the bulk of the work off into the
|
|
scheduler.
|
|
</p><!-- l. 1928 --><p class='indent'> The example below modifies the previous example to also run an additional task
|
|
when an interrupt is triggered.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb81'><a id='x1-59002r1'></a><span class='ecrm-0500'>1</span><span id='textcolor2662'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-59004r2'></a><span class='ecrm-0500'>2</span><span id='textcolor2663'><span class='ectt-0800'> * bottomhalf.c - Top and bottom half interrupt handling</span></span>
|
|
<a id='x1-59006r3'></a><span class='ecrm-0500'>3</span><span id='textcolor2664'><span class='ectt-0800'> *</span></span>
|
|
<a id='x1-59008r4'></a><span class='ecrm-0500'>4</span><span id='textcolor2665'><span class='ectt-0800'> * Based upon the RPi example by Stefan Wendler (devnull@kaltpost.de)</span></span>
|
|
<a id='x1-59010r5'></a><span class='ecrm-0500'>5</span><span id='textcolor2666'><span class='ectt-0800'> * from:</span></span>
|
|
<a id='x1-59012r6'></a><span class='ecrm-0500'>6</span><span id='textcolor2667'><span class='ectt-0800'> * https://github.com/wendlers/rpi-kmod-samples</span></span>
|
|
<a id='x1-59014r7'></a><span class='ecrm-0500'>7</span><span id='textcolor2668'><span class='ectt-0800'> *</span></span>
|
|
<a id='x1-59016r8'></a><span class='ecrm-0500'>8</span><span id='textcolor2669'><span class='ectt-0800'> * Press one button to turn on an LED and another to turn it off</span></span>
|
|
<a id='x1-59018r9'></a><span class='ecrm-0500'>9</span><span id='textcolor2670'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-59020r10'></a><span class='ecrm-0500'>10</span>
|
|
<a id='x1-59022r11'></a><span class='ecrm-0500'>11</span><span id='textcolor2671'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2672'><span class='ectt-0800'><linux/delay.h></span></span>
|
|
<a id='x1-59024r12'></a><span class='ecrm-0500'>12</span><span id='textcolor2673'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2674'><span class='ectt-0800'><linux/gpio.h></span></span>
|
|
<a id='x1-59026r13'></a><span class='ecrm-0500'>13</span><span id='textcolor2675'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2676'><span class='ectt-0800'><linux/interrupt.h></span></span>
|
|
<a id='x1-59028r14'></a><span class='ecrm-0500'>14</span><span id='textcolor2677'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2678'><span class='ectt-0800'><linux/module.h></span></span>
|
|
<a id='x1-59030r15'></a><span class='ecrm-0500'>15</span><span id='textcolor2679'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2680'><span class='ectt-0800'><linux/printk.h></span></span>
|
|
<a id='x1-59032r16'></a><span class='ecrm-0500'>16</span><span id='textcolor2681'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2682'><span class='ectt-0800'><linux/init.h></span></span>
|
|
<a id='x1-59034r17'></a><span class='ecrm-0500'>17</span>
|
|
<a id='x1-59036r18'></a><span class='ecrm-0500'>18</span><span id='textcolor2683'><span class='ectt-0800'>/* Macro DECLARE_TASKLET_OLD exists for compatibility.</span></span>
|
|
<a id='x1-59038r19'></a><span class='ecrm-0500'>19</span><span id='textcolor2684'><span class='ectt-0800'> * See https://lwn.net/Articles/830964/</span></span>
|
|
<a id='x1-59040r20'></a><span class='ecrm-0500'>20</span><span id='textcolor2685'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-59042r21'></a><span class='ecrm-0500'>21</span><span id='textcolor2686'><span class='ectt-0800'>#ifndef DECLARE_TASKLET_OLD</span></span>
|
|
<a id='x1-59044r22'></a><span class='ecrm-0500'>22</span><span id='textcolor2687'><span class='ectt-0800'>#define DECLARE_TASKLET_OLD(arg1, arg2) DECLARE_TASKLET(arg1, arg2, 0L)</span></span>
|
|
<a id='x1-59046r23'></a><span class='ecrm-0500'>23</span><span id='textcolor2688'><span class='ectt-0800'>#endif</span></span>
|
|
<a id='x1-59048r24'></a><span class='ecrm-0500'>24</span>
|
|
<a id='x1-59050r25'></a><span class='ecrm-0500'>25</span><span id='textcolor2689'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2690'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> button_irqs[] = { -1, -1 };</span>
|
|
<a id='x1-59052r26'></a><span class='ecrm-0500'>26</span>
|
|
<a id='x1-59054r27'></a><span class='ecrm-0500'>27</span><span id='textcolor2691'><span class='ectt-0800'>/* Define GPIOs for LEDs.</span></span>
|
|
<a id='x1-59056r28'></a><span class='ecrm-0500'>28</span><span id='textcolor2692'><span class='ectt-0800'> * TODO: Change the numbers for the GPIO on your board.</span></span>
|
|
<a id='x1-59058r29'></a><span class='ecrm-0500'>29</span><span id='textcolor2693'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-59060r30'></a><span class='ecrm-0500'>30</span><span id='textcolor2694'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2695'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> gpio leds[] = { { 4, GPIOF_OUT_INIT_LOW, </span><span id='textcolor2696'><span class='ectt-0800'>"LED 1"</span></span><span class='ectt-0800'> } };</span>
|
|
<a id='x1-59062r31'></a><span class='ecrm-0500'>31</span>
|
|
<a id='x1-59064r32'></a><span class='ecrm-0500'>32</span><span id='textcolor2697'><span class='ectt-0800'>/* Define GPIOs for BUTTONS</span></span>
|
|
<a id='x1-59066r33'></a><span class='ecrm-0500'>33</span><span id='textcolor2698'><span class='ectt-0800'> * TODO: Change the numbers for the GPIO on your board.</span></span>
|
|
<a id='x1-59068r34'></a><span class='ecrm-0500'>34</span><span id='textcolor2699'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-59070r35'></a><span class='ecrm-0500'>35</span><span id='textcolor2700'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2701'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> gpio buttons[] = {</span>
|
|
<a id='x1-59072r36'></a><span class='ecrm-0500'>36</span><span class='ectt-0800'> { 17, GPIOF_IN, </span><span id='textcolor2702'><span class='ectt-0800'>"LED 1 ON BUTTON"</span></span><span class='ectt-0800'> },</span>
|
|
<a id='x1-59074r37'></a><span class='ecrm-0500'>37</span><span class='ectt-0800'> { 18, GPIOF_IN, </span><span id='textcolor2703'><span class='ectt-0800'>"LED 1 OFF BUTTON"</span></span><span class='ectt-0800'> },</span>
|
|
<a id='x1-59076r38'></a><span class='ecrm-0500'>38</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-59078r39'></a><span class='ecrm-0500'>39</span>
|
|
<a id='x1-59080r40'></a><span class='ecrm-0500'>40</span><span id='textcolor2704'><span class='ectt-0800'>/* Tasklet containing some non-trivial amount of processing */</span></span>
|
|
<a id='x1-59082r41'></a><span class='ecrm-0500'>41</span><span id='textcolor2705'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2706'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> bottomhalf_tasklet_fn(</span><span id='textcolor2707'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor2708'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> data)</span>
|
|
<a id='x1-59084r42'></a><span class='ecrm-0500'>42</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-59086r43'></a><span class='ecrm-0500'>43</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2709'><span class='ectt-0800'>"Bottom half tasklet starts</span></span><span id='textcolor2710'><span class='ectt-0800'>\n</span></span><span id='textcolor2711'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-59088r44'></a><span class='ecrm-0500'>44</span><span class='ectt-0800'> </span><span id='textcolor2712'><span class='ectt-0800'>/* do something which takes a while */</span></span>
|
|
<a id='x1-59090r45'></a><span class='ecrm-0500'>45</span><span class='ectt-0800'> mdelay(500);</span>
|
|
<a id='x1-59092r46'></a><span class='ecrm-0500'>46</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2713'><span class='ectt-0800'>"Bottom half tasklet ends</span></span><span id='textcolor2714'><span class='ectt-0800'>\n</span></span><span id='textcolor2715'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-59094r47'></a><span class='ecrm-0500'>47</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-59096r48'></a><span class='ecrm-0500'>48</span>
|
|
<a id='x1-59098r49'></a><span class='ecrm-0500'>49</span><span id='textcolor2716'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> DECLARE_TASKLET_OLD(buttontask, bottomhalf_tasklet_fn);</span>
|
|
<a id='x1-59100r50'></a><span class='ecrm-0500'>50</span>
|
|
<a id='x1-59102r51'></a><span class='ecrm-0500'>51</span><span id='textcolor2717'><span class='ectt-0800'>/* interrupt function triggered when a button is pressed */</span></span>
|
|
<a id='x1-59104r52'></a><span class='ecrm-0500'>52</span><span id='textcolor2718'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> irqreturn_t button_isr(</span><span id='textcolor2719'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> irq, </span><span id='textcolor2720'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> *data)</span>
|
|
<a id='x1-59106r53'></a><span class='ecrm-0500'>53</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-59108r54'></a><span class='ecrm-0500'>54</span><span class='ectt-0800'> </span><span id='textcolor2721'><span class='ectt-0800'>/* Do something quickly right now */</span></span>
|
|
<a id='x1-59110r55'></a><span class='ecrm-0500'>55</span><span class='ectt-0800'> </span><span id='textcolor2722'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (irq == button_irqs[0] && !gpio_get_value(leds[0].gpio))</span>
|
|
<a id='x1-59112r56'></a><span class='ecrm-0500'>56</span><span class='ectt-0800'> gpio_set_value(leds[0].gpio, 1);</span>
|
|
<a id='x1-59114r57'></a><span class='ecrm-0500'>57</span><span class='ectt-0800'> </span><span id='textcolor2723'><span class='ectt-0800'>else</span></span><span class='ectt-0800'> </span><span id='textcolor2724'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (irq == button_irqs[1] && gpio_get_value(leds[0].gpio))</span>
|
|
<a id='x1-59116r58'></a><span class='ecrm-0500'>58</span><span class='ectt-0800'> gpio_set_value(leds[0].gpio, 0);</span>
|
|
<a id='x1-59118r59'></a><span class='ecrm-0500'>59</span>
|
|
<a id='x1-59120r60'></a><span class='ecrm-0500'>60</span><span class='ectt-0800'> </span><span id='textcolor2725'><span class='ectt-0800'>/* Do the rest at leisure via the scheduler */</span></span>
|
|
<a id='x1-59122r61'></a><span class='ecrm-0500'>61</span><span class='ectt-0800'> tasklet_schedule(&buttontask);</span>
|
|
<a id='x1-59124r62'></a><span class='ecrm-0500'>62</span>
|
|
<a id='x1-59126r63'></a><span class='ecrm-0500'>63</span><span class='ectt-0800'> </span><span id='textcolor2726'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> IRQ_HANDLED;</span>
|
|
<a id='x1-59128r64'></a><span class='ecrm-0500'>64</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-59130r65'></a><span class='ecrm-0500'>65</span>
|
|
<a id='x1-59132r66'></a><span class='ecrm-0500'>66</span><span id='textcolor2727'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2728'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __init bottomhalf_init(</span><span id='textcolor2729'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-59134r67'></a><span class='ecrm-0500'>67</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-59136r68'></a><span class='ecrm-0500'>68</span><span class='ectt-0800'> </span><span id='textcolor2730'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> ret = 0;</span>
|
|
<a id='x1-59138r69'></a><span class='ecrm-0500'>69</span>
|
|
<a id='x1-59140r70'></a><span class='ecrm-0500'>70</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2731'><span class='ectt-0800'>"%s</span></span><span id='textcolor2732'><span class='ectt-0800'>\n</span></span><span id='textcolor2733'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, __func__);</span>
|
|
<a id='x1-59142r71'></a><span class='ecrm-0500'>71</span>
|
|
<a id='x1-59144r72'></a><span class='ecrm-0500'>72</span><span class='ectt-0800'> </span><span id='textcolor2734'><span class='ectt-0800'>/* register LED gpios */</span></span>
|
|
<a id='x1-59146r73'></a><span class='ecrm-0500'>73</span><span class='ectt-0800'> ret = gpio_request_array(leds, ARRAY_SIZE(leds));</span>
|
|
<a id='x1-59148r74'></a><span class='ecrm-0500'>74</span>
|
|
<a id='x1-59150r75'></a><span class='ecrm-0500'>75</span><span class='ectt-0800'> </span><span id='textcolor2735'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (ret) {</span>
|
|
<a id='x1-59152r76'></a><span class='ecrm-0500'>76</span><span class='ectt-0800'> pr_err(</span><span id='textcolor2736'><span class='ectt-0800'>"Unable to request GPIOs for LEDs: %d</span></span><span id='textcolor2737'><span class='ectt-0800'>\n</span></span><span id='textcolor2738'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, ret);</span>
|
|
<a id='x1-59154r77'></a><span class='ecrm-0500'>77</span><span class='ectt-0800'> </span><span id='textcolor2739'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> ret;</span>
|
|
<a id='x1-59156r78'></a><span class='ecrm-0500'>78</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-59158r79'></a><span class='ecrm-0500'>79</span>
|
|
<a id='x1-59160r80'></a><span class='ecrm-0500'>80</span><span class='ectt-0800'> </span><span id='textcolor2740'><span class='ectt-0800'>/* register BUTTON gpios */</span></span>
|
|
<a id='x1-59162r81'></a><span class='ecrm-0500'>81</span><span class='ectt-0800'> ret = gpio_request_array(buttons, ARRAY_SIZE(buttons));</span>
|
|
<a id='x1-59164r82'></a><span class='ecrm-0500'>82</span>
|
|
<a id='x1-59166r83'></a><span class='ecrm-0500'>83</span><span class='ectt-0800'> </span><span id='textcolor2741'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (ret) {</span>
|
|
<a id='x1-59168r84'></a><span class='ecrm-0500'>84</span><span class='ectt-0800'> pr_err(</span><span id='textcolor2742'><span class='ectt-0800'>"Unable to request GPIOs for BUTTONs: %d</span></span><span id='textcolor2743'><span class='ectt-0800'>\n</span></span><span id='textcolor2744'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, ret);</span>
|
|
<a id='x1-59170r85'></a><span class='ecrm-0500'>85</span><span class='ectt-0800'> </span><span id='textcolor2745'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> fail1;</span>
|
|
<a id='x1-59172r86'></a><span class='ecrm-0500'>86</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-59174r87'></a><span class='ecrm-0500'>87</span>
|
|
<a id='x1-59176r88'></a><span class='ecrm-0500'>88</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2746'><span class='ectt-0800'>"Current button1 value: %d</span></span><span id='textcolor2747'><span class='ectt-0800'>\n</span></span><span id='textcolor2748'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, gpio_get_value(buttons[0].gpio));</span>
|
|
<a id='x1-59178r89'></a><span class='ecrm-0500'>89</span>
|
|
<a id='x1-59180r90'></a><span class='ecrm-0500'>90</span><span class='ectt-0800'> ret = gpio_to_irq(buttons[0].gpio);</span>
|
|
<a id='x1-59182r91'></a><span class='ecrm-0500'>91</span>
|
|
<a id='x1-59184r92'></a><span class='ecrm-0500'>92</span><span class='ectt-0800'> </span><span id='textcolor2749'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (ret < 0) {</span>
|
|
<a id='x1-59186r93'></a><span class='ecrm-0500'>93</span><span class='ectt-0800'> pr_err(</span><span id='textcolor2750'><span class='ectt-0800'>"Unable to request IRQ: %d</span></span><span id='textcolor2751'><span class='ectt-0800'>\n</span></span><span id='textcolor2752'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, ret);</span>
|
|
<a id='x1-59188r94'></a><span class='ecrm-0500'>94</span><span class='ectt-0800'> </span><span id='textcolor2753'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> fail2;</span>
|
|
<a id='x1-59190r95'></a><span class='ecrm-0500'>95</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-59192r96'></a><span class='ecrm-0500'>96</span>
|
|
<a id='x1-59194r97'></a><span class='ecrm-0500'>97</span><span class='ectt-0800'> button_irqs[0] = ret;</span>
|
|
<a id='x1-59196r98'></a><span class='ecrm-0500'>98</span>
|
|
<a id='x1-59198r99'></a><span class='ecrm-0500'>99</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2754'><span class='ectt-0800'>"Successfully requested BUTTON1 IRQ # %d</span></span><span id='textcolor2755'><span class='ectt-0800'>\n</span></span><span id='textcolor2756'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, button_irqs[0]);</span>
|
|
<a id='x1-59200r100'></a><span class='ecrm-0500'>100</span>
|
|
<a id='x1-59202r101'></a><span class='ecrm-0500'>101</span><span class='ectt-0800'> ret = request_irq(button_irqs[0], button_isr,</span>
|
|
<a id='x1-59204r102'></a><span class='ecrm-0500'>102</span><span class='ectt-0800'> IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,</span>
|
|
<a id='x1-59206r103'></a><span class='ecrm-0500'>103</span><span class='ectt-0800'> </span><span id='textcolor2757'><span class='ectt-0800'>"gpiomod#button1"</span></span><span class='ectt-0800'>, NULL);</span>
|
|
<a id='x1-59208r104'></a><span class='ecrm-0500'>104</span>
|
|
<a id='x1-59210r105'></a><span class='ecrm-0500'>105</span><span class='ectt-0800'> </span><span id='textcolor2758'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (ret) {</span>
|
|
<a id='x1-59212r106'></a><span class='ecrm-0500'>106</span><span class='ectt-0800'> pr_err(</span><span id='textcolor2759'><span class='ectt-0800'>"Unable to request IRQ: %d</span></span><span id='textcolor2760'><span class='ectt-0800'>\n</span></span><span id='textcolor2761'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, ret);</span>
|
|
<a id='x1-59214r107'></a><span class='ecrm-0500'>107</span><span class='ectt-0800'> </span><span id='textcolor2762'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> fail2;</span>
|
|
<a id='x1-59216r108'></a><span class='ecrm-0500'>108</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-59218r109'></a><span class='ecrm-0500'>109</span>
|
|
<a id='x1-59220r110'></a><span class='ecrm-0500'>110</span><span class='ectt-0800'> ret = gpio_to_irq(buttons[1].gpio);</span>
|
|
<a id='x1-59222r111'></a><span class='ecrm-0500'>111</span>
|
|
<a id='x1-59224r112'></a><span class='ecrm-0500'>112</span><span class='ectt-0800'> </span><span id='textcolor2763'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (ret < 0) {</span>
|
|
<a id='x1-59226r113'></a><span class='ecrm-0500'>113</span><span class='ectt-0800'> pr_err(</span><span id='textcolor2764'><span class='ectt-0800'>"Unable to request IRQ: %d</span></span><span id='textcolor2765'><span class='ectt-0800'>\n</span></span><span id='textcolor2766'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, ret);</span>
|
|
<a id='x1-59228r114'></a><span class='ecrm-0500'>114</span><span class='ectt-0800'> </span><span id='textcolor2767'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> fail2;</span>
|
|
<a id='x1-59230r115'></a><span class='ecrm-0500'>115</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-59232r116'></a><span class='ecrm-0500'>116</span>
|
|
<a id='x1-59234r117'></a><span class='ecrm-0500'>117</span><span class='ectt-0800'> button_irqs[1] = ret;</span>
|
|
<a id='x1-59236r118'></a><span class='ecrm-0500'>118</span>
|
|
<a id='x1-59238r119'></a><span class='ecrm-0500'>119</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2768'><span class='ectt-0800'>"Successfully requested BUTTON2 IRQ # %d</span></span><span id='textcolor2769'><span class='ectt-0800'>\n</span></span><span id='textcolor2770'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, button_irqs[1]);</span>
|
|
<a id='x1-59240r120'></a><span class='ecrm-0500'>120</span>
|
|
<a id='x1-59242r121'></a><span class='ecrm-0500'>121</span><span class='ectt-0800'> ret = request_irq(button_irqs[1], button_isr,</span>
|
|
<a id='x1-59244r122'></a><span class='ecrm-0500'>122</span><span class='ectt-0800'> IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,</span>
|
|
<a id='x1-59246r123'></a><span class='ecrm-0500'>123</span><span class='ectt-0800'> </span><span id='textcolor2771'><span class='ectt-0800'>"gpiomod#button2"</span></span><span class='ectt-0800'>, NULL);</span>
|
|
<a id='x1-59248r124'></a><span class='ecrm-0500'>124</span>
|
|
<a id='x1-59250r125'></a><span class='ecrm-0500'>125</span><span class='ectt-0800'> </span><span id='textcolor2772'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (ret) {</span>
|
|
<a id='x1-59252r126'></a><span class='ecrm-0500'>126</span><span class='ectt-0800'> pr_err(</span><span id='textcolor2773'><span class='ectt-0800'>"Unable to request IRQ: %d</span></span><span id='textcolor2774'><span class='ectt-0800'>\n</span></span><span id='textcolor2775'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, ret);</span>
|
|
<a id='x1-59254r127'></a><span class='ecrm-0500'>127</span><span class='ectt-0800'> </span><span id='textcolor2776'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> fail3;</span>
|
|
<a id='x1-59256r128'></a><span class='ecrm-0500'>128</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-59258r129'></a><span class='ecrm-0500'>129</span>
|
|
<a id='x1-59260r130'></a><span class='ecrm-0500'>130</span><span class='ectt-0800'> </span><span id='textcolor2777'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-59262r131'></a><span class='ecrm-0500'>131</span>
|
|
<a id='x1-59264r132'></a><span class='ecrm-0500'>132</span><span id='textcolor2778'><span class='ectt-0800'>/* cleanup what has been setup so far */</span></span>
|
|
<a id='x1-59266r133'></a><span class='ecrm-0500'>133</span><span class='ectt-0800'>fail3:</span>
|
|
<a id='x1-59268r134'></a><span class='ecrm-0500'>134</span><span class='ectt-0800'> free_irq(button_irqs[0], NULL);</span>
|
|
<a id='x1-59270r135'></a><span class='ecrm-0500'>135</span>
|
|
<a id='x1-59272r136'></a><span class='ecrm-0500'>136</span><span class='ectt-0800'>fail2:</span>
|
|
<a id='x1-59274r137'></a><span class='ecrm-0500'>137</span><span class='ectt-0800'> gpio_free_array(buttons, ARRAY_SIZE(leds));</span>
|
|
<a id='x1-59276r138'></a><span class='ecrm-0500'>138</span>
|
|
<a id='x1-59278r139'></a><span class='ecrm-0500'>139</span><span class='ectt-0800'>fail1:</span>
|
|
<a id='x1-59280r140'></a><span class='ecrm-0500'>140</span><span class='ectt-0800'> gpio_free_array(leds, ARRAY_SIZE(leds));</span>
|
|
<a id='x1-59282r141'></a><span class='ecrm-0500'>141</span>
|
|
<a id='x1-59284r142'></a><span class='ecrm-0500'>142</span><span class='ectt-0800'> </span><span id='textcolor2779'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> ret;</span>
|
|
<a id='x1-59286r143'></a><span class='ecrm-0500'>143</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-59288r144'></a><span class='ecrm-0500'>144</span>
|
|
<a id='x1-59290r145'></a><span class='ecrm-0500'>145</span><span id='textcolor2780'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2781'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> __exit bottomhalf_exit(</span><span id='textcolor2782'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-59292r146'></a><span class='ecrm-0500'>146</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-59294r147'></a><span class='ecrm-0500'>147</span><span class='ectt-0800'> </span><span id='textcolor2783'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> i;</span>
|
|
<a id='x1-59296r148'></a><span class='ecrm-0500'>148</span>
|
|
<a id='x1-59298r149'></a><span class='ecrm-0500'>149</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2784'><span class='ectt-0800'>"%s</span></span><span id='textcolor2785'><span class='ectt-0800'>\n</span></span><span id='textcolor2786'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, __func__);</span>
|
|
<a id='x1-59300r150'></a><span class='ecrm-0500'>150</span>
|
|
<a id='x1-59302r151'></a><span class='ecrm-0500'>151</span><span class='ectt-0800'> </span><span id='textcolor2787'><span class='ectt-0800'>/* free irqs */</span></span>
|
|
<a id='x1-59304r152'></a><span class='ecrm-0500'>152</span><span class='ectt-0800'> free_irq(button_irqs[0], NULL);</span>
|
|
<a id='x1-59306r153'></a><span class='ecrm-0500'>153</span><span class='ectt-0800'> free_irq(button_irqs[1], NULL);</span>
|
|
<a id='x1-59308r154'></a><span class='ecrm-0500'>154</span>
|
|
<a id='x1-59310r155'></a><span class='ecrm-0500'>155</span><span class='ectt-0800'> </span><span id='textcolor2788'><span class='ectt-0800'>/* turn all LEDs off */</span></span>
|
|
<a id='x1-59312r156'></a><span class='ecrm-0500'>156</span><span class='ectt-0800'> </span><span id='textcolor2789'><span class='ectt-0800'>for</span></span><span class='ectt-0800'> (i = 0; i < ARRAY_SIZE(leds); i++)</span>
|
|
<a id='x1-59314r157'></a><span class='ecrm-0500'>157</span><span class='ectt-0800'> gpio_set_value(leds[i].gpio, 0);</span>
|
|
<a id='x1-59316r158'></a><span class='ecrm-0500'>158</span>
|
|
<a id='x1-59318r159'></a><span class='ecrm-0500'>159</span><span class='ectt-0800'> </span><span id='textcolor2790'><span class='ectt-0800'>/* unregister */</span></span>
|
|
<a id='x1-59320r160'></a><span class='ecrm-0500'>160</span><span class='ectt-0800'> gpio_free_array(leds, ARRAY_SIZE(leds));</span>
|
|
<a id='x1-59322r161'></a><span class='ecrm-0500'>161</span><span class='ectt-0800'> gpio_free_array(buttons, ARRAY_SIZE(buttons));</span>
|
|
<a id='x1-59324r162'></a><span class='ecrm-0500'>162</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-59326r163'></a><span class='ecrm-0500'>163</span>
|
|
<a id='x1-59328r164'></a><span class='ecrm-0500'>164</span><span class='ectt-0800'>module_init(bottomhalf_init);</span>
|
|
<a id='x1-59330r165'></a><span class='ecrm-0500'>165</span><span class='ectt-0800'>module_exit(bottomhalf_exit);</span>
|
|
<a id='x1-59332r166'></a><span class='ecrm-0500'>166</span>
|
|
<a id='x1-59334r167'></a><span class='ecrm-0500'>167</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor2791'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-59336r168'></a><span class='ecrm-0500'>168</span><span class='ectt-0800'>MODULE_DESCRIPTION(</span><span id='textcolor2792'><span class='ectt-0800'>"Interrupt with top and bottom half"</span></span><span class='ectt-0800'>);</span></pre>
|
|
<!-- l. 1932 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='threaded-irq'><span class='titlemark'>15.4 </span> <a id='x1-6000015.4'></a>Threaded IRQ</h4>
|
|
<!-- l. 1934 --><p class='noindent'>Threaded IRQ is a mechanism to organize both top-half and bottom-half
|
|
of an IRQ at once. A threaded IRQ splits the one handler in
|
|
<code> <span class='ectt-1000'>request_irq()</span>
|
|
</code> into two: one for the top-half, the other for the bottom-half. The
|
|
<code> <span class='ectt-1000'>request_threaded_irq()</span>
|
|
</code> is the function for using threaded IRQs. Two handlers are registered at once in the
|
|
<code> <span class='ectt-1000'>request_threaded_irq()</span>
|
|
</code>.
|
|
</p><!-- l. 1939 --><p class='indent'> Those two handlers run in different context. The top-half handler runs
|
|
in interrupt context. It’s the equivalence of the handler passed to the
|
|
<code> <span class='ectt-1000'>request_irq()</span>
|
|
</code>. The bottom-half handler on the other hand runs in its own thread. This
|
|
thread is created on registration of a threaded IRQ. Its sole purpose is to run
|
|
this bottom-half handler. This is where a threaded IRQ is “threaded”. If
|
|
<code> <span class='ectt-1000'>IRQ_WAKE_THREAD</span>
|
|
</code> is returned by the top-half handler, that bottom-half serving thread will wake up.
|
|
The thread then runs the bottom-half handler.
|
|
</p><!-- l. 1949 --><p class='indent'> Here is an example of how to do the same thing as before, with top and bottom
|
|
halves, but using threads.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb82'><a id='x1-60007r1'></a><span class='ecrm-0500'>1</span><span id='textcolor2793'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-60009r2'></a><span class='ecrm-0500'>2</span><span id='textcolor2794'><span class='ectt-0800'> * bh_thread.c - Top and bottom half interrupt handling</span></span>
|
|
<a id='x1-60011r3'></a><span class='ecrm-0500'>3</span><span id='textcolor2795'><span class='ectt-0800'> *</span></span>
|
|
<a id='x1-60013r4'></a><span class='ecrm-0500'>4</span><span id='textcolor2796'><span class='ectt-0800'> * Based upon the RPi example by Stefan Wendler (devnull@kaltpost.de)</span></span>
|
|
<a id='x1-60015r5'></a><span class='ecrm-0500'>5</span><span id='textcolor2797'><span class='ectt-0800'> * from:</span></span>
|
|
<a id='x1-60017r6'></a><span class='ecrm-0500'>6</span><span id='textcolor2798'><span class='ectt-0800'> * https://github.com/wendlers/rpi-kmod-samples</span></span>
|
|
<a id='x1-60019r7'></a><span class='ecrm-0500'>7</span><span id='textcolor2799'><span class='ectt-0800'> *</span></span>
|
|
<a id='x1-60021r8'></a><span class='ecrm-0500'>8</span><span id='textcolor2800'><span class='ectt-0800'> * Press one button to turn on a LED and another to turn it off</span></span>
|
|
<a id='x1-60023r9'></a><span class='ecrm-0500'>9</span><span id='textcolor2801'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-60025r10'></a><span class='ecrm-0500'>10</span>
|
|
<a id='x1-60027r11'></a><span class='ecrm-0500'>11</span><span id='textcolor2802'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2803'><span class='ectt-0800'><linux/module.h></span></span>
|
|
<a id='x1-60029r12'></a><span class='ecrm-0500'>12</span><span id='textcolor2804'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2805'><span class='ectt-0800'><linux/kernel.h></span></span>
|
|
<a id='x1-60031r13'></a><span class='ecrm-0500'>13</span><span id='textcolor2806'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2807'><span class='ectt-0800'><linux/gpio.h></span></span>
|
|
<a id='x1-60033r14'></a><span class='ecrm-0500'>14</span><span id='textcolor2808'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2809'><span class='ectt-0800'><linux/delay.h></span></span>
|
|
<a id='x1-60035r15'></a><span class='ecrm-0500'>15</span><span id='textcolor2810'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2811'><span class='ectt-0800'><linux/interrupt.h></span></span>
|
|
<a id='x1-60037r16'></a><span class='ecrm-0500'>16</span>
|
|
<a id='x1-60039r17'></a><span class='ecrm-0500'>17</span><span id='textcolor2812'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2813'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> button_irqs[] = { -1, -1 };</span>
|
|
<a id='x1-60041r18'></a><span class='ecrm-0500'>18</span>
|
|
<a id='x1-60043r19'></a><span class='ecrm-0500'>19</span><span id='textcolor2814'><span class='ectt-0800'>/* Define GPIOs for LEDs.</span></span>
|
|
<a id='x1-60045r20'></a><span class='ecrm-0500'>20</span><span id='textcolor2815'><span class='ectt-0800'> * FIXME: Change the numbers for the GPIO on your board.</span></span>
|
|
<a id='x1-60047r21'></a><span class='ecrm-0500'>21</span><span id='textcolor2816'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-60049r22'></a><span class='ecrm-0500'>22</span><span id='textcolor2817'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2818'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> gpio leds[] = { { 4, GPIOF_OUT_INIT_LOW, </span><span id='textcolor2819'><span class='ectt-0800'>"LED 1"</span></span><span class='ectt-0800'> } };</span>
|
|
<a id='x1-60051r23'></a><span class='ecrm-0500'>23</span>
|
|
<a id='x1-60053r24'></a><span class='ecrm-0500'>24</span><span id='textcolor2820'><span class='ectt-0800'>/* Define GPIOs for BUTTONS</span></span>
|
|
<a id='x1-60055r25'></a><span class='ecrm-0500'>25</span><span id='textcolor2821'><span class='ectt-0800'> * FIXME: Change the numbers for the GPIO on your board.</span></span>
|
|
<a id='x1-60057r26'></a><span class='ecrm-0500'>26</span><span id='textcolor2822'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-60059r27'></a><span class='ecrm-0500'>27</span><span id='textcolor2823'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2824'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> gpio buttons[] = {</span>
|
|
<a id='x1-60061r28'></a><span class='ecrm-0500'>28</span><span class='ectt-0800'> { 17, GPIOF_IN, </span><span id='textcolor2825'><span class='ectt-0800'>"LED 1 ON BUTTON"</span></span><span class='ectt-0800'> },</span>
|
|
<a id='x1-60063r29'></a><span class='ecrm-0500'>29</span><span class='ectt-0800'> { 18, GPIOF_IN, </span><span id='textcolor2826'><span class='ectt-0800'>"LED 1 OFF BUTTON"</span></span><span class='ectt-0800'> },</span>
|
|
<a id='x1-60065r30'></a><span class='ecrm-0500'>30</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-60067r31'></a><span class='ecrm-0500'>31</span>
|
|
<a id='x1-60069r32'></a><span class='ecrm-0500'>32</span><span id='textcolor2827'><span class='ectt-0800'>/* This happens immediately, when the IRQ is triggered */</span></span>
|
|
<a id='x1-60071r33'></a><span class='ecrm-0500'>33</span><span id='textcolor2828'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> irqreturn_t button_top_half(</span><span id='textcolor2829'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> irq, </span><span id='textcolor2830'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> *ident)</span>
|
|
<a id='x1-60073r34'></a><span class='ecrm-0500'>34</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-60075r35'></a><span class='ecrm-0500'>35</span><span class='ectt-0800'> </span><span id='textcolor2831'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> IRQ_WAKE_THREAD;</span>
|
|
<a id='x1-60077r36'></a><span class='ecrm-0500'>36</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-60079r37'></a><span class='ecrm-0500'>37</span>
|
|
<a id='x1-60081r38'></a><span class='ecrm-0500'>38</span><span id='textcolor2832'><span class='ectt-0800'>/* This can happen at leisure, freeing up IRQs for other high priority task */</span></span>
|
|
<a id='x1-60083r39'></a><span class='ecrm-0500'>39</span><span id='textcolor2833'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> irqreturn_t button_bottom_half(</span><span id='textcolor2834'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> irq, </span><span id='textcolor2835'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> *ident)</span>
|
|
<a id='x1-60085r40'></a><span class='ecrm-0500'>40</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-60087r41'></a><span class='ecrm-0500'>41</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2836'><span class='ectt-0800'>"Bottom half task starts</span></span><span id='textcolor2837'><span class='ectt-0800'>\n</span></span><span id='textcolor2838'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-60089r42'></a><span class='ecrm-0500'>42</span><span class='ectt-0800'> mdelay(500); </span><span id='textcolor2839'><span class='ectt-0800'>/* do something which takes a while */</span></span>
|
|
<a id='x1-60091r43'></a><span class='ecrm-0500'>43</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2840'><span class='ectt-0800'>"Bottom half task ends</span></span><span id='textcolor2841'><span class='ectt-0800'>\n</span></span><span id='textcolor2842'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-60093r44'></a><span class='ecrm-0500'>44</span><span class='ectt-0800'> </span><span id='textcolor2843'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> IRQ_HANDLED;</span>
|
|
<a id='x1-60095r45'></a><span class='ecrm-0500'>45</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-60097r46'></a><span class='ecrm-0500'>46</span>
|
|
<a id='x1-60099r47'></a><span class='ecrm-0500'>47</span><span id='textcolor2844'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2845'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __init bottomhalf_init(</span><span id='textcolor2846'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-60101r48'></a><span class='ecrm-0500'>48</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-60103r49'></a><span class='ecrm-0500'>49</span><span class='ectt-0800'> </span><span id='textcolor2847'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> ret = 0;</span>
|
|
<a id='x1-60105r50'></a><span class='ecrm-0500'>50</span>
|
|
<a id='x1-60107r51'></a><span class='ecrm-0500'>51</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2848'><span class='ectt-0800'>"%s</span></span><span id='textcolor2849'><span class='ectt-0800'>\n</span></span><span id='textcolor2850'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, __func__);</span>
|
|
<a id='x1-60109r52'></a><span class='ecrm-0500'>52</span>
|
|
<a id='x1-60111r53'></a><span class='ecrm-0500'>53</span><span class='ectt-0800'> </span><span id='textcolor2851'><span class='ectt-0800'>/* register LED gpios */</span></span>
|
|
<a id='x1-60113r54'></a><span class='ecrm-0500'>54</span><span class='ectt-0800'> ret = gpio_request_array(leds, ARRAY_SIZE(leds));</span>
|
|
<a id='x1-60115r55'></a><span class='ecrm-0500'>55</span>
|
|
<a id='x1-60117r56'></a><span class='ecrm-0500'>56</span><span class='ectt-0800'> </span><span id='textcolor2852'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (ret) {</span>
|
|
<a id='x1-60119r57'></a><span class='ecrm-0500'>57</span><span class='ectt-0800'> pr_err(</span><span id='textcolor2853'><span class='ectt-0800'>"Unable to request GPIOs for LEDs: %d</span></span><span id='textcolor2854'><span class='ectt-0800'>\n</span></span><span id='textcolor2855'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, ret);</span>
|
|
<a id='x1-60121r58'></a><span class='ecrm-0500'>58</span><span class='ectt-0800'> </span><span id='textcolor2856'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> ret;</span>
|
|
<a id='x1-60123r59'></a><span class='ecrm-0500'>59</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-60125r60'></a><span class='ecrm-0500'>60</span>
|
|
<a id='x1-60127r61'></a><span class='ecrm-0500'>61</span><span class='ectt-0800'> </span><span id='textcolor2857'><span class='ectt-0800'>/* register BUTTON gpios */</span></span>
|
|
<a id='x1-60129r62'></a><span class='ecrm-0500'>62</span><span class='ectt-0800'> ret = gpio_request_array(buttons, ARRAY_SIZE(buttons));</span>
|
|
<a id='x1-60131r63'></a><span class='ecrm-0500'>63</span>
|
|
<a id='x1-60133r64'></a><span class='ecrm-0500'>64</span><span class='ectt-0800'> </span><span id='textcolor2858'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (ret) {</span>
|
|
<a id='x1-60135r65'></a><span class='ecrm-0500'>65</span><span class='ectt-0800'> pr_err(</span><span id='textcolor2859'><span class='ectt-0800'>"Unable to request GPIOs for BUTTONs: %d</span></span><span id='textcolor2860'><span class='ectt-0800'>\n</span></span><span id='textcolor2861'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, ret);</span>
|
|
<a id='x1-60137r66'></a><span class='ecrm-0500'>66</span><span class='ectt-0800'> </span><span id='textcolor2862'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> fail1;</span>
|
|
<a id='x1-60139r67'></a><span class='ecrm-0500'>67</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-60141r68'></a><span class='ecrm-0500'>68</span>
|
|
<a id='x1-60143r69'></a><span class='ecrm-0500'>69</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2863'><span class='ectt-0800'>"Current button1 value: %d</span></span><span id='textcolor2864'><span class='ectt-0800'>\n</span></span><span id='textcolor2865'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, gpio_get_value(buttons[0].gpio));</span>
|
|
<a id='x1-60145r70'></a><span class='ecrm-0500'>70</span>
|
|
<a id='x1-60147r71'></a><span class='ecrm-0500'>71</span><span class='ectt-0800'> ret = gpio_to_irq(buttons[0].gpio);</span>
|
|
<a id='x1-60149r72'></a><span class='ecrm-0500'>72</span>
|
|
<a id='x1-60151r73'></a><span class='ecrm-0500'>73</span><span class='ectt-0800'> </span><span id='textcolor2866'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (ret < 0) {</span>
|
|
<a id='x1-60153r74'></a><span class='ecrm-0500'>74</span><span class='ectt-0800'> pr_err(</span><span id='textcolor2867'><span class='ectt-0800'>"Unable to request IRQ: %d</span></span><span id='textcolor2868'><span class='ectt-0800'>\n</span></span><span id='textcolor2869'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, ret);</span>
|
|
<a id='x1-60155r75'></a><span class='ecrm-0500'>75</span><span class='ectt-0800'> </span><span id='textcolor2870'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> fail2;</span>
|
|
<a id='x1-60157r76'></a><span class='ecrm-0500'>76</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-60159r77'></a><span class='ecrm-0500'>77</span>
|
|
<a id='x1-60161r78'></a><span class='ecrm-0500'>78</span><span class='ectt-0800'> button_irqs[0] = ret;</span>
|
|
<a id='x1-60163r79'></a><span class='ecrm-0500'>79</span>
|
|
<a id='x1-60165r80'></a><span class='ecrm-0500'>80</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2871'><span class='ectt-0800'>"Successfully requested BUTTON1 IRQ # %d</span></span><span id='textcolor2872'><span class='ectt-0800'>\n</span></span><span id='textcolor2873'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, button_irqs[0]);</span>
|
|
<a id='x1-60167r81'></a><span class='ecrm-0500'>81</span>
|
|
<a id='x1-60169r82'></a><span class='ecrm-0500'>82</span><span class='ectt-0800'> ret = request_threaded_irq(button_irqs[0], button_top_half,</span>
|
|
<a id='x1-60171r83'></a><span class='ecrm-0500'>83</span><span class='ectt-0800'> button_bottom_half,</span>
|
|
<a id='x1-60173r84'></a><span class='ecrm-0500'>84</span><span class='ectt-0800'> IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,</span>
|
|
<a id='x1-60175r85'></a><span class='ecrm-0500'>85</span><span class='ectt-0800'> </span><span id='textcolor2874'><span class='ectt-0800'>"gpiomod#button1"</span></span><span class='ectt-0800'>, &buttons[0]);</span>
|
|
<a id='x1-60177r86'></a><span class='ecrm-0500'>86</span>
|
|
<a id='x1-60179r87'></a><span class='ecrm-0500'>87</span><span class='ectt-0800'> </span><span id='textcolor2875'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (ret) {</span>
|
|
<a id='x1-60181r88'></a><span class='ecrm-0500'>88</span><span class='ectt-0800'> pr_err(</span><span id='textcolor2876'><span class='ectt-0800'>"Unable to request IRQ: %d</span></span><span id='textcolor2877'><span class='ectt-0800'>\n</span></span><span id='textcolor2878'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, ret);</span>
|
|
<a id='x1-60183r89'></a><span class='ecrm-0500'>89</span><span class='ectt-0800'> </span><span id='textcolor2879'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> fail2;</span>
|
|
<a id='x1-60185r90'></a><span class='ecrm-0500'>90</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-60187r91'></a><span class='ecrm-0500'>91</span>
|
|
<a id='x1-60189r92'></a><span class='ecrm-0500'>92</span><span class='ectt-0800'> ret = gpio_to_irq(buttons[1].gpio);</span>
|
|
<a id='x1-60191r93'></a><span class='ecrm-0500'>93</span>
|
|
<a id='x1-60193r94'></a><span class='ecrm-0500'>94</span><span class='ectt-0800'> </span><span id='textcolor2880'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (ret < 0) {</span>
|
|
<a id='x1-60195r95'></a><span class='ecrm-0500'>95</span><span class='ectt-0800'> pr_err(</span><span id='textcolor2881'><span class='ectt-0800'>"Unable to request IRQ: %d</span></span><span id='textcolor2882'><span class='ectt-0800'>\n</span></span><span id='textcolor2883'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, ret);</span>
|
|
<a id='x1-60197r96'></a><span class='ecrm-0500'>96</span><span class='ectt-0800'> </span><span id='textcolor2884'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> fail2;</span>
|
|
<a id='x1-60199r97'></a><span class='ecrm-0500'>97</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-60201r98'></a><span class='ecrm-0500'>98</span>
|
|
<a id='x1-60203r99'></a><span class='ecrm-0500'>99</span><span class='ectt-0800'> button_irqs[1] = ret;</span>
|
|
<a id='x1-60205r100'></a><span class='ecrm-0500'>100</span>
|
|
<a id='x1-60207r101'></a><span class='ecrm-0500'>101</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2885'><span class='ectt-0800'>"Successfully requested BUTTON2 IRQ # %d</span></span><span id='textcolor2886'><span class='ectt-0800'>\n</span></span><span id='textcolor2887'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, button_irqs[1]);</span>
|
|
<a id='x1-60209r102'></a><span class='ecrm-0500'>102</span>
|
|
<a id='x1-60211r103'></a><span class='ecrm-0500'>103</span><span class='ectt-0800'> ret = request_threaded_irq(button_irqs[1], button_top_half,</span>
|
|
<a id='x1-60213r104'></a><span class='ecrm-0500'>104</span><span class='ectt-0800'> button_bottom_half,</span>
|
|
<a id='x1-60215r105'></a><span class='ecrm-0500'>105</span><span class='ectt-0800'> IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,</span>
|
|
<a id='x1-60217r106'></a><span class='ecrm-0500'>106</span><span class='ectt-0800'> </span><span id='textcolor2888'><span class='ectt-0800'>"gpiomod#button2"</span></span><span class='ectt-0800'>, &buttons[1]);</span>
|
|
<a id='x1-60219r107'></a><span class='ecrm-0500'>107</span>
|
|
<a id='x1-60221r108'></a><span class='ecrm-0500'>108</span><span class='ectt-0800'> </span><span id='textcolor2889'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (ret) {</span>
|
|
<a id='x1-60223r109'></a><span class='ecrm-0500'>109</span><span class='ectt-0800'> pr_err(</span><span id='textcolor2890'><span class='ectt-0800'>"Unable to request IRQ: %d</span></span><span id='textcolor2891'><span class='ectt-0800'>\n</span></span><span id='textcolor2892'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, ret);</span>
|
|
<a id='x1-60225r110'></a><span class='ecrm-0500'>110</span><span class='ectt-0800'> </span><span id='textcolor2893'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> fail3;</span>
|
|
<a id='x1-60227r111'></a><span class='ecrm-0500'>111</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-60229r112'></a><span class='ecrm-0500'>112</span>
|
|
<a id='x1-60231r113'></a><span class='ecrm-0500'>113</span><span class='ectt-0800'> </span><span id='textcolor2894'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-60233r114'></a><span class='ecrm-0500'>114</span>
|
|
<a id='x1-60235r115'></a><span class='ecrm-0500'>115</span><span id='textcolor2895'><span class='ectt-0800'>/* cleanup what has been setup so far */</span></span>
|
|
<a id='x1-60237r116'></a><span class='ecrm-0500'>116</span><span class='ectt-0800'>fail3:</span>
|
|
<a id='x1-60239r117'></a><span class='ecrm-0500'>117</span><span class='ectt-0800'> free_irq(button_irqs[0], NULL);</span>
|
|
<a id='x1-60241r118'></a><span class='ecrm-0500'>118</span>
|
|
<a id='x1-60243r119'></a><span class='ecrm-0500'>119</span><span class='ectt-0800'>fail2:</span>
|
|
<a id='x1-60245r120'></a><span class='ecrm-0500'>120</span><span class='ectt-0800'> gpio_free_array(buttons, ARRAY_SIZE(leds));</span>
|
|
<a id='x1-60247r121'></a><span class='ecrm-0500'>121</span>
|
|
<a id='x1-60249r122'></a><span class='ecrm-0500'>122</span><span class='ectt-0800'>fail1:</span>
|
|
<a id='x1-60251r123'></a><span class='ecrm-0500'>123</span><span class='ectt-0800'> gpio_free_array(leds, ARRAY_SIZE(leds));</span>
|
|
<a id='x1-60253r124'></a><span class='ecrm-0500'>124</span>
|
|
<a id='x1-60255r125'></a><span class='ecrm-0500'>125</span><span class='ectt-0800'> </span><span id='textcolor2896'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> ret;</span>
|
|
<a id='x1-60257r126'></a><span class='ecrm-0500'>126</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-60259r127'></a><span class='ecrm-0500'>127</span>
|
|
<a id='x1-60261r128'></a><span class='ecrm-0500'>128</span><span id='textcolor2897'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor2898'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> __exit bottomhalf_exit(</span><span id='textcolor2899'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-60263r129'></a><span class='ecrm-0500'>129</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-60265r130'></a><span class='ecrm-0500'>130</span><span class='ectt-0800'> </span><span id='textcolor2900'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> i;</span>
|
|
<a id='x1-60267r131'></a><span class='ecrm-0500'>131</span>
|
|
<a id='x1-60269r132'></a><span class='ecrm-0500'>132</span><span class='ectt-0800'> pr_info(</span><span id='textcolor2901'><span class='ectt-0800'>"%s</span></span><span id='textcolor2902'><span class='ectt-0800'>\n</span></span><span id='textcolor2903'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, __func__);</span>
|
|
<a id='x1-60271r133'></a><span class='ecrm-0500'>133</span>
|
|
<a id='x1-60273r134'></a><span class='ecrm-0500'>134</span><span class='ectt-0800'> </span><span id='textcolor2904'><span class='ectt-0800'>/* free irqs */</span></span>
|
|
<a id='x1-60275r135'></a><span class='ecrm-0500'>135</span><span class='ectt-0800'> free_irq(button_irqs[0], NULL);</span>
|
|
<a id='x1-60277r136'></a><span class='ecrm-0500'>136</span><span class='ectt-0800'> free_irq(button_irqs[1], NULL);</span>
|
|
<a id='x1-60279r137'></a><span class='ecrm-0500'>137</span>
|
|
<a id='x1-60281r138'></a><span class='ecrm-0500'>138</span><span class='ectt-0800'> </span><span id='textcolor2905'><span class='ectt-0800'>/* turn all LEDs off */</span></span>
|
|
<a id='x1-60283r139'></a><span class='ecrm-0500'>139</span><span class='ectt-0800'> </span><span id='textcolor2906'><span class='ectt-0800'>for</span></span><span class='ectt-0800'> (i = 0; i < ARRAY_SIZE(leds); i++)</span>
|
|
<a id='x1-60285r140'></a><span class='ecrm-0500'>140</span><span class='ectt-0800'> gpio_set_value(leds[i].gpio, 0);</span>
|
|
<a id='x1-60287r141'></a><span class='ecrm-0500'>141</span>
|
|
<a id='x1-60289r142'></a><span class='ecrm-0500'>142</span><span class='ectt-0800'> </span><span id='textcolor2907'><span class='ectt-0800'>/* unregister */</span></span>
|
|
<a id='x1-60291r143'></a><span class='ecrm-0500'>143</span><span class='ectt-0800'> gpio_free_array(leds, ARRAY_SIZE(leds));</span>
|
|
<a id='x1-60293r144'></a><span class='ecrm-0500'>144</span><span class='ectt-0800'> gpio_free_array(buttons, ARRAY_SIZE(buttons));</span>
|
|
<a id='x1-60295r145'></a><span class='ecrm-0500'>145</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-60297r146'></a><span class='ecrm-0500'>146</span>
|
|
<a id='x1-60299r147'></a><span class='ecrm-0500'>147</span><span class='ectt-0800'>module_init(bottomhalf_init);</span>
|
|
<a id='x1-60301r148'></a><span class='ecrm-0500'>148</span><span class='ectt-0800'>module_exit(bottomhalf_exit);</span>
|
|
<a id='x1-60303r149'></a><span class='ecrm-0500'>149</span>
|
|
<a id='x1-60305r150'></a><span class='ecrm-0500'>150</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor2908'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-60307r151'></a><span class='ecrm-0500'>151</span><span class='ectt-0800'>MODULE_DESCRIPTION(</span><span id='textcolor2909'><span class='ectt-0800'>"Interrupt with top and bottom half"</span></span><span class='ectt-0800'>);</span></pre>
|
|
<!-- l. 1953 --><p class='indent'> A threaded IRQ is registered using <code> <span class='ectt-1000'>request_threaded_irq()</span>
|
|
</code>. This function only takes one additional parameter than the
|
|
<code> <span class='ectt-1000'>request_irq()</span>
|
|
</code> – the bottom-half handling function that runs in its own thread. In this example it is
|
|
the <code> <span class='ectt-1000'>button_bottom_half()</span>
|
|
</code>. Usage of other parameters are the same as
|
|
<code> <span class='ectt-1000'>request_irq()</span>
|
|
|
|
|
|
|
|
</code>.
|
|
</p><!-- l. 1958 --><p class='indent'> Presence of both handlers is not mandatory. If either of them is not needed, pass
|
|
the <code> <span class='ectt-1000'>NULL</span>
|
|
</code> instead. A <code> <span class='ectt-1000'>NULL</span>
|
|
</code> top-half handler implies that no action is taken except to wake up the
|
|
bottom-half serving thread, which runs the bottom-half handler. Similarly, a
|
|
<code> <span class='ectt-1000'>NULL</span>
|
|
</code> bottom-half handler effectively acts as if
|
|
<code> <span class='ectt-1000'>request_irq()</span>
|
|
</code> were used. In fact, this is how <code> <span class='ectt-1000'>request_irq()</span>
|
|
</code> is implemented.
|
|
</p><!-- l. 1964 --><p class='indent'> Note that passing <code> <span class='ectt-1000'>NULL</span>
|
|
</code> to both handlers is considered an error and will make registration fail.
|
|
</p><!-- l. 1966 --><p class='noindent'>
|
|
</p>
|
|
<h3 class='sectionHead' id='virtual-input-device-driver'><span class='titlemark'>16 </span> <a id='x1-6100016'></a>Virtual Input Device Driver</h3>
|
|
<!-- l. 1968 --><p class='noindent'>The input device driver is a module that provides a way to communicate
|
|
with the interaction device via the event. For example, the keyboard
|
|
can send the press or release event to tell the kernel what we want to
|
|
do. The input device driver will allocate a new input structure with
|
|
<code> <span class='ectt-1000'>input_allocate_device()</span>
|
|
</code> and sets up input bitfields, device id, version, etc. After that, registers it by calling
|
|
<code> <span class='ectt-1000'>input_register_device()</span>
|
|
</code>.
|
|
</p><!-- l. 1973 --><p class='indent'> Here is an example, vinput, It is an API to allow easy
|
|
development of virtual input drivers. The drivers needs to export a
|
|
<code> <span class='ectt-1000'>vinput_device()</span>
|
|
</code> that contains the virtual device name and
|
|
<code> <span class='ectt-1000'>vinput_ops</span>
|
|
</code> structure that describes:
|
|
</p>
|
|
<ul class='itemize1'>
|
|
<li class='itemize'>the init function: <code> <span class='ectt-1000'>init()</span>
|
|
</code>
|
|
</li>
|
|
<li class='itemize'>the input event injection function: <code> <span class='ectt-1000'>send()</span>
|
|
|
|
|
|
|
|
</code>
|
|
</li>
|
|
<li class='itemize'>the readback function: <code> <span class='ectt-1000'>read()</span>
|
|
</code></li></ul>
|
|
<!-- l. 1983 --><p class='indent'> Then using <code> <span class='ectt-1000'>vinput_register_device()</span>
|
|
</code> and <code> <span class='ectt-1000'>vinput_unregister_device()</span>
|
|
</code> will add a new device to the list of support virtual input devices.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb83'><a id='x1-61012r1'></a><span class='ecrm-0500'>1</span><span id='textcolor2910'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> init(</span><span id='textcolor2911'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> vinput *);</span></pre>
|
|
<!-- l. 1989 --><p class='indent'> This function is passed a <code> <span id='textcolor2912'><span class='ectt-1000'>struct</span></span><span class='ectt-1000'> vinput</span>
|
|
</code> already initialized with an allocated <code> <span id='textcolor2913'><span class='ectt-1000'>struct</span></span><span class='ectt-1000'> input_dev</span>
|
|
</code>. The <code> <span class='ectt-1000'>init()</span>
|
|
</code> function is responsible for initializing the capabilities of the input device and register
|
|
it.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb84'><a id='x1-61018r1'></a><span class='ecrm-0500'>1</span><span id='textcolor2914'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> send(</span><span id='textcolor2915'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> vinput *, </span><span id='textcolor2916'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *, </span><span id='textcolor2917'><span class='ectt-0800'>int</span></span><span class='ectt-0800'>);</span></pre>
|
|
<!-- l. 1996 --><p class='indent'> This function will receive a user string to interpret and inject the event using the
|
|
<code> <span class='ectt-1000'>input_report_XXXX</span>
|
|
</code> or <code> <span class='ectt-1000'>input_event</span>
|
|
</code> call. The string is already copied from user.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb85'><a id='x1-61023r1'></a><span class='ecrm-0500'>1</span><span id='textcolor2918'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> read(</span><span id='textcolor2919'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> vinput *, </span><span id='textcolor2920'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *, </span><span id='textcolor2921'><span class='ectt-0800'>int</span></span><span class='ectt-0800'>);</span></pre>
|
|
<!-- l. 2003 --><p class='indent'> This function is used for debugging and should fill the buffer parameter with the
|
|
last event sent in the virtual input device format. The buffer will then be copied to
|
|
user.
|
|
</p><!-- l. 2006 --><p class='indent'> vinput devices are created and destroyed using sysfs. And, event injection is done
|
|
through a <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/dev</span></span></span> node. The device name will be used by the userland to export a new
|
|
virtual input device.
|
|
</p><!-- l. 2010 --><p class='indent'> The <code> <span class='ectt-1000'>class_attribute</span>
|
|
</code> structure is similar to other attribute types we talked about in section <a href='#sysfs-interacting-with-your-module'>8<!-- tex4ht:ref: sec:sysfs --></a>:
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb86'><a id='x1-61033r1'></a><span class='ecrm-0500'>1</span><span id='textcolor2922'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> class_attribute {</span>
|
|
<a id='x1-61035r2'></a><span class='ecrm-0500'>2</span><span class='ectt-0800'> </span><span id='textcolor2923'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> attribute attr;</span>
|
|
<a id='x1-61037r3'></a><span class='ecrm-0500'>3</span><span class='ectt-0800'> </span><span id='textcolor2924'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> (*show)(</span><span id='textcolor2925'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> class *class, </span><span id='textcolor2926'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> class_attribute *attr,</span>
|
|
<a id='x1-61039r4'></a><span class='ecrm-0500'>4</span><span class='ectt-0800'> </span><span id='textcolor2927'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *buf);</span>
|
|
<a id='x1-61041r5'></a><span class='ecrm-0500'>5</span><span class='ectt-0800'> </span><span id='textcolor2928'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> (*store)(</span><span id='textcolor2929'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> class *class, </span><span id='textcolor2930'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> class_attribute *attr,</span>
|
|
<a id='x1-61043r6'></a><span class='ecrm-0500'>6</span><span class='ectt-0800'> </span><span id='textcolor2931'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor2932'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *buf, </span><span id='textcolor2933'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'> count);</span>
|
|
<a id='x1-61045r7'></a><span class='ecrm-0500'>7</span><span class='ectt-0800'>};</span></pre>
|
|
|
|
|
|
|
|
<!-- l. 2022 --><p class='indent'> In <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>vinput.c</span></span></span>, the macro <code> <span class='ectt-1000'>CLASS_ATTR_WO(export/unexport)</span>
|
|
</code> defined in <a href='https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/include/linux/device.h'>include/linux/device.h</a> (in this case, <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>device.h</span></span></span> is included in <a href='https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/include/linux/input.h'>include/linux/input.h</a>)
|
|
will generate the <code> <span class='ectt-1000'>class_attribute</span>
|
|
</code> structures which are named <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>class_attr_export/unexport</span></span></span>. Then, put them into
|
|
<code> <span class='ectt-1000'>vinput_class_attrs</span>
|
|
</code> array and the macro <code> <span class='ectt-1000'>ATTRIBUTE_GROUPS(vinput_class)</span>
|
|
</code> will generate the <code> <span id='textcolor2934'><span class='ectt-1000'>struct</span></span><span class='ectt-1000'> attribute_group vinput_class_group</span>
|
|
</code> that should be assigned in <code> <span class='ectt-1000'>vinput_class</span>
|
|
</code>. Finally, call <code> <span class='ectt-1000'>class_register(&vinput_class)</span>
|
|
</code> to create attributes in sysfs.
|
|
</p><!-- l. 2026 --><p class='indent'> To create a <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>vinputX</span></span></span> sysfs entry and <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/dev</span></span></span> node.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb87'><a id='x1-61055r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>echo </span><span id='textcolor2935'><span class='ectt-1000'>"vkbd"</span></span><span class='ectt-1000'> | sudo tee /sys/class/vinput/export</span></pre>
|
|
<!-- l. 2032 --><p class='indent'> To unexport the device, just echo its id in unexport:
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb88'><a id='x1-61058r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>echo </span><span id='textcolor2936'><span class='ectt-1000'>"0"</span></span><span class='ectt-1000'> | sudo tee /sys/class/vinput/unexport</span></pre>
|
|
|
|
<!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb89'><a id='x1-61060r1'></a><span class='ecrm-0500'>1</span><span id='textcolor2937'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-61062r2'></a><span class='ecrm-0500'>2</span><span id='textcolor2938'><span class='ectt-0800'> * vinput.h</span></span>
|
|
<a id='x1-61064r3'></a><span class='ecrm-0500'>3</span><span id='textcolor2939'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-61066r4'></a><span class='ecrm-0500'>4</span>
|
|
<a id='x1-61068r5'></a><span class='ecrm-0500'>5</span><span id='textcolor2940'><span class='ectt-0800'>#ifndef VINPUT_H</span></span>
|
|
<a id='x1-61070r6'></a><span class='ecrm-0500'>6</span><span id='textcolor2941'><span class='ectt-0800'>#define VINPUT_H</span></span>
|
|
<a id='x1-61072r7'></a><span class='ecrm-0500'>7</span>
|
|
<a id='x1-61074r8'></a><span class='ecrm-0500'>8</span><span id='textcolor2942'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2943'><span class='ectt-0800'><linux/input.h></span></span>
|
|
<a id='x1-61076r9'></a><span class='ecrm-0500'>9</span><span id='textcolor2944'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2945'><span class='ectt-0800'><linux/spinlock.h></span></span>
|
|
<a id='x1-61078r10'></a><span class='ecrm-0500'>10</span>
|
|
<a id='x1-61080r11'></a><span class='ecrm-0500'>11</span><span id='textcolor2946'><span class='ectt-0800'>#define VINPUT_MAX_LEN 128</span></span>
|
|
<a id='x1-61082r12'></a><span class='ecrm-0500'>12</span><span id='textcolor2947'><span class='ectt-0800'>#define MAX_VINPUT 32</span></span>
|
|
<a id='x1-61084r13'></a><span class='ecrm-0500'>13</span><span id='textcolor2948'><span class='ectt-0800'>#define VINPUT_MINORS MAX_VINPUT</span></span>
|
|
<a id='x1-61086r14'></a><span class='ecrm-0500'>14</span>
|
|
<a id='x1-61088r15'></a><span class='ecrm-0500'>15</span><span id='textcolor2949'><span class='ectt-0800'>#define dev_to_vinput(dev) container_of(dev, struct vinput, dev)</span></span>
|
|
<a id='x1-61090r16'></a><span class='ecrm-0500'>16</span>
|
|
<a id='x1-61092r17'></a><span class='ecrm-0500'>17</span><span id='textcolor2950'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> vinput_device;</span>
|
|
<a id='x1-61094r18'></a><span class='ecrm-0500'>18</span>
|
|
<a id='x1-61096r19'></a><span class='ecrm-0500'>19</span><span id='textcolor2951'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> vinput {</span>
|
|
<a id='x1-61098r20'></a><span class='ecrm-0500'>20</span><span class='ectt-0800'> </span><span id='textcolor2952'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> id;</span>
|
|
<a id='x1-61100r21'></a><span class='ecrm-0500'>21</span><span class='ectt-0800'> </span><span id='textcolor2953'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> devno;</span>
|
|
<a id='x1-61102r22'></a><span class='ecrm-0500'>22</span><span class='ectt-0800'> </span><span id='textcolor2954'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> last_entry;</span>
|
|
<a id='x1-61104r23'></a><span class='ecrm-0500'>23</span><span class='ectt-0800'> spinlock_t lock;</span>
|
|
<a id='x1-61106r24'></a><span class='ecrm-0500'>24</span>
|
|
<a id='x1-61108r25'></a><span class='ecrm-0500'>25</span><span class='ectt-0800'> </span><span id='textcolor2955'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> *priv_data;</span>
|
|
<a id='x1-61110r26'></a><span class='ecrm-0500'>26</span>
|
|
<a id='x1-61112r27'></a><span class='ecrm-0500'>27</span><span class='ectt-0800'> </span><span id='textcolor2956'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> device dev;</span>
|
|
<a id='x1-61114r28'></a><span class='ecrm-0500'>28</span><span class='ectt-0800'> </span><span id='textcolor2957'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> list_head list;</span>
|
|
<a id='x1-61116r29'></a><span class='ecrm-0500'>29</span><span class='ectt-0800'> </span><span id='textcolor2958'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> input_dev *input;</span>
|
|
<a id='x1-61118r30'></a><span class='ecrm-0500'>30</span><span class='ectt-0800'> </span><span id='textcolor2959'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> vinput_device *type;</span>
|
|
<a id='x1-61120r31'></a><span class='ecrm-0500'>31</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-61122r32'></a><span class='ecrm-0500'>32</span>
|
|
<a id='x1-61124r33'></a><span class='ecrm-0500'>33</span><span id='textcolor2960'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> vinput_ops {</span>
|
|
<a id='x1-61126r34'></a><span class='ecrm-0500'>34</span><span class='ectt-0800'> </span><span id='textcolor2961'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> (*init)(</span><span id='textcolor2962'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> vinput *);</span>
|
|
<a id='x1-61128r35'></a><span class='ecrm-0500'>35</span><span class='ectt-0800'> </span><span id='textcolor2963'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> (*kill)(</span><span id='textcolor2964'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> vinput *);</span>
|
|
<a id='x1-61130r36'></a><span class='ecrm-0500'>36</span><span class='ectt-0800'> </span><span id='textcolor2965'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> (*send)(</span><span id='textcolor2966'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> vinput *, </span><span id='textcolor2967'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *, </span><span id='textcolor2968'><span class='ectt-0800'>int</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-61132r37'></a><span class='ecrm-0500'>37</span><span class='ectt-0800'> </span><span id='textcolor2969'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> (*read)(</span><span id='textcolor2970'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> vinput *, </span><span id='textcolor2971'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *, </span><span id='textcolor2972'><span class='ectt-0800'>int</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-61134r38'></a><span class='ecrm-0500'>38</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-61136r39'></a><span class='ecrm-0500'>39</span>
|
|
<a id='x1-61138r40'></a><span class='ecrm-0500'>40</span><span id='textcolor2973'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> vinput_device {</span>
|
|
<a id='x1-61140r41'></a><span class='ecrm-0500'>41</span><span class='ectt-0800'> </span><span id='textcolor2974'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> name[16];</span>
|
|
<a id='x1-61142r42'></a><span class='ecrm-0500'>42</span><span class='ectt-0800'> </span><span id='textcolor2975'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> list_head list;</span>
|
|
<a id='x1-61144r43'></a><span class='ecrm-0500'>43</span><span class='ectt-0800'> </span><span id='textcolor2976'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> vinput_ops *ops;</span>
|
|
<a id='x1-61146r44'></a><span class='ecrm-0500'>44</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-61148r45'></a><span class='ecrm-0500'>45</span>
|
|
<a id='x1-61150r46'></a><span class='ecrm-0500'>46</span><span id='textcolor2977'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> vinput_register(</span><span id='textcolor2978'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> vinput_device *dev);</span>
|
|
<a id='x1-61152r47'></a><span class='ecrm-0500'>47</span><span id='textcolor2979'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> vinput_unregister(</span><span id='textcolor2980'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> vinput_device *dev);</span>
|
|
<a id='x1-61154r48'></a><span class='ecrm-0500'>48</span>
|
|
<a id='x1-61156r49'></a><span class='ecrm-0500'>49</span><span id='textcolor2981'><span class='ectt-0800'>#endif</span></span></pre>
|
|
|
|
<!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb90'><a id='x1-61158r1'></a><span class='ecrm-0500'>1</span><span id='textcolor2982'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-61160r2'></a><span class='ecrm-0500'>2</span><span id='textcolor2983'><span class='ectt-0800'> * vinput.c</span></span>
|
|
<a id='x1-61162r3'></a><span class='ecrm-0500'>3</span><span id='textcolor2984'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-61164r4'></a><span class='ecrm-0500'>4</span>
|
|
<a id='x1-61166r5'></a><span class='ecrm-0500'>5</span><span id='textcolor2985'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2986'><span class='ectt-0800'><linux/cdev.h></span></span>
|
|
<a id='x1-61168r6'></a><span class='ecrm-0500'>6</span><span id='textcolor2987'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2988'><span class='ectt-0800'><linux/input.h></span></span>
|
|
<a id='x1-61170r7'></a><span class='ecrm-0500'>7</span><span id='textcolor2989'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2990'><span class='ectt-0800'><linux/module.h></span></span>
|
|
<a id='x1-61172r8'></a><span class='ecrm-0500'>8</span><span id='textcolor2991'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2992'><span class='ectt-0800'><linux/slab.h></span></span>
|
|
<a id='x1-61174r9'></a><span class='ecrm-0500'>9</span><span id='textcolor2993'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2994'><span class='ectt-0800'><linux/spinlock.h></span></span>
|
|
<a id='x1-61176r10'></a><span class='ecrm-0500'>10</span><span id='textcolor2995'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2996'><span class='ectt-0800'><linux/version.h></span></span>
|
|
<a id='x1-61178r11'></a><span class='ecrm-0500'>11</span>
|
|
<a id='x1-61180r12'></a><span class='ecrm-0500'>12</span><span id='textcolor2997'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor2998'><span class='ectt-0800'><asm/uaccess.h></span></span>
|
|
<a id='x1-61182r13'></a><span class='ecrm-0500'>13</span>
|
|
<a id='x1-61184r14'></a><span class='ecrm-0500'>14</span><span id='textcolor2999'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor3000'><span class='ectt-0800'>"vinput.h"</span></span>
|
|
<a id='x1-61186r15'></a><span class='ecrm-0500'>15</span>
|
|
<a id='x1-61188r16'></a><span class='ecrm-0500'>16</span><span id='textcolor3001'><span class='ectt-0800'>#define DRIVER_NAME "vinput"</span></span>
|
|
<a id='x1-61190r17'></a><span class='ecrm-0500'>17</span>
|
|
<a id='x1-61192r18'></a><span class='ecrm-0500'>18</span><span id='textcolor3002'><span class='ectt-0800'>#define dev_to_vinput(dev) container_of(dev, struct vinput, dev)</span></span>
|
|
<a id='x1-61194r19'></a><span class='ecrm-0500'>19</span>
|
|
<a id='x1-61196r20'></a><span class='ecrm-0500'>20</span><span id='textcolor3003'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> DECLARE_BITMAP(vinput_ids, VINPUT_MINORS);</span>
|
|
<a id='x1-61198r21'></a><span class='ecrm-0500'>21</span>
|
|
<a id='x1-61200r22'></a><span class='ecrm-0500'>22</span><span id='textcolor3004'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> LIST_HEAD(vinput_devices);</span>
|
|
<a id='x1-61202r23'></a><span class='ecrm-0500'>23</span><span id='textcolor3005'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> LIST_HEAD(vinput_vdevices);</span>
|
|
<a id='x1-61204r24'></a><span class='ecrm-0500'>24</span>
|
|
<a id='x1-61206r25'></a><span class='ecrm-0500'>25</span><span id='textcolor3006'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3007'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> vinput_dev;</span>
|
|
<a id='x1-61208r26'></a><span class='ecrm-0500'>26</span><span id='textcolor3008'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3009'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> spinlock vinput_lock;</span>
|
|
<a id='x1-61210r27'></a><span class='ecrm-0500'>27</span><span id='textcolor3010'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3011'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> class vinput_class;</span>
|
|
<a id='x1-61212r28'></a><span class='ecrm-0500'>28</span>
|
|
<a id='x1-61214r29'></a><span class='ecrm-0500'>29</span><span id='textcolor3012'><span class='ectt-0800'>/* Search the name of vinput device in the vinput_devices linked list,</span></span>
|
|
<a id='x1-61216r30'></a><span class='ecrm-0500'>30</span><span id='textcolor3013'><span class='ectt-0800'> * which added at vinput_register().</span></span>
|
|
<a id='x1-61218r31'></a><span class='ecrm-0500'>31</span><span id='textcolor3014'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-61220r32'></a><span class='ecrm-0500'>32</span><span id='textcolor3015'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3016'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> vinput_device *vinput_get_device_by_type(</span><span id='textcolor3017'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor3018'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *type)</span>
|
|
<a id='x1-61222r33'></a><span class='ecrm-0500'>33</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-61224r34'></a><span class='ecrm-0500'>34</span><span class='ectt-0800'> </span><span id='textcolor3019'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> found = 0;</span>
|
|
<a id='x1-61226r35'></a><span class='ecrm-0500'>35</span><span class='ectt-0800'> </span><span id='textcolor3020'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> vinput_device *vinput;</span>
|
|
<a id='x1-61228r36'></a><span class='ecrm-0500'>36</span><span class='ectt-0800'> </span><span id='textcolor3021'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> list_head *curr;</span>
|
|
<a id='x1-61230r37'></a><span class='ecrm-0500'>37</span>
|
|
<a id='x1-61232r38'></a><span class='ecrm-0500'>38</span><span class='ectt-0800'> spin_lock(&vinput_lock);</span>
|
|
<a id='x1-61234r39'></a><span class='ecrm-0500'>39</span><span class='ectt-0800'> list_for_each (curr, &vinput_devices) {</span>
|
|
<a id='x1-61236r40'></a><span class='ecrm-0500'>40</span><span class='ectt-0800'> vinput = list_entry(curr, </span><span id='textcolor3022'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> vinput_device, list);</span>
|
|
<a id='x1-61238r41'></a><span class='ecrm-0500'>41</span><span class='ectt-0800'> </span><span id='textcolor3023'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (vinput && strncmp(type, vinput->name, strlen(vinput->name)) == 0) {</span>
|
|
<a id='x1-61240r42'></a><span class='ecrm-0500'>42</span><span class='ectt-0800'> found = 1;</span>
|
|
<a id='x1-61242r43'></a><span class='ecrm-0500'>43</span><span class='ectt-0800'> </span><span id='textcolor3024'><span class='ectt-0800'>break</span></span><span class='ectt-0800'>;</span>
|
|
<a id='x1-61244r44'></a><span class='ecrm-0500'>44</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-61246r45'></a><span class='ecrm-0500'>45</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-61248r46'></a><span class='ecrm-0500'>46</span><span class='ectt-0800'> spin_unlock(&vinput_lock);</span>
|
|
<a id='x1-61250r47'></a><span class='ecrm-0500'>47</span>
|
|
<a id='x1-61252r48'></a><span class='ecrm-0500'>48</span><span class='ectt-0800'> </span><span id='textcolor3025'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (found)</span>
|
|
<a id='x1-61254r49'></a><span class='ecrm-0500'>49</span><span class='ectt-0800'> </span><span id='textcolor3026'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> vinput;</span>
|
|
<a id='x1-61256r50'></a><span class='ecrm-0500'>50</span><span class='ectt-0800'> </span><span id='textcolor3027'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> ERR_PTR(-ENODEV);</span>
|
|
<a id='x1-61258r51'></a><span class='ecrm-0500'>51</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-61260r52'></a><span class='ecrm-0500'>52</span>
|
|
<a id='x1-61262r53'></a><span class='ecrm-0500'>53</span><span id='textcolor3028'><span class='ectt-0800'>/* Search the id of virtual device in the vinput_vdevices linked list,</span></span>
|
|
<a id='x1-61264r54'></a><span class='ecrm-0500'>54</span><span id='textcolor3029'><span class='ectt-0800'> * which added at vinput_alloc_vdevice().</span></span>
|
|
<a id='x1-61266r55'></a><span class='ecrm-0500'>55</span><span id='textcolor3030'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-61268r56'></a><span class='ecrm-0500'>56</span><span id='textcolor3031'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3032'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> vinput *vinput_get_vdevice_by_id(</span><span id='textcolor3033'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> id)</span>
|
|
<a id='x1-61270r57'></a><span class='ecrm-0500'>57</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-61272r58'></a><span class='ecrm-0500'>58</span><span class='ectt-0800'> </span><span id='textcolor3034'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> vinput *vinput = NULL;</span>
|
|
<a id='x1-61274r59'></a><span class='ecrm-0500'>59</span><span class='ectt-0800'> </span><span id='textcolor3035'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> list_head *curr;</span>
|
|
<a id='x1-61276r60'></a><span class='ecrm-0500'>60</span>
|
|
<a id='x1-61278r61'></a><span class='ecrm-0500'>61</span><span class='ectt-0800'> spin_lock(&vinput_lock);</span>
|
|
<a id='x1-61280r62'></a><span class='ecrm-0500'>62</span><span class='ectt-0800'> list_for_each (curr, &vinput_vdevices) {</span>
|
|
<a id='x1-61282r63'></a><span class='ecrm-0500'>63</span><span class='ectt-0800'> vinput = list_entry(curr, </span><span id='textcolor3036'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> vinput, list);</span>
|
|
<a id='x1-61284r64'></a><span class='ecrm-0500'>64</span><span class='ectt-0800'> </span><span id='textcolor3037'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (vinput && vinput->id == id)</span>
|
|
<a id='x1-61286r65'></a><span class='ecrm-0500'>65</span><span class='ectt-0800'> </span><span id='textcolor3038'><span class='ectt-0800'>break</span></span><span class='ectt-0800'>;</span>
|
|
<a id='x1-61288r66'></a><span class='ecrm-0500'>66</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-61290r67'></a><span class='ecrm-0500'>67</span><span class='ectt-0800'> spin_unlock(&vinput_lock);</span>
|
|
<a id='x1-61292r68'></a><span class='ecrm-0500'>68</span>
|
|
<a id='x1-61294r69'></a><span class='ecrm-0500'>69</span><span class='ectt-0800'> </span><span id='textcolor3039'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (vinput && vinput->id == id)</span>
|
|
<a id='x1-61296r70'></a><span class='ecrm-0500'>70</span><span class='ectt-0800'> </span><span id='textcolor3040'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> vinput;</span>
|
|
<a id='x1-61298r71'></a><span class='ecrm-0500'>71</span><span class='ectt-0800'> </span><span id='textcolor3041'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> ERR_PTR(-ENODEV);</span>
|
|
<a id='x1-61300r72'></a><span class='ecrm-0500'>72</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-61302r73'></a><span class='ecrm-0500'>73</span>
|
|
<a id='x1-61304r74'></a><span class='ecrm-0500'>74</span><span id='textcolor3042'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3043'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> vinput_open(</span><span id='textcolor3044'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> inode *inode, </span><span id='textcolor3045'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file)</span>
|
|
<a id='x1-61306r75'></a><span class='ecrm-0500'>75</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-61308r76'></a><span class='ecrm-0500'>76</span><span class='ectt-0800'> </span><span id='textcolor3046'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> err = 0;</span>
|
|
<a id='x1-61310r77'></a><span class='ecrm-0500'>77</span><span class='ectt-0800'> </span><span id='textcolor3047'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> vinput *vinput = NULL;</span>
|
|
<a id='x1-61312r78'></a><span class='ecrm-0500'>78</span>
|
|
<a id='x1-61314r79'></a><span class='ecrm-0500'>79</span><span class='ectt-0800'> vinput = vinput_get_vdevice_by_id(iminor(inode));</span>
|
|
<a id='x1-61316r80'></a><span class='ecrm-0500'>80</span>
|
|
<a id='x1-61318r81'></a><span class='ecrm-0500'>81</span><span class='ectt-0800'> </span><span id='textcolor3048'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (IS_ERR(vinput))</span>
|
|
<a id='x1-61320r82'></a><span class='ecrm-0500'>82</span><span class='ectt-0800'> err = PTR_ERR(vinput);</span>
|
|
<a id='x1-61322r83'></a><span class='ecrm-0500'>83</span><span class='ectt-0800'> </span><span id='textcolor3049'><span class='ectt-0800'>else</span></span>
|
|
<a id='x1-61324r84'></a><span class='ecrm-0500'>84</span><span class='ectt-0800'> file->private_data = vinput;</span>
|
|
<a id='x1-61326r85'></a><span class='ecrm-0500'>85</span>
|
|
<a id='x1-61328r86'></a><span class='ecrm-0500'>86</span><span class='ectt-0800'> </span><span id='textcolor3050'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> err;</span>
|
|
<a id='x1-61330r87'></a><span class='ecrm-0500'>87</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-61332r88'></a><span class='ecrm-0500'>88</span>
|
|
<a id='x1-61334r89'></a><span class='ecrm-0500'>89</span><span id='textcolor3051'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3052'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> vinput_release(</span><span id='textcolor3053'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> inode *inode, </span><span id='textcolor3054'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file)</span>
|
|
<a id='x1-61336r90'></a><span class='ecrm-0500'>90</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-61338r91'></a><span class='ecrm-0500'>91</span><span class='ectt-0800'> </span><span id='textcolor3055'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-61340r92'></a><span class='ecrm-0500'>92</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-61342r93'></a><span class='ecrm-0500'>93</span>
|
|
<a id='x1-61344r94'></a><span class='ecrm-0500'>94</span><span id='textcolor3056'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3057'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> vinput_read(</span><span id='textcolor3058'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file, </span><span id='textcolor3059'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *buffer, </span><span id='textcolor3060'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'> count,</span>
|
|
<a id='x1-61346r95'></a><span class='ecrm-0500'>95</span><span class='ectt-0800'> loff_t *offset)</span>
|
|
<a id='x1-61348r96'></a><span class='ecrm-0500'>96</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-61350r97'></a><span class='ecrm-0500'>97</span><span class='ectt-0800'> </span><span id='textcolor3061'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> len;</span>
|
|
<a id='x1-61352r98'></a><span class='ecrm-0500'>98</span><span class='ectt-0800'> </span><span id='textcolor3062'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> buff[VINPUT_MAX_LEN + 1];</span>
|
|
<a id='x1-61354r99'></a><span class='ecrm-0500'>99</span><span class='ectt-0800'> </span><span id='textcolor3063'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> vinput *vinput = file->private_data;</span>
|
|
<a id='x1-61356r100'></a><span class='ecrm-0500'>100</span>
|
|
<a id='x1-61358r101'></a><span class='ecrm-0500'>101</span><span class='ectt-0800'> len = vinput->type->ops->read(vinput, buff, count);</span>
|
|
<a id='x1-61360r102'></a><span class='ecrm-0500'>102</span>
|
|
<a id='x1-61362r103'></a><span class='ecrm-0500'>103</span><span class='ectt-0800'> </span><span id='textcolor3064'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (*offset > len)</span>
|
|
<a id='x1-61364r104'></a><span class='ecrm-0500'>104</span><span class='ectt-0800'> count = 0;</span>
|
|
<a id='x1-61366r105'></a><span class='ecrm-0500'>105</span><span class='ectt-0800'> </span><span id='textcolor3065'><span class='ectt-0800'>else</span></span><span class='ectt-0800'> </span><span id='textcolor3066'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (count + *offset > VINPUT_MAX_LEN)</span>
|
|
<a id='x1-61368r106'></a><span class='ecrm-0500'>106</span><span class='ectt-0800'> count = len - *offset;</span>
|
|
<a id='x1-61370r107'></a><span class='ecrm-0500'>107</span>
|
|
<a id='x1-61372r108'></a><span class='ecrm-0500'>108</span><span class='ectt-0800'> </span><span id='textcolor3067'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (raw_copy_to_user(buffer, buff + *offset, count))</span>
|
|
<a id='x1-61374r109'></a><span class='ecrm-0500'>109</span><span class='ectt-0800'> count = -EFAULT;</span>
|
|
<a id='x1-61376r110'></a><span class='ecrm-0500'>110</span>
|
|
<a id='x1-61378r111'></a><span class='ecrm-0500'>111</span><span class='ectt-0800'> *offset += count;</span>
|
|
<a id='x1-61380r112'></a><span class='ecrm-0500'>112</span>
|
|
<a id='x1-61382r113'></a><span class='ecrm-0500'>113</span><span class='ectt-0800'> </span><span id='textcolor3068'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> count;</span>
|
|
<a id='x1-61384r114'></a><span class='ecrm-0500'>114</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-61386r115'></a><span class='ecrm-0500'>115</span>
|
|
<a id='x1-61388r116'></a><span class='ecrm-0500'>116</span><span id='textcolor3069'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3070'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> vinput_write(</span><span id='textcolor3071'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file, </span><span id='textcolor3072'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor3073'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *buffer,</span>
|
|
<a id='x1-61390r117'></a><span class='ecrm-0500'>117</span><span class='ectt-0800'> </span><span id='textcolor3074'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'> count, loff_t *offset)</span>
|
|
<a id='x1-61392r118'></a><span class='ecrm-0500'>118</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-61394r119'></a><span class='ecrm-0500'>119</span><span class='ectt-0800'> </span><span id='textcolor3075'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> buff[VINPUT_MAX_LEN + 1];</span>
|
|
<a id='x1-61396r120'></a><span class='ecrm-0500'>120</span><span class='ectt-0800'> </span><span id='textcolor3076'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> vinput *vinput = file->private_data;</span>
|
|
<a id='x1-61398r121'></a><span class='ecrm-0500'>121</span>
|
|
<a id='x1-61400r122'></a><span class='ecrm-0500'>122</span><span class='ectt-0800'> memset(buff, 0, </span><span id='textcolor3077'><span class='ectt-0800'>sizeof</span></span><span class='ectt-0800'>(</span><span id='textcolor3078'><span class='ectt-0800'>char</span></span><span class='ectt-0800'>) * (VINPUT_MAX_LEN + 1));</span>
|
|
<a id='x1-61402r123'></a><span class='ecrm-0500'>123</span>
|
|
<a id='x1-61404r124'></a><span class='ecrm-0500'>124</span><span class='ectt-0800'> </span><span id='textcolor3079'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (count > VINPUT_MAX_LEN) {</span>
|
|
<a id='x1-61406r125'></a><span class='ecrm-0500'>125</span><span class='ectt-0800'> dev_warn(&vinput->dev, </span><span id='textcolor3080'><span class='ectt-0800'>"Too long. %d bytes allowed</span></span><span id='textcolor3081'><span class='ectt-0800'>\n</span></span><span id='textcolor3082'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, VINPUT_MAX_LEN);</span>
|
|
<a id='x1-61408r126'></a><span class='ecrm-0500'>126</span><span class='ectt-0800'> </span><span id='textcolor3083'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -EINVAL;</span>
|
|
<a id='x1-61410r127'></a><span class='ecrm-0500'>127</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-61412r128'></a><span class='ecrm-0500'>128</span>
|
|
<a id='x1-61414r129'></a><span class='ecrm-0500'>129</span><span class='ectt-0800'> </span><span id='textcolor3084'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (raw_copy_from_user(buff, buffer, count))</span>
|
|
<a id='x1-61416r130'></a><span class='ecrm-0500'>130</span><span class='ectt-0800'> </span><span id='textcolor3085'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -EFAULT;</span>
|
|
<a id='x1-61418r131'></a><span class='ecrm-0500'>131</span>
|
|
<a id='x1-61420r132'></a><span class='ecrm-0500'>132</span><span class='ectt-0800'> </span><span id='textcolor3086'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> vinput->type->ops->send(vinput, buff, count);</span>
|
|
<a id='x1-61422r133'></a><span class='ecrm-0500'>133</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-61424r134'></a><span class='ecrm-0500'>134</span>
|
|
<a id='x1-61426r135'></a><span class='ecrm-0500'>135</span><span id='textcolor3087'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3088'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor3089'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file_operations vinput_fops = {</span>
|
|
<a id='x1-61428r136'></a><span class='ecrm-0500'>136</span><span id='textcolor3090'><span class='ectt-0800'>#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 0)</span></span>
|
|
<a id='x1-61430r137'></a><span class='ecrm-0500'>137</span><span class='ectt-0800'> .owner = THIS_MODULE,</span>
|
|
<a id='x1-61432r138'></a><span class='ecrm-0500'>138</span><span id='textcolor3091'><span class='ectt-0800'>#endif</span></span>
|
|
<a id='x1-61434r139'></a><span class='ecrm-0500'>139</span><span class='ectt-0800'> .open = vinput_open,</span>
|
|
<a id='x1-61436r140'></a><span class='ecrm-0500'>140</span><span class='ectt-0800'> .release = vinput_release,</span>
|
|
<a id='x1-61438r141'></a><span class='ecrm-0500'>141</span><span class='ectt-0800'> .read = vinput_read,</span>
|
|
<a id='x1-61440r142'></a><span class='ecrm-0500'>142</span><span class='ectt-0800'> .write = vinput_write,</span>
|
|
<a id='x1-61442r143'></a><span class='ecrm-0500'>143</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-61444r144'></a><span class='ecrm-0500'>144</span>
|
|
<a id='x1-61446r145'></a><span class='ecrm-0500'>145</span><span id='textcolor3092'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3093'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> vinput_unregister_vdevice(</span><span id='textcolor3094'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> vinput *vinput)</span>
|
|
<a id='x1-61448r146'></a><span class='ecrm-0500'>146</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-61450r147'></a><span class='ecrm-0500'>147</span><span class='ectt-0800'> input_unregister_device(vinput->input);</span>
|
|
<a id='x1-61452r148'></a><span class='ecrm-0500'>148</span><span class='ectt-0800'> </span><span id='textcolor3095'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (vinput->type->ops->kill)</span>
|
|
<a id='x1-61454r149'></a><span class='ecrm-0500'>149</span><span class='ectt-0800'> vinput->type->ops->kill(vinput);</span>
|
|
<a id='x1-61456r150'></a><span class='ecrm-0500'>150</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-61458r151'></a><span class='ecrm-0500'>151</span>
|
|
<a id='x1-61460r152'></a><span class='ecrm-0500'>152</span><span id='textcolor3096'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3097'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> vinput_destroy_vdevice(</span><span id='textcolor3098'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> vinput *vinput)</span>
|
|
<a id='x1-61462r153'></a><span class='ecrm-0500'>153</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-61464r154'></a><span class='ecrm-0500'>154</span><span class='ectt-0800'> </span><span id='textcolor3099'><span class='ectt-0800'>/* Remove from the list first */</span></span>
|
|
<a id='x1-61466r155'></a><span class='ecrm-0500'>155</span><span class='ectt-0800'> spin_lock(&vinput_lock);</span>
|
|
<a id='x1-61468r156'></a><span class='ecrm-0500'>156</span><span class='ectt-0800'> list_del(&vinput->list);</span>
|
|
<a id='x1-61470r157'></a><span class='ecrm-0500'>157</span><span class='ectt-0800'> clear_bit(vinput->id, vinput_ids);</span>
|
|
<a id='x1-61472r158'></a><span class='ecrm-0500'>158</span><span class='ectt-0800'> spin_unlock(&vinput_lock);</span>
|
|
<a id='x1-61474r159'></a><span class='ecrm-0500'>159</span>
|
|
<a id='x1-61476r160'></a><span class='ecrm-0500'>160</span><span class='ectt-0800'> module_put(THIS_MODULE);</span>
|
|
<a id='x1-61478r161'></a><span class='ecrm-0500'>161</span>
|
|
<a id='x1-61480r162'></a><span class='ecrm-0500'>162</span><span class='ectt-0800'> kfree(vinput);</span>
|
|
<a id='x1-61482r163'></a><span class='ecrm-0500'>163</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-61484r164'></a><span class='ecrm-0500'>164</span>
|
|
<a id='x1-61486r165'></a><span class='ecrm-0500'>165</span><span id='textcolor3100'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3101'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> vinput_release_dev(</span><span id='textcolor3102'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> device *dev)</span>
|
|
<a id='x1-61488r166'></a><span class='ecrm-0500'>166</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-61490r167'></a><span class='ecrm-0500'>167</span><span class='ectt-0800'> </span><span id='textcolor3103'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> vinput *vinput = dev_to_vinput(dev);</span>
|
|
<a id='x1-61492r168'></a><span class='ecrm-0500'>168</span><span class='ectt-0800'> </span><span id='textcolor3104'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> id = vinput->id;</span>
|
|
<a id='x1-61494r169'></a><span class='ecrm-0500'>169</span>
|
|
<a id='x1-61496r170'></a><span class='ecrm-0500'>170</span><span class='ectt-0800'> vinput_destroy_vdevice(vinput);</span>
|
|
<a id='x1-61498r171'></a><span class='ecrm-0500'>171</span>
|
|
<a id='x1-61500r172'></a><span class='ecrm-0500'>172</span><span class='ectt-0800'> pr_debug(</span><span id='textcolor3105'><span class='ectt-0800'>"released vinput%d.</span></span><span id='textcolor3106'><span class='ectt-0800'>\n</span></span><span id='textcolor3107'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, id);</span>
|
|
<a id='x1-61502r173'></a><span class='ecrm-0500'>173</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-61504r174'></a><span class='ecrm-0500'>174</span>
|
|
<a id='x1-61506r175'></a><span class='ecrm-0500'>175</span><span id='textcolor3108'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3109'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> vinput *vinput_alloc_vdevice(</span><span id='textcolor3110'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-61508r176'></a><span class='ecrm-0500'>176</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-61510r177'></a><span class='ecrm-0500'>177</span><span class='ectt-0800'> </span><span id='textcolor3111'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> err;</span>
|
|
<a id='x1-61512r178'></a><span class='ecrm-0500'>178</span><span class='ectt-0800'> </span><span id='textcolor3112'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> vinput *vinput = kzalloc(</span><span id='textcolor3113'><span class='ectt-0800'>sizeof</span></span><span class='ectt-0800'>(</span><span id='textcolor3114'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> vinput), GFP_KERNEL);</span>
|
|
<a id='x1-61514r179'></a><span class='ecrm-0500'>179</span>
|
|
<a id='x1-61516r180'></a><span class='ecrm-0500'>180</span><span class='ectt-0800'> try_module_get(THIS_MODULE);</span>
|
|
<a id='x1-61518r181'></a><span class='ecrm-0500'>181</span>
|
|
<a id='x1-61520r182'></a><span class='ecrm-0500'>182</span><span class='ectt-0800'> memset(vinput, 0, </span><span id='textcolor3115'><span class='ectt-0800'>sizeof</span></span><span class='ectt-0800'>(</span><span id='textcolor3116'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> vinput));</span>
|
|
<a id='x1-61522r183'></a><span class='ecrm-0500'>183</span>
|
|
<a id='x1-61524r184'></a><span class='ecrm-0500'>184</span><span class='ectt-0800'> spin_lock_init(&vinput->lock);</span>
|
|
<a id='x1-61526r185'></a><span class='ecrm-0500'>185</span>
|
|
<a id='x1-61528r186'></a><span class='ecrm-0500'>186</span><span class='ectt-0800'> spin_lock(&vinput_lock);</span>
|
|
<a id='x1-61530r187'></a><span class='ecrm-0500'>187</span><span class='ectt-0800'> vinput->id = find_first_zero_bit(vinput_ids, VINPUT_MINORS);</span>
|
|
<a id='x1-61532r188'></a><span class='ecrm-0500'>188</span><span class='ectt-0800'> </span><span id='textcolor3117'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (vinput->id >= VINPUT_MINORS) {</span>
|
|
<a id='x1-61534r189'></a><span class='ecrm-0500'>189</span><span class='ectt-0800'> err = -ENOBUFS;</span>
|
|
<a id='x1-61536r190'></a><span class='ecrm-0500'>190</span><span class='ectt-0800'> </span><span id='textcolor3118'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> fail_id;</span>
|
|
<a id='x1-61538r191'></a><span class='ecrm-0500'>191</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-61540r192'></a><span class='ecrm-0500'>192</span><span class='ectt-0800'> set_bit(vinput->id, vinput_ids);</span>
|
|
<a id='x1-61542r193'></a><span class='ecrm-0500'>193</span><span class='ectt-0800'> list_add(&vinput->list, &vinput_vdevices);</span>
|
|
<a id='x1-61544r194'></a><span class='ecrm-0500'>194</span><span class='ectt-0800'> spin_unlock(&vinput_lock);</span>
|
|
<a id='x1-61546r195'></a><span class='ecrm-0500'>195</span>
|
|
<a id='x1-61548r196'></a><span class='ecrm-0500'>196</span><span class='ectt-0800'> </span><span id='textcolor3119'><span class='ectt-0800'>/* allocate the input device */</span></span>
|
|
<a id='x1-61550r197'></a><span class='ecrm-0500'>197</span><span class='ectt-0800'> vinput->input = input_allocate_device();</span>
|
|
<a id='x1-61552r198'></a><span class='ecrm-0500'>198</span><span class='ectt-0800'> </span><span id='textcolor3120'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (vinput->input == NULL) {</span>
|
|
<a id='x1-61554r199'></a><span class='ecrm-0500'>199</span><span class='ectt-0800'> pr_err(</span><span id='textcolor3121'><span class='ectt-0800'>"vinput: Cannot allocate vinput input device</span></span><span id='textcolor3122'><span class='ectt-0800'>\n</span></span><span id='textcolor3123'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-61556r200'></a><span class='ecrm-0500'>200</span><span class='ectt-0800'> err = -ENOMEM;</span>
|
|
<a id='x1-61558r201'></a><span class='ecrm-0500'>201</span><span class='ectt-0800'> </span><span id='textcolor3124'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> fail_input_dev;</span>
|
|
<a id='x1-61560r202'></a><span class='ecrm-0500'>202</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-61562r203'></a><span class='ecrm-0500'>203</span>
|
|
<a id='x1-61564r204'></a><span class='ecrm-0500'>204</span><span class='ectt-0800'> </span><span id='textcolor3125'><span class='ectt-0800'>/* initialize device */</span></span>
|
|
<a id='x1-61566r205'></a><span class='ecrm-0500'>205</span><span class='ectt-0800'> vinput->dev.class = &vinput_class;</span>
|
|
<a id='x1-61568r206'></a><span class='ecrm-0500'>206</span><span class='ectt-0800'> vinput->dev.release = vinput_release_dev;</span>
|
|
<a id='x1-61570r207'></a><span class='ecrm-0500'>207</span><span class='ectt-0800'> vinput->dev.devt = MKDEV(vinput_dev, vinput->id);</span>
|
|
<a id='x1-61572r208'></a><span class='ecrm-0500'>208</span><span class='ectt-0800'> dev_set_name(&vinput->dev, DRIVER_NAME </span><span id='textcolor3126'><span class='ectt-0800'>"%lu"</span></span><span class='ectt-0800'>, vinput->id);</span>
|
|
<a id='x1-61574r209'></a><span class='ecrm-0500'>209</span>
|
|
<a id='x1-61576r210'></a><span class='ecrm-0500'>210</span><span class='ectt-0800'> </span><span id='textcolor3127'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> vinput;</span>
|
|
<a id='x1-61578r211'></a><span class='ecrm-0500'>211</span>
|
|
<a id='x1-61580r212'></a><span class='ecrm-0500'>212</span><span class='ectt-0800'>fail_input_dev:</span>
|
|
<a id='x1-61582r213'></a><span class='ecrm-0500'>213</span><span class='ectt-0800'> spin_lock(&vinput_lock);</span>
|
|
<a id='x1-61584r214'></a><span class='ecrm-0500'>214</span><span class='ectt-0800'> list_del(&vinput->list);</span>
|
|
<a id='x1-61586r215'></a><span class='ecrm-0500'>215</span><span class='ectt-0800'>fail_id:</span>
|
|
<a id='x1-61588r216'></a><span class='ecrm-0500'>216</span><span class='ectt-0800'> spin_unlock(&vinput_lock);</span>
|
|
<a id='x1-61590r217'></a><span class='ecrm-0500'>217</span><span class='ectt-0800'> module_put(THIS_MODULE);</span>
|
|
<a id='x1-61592r218'></a><span class='ecrm-0500'>218</span><span class='ectt-0800'> kfree(vinput);</span>
|
|
<a id='x1-61594r219'></a><span class='ecrm-0500'>219</span>
|
|
<a id='x1-61596r220'></a><span class='ecrm-0500'>220</span><span class='ectt-0800'> </span><span id='textcolor3128'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> ERR_PTR(err);</span>
|
|
<a id='x1-61598r221'></a><span class='ecrm-0500'>221</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-61600r222'></a><span class='ecrm-0500'>222</span>
|
|
<a id='x1-61602r223'></a><span class='ecrm-0500'>223</span><span id='textcolor3129'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3130'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> vinput_register_vdevice(</span><span id='textcolor3131'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> vinput *vinput)</span>
|
|
<a id='x1-61604r224'></a><span class='ecrm-0500'>224</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-61606r225'></a><span class='ecrm-0500'>225</span><span class='ectt-0800'> </span><span id='textcolor3132'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> err = 0;</span>
|
|
<a id='x1-61608r226'></a><span class='ecrm-0500'>226</span>
|
|
<a id='x1-61610r227'></a><span class='ecrm-0500'>227</span><span class='ectt-0800'> </span><span id='textcolor3133'><span class='ectt-0800'>/* register the input device */</span></span>
|
|
<a id='x1-61612r228'></a><span class='ecrm-0500'>228</span><span class='ectt-0800'> vinput->input->name = vinput->type->name;</span>
|
|
<a id='x1-61614r229'></a><span class='ecrm-0500'>229</span><span class='ectt-0800'> vinput->input->phys = </span><span id='textcolor3134'><span class='ectt-0800'>"vinput"</span></span><span class='ectt-0800'>;</span>
|
|
<a id='x1-61616r230'></a><span class='ecrm-0500'>230</span><span class='ectt-0800'> vinput->input->dev.parent = &vinput->dev;</span>
|
|
<a id='x1-61618r231'></a><span class='ecrm-0500'>231</span>
|
|
<a id='x1-61620r232'></a><span class='ecrm-0500'>232</span><span class='ectt-0800'> vinput->input->id.bustype = BUS_VIRTUAL;</span>
|
|
<a id='x1-61622r233'></a><span class='ecrm-0500'>233</span><span class='ectt-0800'> vinput->input->id.product = 0x0000;</span>
|
|
<a id='x1-61624r234'></a><span class='ecrm-0500'>234</span><span class='ectt-0800'> vinput->input->id.vendor = 0x0000;</span>
|
|
<a id='x1-61626r235'></a><span class='ecrm-0500'>235</span><span class='ectt-0800'> vinput->input->id.version = 0x0000;</span>
|
|
<a id='x1-61628r236'></a><span class='ecrm-0500'>236</span>
|
|
<a id='x1-61630r237'></a><span class='ecrm-0500'>237</span><span class='ectt-0800'> err = vinput->type->ops->init(vinput);</span>
|
|
<a id='x1-61632r238'></a><span class='ecrm-0500'>238</span>
|
|
<a id='x1-61634r239'></a><span class='ecrm-0500'>239</span><span class='ectt-0800'> </span><span id='textcolor3135'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (err == 0)</span>
|
|
<a id='x1-61636r240'></a><span class='ecrm-0500'>240</span><span class='ectt-0800'> dev_info(&vinput->dev, </span><span id='textcolor3136'><span class='ectt-0800'>"Registered virtual input %s %ld</span></span><span id='textcolor3137'><span class='ectt-0800'>\n</span></span><span id='textcolor3138'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>,</span>
|
|
<a id='x1-61638r241'></a><span class='ecrm-0500'>241</span><span class='ectt-0800'> vinput->type->name, vinput->id);</span>
|
|
<a id='x1-61640r242'></a><span class='ecrm-0500'>242</span>
|
|
<a id='x1-61642r243'></a><span class='ecrm-0500'>243</span><span class='ectt-0800'> </span><span id='textcolor3139'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> err;</span>
|
|
<a id='x1-61644r244'></a><span class='ecrm-0500'>244</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-61646r245'></a><span class='ecrm-0500'>245</span>
|
|
<a id='x1-61648r246'></a><span class='ecrm-0500'>246</span><span id='textcolor3140'><span class='ectt-0800'>#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0)</span></span>
|
|
<a id='x1-61650r247'></a><span class='ecrm-0500'>247</span><span id='textcolor3141'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3142'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> export_store(</span><span id='textcolor3143'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor3144'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> class *class,</span>
|
|
<a id='x1-61652r248'></a><span class='ecrm-0500'>248</span><span class='ectt-0800'> </span><span id='textcolor3145'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor3146'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> class_attribute *attr,</span>
|
|
<a id='x1-61654r249'></a><span class='ecrm-0500'>249</span><span id='textcolor3147'><span class='ectt-0800'>#else</span></span>
|
|
<a id='x1-61656r250'></a><span class='ecrm-0500'>250</span><span id='textcolor3148'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3149'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> export_store(</span><span id='textcolor3150'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> class *class, </span><span id='textcolor3151'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> class_attribute *attr,</span>
|
|
<a id='x1-61658r251'></a><span class='ecrm-0500'>251</span><span id='textcolor3152'><span class='ectt-0800'>#endif</span></span>
|
|
<a id='x1-61660r252'></a><span class='ecrm-0500'>252</span><span class='ectt-0800'> </span><span id='textcolor3153'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor3154'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *buf, </span><span id='textcolor3155'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'> len)</span>
|
|
<a id='x1-61662r253'></a><span class='ecrm-0500'>253</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-61664r254'></a><span class='ecrm-0500'>254</span><span class='ectt-0800'> </span><span id='textcolor3156'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> err;</span>
|
|
<a id='x1-61666r255'></a><span class='ecrm-0500'>255</span><span class='ectt-0800'> </span><span id='textcolor3157'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> vinput *vinput;</span>
|
|
<a id='x1-61668r256'></a><span class='ecrm-0500'>256</span><span class='ectt-0800'> </span><span id='textcolor3158'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> vinput_device *device;</span>
|
|
<a id='x1-61670r257'></a><span class='ecrm-0500'>257</span>
|
|
<a id='x1-61672r258'></a><span class='ecrm-0500'>258</span><span class='ectt-0800'> device = vinput_get_device_by_type(buf);</span>
|
|
<a id='x1-61674r259'></a><span class='ecrm-0500'>259</span><span class='ectt-0800'> </span><span id='textcolor3159'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (IS_ERR(device)) {</span>
|
|
<a id='x1-61676r260'></a><span class='ecrm-0500'>260</span><span class='ectt-0800'> pr_info(</span><span id='textcolor3160'><span class='ectt-0800'>"vinput: This virtual device isn</span><span class='tctt-0800'>'</span><span class='ectt-0800'>t registered</span></span><span id='textcolor3161'><span class='ectt-0800'>\n</span></span><span id='textcolor3162'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-61678r261'></a><span class='ecrm-0500'>261</span><span class='ectt-0800'> err = PTR_ERR(device);</span>
|
|
<a id='x1-61680r262'></a><span class='ecrm-0500'>262</span><span class='ectt-0800'> </span><span id='textcolor3163'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> fail;</span>
|
|
<a id='x1-61682r263'></a><span class='ecrm-0500'>263</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-61684r264'></a><span class='ecrm-0500'>264</span>
|
|
<a id='x1-61686r265'></a><span class='ecrm-0500'>265</span><span class='ectt-0800'> vinput = vinput_alloc_vdevice();</span>
|
|
<a id='x1-61688r266'></a><span class='ecrm-0500'>266</span><span class='ectt-0800'> </span><span id='textcolor3164'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (IS_ERR(vinput)) {</span>
|
|
<a id='x1-61690r267'></a><span class='ecrm-0500'>267</span><span class='ectt-0800'> err = PTR_ERR(vinput);</span>
|
|
<a id='x1-61692r268'></a><span class='ecrm-0500'>268</span><span class='ectt-0800'> </span><span id='textcolor3165'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> fail;</span>
|
|
<a id='x1-61694r269'></a><span class='ecrm-0500'>269</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-61696r270'></a><span class='ecrm-0500'>270</span>
|
|
<a id='x1-61698r271'></a><span class='ecrm-0500'>271</span><span class='ectt-0800'> vinput->type = device;</span>
|
|
<a id='x1-61700r272'></a><span class='ecrm-0500'>272</span><span class='ectt-0800'> err = device_register(&vinput->dev);</span>
|
|
<a id='x1-61702r273'></a><span class='ecrm-0500'>273</span><span class='ectt-0800'> </span><span id='textcolor3166'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (err < 0)</span>
|
|
<a id='x1-61704r274'></a><span class='ecrm-0500'>274</span><span class='ectt-0800'> </span><span id='textcolor3167'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> fail_register;</span>
|
|
<a id='x1-61706r275'></a><span class='ecrm-0500'>275</span>
|
|
<a id='x1-61708r276'></a><span class='ecrm-0500'>276</span><span class='ectt-0800'> err = vinput_register_vdevice(vinput);</span>
|
|
<a id='x1-61710r277'></a><span class='ecrm-0500'>277</span><span class='ectt-0800'> </span><span id='textcolor3168'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (err < 0)</span>
|
|
<a id='x1-61712r278'></a><span class='ecrm-0500'>278</span><span class='ectt-0800'> </span><span id='textcolor3169'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> fail_register_vinput;</span>
|
|
<a id='x1-61714r279'></a><span class='ecrm-0500'>279</span>
|
|
<a id='x1-61716r280'></a><span class='ecrm-0500'>280</span><span class='ectt-0800'> </span><span id='textcolor3170'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> len;</span>
|
|
<a id='x1-61718r281'></a><span class='ecrm-0500'>281</span>
|
|
<a id='x1-61720r282'></a><span class='ecrm-0500'>282</span><span class='ectt-0800'>fail_register_vinput:</span>
|
|
<a id='x1-61722r283'></a><span class='ecrm-0500'>283</span><span class='ectt-0800'> device_unregister(&vinput->dev);</span>
|
|
<a id='x1-61724r284'></a><span class='ecrm-0500'>284</span><span class='ectt-0800'>fail_register:</span>
|
|
<a id='x1-61726r285'></a><span class='ecrm-0500'>285</span><span class='ectt-0800'> vinput_destroy_vdevice(vinput);</span>
|
|
<a id='x1-61728r286'></a><span class='ecrm-0500'>286</span><span class='ectt-0800'>fail:</span>
|
|
<a id='x1-61730r287'></a><span class='ecrm-0500'>287</span><span class='ectt-0800'> </span><span id='textcolor3171'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> err;</span>
|
|
<a id='x1-61732r288'></a><span class='ecrm-0500'>288</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-61734r289'></a><span class='ecrm-0500'>289</span><span id='textcolor3172'><span class='ectt-0800'>/* This macro generates class_attr_export structure and export_store() */</span></span>
|
|
<a id='x1-61736r290'></a><span class='ecrm-0500'>290</span><span id='textcolor3173'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> CLASS_ATTR_WO(export);</span>
|
|
<a id='x1-61738r291'></a><span class='ecrm-0500'>291</span>
|
|
<a id='x1-61740r292'></a><span class='ecrm-0500'>292</span><span id='textcolor3174'><span class='ectt-0800'>#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0)</span></span>
|
|
<a id='x1-61742r293'></a><span class='ecrm-0500'>293</span><span id='textcolor3175'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3176'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> unexport_store(</span><span id='textcolor3177'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor3178'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> class *class,</span>
|
|
<a id='x1-61744r294'></a><span class='ecrm-0500'>294</span><span class='ectt-0800'> </span><span id='textcolor3179'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor3180'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> class_attribute *attr,</span>
|
|
<a id='x1-61746r295'></a><span class='ecrm-0500'>295</span><span id='textcolor3181'><span class='ectt-0800'>#else</span></span>
|
|
<a id='x1-61748r296'></a><span class='ecrm-0500'>296</span><span id='textcolor3182'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3183'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> unexport_store(</span><span id='textcolor3184'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> class *class, </span><span id='textcolor3185'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> class_attribute *attr,</span>
|
|
<a id='x1-61750r297'></a><span class='ecrm-0500'>297</span><span id='textcolor3186'><span class='ectt-0800'>#endif</span></span>
|
|
<a id='x1-61752r298'></a><span class='ecrm-0500'>298</span><span class='ectt-0800'> </span><span id='textcolor3187'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor3188'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *buf, </span><span id='textcolor3189'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'> len)</span>
|
|
<a id='x1-61754r299'></a><span class='ecrm-0500'>299</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-61756r300'></a><span class='ecrm-0500'>300</span><span class='ectt-0800'> </span><span id='textcolor3190'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> err;</span>
|
|
<a id='x1-61758r301'></a><span class='ecrm-0500'>301</span><span class='ectt-0800'> </span><span id='textcolor3191'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor3192'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> id;</span>
|
|
<a id='x1-61760r302'></a><span class='ecrm-0500'>302</span><span class='ectt-0800'> </span><span id='textcolor3193'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> vinput *vinput;</span>
|
|
<a id='x1-61762r303'></a><span class='ecrm-0500'>303</span>
|
|
<a id='x1-61764r304'></a><span class='ecrm-0500'>304</span><span class='ectt-0800'> err = kstrtol(buf, 10, &id);</span>
|
|
<a id='x1-61766r305'></a><span class='ecrm-0500'>305</span><span class='ectt-0800'> </span><span id='textcolor3194'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (err) {</span>
|
|
<a id='x1-61768r306'></a><span class='ecrm-0500'>306</span><span class='ectt-0800'> err = -EINVAL;</span>
|
|
<a id='x1-61770r307'></a><span class='ecrm-0500'>307</span><span class='ectt-0800'> </span><span id='textcolor3195'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> failed;</span>
|
|
<a id='x1-61772r308'></a><span class='ecrm-0500'>308</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-61774r309'></a><span class='ecrm-0500'>309</span>
|
|
<a id='x1-61776r310'></a><span class='ecrm-0500'>310</span><span class='ectt-0800'> vinput = vinput_get_vdevice_by_id(id);</span>
|
|
<a id='x1-61778r311'></a><span class='ecrm-0500'>311</span><span class='ectt-0800'> </span><span id='textcolor3196'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (IS_ERR(vinput)) {</span>
|
|
<a id='x1-61780r312'></a><span class='ecrm-0500'>312</span><span class='ectt-0800'> pr_err(</span><span id='textcolor3197'><span class='ectt-0800'>"vinput: No such vinput device %ld</span></span><span id='textcolor3198'><span class='ectt-0800'>\n</span></span><span id='textcolor3199'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, id);</span>
|
|
<a id='x1-61782r313'></a><span class='ecrm-0500'>313</span><span class='ectt-0800'> err = PTR_ERR(vinput);</span>
|
|
<a id='x1-61784r314'></a><span class='ecrm-0500'>314</span><span class='ectt-0800'> </span><span id='textcolor3200'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> failed;</span>
|
|
<a id='x1-61786r315'></a><span class='ecrm-0500'>315</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-61788r316'></a><span class='ecrm-0500'>316</span>
|
|
<a id='x1-61790r317'></a><span class='ecrm-0500'>317</span><span class='ectt-0800'> vinput_unregister_vdevice(vinput);</span>
|
|
<a id='x1-61792r318'></a><span class='ecrm-0500'>318</span><span class='ectt-0800'> device_unregister(&vinput->dev);</span>
|
|
<a id='x1-61794r319'></a><span class='ecrm-0500'>319</span>
|
|
<a id='x1-61796r320'></a><span class='ecrm-0500'>320</span><span class='ectt-0800'> </span><span id='textcolor3201'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> len;</span>
|
|
<a id='x1-61798r321'></a><span class='ecrm-0500'>321</span><span class='ectt-0800'>failed:</span>
|
|
<a id='x1-61800r322'></a><span class='ecrm-0500'>322</span><span class='ectt-0800'> </span><span id='textcolor3202'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> err;</span>
|
|
<a id='x1-61802r323'></a><span class='ecrm-0500'>323</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-61804r324'></a><span class='ecrm-0500'>324</span><span id='textcolor3203'><span class='ectt-0800'>/* This macro generates class_attr_unexport structure and unexport_store() */</span></span>
|
|
<a id='x1-61806r325'></a><span class='ecrm-0500'>325</span><span id='textcolor3204'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> CLASS_ATTR_WO(unexport);</span>
|
|
<a id='x1-61808r326'></a><span class='ecrm-0500'>326</span>
|
|
<a id='x1-61810r327'></a><span class='ecrm-0500'>327</span><span id='textcolor3205'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3206'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> attribute *vinput_class_attrs[] = {</span>
|
|
<a id='x1-61812r328'></a><span class='ecrm-0500'>328</span><span class='ectt-0800'> &class_attr_export.attr,</span>
|
|
<a id='x1-61814r329'></a><span class='ecrm-0500'>329</span><span class='ectt-0800'> &class_attr_unexport.attr,</span>
|
|
<a id='x1-61816r330'></a><span class='ecrm-0500'>330</span><span class='ectt-0800'> NULL,</span>
|
|
<a id='x1-61818r331'></a><span class='ecrm-0500'>331</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-61820r332'></a><span class='ecrm-0500'>332</span>
|
|
<a id='x1-61822r333'></a><span class='ecrm-0500'>333</span><span id='textcolor3207'><span class='ectt-0800'>/* This macro generates vinput_class_groups structure */</span></span>
|
|
<a id='x1-61824r334'></a><span class='ecrm-0500'>334</span><span class='ectt-0800'>ATTRIBUTE_GROUPS(vinput_class);</span>
|
|
<a id='x1-61826r335'></a><span class='ecrm-0500'>335</span>
|
|
<a id='x1-61828r336'></a><span class='ecrm-0500'>336</span><span id='textcolor3208'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3209'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> class vinput_class = {</span>
|
|
<a id='x1-61830r337'></a><span class='ecrm-0500'>337</span><span class='ectt-0800'> .name = </span><span id='textcolor3210'><span class='ectt-0800'>"vinput"</span></span><span class='ectt-0800'>,</span>
|
|
<a id='x1-61832r338'></a><span class='ecrm-0500'>338</span><span id='textcolor3211'><span class='ectt-0800'>#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 0)</span></span>
|
|
<a id='x1-61834r339'></a><span class='ecrm-0500'>339</span><span class='ectt-0800'> .owner = THIS_MODULE,</span>
|
|
<a id='x1-61836r340'></a><span class='ecrm-0500'>340</span><span id='textcolor3212'><span class='ectt-0800'>#endif</span></span>
|
|
<a id='x1-61838r341'></a><span class='ecrm-0500'>341</span><span class='ectt-0800'> .class_groups = vinput_class_groups,</span>
|
|
<a id='x1-61840r342'></a><span class='ecrm-0500'>342</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-61842r343'></a><span class='ecrm-0500'>343</span>
|
|
<a id='x1-61844r344'></a><span class='ecrm-0500'>344</span><span id='textcolor3213'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> vinput_register(</span><span id='textcolor3214'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> vinput_device *dev)</span>
|
|
<a id='x1-61846r345'></a><span class='ecrm-0500'>345</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-61848r346'></a><span class='ecrm-0500'>346</span><span class='ectt-0800'> spin_lock(&vinput_lock);</span>
|
|
<a id='x1-61850r347'></a><span class='ecrm-0500'>347</span><span class='ectt-0800'> list_add(&dev->list, &vinput_devices);</span>
|
|
<a id='x1-61852r348'></a><span class='ecrm-0500'>348</span><span class='ectt-0800'> spin_unlock(&vinput_lock);</span>
|
|
<a id='x1-61854r349'></a><span class='ecrm-0500'>349</span>
|
|
<a id='x1-61856r350'></a><span class='ecrm-0500'>350</span><span class='ectt-0800'> pr_info(</span><span id='textcolor3215'><span class='ectt-0800'>"vinput: registered new virtual input device </span><span class='tctt-0800'>'</span><span class='ectt-0800'>%s</span><span class='tctt-0800'>'</span></span><span id='textcolor3216'><span class='ectt-0800'>\n</span></span><span id='textcolor3217'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, dev->name);</span>
|
|
<a id='x1-61858r351'></a><span class='ecrm-0500'>351</span>
|
|
<a id='x1-61860r352'></a><span class='ecrm-0500'>352</span><span class='ectt-0800'> </span><span id='textcolor3218'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-61862r353'></a><span class='ecrm-0500'>353</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-61864r354'></a><span class='ecrm-0500'>354</span><span class='ectt-0800'>EXPORT_SYMBOL(vinput_register);</span>
|
|
<a id='x1-61866r355'></a><span class='ecrm-0500'>355</span>
|
|
<a id='x1-61868r356'></a><span class='ecrm-0500'>356</span><span id='textcolor3219'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> vinput_unregister(</span><span id='textcolor3220'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> vinput_device *dev)</span>
|
|
<a id='x1-61870r357'></a><span class='ecrm-0500'>357</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-61872r358'></a><span class='ecrm-0500'>358</span><span class='ectt-0800'> </span><span id='textcolor3221'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> list_head *curr, *next;</span>
|
|
<a id='x1-61874r359'></a><span class='ecrm-0500'>359</span>
|
|
<a id='x1-61876r360'></a><span class='ecrm-0500'>360</span><span class='ectt-0800'> </span><span id='textcolor3222'><span class='ectt-0800'>/* Remove from the list first */</span></span>
|
|
<a id='x1-61878r361'></a><span class='ecrm-0500'>361</span><span class='ectt-0800'> spin_lock(&vinput_lock);</span>
|
|
<a id='x1-61880r362'></a><span class='ecrm-0500'>362</span><span class='ectt-0800'> list_del(&dev->list);</span>
|
|
<a id='x1-61882r363'></a><span class='ecrm-0500'>363</span><span class='ectt-0800'> spin_unlock(&vinput_lock);</span>
|
|
<a id='x1-61884r364'></a><span class='ecrm-0500'>364</span>
|
|
<a id='x1-61886r365'></a><span class='ecrm-0500'>365</span><span class='ectt-0800'> </span><span id='textcolor3223'><span class='ectt-0800'>/* unregister all devices of this type */</span></span>
|
|
<a id='x1-61888r366'></a><span class='ecrm-0500'>366</span><span class='ectt-0800'> list_for_each_safe (curr, next, &vinput_vdevices) {</span>
|
|
<a id='x1-61890r367'></a><span class='ecrm-0500'>367</span><span class='ectt-0800'> </span><span id='textcolor3224'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> vinput *vinput = list_entry(curr, </span><span id='textcolor3225'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> vinput, list);</span>
|
|
<a id='x1-61892r368'></a><span class='ecrm-0500'>368</span><span class='ectt-0800'> </span><span id='textcolor3226'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (vinput && vinput->type == dev) {</span>
|
|
<a id='x1-61894r369'></a><span class='ecrm-0500'>369</span><span class='ectt-0800'> vinput_unregister_vdevice(vinput);</span>
|
|
<a id='x1-61896r370'></a><span class='ecrm-0500'>370</span><span class='ectt-0800'> device_unregister(&vinput->dev);</span>
|
|
<a id='x1-61898r371'></a><span class='ecrm-0500'>371</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-61900r372'></a><span class='ecrm-0500'>372</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-61902r373'></a><span class='ecrm-0500'>373</span>
|
|
<a id='x1-61904r374'></a><span class='ecrm-0500'>374</span><span class='ectt-0800'> pr_info(</span><span id='textcolor3227'><span class='ectt-0800'>"vinput: unregistered virtual input device </span><span class='tctt-0800'>'</span><span class='ectt-0800'>%s</span><span class='tctt-0800'>'</span></span><span id='textcolor3228'><span class='ectt-0800'>\n</span></span><span id='textcolor3229'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, dev->name);</span>
|
|
<a id='x1-61906r375'></a><span class='ecrm-0500'>375</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-61908r376'></a><span class='ecrm-0500'>376</span><span class='ectt-0800'>EXPORT_SYMBOL(vinput_unregister);</span>
|
|
<a id='x1-61910r377'></a><span class='ecrm-0500'>377</span>
|
|
<a id='x1-61912r378'></a><span class='ecrm-0500'>378</span><span id='textcolor3230'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3231'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __init vinput_init(</span><span id='textcolor3232'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-61914r379'></a><span class='ecrm-0500'>379</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-61916r380'></a><span class='ecrm-0500'>380</span><span class='ectt-0800'> </span><span id='textcolor3233'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> err = 0;</span>
|
|
<a id='x1-61918r381'></a><span class='ecrm-0500'>381</span>
|
|
<a id='x1-61920r382'></a><span class='ecrm-0500'>382</span><span class='ectt-0800'> pr_info(</span><span id='textcolor3234'><span class='ectt-0800'>"vinput: Loading virtual input driver</span></span><span id='textcolor3235'><span class='ectt-0800'>\n</span></span><span id='textcolor3236'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-61922r383'></a><span class='ecrm-0500'>383</span>
|
|
<a id='x1-61924r384'></a><span class='ecrm-0500'>384</span><span class='ectt-0800'> vinput_dev = register_chrdev(0, DRIVER_NAME, &vinput_fops);</span>
|
|
<a id='x1-61926r385'></a><span class='ecrm-0500'>385</span><span class='ectt-0800'> </span><span id='textcolor3237'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (vinput_dev < 0) {</span>
|
|
<a id='x1-61928r386'></a><span class='ecrm-0500'>386</span><span class='ectt-0800'> pr_err(</span><span id='textcolor3238'><span class='ectt-0800'>"vinput: Unable to allocate char dev region</span></span><span id='textcolor3239'><span class='ectt-0800'>\n</span></span><span id='textcolor3240'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-61930r387'></a><span class='ecrm-0500'>387</span><span class='ectt-0800'> err = vinput_dev;</span>
|
|
<a id='x1-61932r388'></a><span class='ecrm-0500'>388</span><span class='ectt-0800'> </span><span id='textcolor3241'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> failed_alloc;</span>
|
|
<a id='x1-61934r389'></a><span class='ecrm-0500'>389</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-61936r390'></a><span class='ecrm-0500'>390</span>
|
|
<a id='x1-61938r391'></a><span class='ecrm-0500'>391</span><span class='ectt-0800'> spin_lock_init(&vinput_lock);</span>
|
|
<a id='x1-61940r392'></a><span class='ecrm-0500'>392</span>
|
|
<a id='x1-61942r393'></a><span class='ecrm-0500'>393</span><span class='ectt-0800'> err = class_register(&vinput_class);</span>
|
|
<a id='x1-61944r394'></a><span class='ecrm-0500'>394</span><span class='ectt-0800'> </span><span id='textcolor3242'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (err < 0) {</span>
|
|
<a id='x1-61946r395'></a><span class='ecrm-0500'>395</span><span class='ectt-0800'> pr_err(</span><span id='textcolor3243'><span class='ectt-0800'>"vinput: Unable to register vinput class</span></span><span id='textcolor3244'><span class='ectt-0800'>\n</span></span><span id='textcolor3245'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-61948r396'></a><span class='ecrm-0500'>396</span><span class='ectt-0800'> </span><span id='textcolor3246'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> failed_class;</span>
|
|
<a id='x1-61950r397'></a><span class='ecrm-0500'>397</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-61952r398'></a><span class='ecrm-0500'>398</span>
|
|
<a id='x1-61954r399'></a><span class='ecrm-0500'>399</span><span class='ectt-0800'> </span><span id='textcolor3247'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-61956r400'></a><span class='ecrm-0500'>400</span><span class='ectt-0800'>failed_class:</span>
|
|
<a id='x1-61958r401'></a><span class='ecrm-0500'>401</span><span class='ectt-0800'> class_unregister(&vinput_class);</span>
|
|
<a id='x1-61960r402'></a><span class='ecrm-0500'>402</span><span class='ectt-0800'>failed_alloc:</span>
|
|
<a id='x1-61962r403'></a><span class='ecrm-0500'>403</span><span class='ectt-0800'> </span><span id='textcolor3248'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> err;</span>
|
|
<a id='x1-61964r404'></a><span class='ecrm-0500'>404</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-61966r405'></a><span class='ecrm-0500'>405</span>
|
|
<a id='x1-61968r406'></a><span class='ecrm-0500'>406</span><span id='textcolor3249'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3250'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> __exit vinput_end(</span><span id='textcolor3251'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-61970r407'></a><span class='ecrm-0500'>407</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-61972r408'></a><span class='ecrm-0500'>408</span><span class='ectt-0800'> pr_info(</span><span id='textcolor3252'><span class='ectt-0800'>"vinput: Unloading virtual input driver</span></span><span id='textcolor3253'><span class='ectt-0800'>\n</span></span><span id='textcolor3254'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-61974r409'></a><span class='ecrm-0500'>409</span>
|
|
<a id='x1-61976r410'></a><span class='ecrm-0500'>410</span><span class='ectt-0800'> unregister_chrdev(vinput_dev, DRIVER_NAME);</span>
|
|
<a id='x1-61978r411'></a><span class='ecrm-0500'>411</span><span class='ectt-0800'> class_unregister(&vinput_class);</span>
|
|
<a id='x1-61980r412'></a><span class='ecrm-0500'>412</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-61982r413'></a><span class='ecrm-0500'>413</span>
|
|
<a id='x1-61984r414'></a><span class='ecrm-0500'>414</span><span class='ectt-0800'>module_init(vinput_init);</span>
|
|
<a id='x1-61986r415'></a><span class='ecrm-0500'>415</span><span class='ectt-0800'>module_exit(vinput_end);</span>
|
|
<a id='x1-61988r416'></a><span class='ecrm-0500'>416</span>
|
|
<a id='x1-61990r417'></a><span class='ecrm-0500'>417</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor3255'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-61992r418'></a><span class='ecrm-0500'>418</span><span class='ectt-0800'>MODULE_DESCRIPTION(</span><span id='textcolor3256'><span class='ectt-0800'>"Emulate input events"</span></span><span class='ectt-0800'>);</span></pre>
|
|
<!-- l. 2041 --><p class='indent'> Here the virtual keyboard is one of example to use vinput. It supports all
|
|
<code> <span class='ectt-1000'>KEY_MAX</span>
|
|
</code> keycodes. The injection format is the <code> <span class='ectt-1000'>KEY_CODE</span>
|
|
</code> such as defined in <a href='https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/include/linux/input.h'>include/linux/input.h</a>. A positive value means
|
|
<code> <span class='ectt-1000'>KEY_PRESS</span>
|
|
</code> while a negative value is a <code> <span class='ectt-1000'>KEY_RELEASE</span>
|
|
</code>. The keyboard supports repetition when the key stays pressed for too long. The
|
|
following demonstrates how simulation work.
|
|
</p><!-- l. 2048 --><p class='indent'> Simulate a key press on "g" (<code> <span class='ectt-1000'>KEY_G</span>
|
|
</code> = 34):
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb91'><a id='x1-62000r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>echo </span><span id='textcolor3257'><span class='ectt-1000'>"+34"</span></span><span class='ectt-1000'> | sudo tee /dev/vinput0</span></pre>
|
|
<!-- l. 2054 --><p class='indent'> Simulate a key release on "g" (<code> <span class='ectt-1000'>KEY_G</span>
|
|
</code> = 34):
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
|
|
|
|
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb92'><a id='x1-62004r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>echo </span><span id='textcolor3258'><span class='ectt-1000'>"-34"</span></span><span class='ectt-1000'> | sudo tee /dev/vinput0</span></pre>
|
|
|
|
<!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb93'><a id='x1-62006r1'></a><span class='ecrm-0500'>1</span><span id='textcolor3259'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-62008r2'></a><span class='ecrm-0500'>2</span><span id='textcolor3260'><span class='ectt-0800'> * vkbd.c</span></span>
|
|
<a id='x1-62010r3'></a><span class='ecrm-0500'>3</span><span id='textcolor3261'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-62012r4'></a><span class='ecrm-0500'>4</span>
|
|
<a id='x1-62014r5'></a><span class='ecrm-0500'>5</span><span id='textcolor3262'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor3263'><span class='ectt-0800'><linux/init.h></span></span>
|
|
<a id='x1-62016r6'></a><span class='ecrm-0500'>6</span><span id='textcolor3264'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor3265'><span class='ectt-0800'><linux/input.h></span></span>
|
|
<a id='x1-62018r7'></a><span class='ecrm-0500'>7</span><span id='textcolor3266'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor3267'><span class='ectt-0800'><linux/module.h></span></span>
|
|
<a id='x1-62020r8'></a><span class='ecrm-0500'>8</span><span id='textcolor3268'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor3269'><span class='ectt-0800'><linux/spinlock.h></span></span>
|
|
<a id='x1-62022r9'></a><span class='ecrm-0500'>9</span>
|
|
<a id='x1-62024r10'></a><span class='ecrm-0500'>10</span><span id='textcolor3270'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor3271'><span class='ectt-0800'>"vinput.h"</span></span>
|
|
<a id='x1-62026r11'></a><span class='ecrm-0500'>11</span>
|
|
<a id='x1-62028r12'></a><span class='ecrm-0500'>12</span><span id='textcolor3272'><span class='ectt-0800'>#define VINPUT_KBD "vkbd"</span></span>
|
|
<a id='x1-62030r13'></a><span class='ecrm-0500'>13</span><span id='textcolor3273'><span class='ectt-0800'>#define VINPUT_RELEASE 0</span></span>
|
|
<a id='x1-62032r14'></a><span class='ecrm-0500'>14</span><span id='textcolor3274'><span class='ectt-0800'>#define VINPUT_PRESS 1</span></span>
|
|
<a id='x1-62034r15'></a><span class='ecrm-0500'>15</span>
|
|
<a id='x1-62036r16'></a><span class='ecrm-0500'>16</span><span id='textcolor3275'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3276'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor3277'><span class='ectt-0800'>short</span></span><span class='ectt-0800'> vkeymap[KEY_MAX];</span>
|
|
<a id='x1-62038r17'></a><span class='ecrm-0500'>17</span>
|
|
<a id='x1-62040r18'></a><span class='ecrm-0500'>18</span><span id='textcolor3278'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3279'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> vinput_vkbd_init(</span><span id='textcolor3280'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> vinput *vinput)</span>
|
|
<a id='x1-62042r19'></a><span class='ecrm-0500'>19</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-62044r20'></a><span class='ecrm-0500'>20</span><span class='ectt-0800'> </span><span id='textcolor3281'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> i;</span>
|
|
<a id='x1-62046r21'></a><span class='ecrm-0500'>21</span>
|
|
<a id='x1-62048r22'></a><span class='ecrm-0500'>22</span><span class='ectt-0800'> </span><span id='textcolor3282'><span class='ectt-0800'>/* Set up the input bitfield */</span></span>
|
|
<a id='x1-62050r23'></a><span class='ecrm-0500'>23</span><span class='ectt-0800'> vinput->input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);</span>
|
|
<a id='x1-62052r24'></a><span class='ecrm-0500'>24</span><span class='ectt-0800'> vinput->input->keycodesize = </span><span id='textcolor3283'><span class='ectt-0800'>sizeof</span></span><span class='ectt-0800'>(</span><span id='textcolor3284'><span class='ectt-0800'>unsigned</span></span><span class='ectt-0800'> </span><span id='textcolor3285'><span class='ectt-0800'>short</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-62054r25'></a><span class='ecrm-0500'>25</span><span class='ectt-0800'> vinput->input->keycodemax = KEY_MAX;</span>
|
|
<a id='x1-62056r26'></a><span class='ecrm-0500'>26</span><span class='ectt-0800'> vinput->input->keycode = vkeymap;</span>
|
|
<a id='x1-62058r27'></a><span class='ecrm-0500'>27</span>
|
|
<a id='x1-62060r28'></a><span class='ecrm-0500'>28</span><span class='ectt-0800'> </span><span id='textcolor3286'><span class='ectt-0800'>for</span></span><span class='ectt-0800'> (i = 0; i < KEY_MAX; i++)</span>
|
|
<a id='x1-62062r29'></a><span class='ecrm-0500'>29</span><span class='ectt-0800'> set_bit(vkeymap[i], vinput->input->keybit);</span>
|
|
<a id='x1-62064r30'></a><span class='ecrm-0500'>30</span>
|
|
<a id='x1-62066r31'></a><span class='ecrm-0500'>31</span><span class='ectt-0800'> </span><span id='textcolor3287'><span class='ectt-0800'>/* vinput will help us allocate new input device structure via</span></span>
|
|
<a id='x1-62068r32'></a><span class='ecrm-0500'>32</span><span id='textcolor3288'><span class='ectt-0800'> * input_allocate_device(). So, we can register it straightforwardly.</span></span>
|
|
<a id='x1-62070r33'></a><span class='ecrm-0500'>33</span><span id='textcolor3289'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-62072r34'></a><span class='ecrm-0500'>34</span><span class='ectt-0800'> </span><span id='textcolor3290'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> input_register_device(vinput->input);</span>
|
|
<a id='x1-62074r35'></a><span class='ecrm-0500'>35</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-62076r36'></a><span class='ecrm-0500'>36</span>
|
|
<a id='x1-62078r37'></a><span class='ecrm-0500'>37</span><span id='textcolor3291'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3292'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> vinput_vkbd_read(</span><span id='textcolor3293'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> vinput *vinput, </span><span id='textcolor3294'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *buff, </span><span id='textcolor3295'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> len)</span>
|
|
<a id='x1-62080r38'></a><span class='ecrm-0500'>38</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-62082r39'></a><span class='ecrm-0500'>39</span><span class='ectt-0800'> spin_lock(&vinput->lock);</span>
|
|
<a id='x1-62084r40'></a><span class='ecrm-0500'>40</span><span class='ectt-0800'> len = snprintf(buff, len, </span><span id='textcolor3296'><span class='ectt-0800'>"%+ld</span></span><span id='textcolor3297'><span class='ectt-0800'>\n</span></span><span id='textcolor3298'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, vinput->last_entry);</span>
|
|
<a id='x1-62086r41'></a><span class='ecrm-0500'>41</span><span class='ectt-0800'> spin_unlock(&vinput->lock);</span>
|
|
<a id='x1-62088r42'></a><span class='ecrm-0500'>42</span>
|
|
<a id='x1-62090r43'></a><span class='ecrm-0500'>43</span><span class='ectt-0800'> </span><span id='textcolor3299'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> len;</span>
|
|
<a id='x1-62092r44'></a><span class='ecrm-0500'>44</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-62094r45'></a><span class='ecrm-0500'>45</span>
|
|
<a id='x1-62096r46'></a><span class='ecrm-0500'>46</span><span id='textcolor3300'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3301'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> vinput_vkbd_send(</span><span id='textcolor3302'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> vinput *vinput, </span><span id='textcolor3303'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *buff, </span><span id='textcolor3304'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> len)</span>
|
|
<a id='x1-62098r47'></a><span class='ecrm-0500'>47</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-62100r48'></a><span class='ecrm-0500'>48</span><span class='ectt-0800'> </span><span id='textcolor3305'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> ret;</span>
|
|
<a id='x1-62102r49'></a><span class='ecrm-0500'>49</span><span class='ectt-0800'> </span><span id='textcolor3306'><span class='ectt-0800'>long</span></span><span class='ectt-0800'> key = 0;</span>
|
|
<a id='x1-62104r50'></a><span class='ecrm-0500'>50</span><span class='ectt-0800'> </span><span id='textcolor3307'><span class='ectt-0800'>short</span></span><span class='ectt-0800'> type = VINPUT_PRESS;</span>
|
|
<a id='x1-62106r51'></a><span class='ecrm-0500'>51</span>
|
|
<a id='x1-62108r52'></a><span class='ecrm-0500'>52</span><span class='ectt-0800'> </span><span id='textcolor3308'><span class='ectt-0800'>/* Determine which event was received (press or release)</span></span>
|
|
<a id='x1-62110r53'></a><span class='ecrm-0500'>53</span><span id='textcolor3309'><span class='ectt-0800'> * and store the state.</span></span>
|
|
<a id='x1-62112r54'></a><span class='ecrm-0500'>54</span><span id='textcolor3310'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-62114r55'></a><span class='ecrm-0500'>55</span><span class='ectt-0800'> </span><span id='textcolor3311'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (buff[0] == </span><span id='textcolor3312'><span class='tctt-0800'>'</span><span class='ectt-0800'>+</span><span class='tctt-0800'>'</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-62116r56'></a><span class='ecrm-0500'>56</span><span class='ectt-0800'> ret = kstrtol(buff + 1, 10, &key);</span>
|
|
<a id='x1-62118r57'></a><span class='ecrm-0500'>57</span><span class='ectt-0800'> </span><span id='textcolor3313'><span class='ectt-0800'>else</span></span>
|
|
<a id='x1-62120r58'></a><span class='ecrm-0500'>58</span><span class='ectt-0800'> ret = kstrtol(buff, 10, &key);</span>
|
|
<a id='x1-62122r59'></a><span class='ecrm-0500'>59</span><span class='ectt-0800'> </span><span id='textcolor3314'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (ret)</span>
|
|
<a id='x1-62124r60'></a><span class='ecrm-0500'>60</span><span class='ectt-0800'> dev_err(&vinput->dev, </span><span id='textcolor3315'><span class='ectt-0800'>"error during kstrtol: -%d</span></span><span id='textcolor3316'><span class='ectt-0800'>\n</span></span><span id='textcolor3317'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, ret);</span>
|
|
<a id='x1-62126r61'></a><span class='ecrm-0500'>61</span><span class='ectt-0800'> spin_lock(&vinput->lock);</span>
|
|
<a id='x1-62128r62'></a><span class='ecrm-0500'>62</span><span class='ectt-0800'> vinput->last_entry = key;</span>
|
|
<a id='x1-62130r63'></a><span class='ecrm-0500'>63</span><span class='ectt-0800'> spin_unlock(&vinput->lock);</span>
|
|
<a id='x1-62132r64'></a><span class='ecrm-0500'>64</span>
|
|
<a id='x1-62134r65'></a><span class='ecrm-0500'>65</span><span class='ectt-0800'> </span><span id='textcolor3318'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (key < 0) {</span>
|
|
<a id='x1-62136r66'></a><span class='ecrm-0500'>66</span><span class='ectt-0800'> type = VINPUT_RELEASE;</span>
|
|
<a id='x1-62138r67'></a><span class='ecrm-0500'>67</span><span class='ectt-0800'> key = -key;</span>
|
|
<a id='x1-62140r68'></a><span class='ecrm-0500'>68</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-62142r69'></a><span class='ecrm-0500'>69</span>
|
|
<a id='x1-62144r70'></a><span class='ecrm-0500'>70</span><span class='ectt-0800'> dev_info(&vinput->dev, </span><span id='textcolor3319'><span class='ectt-0800'>"Event %s code %ld</span></span><span id='textcolor3320'><span class='ectt-0800'>\n</span></span><span id='textcolor3321'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>,</span>
|
|
<a id='x1-62146r71'></a><span class='ecrm-0500'>71</span><span class='ectt-0800'> (type == VINPUT_RELEASE) ? </span><span id='textcolor3322'><span class='ectt-0800'>"VINPUT_RELEASE"</span></span><span class='ectt-0800'> : </span><span id='textcolor3323'><span class='ectt-0800'>"VINPUT_PRESS"</span></span><span class='ectt-0800'>, key);</span>
|
|
<a id='x1-62148r72'></a><span class='ecrm-0500'>72</span>
|
|
<a id='x1-62150r73'></a><span class='ecrm-0500'>73</span><span class='ectt-0800'> </span><span id='textcolor3324'><span class='ectt-0800'>/* Report the state received to input subsystem. */</span></span>
|
|
<a id='x1-62152r74'></a><span class='ecrm-0500'>74</span><span class='ectt-0800'> input_report_key(vinput->input, key, type);</span>
|
|
<a id='x1-62154r75'></a><span class='ecrm-0500'>75</span><span class='ectt-0800'> </span><span id='textcolor3325'><span class='ectt-0800'>/* Tell input subsystem that it finished the report. */</span></span>
|
|
<a id='x1-62156r76'></a><span class='ecrm-0500'>76</span><span class='ectt-0800'> input_sync(vinput->input);</span>
|
|
<a id='x1-62158r77'></a><span class='ecrm-0500'>77</span>
|
|
<a id='x1-62160r78'></a><span class='ecrm-0500'>78</span><span class='ectt-0800'> </span><span id='textcolor3326'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> len;</span>
|
|
<a id='x1-62162r79'></a><span class='ecrm-0500'>79</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-62164r80'></a><span class='ecrm-0500'>80</span>
|
|
<a id='x1-62166r81'></a><span class='ecrm-0500'>81</span><span id='textcolor3327'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3328'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> vinput_ops vkbd_ops = {</span>
|
|
<a id='x1-62168r82'></a><span class='ecrm-0500'>82</span><span class='ectt-0800'> .init = vinput_vkbd_init,</span>
|
|
<a id='x1-62170r83'></a><span class='ecrm-0500'>83</span><span class='ectt-0800'> .send = vinput_vkbd_send,</span>
|
|
<a id='x1-62172r84'></a><span class='ecrm-0500'>84</span><span class='ectt-0800'> .read = vinput_vkbd_read,</span>
|
|
<a id='x1-62174r85'></a><span class='ecrm-0500'>85</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-62176r86'></a><span class='ecrm-0500'>86</span>
|
|
<a id='x1-62178r87'></a><span class='ecrm-0500'>87</span><span id='textcolor3329'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3330'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> vinput_device vkbd_dev = {</span>
|
|
<a id='x1-62180r88'></a><span class='ecrm-0500'>88</span><span class='ectt-0800'> .name = VINPUT_KBD,</span>
|
|
<a id='x1-62182r89'></a><span class='ecrm-0500'>89</span><span class='ectt-0800'> .ops = &vkbd_ops,</span>
|
|
<a id='x1-62184r90'></a><span class='ecrm-0500'>90</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-62186r91'></a><span class='ecrm-0500'>91</span>
|
|
<a id='x1-62188r92'></a><span class='ecrm-0500'>92</span><span id='textcolor3331'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3332'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __init vkbd_init(</span><span id='textcolor3333'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-62190r93'></a><span class='ecrm-0500'>93</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-62192r94'></a><span class='ecrm-0500'>94</span><span class='ectt-0800'> </span><span id='textcolor3334'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> i;</span>
|
|
<a id='x1-62194r95'></a><span class='ecrm-0500'>95</span>
|
|
<a id='x1-62196r96'></a><span class='ecrm-0500'>96</span><span class='ectt-0800'> </span><span id='textcolor3335'><span class='ectt-0800'>for</span></span><span class='ectt-0800'> (i = 0; i < KEY_MAX; i++)</span>
|
|
<a id='x1-62198r97'></a><span class='ecrm-0500'>97</span><span class='ectt-0800'> vkeymap[i] = i;</span>
|
|
<a id='x1-62200r98'></a><span class='ecrm-0500'>98</span><span class='ectt-0800'> </span><span id='textcolor3336'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> vinput_register(&vkbd_dev);</span>
|
|
<a id='x1-62202r99'></a><span class='ecrm-0500'>99</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-62204r100'></a><span class='ecrm-0500'>100</span>
|
|
<a id='x1-62206r101'></a><span class='ecrm-0500'>101</span><span id='textcolor3337'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3338'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> __exit vkbd_end(</span><span id='textcolor3339'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-62208r102'></a><span class='ecrm-0500'>102</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-62210r103'></a><span class='ecrm-0500'>103</span><span class='ectt-0800'> vinput_unregister(&vkbd_dev);</span>
|
|
<a id='x1-62212r104'></a><span class='ecrm-0500'>104</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-62214r105'></a><span class='ecrm-0500'>105</span>
|
|
<a id='x1-62216r106'></a><span class='ecrm-0500'>106</span><span class='ectt-0800'>module_init(vkbd_init);</span>
|
|
<a id='x1-62218r107'></a><span class='ecrm-0500'>107</span><span class='ectt-0800'>module_exit(vkbd_end);</span>
|
|
<a id='x1-62220r108'></a><span class='ecrm-0500'>108</span>
|
|
<a id='x1-62222r109'></a><span class='ecrm-0500'>109</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor3340'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-62224r110'></a><span class='ecrm-0500'>110</span><span class='ectt-0800'>MODULE_DESCRIPTION(</span><span id='textcolor3341'><span class='ectt-0800'>"Emulate keyboard input events through /dev/vinput"</span></span><span class='ectt-0800'>);</span></pre>
|
|
<!-- l. 2064 --><p class='noindent'>
|
|
</p>
|
|
<h3 class='sectionHead' id='standardizing-the-interfaces-the-device-model'><span class='titlemark'>17 </span> <a id='x1-6300017'></a>Standardizing the interfaces: The Device Model</h3>
|
|
<!-- l. 2066 --><p class='noindent'>Up to this point we have seen all kinds of modules doing all kinds of things, but there
|
|
was no consistency in their interfaces with the rest of the kernel. To impose some
|
|
consistency such that there is at minimum a standardized way to start, suspend and
|
|
resume a device model was added. An example is shown below, and you can
|
|
use this as a template to add your own suspend, resume or other interface
|
|
functions.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb94'><a id='x1-63002r1'></a><span class='ecrm-0500'>1</span><span id='textcolor3342'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-63004r2'></a><span class='ecrm-0500'>2</span><span id='textcolor3343'><span class='ectt-0800'> * devicemodel.c</span></span>
|
|
<a id='x1-63006r3'></a><span class='ecrm-0500'>3</span><span id='textcolor3344'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-63008r4'></a><span class='ecrm-0500'>4</span><span id='textcolor3345'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor3346'><span class='ectt-0800'><linux/kernel.h></span></span>
|
|
<a id='x1-63010r5'></a><span class='ecrm-0500'>5</span><span id='textcolor3347'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor3348'><span class='ectt-0800'><linux/module.h></span></span>
|
|
<a id='x1-63012r6'></a><span class='ecrm-0500'>6</span><span id='textcolor3349'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor3350'><span class='ectt-0800'><linux/platform_device.h></span></span>
|
|
<a id='x1-63014r7'></a><span class='ecrm-0500'>7</span>
|
|
<a id='x1-63016r8'></a><span class='ecrm-0500'>8</span><span id='textcolor3351'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> devicemodel_data {</span>
|
|
<a id='x1-63018r9'></a><span class='ecrm-0500'>9</span><span class='ectt-0800'> </span><span id='textcolor3352'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *greeting;</span>
|
|
<a id='x1-63020r10'></a><span class='ecrm-0500'>10</span><span class='ectt-0800'> </span><span id='textcolor3353'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> number;</span>
|
|
<a id='x1-63022r11'></a><span class='ecrm-0500'>11</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-63024r12'></a><span class='ecrm-0500'>12</span>
|
|
<a id='x1-63026r13'></a><span class='ecrm-0500'>13</span><span id='textcolor3354'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3355'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> devicemodel_probe(</span><span id='textcolor3356'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> platform_device *dev)</span>
|
|
<a id='x1-63028r14'></a><span class='ecrm-0500'>14</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-63030r15'></a><span class='ecrm-0500'>15</span><span class='ectt-0800'> </span><span id='textcolor3357'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> devicemodel_data *pd =</span>
|
|
<a id='x1-63032r16'></a><span class='ecrm-0500'>16</span><span class='ectt-0800'> (</span><span id='textcolor3358'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> devicemodel_data *)(dev->dev.platform_data);</span>
|
|
<a id='x1-63034r17'></a><span class='ecrm-0500'>17</span>
|
|
<a id='x1-63036r18'></a><span class='ecrm-0500'>18</span><span class='ectt-0800'> pr_info(</span><span id='textcolor3359'><span class='ectt-0800'>"devicemodel probe</span></span><span id='textcolor3360'><span class='ectt-0800'>\n</span></span><span id='textcolor3361'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-63038r19'></a><span class='ecrm-0500'>19</span><span class='ectt-0800'> pr_info(</span><span id='textcolor3362'><span class='ectt-0800'>"devicemodel greeting: %s; %d</span></span><span id='textcolor3363'><span class='ectt-0800'>\n</span></span><span id='textcolor3364'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, pd->greeting, pd->number);</span>
|
|
<a id='x1-63040r20'></a><span class='ecrm-0500'>20</span>
|
|
<a id='x1-63042r21'></a><span class='ecrm-0500'>21</span><span class='ectt-0800'> </span><span id='textcolor3365'><span class='ectt-0800'>/* Your device initialization code */</span></span>
|
|
<a id='x1-63044r22'></a><span class='ecrm-0500'>22</span>
|
|
<a id='x1-63046r23'></a><span class='ecrm-0500'>23</span><span class='ectt-0800'> </span><span id='textcolor3366'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-63048r24'></a><span class='ecrm-0500'>24</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-63050r25'></a><span class='ecrm-0500'>25</span>
|
|
<a id='x1-63052r26'></a><span class='ecrm-0500'>26</span><span id='textcolor3367'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3368'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> devicemodel_remove(</span><span id='textcolor3369'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> platform_device *dev)</span>
|
|
<a id='x1-63054r27'></a><span class='ecrm-0500'>27</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-63056r28'></a><span class='ecrm-0500'>28</span><span class='ectt-0800'> pr_info(</span><span id='textcolor3370'><span class='ectt-0800'>"devicemodel example removed</span></span><span id='textcolor3371'><span class='ectt-0800'>\n</span></span><span id='textcolor3372'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-63058r29'></a><span class='ecrm-0500'>29</span>
|
|
<a id='x1-63060r30'></a><span class='ecrm-0500'>30</span><span class='ectt-0800'> </span><span id='textcolor3373'><span class='ectt-0800'>/* Your device removal code */</span></span>
|
|
<a id='x1-63062r31'></a><span class='ecrm-0500'>31</span>
|
|
<a id='x1-63064r32'></a><span class='ecrm-0500'>32</span><span class='ectt-0800'> </span><span id='textcolor3374'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-63066r33'></a><span class='ecrm-0500'>33</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-63068r34'></a><span class='ecrm-0500'>34</span>
|
|
<a id='x1-63070r35'></a><span class='ecrm-0500'>35</span><span id='textcolor3375'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3376'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> devicemodel_suspend(</span><span id='textcolor3377'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> device *dev)</span>
|
|
<a id='x1-63072r36'></a><span class='ecrm-0500'>36</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-63074r37'></a><span class='ecrm-0500'>37</span><span class='ectt-0800'> pr_info(</span><span id='textcolor3378'><span class='ectt-0800'>"devicemodel example suspend</span></span><span id='textcolor3379'><span class='ectt-0800'>\n</span></span><span id='textcolor3380'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-63076r38'></a><span class='ecrm-0500'>38</span>
|
|
<a id='x1-63078r39'></a><span class='ecrm-0500'>39</span><span class='ectt-0800'> </span><span id='textcolor3381'><span class='ectt-0800'>/* Your device suspend code */</span></span>
|
|
<a id='x1-63080r40'></a><span class='ecrm-0500'>40</span>
|
|
<a id='x1-63082r41'></a><span class='ecrm-0500'>41</span><span class='ectt-0800'> </span><span id='textcolor3382'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-63084r42'></a><span class='ecrm-0500'>42</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-63086r43'></a><span class='ecrm-0500'>43</span>
|
|
<a id='x1-63088r44'></a><span class='ecrm-0500'>44</span><span id='textcolor3383'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3384'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> devicemodel_resume(</span><span id='textcolor3385'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> device *dev)</span>
|
|
<a id='x1-63090r45'></a><span class='ecrm-0500'>45</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-63092r46'></a><span class='ecrm-0500'>46</span><span class='ectt-0800'> pr_info(</span><span id='textcolor3386'><span class='ectt-0800'>"devicemodel example resume</span></span><span id='textcolor3387'><span class='ectt-0800'>\n</span></span><span id='textcolor3388'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-63094r47'></a><span class='ecrm-0500'>47</span>
|
|
<a id='x1-63096r48'></a><span class='ecrm-0500'>48</span><span class='ectt-0800'> </span><span id='textcolor3389'><span class='ectt-0800'>/* Your device resume code */</span></span>
|
|
<a id='x1-63098r49'></a><span class='ecrm-0500'>49</span>
|
|
<a id='x1-63100r50'></a><span class='ecrm-0500'>50</span><span class='ectt-0800'> </span><span id='textcolor3390'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-63102r51'></a><span class='ecrm-0500'>51</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-63104r52'></a><span class='ecrm-0500'>52</span>
|
|
<a id='x1-63106r53'></a><span class='ecrm-0500'>53</span><span id='textcolor3391'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3392'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor3393'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> dev_pm_ops devicemodel_pm_ops = {</span>
|
|
<a id='x1-63108r54'></a><span class='ecrm-0500'>54</span><span class='ectt-0800'> .suspend = devicemodel_suspend,</span>
|
|
<a id='x1-63110r55'></a><span class='ecrm-0500'>55</span><span class='ectt-0800'> .resume = devicemodel_resume,</span>
|
|
<a id='x1-63112r56'></a><span class='ecrm-0500'>56</span><span class='ectt-0800'> .poweroff = devicemodel_suspend,</span>
|
|
<a id='x1-63114r57'></a><span class='ecrm-0500'>57</span><span class='ectt-0800'> .freeze = devicemodel_suspend,</span>
|
|
<a id='x1-63116r58'></a><span class='ecrm-0500'>58</span><span class='ectt-0800'> .thaw = devicemodel_resume,</span>
|
|
<a id='x1-63118r59'></a><span class='ecrm-0500'>59</span><span class='ectt-0800'> .restore = devicemodel_resume,</span>
|
|
<a id='x1-63120r60'></a><span class='ecrm-0500'>60</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-63122r61'></a><span class='ecrm-0500'>61</span>
|
|
<a id='x1-63124r62'></a><span class='ecrm-0500'>62</span><span id='textcolor3394'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3395'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> platform_driver devicemodel_driver = {</span>
|
|
<a id='x1-63126r63'></a><span class='ecrm-0500'>63</span><span class='ectt-0800'> .driver =</span>
|
|
<a id='x1-63128r64'></a><span class='ecrm-0500'>64</span><span class='ectt-0800'> {</span>
|
|
<a id='x1-63130r65'></a><span class='ecrm-0500'>65</span><span class='ectt-0800'> .name = </span><span id='textcolor3396'><span class='ectt-0800'>"devicemodel_example"</span></span><span class='ectt-0800'>,</span>
|
|
<a id='x1-63132r66'></a><span class='ecrm-0500'>66</span><span class='ectt-0800'> .pm = &devicemodel_pm_ops,</span>
|
|
<a id='x1-63134r67'></a><span class='ecrm-0500'>67</span><span class='ectt-0800'> },</span>
|
|
<a id='x1-63136r68'></a><span class='ecrm-0500'>68</span><span class='ectt-0800'> .probe = devicemodel_probe,</span>
|
|
<a id='x1-63138r69'></a><span class='ecrm-0500'>69</span><span class='ectt-0800'> .remove = devicemodel_remove,</span>
|
|
<a id='x1-63140r70'></a><span class='ecrm-0500'>70</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-63142r71'></a><span class='ecrm-0500'>71</span>
|
|
<a id='x1-63144r72'></a><span class='ecrm-0500'>72</span><span id='textcolor3397'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3398'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __init devicemodel_init(</span><span id='textcolor3399'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-63146r73'></a><span class='ecrm-0500'>73</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-63148r74'></a><span class='ecrm-0500'>74</span><span class='ectt-0800'> </span><span id='textcolor3400'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> ret;</span>
|
|
<a id='x1-63150r75'></a><span class='ecrm-0500'>75</span>
|
|
<a id='x1-63152r76'></a><span class='ecrm-0500'>76</span><span class='ectt-0800'> pr_info(</span><span id='textcolor3401'><span class='ectt-0800'>"devicemodel init</span></span><span id='textcolor3402'><span class='ectt-0800'>\n</span></span><span id='textcolor3403'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-63154r77'></a><span class='ecrm-0500'>77</span>
|
|
<a id='x1-63156r78'></a><span class='ecrm-0500'>78</span><span class='ectt-0800'> ret = platform_driver_register(&devicemodel_driver);</span>
|
|
<a id='x1-63158r79'></a><span class='ecrm-0500'>79</span>
|
|
<a id='x1-63160r80'></a><span class='ecrm-0500'>80</span><span class='ectt-0800'> </span><span id='textcolor3404'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (ret) {</span>
|
|
<a id='x1-63162r81'></a><span class='ecrm-0500'>81</span><span class='ectt-0800'> pr_err(</span><span id='textcolor3405'><span class='ectt-0800'>"Unable to register driver</span></span><span id='textcolor3406'><span class='ectt-0800'>\n</span></span><span id='textcolor3407'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-63164r82'></a><span class='ecrm-0500'>82</span><span class='ectt-0800'> </span><span id='textcolor3408'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> ret;</span>
|
|
<a id='x1-63166r83'></a><span class='ecrm-0500'>83</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-63168r84'></a><span class='ecrm-0500'>84</span>
|
|
<a id='x1-63170r85'></a><span class='ecrm-0500'>85</span><span class='ectt-0800'> </span><span id='textcolor3409'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0;</span>
|
|
<a id='x1-63172r86'></a><span class='ecrm-0500'>86</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-63174r87'></a><span class='ecrm-0500'>87</span>
|
|
<a id='x1-63176r88'></a><span class='ecrm-0500'>88</span><span id='textcolor3410'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3411'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> __exit devicemodel_exit(</span><span id='textcolor3412'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-63178r89'></a><span class='ecrm-0500'>89</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-63180r90'></a><span class='ecrm-0500'>90</span><span class='ectt-0800'> pr_info(</span><span id='textcolor3413'><span class='ectt-0800'>"devicemodel exit</span></span><span id='textcolor3414'><span class='ectt-0800'>\n</span></span><span id='textcolor3415'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-63182r91'></a><span class='ecrm-0500'>91</span><span class='ectt-0800'> platform_driver_unregister(&devicemodel_driver);</span>
|
|
<a id='x1-63184r92'></a><span class='ecrm-0500'>92</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-63186r93'></a><span class='ecrm-0500'>93</span>
|
|
<a id='x1-63188r94'></a><span class='ecrm-0500'>94</span><span class='ectt-0800'>module_init(devicemodel_init);</span>
|
|
<a id='x1-63190r95'></a><span class='ecrm-0500'>95</span><span class='ectt-0800'>module_exit(devicemodel_exit);</span>
|
|
<a id='x1-63192r96'></a><span class='ecrm-0500'>96</span>
|
|
<a id='x1-63194r97'></a><span class='ecrm-0500'>97</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor3416'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-63196r98'></a><span class='ecrm-0500'>98</span><span class='ectt-0800'>MODULE_DESCRIPTION(</span><span id='textcolor3417'><span class='ectt-0800'>"Linux Device Model example"</span></span><span class='ectt-0800'>);</span></pre>
|
|
<!-- l. 2072 --><p class='noindent'>
|
|
</p>
|
|
<h3 class='sectionHead' id='optimizations'><span class='titlemark'>18 </span> <a id='x1-6400018'></a>Optimizations</h3>
|
|
<!-- l. 2074 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='likely-and-unlikely-conditions'><span class='titlemark'>18.1 </span> <a id='x1-6500018.1'></a>Likely and Unlikely conditions</h4>
|
|
<!-- l. 2076 --><p class='noindent'>Sometimes you might want your code to run as quickly as possible,
|
|
especially if it is handling an interrupt or doing something which might
|
|
cause noticeable latency. If your code contains boolean conditions and if
|
|
you know that the conditions are almost always likely to evaluate as either
|
|
<code> <span class='ectt-1000'>true</span>
|
|
</code> or <code> <span class='ectt-1000'>false</span>
|
|
</code>, then you can allow the compiler to optimize for this using the
|
|
<code> <span class='ectt-1000'>likely</span>
|
|
</code> and <code> <span class='ectt-1000'>unlikely</span>
|
|
</code> macros. For example, when allocating memory you are almost always expecting this
|
|
to succeed.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
|
|
|
|
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb95'><a id='x1-65012r1'></a><span class='ecrm-0500'>1</span><span class='ectt-0800'>bvl = bvec_alloc(gfp_mask, nr_iovecs, &idx);</span>
|
|
<a id='x1-65014r2'></a><span class='ecrm-0500'>2</span><span id='textcolor3418'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (unlikely(!bvl)) {</span>
|
|
<a id='x1-65016r3'></a><span class='ecrm-0500'>3</span><span class='ectt-0800'> mempool_free(bio, bio_pool);</span>
|
|
<a id='x1-65018r4'></a><span class='ecrm-0500'>4</span><span class='ectt-0800'> bio = NULL;</span>
|
|
<a id='x1-65020r5'></a><span class='ecrm-0500'>5</span><span class='ectt-0800'> </span><span id='textcolor3419'><span class='ectt-0800'>goto</span></span><span class='ectt-0800'> out;</span>
|
|
<a id='x1-65022r6'></a><span class='ecrm-0500'>6</span><span class='ectt-0800'>}</span></pre>
|
|
<!-- l. 2090 --><p class='indent'> When the <code> <span class='ectt-1000'>unlikely</span>
|
|
</code> macro is used, the compiler alters its machine instruction output, so that it
|
|
continues along the false branch and only jumps if the condition is true. That
|
|
avoids flushing the processor pipeline. The opposite happens if you use the
|
|
<code> <span class='ectt-1000'>likely</span>
|
|
</code> macro.
|
|
</p><!-- l. 2094 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='static-keys'><span class='titlemark'>18.2 </span> <a id='x1-6600018.2'></a>Static keys</h4>
|
|
<!-- l. 2096 --><p class='noindent'>Static keys allow us to enable or disable kernel code paths based on the runtime state
|
|
of key. Its APIs have been available since 2010 (most architectures are already
|
|
supported), use self-modifying code to eliminate the overhead of cache and branch
|
|
prediction. The most typical use case of static keys is for performance-sensitive kernel
|
|
code, such as tracepoints, context switching, networking, etc. These hot paths of the
|
|
kernel often contain branches and can be optimized easily using this technique.
|
|
Before we can use static keys in the kernel, we need to make sure that gcc supports
|
|
<code> <span id='textcolor3420'><span class='ectt-1000'>asm</span></span><span class='ectt-1000'> </span><span id='textcolor3421'><span class='ectt-1000'>goto</span></span>
|
|
</code> inline assembly, and the following kernel configurations are set:
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb96'><a id='x1-66006r1'></a><span class='ecrm-0500'>1</span><span class='ectt-0800'>CONFIG_JUMP_LABEL=y</span>
|
|
<a id='x1-66008r2'></a><span class='ecrm-0500'>2</span><span class='ectt-0800'>CONFIG_HAVE_ARCH_JUMP_LABEL=y</span>
|
|
<a id='x1-66010r3'></a><span class='ecrm-0500'>3</span><span class='ectt-0800'>CONFIG_HAVE_ARCH_JUMP_LABEL_RELATIVE=y</span></pre>
|
|
<!-- l. 2106 --><p class='indent'> To declare a static key, we need to define a global variable using the
|
|
<code> <span class='ectt-1000'>DEFINE_STATIC_KEY_FALSE</span>
|
|
</code> or <code> <span class='ectt-1000'>DEFINE_STATIC_KEY_TRUE</span>
|
|
</code> macro defined in <a href='https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/include/linux/jump_label.h'>include/linux/jump_label.h</a>. This macro initializes the key with
|
|
the given initial value, which is either false or true, respectively. For example, to
|
|
declare a static key with an initial value of false, we can use the following
|
|
code:
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb97'><a id='x1-66015r1'></a><span class='ecrm-0500'>1</span><span class='ectt-0800'>DEFINE_STATIC_KEY_FALSE(fkey);</span></pre>
|
|
<!-- l. 2113 --><p class='indent'> Once the static key has been declared, we need to add branching code to the
|
|
module that uses the static key. For example, the code includes a fastpath, where a
|
|
no-op instruction will be generated at compile time as the key is initialized to false
|
|
and the branch is unlikely to be taken.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb98'><a id='x1-66021r1'></a><span class='ecrm-0500'>1</span><span class='ectt-0800'>pr_info(</span><span id='textcolor3422'><span class='ectt-0800'>"fastpath 1</span></span><span id='textcolor3423'><span class='ectt-0800'>\n</span></span><span id='textcolor3424'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-66023r2'></a><span class='ecrm-0500'>2</span><span id='textcolor3425'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (static_branch_unlikely(&fkey))</span>
|
|
<a id='x1-66025r3'></a><span class='ecrm-0500'>3</span><span class='ectt-0800'> pr_alert(</span><span id='textcolor3426'><span class='ectt-0800'>"do unlikely thing</span></span><span id='textcolor3427'><span class='ectt-0800'>\n</span></span><span id='textcolor3428'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-66027r4'></a><span class='ecrm-0500'>4</span><span class='ectt-0800'>pr_info(</span><span id='textcolor3429'><span class='ectt-0800'>"fastpath 2</span></span><span id='textcolor3430'><span class='ectt-0800'>\n</span></span><span id='textcolor3431'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span></pre>
|
|
|
|
|
|
|
|
<!-- l. 2123 --><p class='indent'> If the key is enabled at runtime by calling
|
|
<code> <span class='ectt-1000'>static_branch_enable(&fkey)</span>
|
|
</code>, the fastpath will be patched with an unconditional jump instruction to the slowpath
|
|
code <code> <span class='ectt-1000'>pr_alert</span>
|
|
</code>, so the branch will always be taken until the key is disabled again.
|
|
</p><!-- l. 2125 --><p class='indent'> The following kernel module derived from <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>chardev.c</span></span></span>, demonstrates how the
|
|
static key works.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb99'><a id='x1-66031r1'></a><span class='ecrm-0500'>1</span><span id='textcolor3432'><span class='ectt-0800'>/*</span></span>
|
|
<a id='x1-66033r2'></a><span class='ecrm-0500'>2</span><span id='textcolor3433'><span class='ectt-0800'> * static_key.c</span></span>
|
|
<a id='x1-66035r3'></a><span class='ecrm-0500'>3</span><span id='textcolor3434'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-66037r4'></a><span class='ecrm-0500'>4</span>
|
|
<a id='x1-66039r5'></a><span class='ecrm-0500'>5</span><span id='textcolor3435'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor3436'><span class='ectt-0800'><linux/atomic.h></span></span>
|
|
<a id='x1-66041r6'></a><span class='ecrm-0500'>6</span><span id='textcolor3437'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor3438'><span class='ectt-0800'><linux/device.h></span></span>
|
|
<a id='x1-66043r7'></a><span class='ecrm-0500'>7</span><span id='textcolor3439'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor3440'><span class='ectt-0800'><linux/fs.h></span></span>
|
|
<a id='x1-66045r8'></a><span class='ecrm-0500'>8</span><span id='textcolor3441'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor3442'><span class='ectt-0800'><linux/kernel.h> /* for sprintf() */</span></span>
|
|
<a id='x1-66047r9'></a><span class='ecrm-0500'>9</span><span id='textcolor3443'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor3444'><span class='ectt-0800'><linux/module.h></span></span>
|
|
<a id='x1-66049r10'></a><span class='ecrm-0500'>10</span><span id='textcolor3445'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor3446'><span class='ectt-0800'><linux/printk.h></span></span>
|
|
<a id='x1-66051r11'></a><span class='ecrm-0500'>11</span><span id='textcolor3447'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor3448'><span class='ectt-0800'><linux/types.h></span></span>
|
|
<a id='x1-66053r12'></a><span class='ecrm-0500'>12</span><span id='textcolor3449'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor3450'><span class='ectt-0800'><linux/uaccess.h> /* for get_user and put_user */</span></span>
|
|
<a id='x1-66055r13'></a><span class='ecrm-0500'>13</span><span id='textcolor3451'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor3452'><span class='ectt-0800'><linux/jump_label.h> /* for static key macros */</span></span>
|
|
<a id='x1-66057r14'></a><span class='ecrm-0500'>14</span><span id='textcolor3453'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor3454'><span class='ectt-0800'><linux/version.h></span></span>
|
|
<a id='x1-66059r15'></a><span class='ecrm-0500'>15</span>
|
|
<a id='x1-66061r16'></a><span class='ecrm-0500'>16</span><span id='textcolor3455'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor3456'><span class='ectt-0800'><asm/errno.h></span></span>
|
|
<a id='x1-66063r17'></a><span class='ecrm-0500'>17</span>
|
|
<a id='x1-66065r18'></a><span class='ecrm-0500'>18</span><span id='textcolor3457'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3458'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> device_open(</span><span id='textcolor3459'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> inode *inode, </span><span id='textcolor3460'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file);</span>
|
|
<a id='x1-66067r19'></a><span class='ecrm-0500'>19</span><span id='textcolor3461'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3462'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> device_release(</span><span id='textcolor3463'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> inode *inode, </span><span id='textcolor3464'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file);</span>
|
|
<a id='x1-66069r20'></a><span class='ecrm-0500'>20</span><span id='textcolor3465'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3466'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> device_read(</span><span id='textcolor3467'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file, </span><span id='textcolor3468'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *buf, </span><span id='textcolor3469'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'> count,</span>
|
|
<a id='x1-66071r21'></a><span class='ecrm-0500'>21</span><span class='ectt-0800'> loff_t *ppos);</span>
|
|
<a id='x1-66073r22'></a><span class='ecrm-0500'>22</span><span id='textcolor3470'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3471'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> device_write(</span><span id='textcolor3472'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file, </span><span id='textcolor3473'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor3474'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *buf,</span>
|
|
<a id='x1-66075r23'></a><span class='ecrm-0500'>23</span><span class='ectt-0800'> </span><span id='textcolor3475'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'> count, loff_t *ppos);</span>
|
|
<a id='x1-66077r24'></a><span class='ecrm-0500'>24</span>
|
|
<a id='x1-66079r25'></a><span class='ecrm-0500'>25</span><span id='textcolor3476'><span class='ectt-0800'>#define SUCCESS 0</span></span>
|
|
<a id='x1-66081r26'></a><span class='ecrm-0500'>26</span><span id='textcolor3477'><span class='ectt-0800'>#define DEVICE_NAME "key_state"</span></span>
|
|
<a id='x1-66083r27'></a><span class='ecrm-0500'>27</span><span id='textcolor3478'><span class='ectt-0800'>#define BUF_LEN 10</span></span>
|
|
<a id='x1-66085r28'></a><span class='ecrm-0500'>28</span>
|
|
<a id='x1-66087r29'></a><span class='ecrm-0500'>29</span><span id='textcolor3479'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3480'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> major;</span>
|
|
<a id='x1-66089r30'></a><span class='ecrm-0500'>30</span>
|
|
<a id='x1-66091r31'></a><span class='ecrm-0500'>31</span><span id='textcolor3481'><span class='ectt-0800'>enum</span></span><span class='ectt-0800'> {</span>
|
|
<a id='x1-66093r32'></a><span class='ecrm-0500'>32</span><span class='ectt-0800'> CDEV_NOT_USED = 0,</span>
|
|
<a id='x1-66095r33'></a><span class='ecrm-0500'>33</span><span class='ectt-0800'> CDEV_EXCLUSIVE_OPEN = 1,</span>
|
|
<a id='x1-66097r34'></a><span class='ecrm-0500'>34</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-66099r35'></a><span class='ecrm-0500'>35</span>
|
|
<a id='x1-66101r36'></a><span class='ecrm-0500'>36</span><span id='textcolor3482'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> atomic_t already_open = ATOMIC_INIT(CDEV_NOT_USED);</span>
|
|
<a id='x1-66103r37'></a><span class='ecrm-0500'>37</span>
|
|
<a id='x1-66105r38'></a><span class='ecrm-0500'>38</span><span id='textcolor3483'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3484'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> msg[BUF_LEN + 1];</span>
|
|
<a id='x1-66107r39'></a><span class='ecrm-0500'>39</span>
|
|
<a id='x1-66109r40'></a><span class='ecrm-0500'>40</span><span id='textcolor3485'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3486'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> class *cls;</span>
|
|
<a id='x1-66111r41'></a><span class='ecrm-0500'>41</span>
|
|
<a id='x1-66113r42'></a><span class='ecrm-0500'>42</span><span id='textcolor3487'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> DEFINE_STATIC_KEY_FALSE(fkey);</span>
|
|
<a id='x1-66115r43'></a><span class='ecrm-0500'>43</span>
|
|
<a id='x1-66117r44'></a><span class='ecrm-0500'>44</span><span id='textcolor3488'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3489'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file_operations chardev_fops = {</span>
|
|
<a id='x1-66119r45'></a><span class='ecrm-0500'>45</span><span id='textcolor3490'><span class='ectt-0800'>#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 0)</span></span>
|
|
<a id='x1-66121r46'></a><span class='ecrm-0500'>46</span><span class='ectt-0800'> .owner = THIS_MODULE,</span>
|
|
<a id='x1-66123r47'></a><span class='ecrm-0500'>47</span><span id='textcolor3491'><span class='ectt-0800'>#endif</span></span>
|
|
<a id='x1-66125r48'></a><span class='ecrm-0500'>48</span><span class='ectt-0800'> .open = device_open,</span>
|
|
<a id='x1-66127r49'></a><span class='ecrm-0500'>49</span><span class='ectt-0800'> .release = device_release,</span>
|
|
<a id='x1-66129r50'></a><span class='ecrm-0500'>50</span><span class='ectt-0800'> .read = device_read,</span>
|
|
<a id='x1-66131r51'></a><span class='ecrm-0500'>51</span><span class='ectt-0800'> .write = device_write,</span>
|
|
<a id='x1-66133r52'></a><span class='ecrm-0500'>52</span><span class='ectt-0800'>};</span>
|
|
<a id='x1-66135r53'></a><span class='ecrm-0500'>53</span>
|
|
<a id='x1-66137r54'></a><span class='ecrm-0500'>54</span><span id='textcolor3492'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3493'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __init chardev_init(</span><span id='textcolor3494'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-66139r55'></a><span class='ecrm-0500'>55</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-66141r56'></a><span class='ecrm-0500'>56</span><span class='ectt-0800'> major = register_chrdev(0, DEVICE_NAME, &chardev_fops);</span>
|
|
<a id='x1-66143r57'></a><span class='ecrm-0500'>57</span><span class='ectt-0800'> </span><span id='textcolor3495'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (major < 0) {</span>
|
|
<a id='x1-66145r58'></a><span class='ecrm-0500'>58</span><span class='ectt-0800'> pr_alert(</span><span id='textcolor3496'><span class='ectt-0800'>"Registering char device failed with %d</span></span><span id='textcolor3497'><span class='ectt-0800'>\n</span></span><span id='textcolor3498'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, major);</span>
|
|
<a id='x1-66147r59'></a><span class='ecrm-0500'>59</span><span class='ectt-0800'> </span><span id='textcolor3499'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> major;</span>
|
|
<a id='x1-66149r60'></a><span class='ecrm-0500'>60</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-66151r61'></a><span class='ecrm-0500'>61</span>
|
|
<a id='x1-66153r62'></a><span class='ecrm-0500'>62</span><span class='ectt-0800'> pr_info(</span><span id='textcolor3500'><span class='ectt-0800'>"I was assigned major number %d</span></span><span id='textcolor3501'><span class='ectt-0800'>\n</span></span><span id='textcolor3502'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, major);</span>
|
|
<a id='x1-66155r63'></a><span class='ecrm-0500'>63</span>
|
|
<a id='x1-66157r64'></a><span class='ecrm-0500'>64</span><span id='textcolor3503'><span class='ectt-0800'>#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 0)</span></span>
|
|
<a id='x1-66159r65'></a><span class='ecrm-0500'>65</span><span class='ectt-0800'> cls = class_create(THIS_MODULE, DEVICE_NAME);</span>
|
|
<a id='x1-66161r66'></a><span class='ecrm-0500'>66</span><span id='textcolor3504'><span class='ectt-0800'>#else</span></span>
|
|
<a id='x1-66163r67'></a><span class='ecrm-0500'>67</span><span class='ectt-0800'> cls = class_create(DEVICE_NAME);</span>
|
|
<a id='x1-66165r68'></a><span class='ecrm-0500'>68</span><span id='textcolor3505'><span class='ectt-0800'>#endif</span></span>
|
|
<a id='x1-66167r69'></a><span class='ecrm-0500'>69</span>
|
|
<a id='x1-66169r70'></a><span class='ecrm-0500'>70</span><span class='ectt-0800'> device_create(cls, NULL, MKDEV(major, 0), NULL, DEVICE_NAME);</span>
|
|
<a id='x1-66171r71'></a><span class='ecrm-0500'>71</span>
|
|
<a id='x1-66173r72'></a><span class='ecrm-0500'>72</span><span class='ectt-0800'> pr_info(</span><span id='textcolor3506'><span class='ectt-0800'>"Device created on /dev/%s</span></span><span id='textcolor3507'><span class='ectt-0800'>\n</span></span><span id='textcolor3508'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, DEVICE_NAME);</span>
|
|
<a id='x1-66175r73'></a><span class='ecrm-0500'>73</span>
|
|
<a id='x1-66177r74'></a><span class='ecrm-0500'>74</span><span class='ectt-0800'> </span><span id='textcolor3509'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> SUCCESS;</span>
|
|
<a id='x1-66179r75'></a><span class='ecrm-0500'>75</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-66181r76'></a><span class='ecrm-0500'>76</span>
|
|
<a id='x1-66183r77'></a><span class='ecrm-0500'>77</span><span id='textcolor3510'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3511'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> __exit chardev_exit(</span><span id='textcolor3512'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span>
|
|
<a id='x1-66185r78'></a><span class='ecrm-0500'>78</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-66187r79'></a><span class='ecrm-0500'>79</span><span class='ectt-0800'> device_destroy(cls, MKDEV(major, 0));</span>
|
|
<a id='x1-66189r80'></a><span class='ecrm-0500'>80</span><span class='ectt-0800'> class_destroy(cls);</span>
|
|
<a id='x1-66191r81'></a><span class='ecrm-0500'>81</span>
|
|
<a id='x1-66193r82'></a><span class='ecrm-0500'>82</span><span class='ectt-0800'> </span><span id='textcolor3513'><span class='ectt-0800'>/* Unregister the device */</span></span>
|
|
<a id='x1-66195r83'></a><span class='ecrm-0500'>83</span><span class='ectt-0800'> unregister_chrdev(major, DEVICE_NAME);</span>
|
|
<a id='x1-66197r84'></a><span class='ecrm-0500'>84</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-66199r85'></a><span class='ecrm-0500'>85</span>
|
|
<a id='x1-66201r86'></a><span class='ecrm-0500'>86</span><span id='textcolor3514'><span class='ectt-0800'>/* Methods */</span></span>
|
|
<a id='x1-66203r87'></a><span class='ecrm-0500'>87</span>
|
|
<a id='x1-66205r88'></a><span class='ecrm-0500'>88</span><span id='textcolor3515'><span class='ectt-0800'>/**</span></span>
|
|
<a id='x1-66207r89'></a><span class='ecrm-0500'>89</span><span id='textcolor3516'><span class='ectt-0800'> * Called when a process tried to open the device file, like</span></span>
|
|
<a id='x1-66209r90'></a><span class='ecrm-0500'>90</span><span id='textcolor3517'><span class='ectt-0800'> * cat /dev/key_state</span></span>
|
|
<a id='x1-66211r91'></a><span class='ecrm-0500'>91</span><span id='textcolor3518'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-66213r92'></a><span class='ecrm-0500'>92</span><span id='textcolor3519'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3520'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> device_open(</span><span id='textcolor3521'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> inode *inode, </span><span id='textcolor3522'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file)</span>
|
|
<a id='x1-66215r93'></a><span class='ecrm-0500'>93</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-66217r94'></a><span class='ecrm-0500'>94</span><span class='ectt-0800'> </span><span id='textcolor3523'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (atomic_cmpxchg(&already_open, CDEV_NOT_USED, CDEV_EXCLUSIVE_OPEN))</span>
|
|
<a id='x1-66219r95'></a><span class='ecrm-0500'>95</span><span class='ectt-0800'> </span><span id='textcolor3524'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -EBUSY;</span>
|
|
<a id='x1-66221r96'></a><span class='ecrm-0500'>96</span>
|
|
<a id='x1-66223r97'></a><span class='ecrm-0500'>97</span><span class='ectt-0800'> sprintf(msg, static_key_enabled(&fkey) ? </span><span id='textcolor3525'><span class='ectt-0800'>"enabled</span></span><span id='textcolor3526'><span class='ectt-0800'>\n</span></span><span id='textcolor3527'><span class='ectt-0800'>"</span></span><span class='ectt-0800'> : </span><span id='textcolor3528'><span class='ectt-0800'>"disabled</span></span><span id='textcolor3529'><span class='ectt-0800'>\n</span></span><span id='textcolor3530'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-66225r98'></a><span class='ecrm-0500'>98</span>
|
|
<a id='x1-66227r99'></a><span class='ecrm-0500'>99</span><span class='ectt-0800'> pr_info(</span><span id='textcolor3531'><span class='ectt-0800'>"fastpath 1</span></span><span id='textcolor3532'><span class='ectt-0800'>\n</span></span><span id='textcolor3533'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-66229r100'></a><span class='ecrm-0500'>100</span><span class='ectt-0800'> </span><span id='textcolor3534'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (static_branch_unlikely(&fkey))</span>
|
|
<a id='x1-66231r101'></a><span class='ecrm-0500'>101</span><span class='ectt-0800'> pr_alert(</span><span id='textcolor3535'><span class='ectt-0800'>"do unlikely thing</span></span><span id='textcolor3536'><span class='ectt-0800'>\n</span></span><span id='textcolor3537'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-66233r102'></a><span class='ecrm-0500'>102</span><span class='ectt-0800'> pr_info(</span><span id='textcolor3538'><span class='ectt-0800'>"fastpath 2</span></span><span id='textcolor3539'><span class='ectt-0800'>\n</span></span><span id='textcolor3540'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-66235r103'></a><span class='ecrm-0500'>103</span>
|
|
<a id='x1-66237r104'></a><span class='ecrm-0500'>104</span><span class='ectt-0800'> try_module_get(THIS_MODULE);</span>
|
|
<a id='x1-66239r105'></a><span class='ecrm-0500'>105</span>
|
|
<a id='x1-66241r106'></a><span class='ecrm-0500'>106</span><span class='ectt-0800'> </span><span id='textcolor3541'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> SUCCESS;</span>
|
|
<a id='x1-66243r107'></a><span class='ecrm-0500'>107</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-66245r108'></a><span class='ecrm-0500'>108</span>
|
|
<a id='x1-66247r109'></a><span class='ecrm-0500'>109</span><span id='textcolor3542'><span class='ectt-0800'>/**</span></span>
|
|
<a id='x1-66249r110'></a><span class='ecrm-0500'>110</span><span id='textcolor3543'><span class='ectt-0800'> * Called when a process closes the device file</span></span>
|
|
<a id='x1-66251r111'></a><span class='ecrm-0500'>111</span><span id='textcolor3544'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-66253r112'></a><span class='ecrm-0500'>112</span><span id='textcolor3545'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3546'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> device_release(</span><span id='textcolor3547'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> inode *inode, </span><span id='textcolor3548'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file)</span>
|
|
<a id='x1-66255r113'></a><span class='ecrm-0500'>113</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-66257r114'></a><span class='ecrm-0500'>114</span><span class='ectt-0800'> </span><span id='textcolor3549'><span class='ectt-0800'>/* We are now ready for our next caller. */</span></span>
|
|
<a id='x1-66259r115'></a><span class='ecrm-0500'>115</span><span class='ectt-0800'> atomic_set(&already_open, CDEV_NOT_USED);</span>
|
|
<a id='x1-66261r116'></a><span class='ecrm-0500'>116</span>
|
|
<a id='x1-66263r117'></a><span class='ecrm-0500'>117</span><span class='ectt-0800'> </span><span id='textcolor3550'><span class='ectt-0800'>/**</span></span>
|
|
<a id='x1-66265r118'></a><span class='ecrm-0500'>118</span><span id='textcolor3551'><span class='ectt-0800'> * Decrement the usage count, or else once you opened the file, you will</span></span>
|
|
<a id='x1-66267r119'></a><span class='ecrm-0500'>119</span><span id='textcolor3552'><span class='ectt-0800'> * never get rid of the module.</span></span>
|
|
<a id='x1-66269r120'></a><span class='ecrm-0500'>120</span><span id='textcolor3553'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-66271r121'></a><span class='ecrm-0500'>121</span><span class='ectt-0800'> module_put(THIS_MODULE);</span>
|
|
<a id='x1-66273r122'></a><span class='ecrm-0500'>122</span>
|
|
<a id='x1-66275r123'></a><span class='ecrm-0500'>123</span><span class='ectt-0800'> </span><span id='textcolor3554'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> SUCCESS;</span>
|
|
<a id='x1-66277r124'></a><span class='ecrm-0500'>124</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-66279r125'></a><span class='ecrm-0500'>125</span>
|
|
<a id='x1-66281r126'></a><span class='ecrm-0500'>126</span><span id='textcolor3555'><span class='ectt-0800'>/**</span></span>
|
|
<a id='x1-66283r127'></a><span class='ecrm-0500'>127</span><span id='textcolor3556'><span class='ectt-0800'> * Called when a process, which already opened the dev file, attempts to</span></span>
|
|
<a id='x1-66285r128'></a><span class='ecrm-0500'>128</span><span id='textcolor3557'><span class='ectt-0800'> * read from it.</span></span>
|
|
<a id='x1-66287r129'></a><span class='ecrm-0500'>129</span><span id='textcolor3558'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-66289r130'></a><span class='ecrm-0500'>130</span><span id='textcolor3559'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3560'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> device_read(</span><span id='textcolor3561'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *filp, </span><span id='textcolor3562'><span class='ectt-0800'>/* see include/linux/fs.h */</span></span>
|
|
<a id='x1-66291r131'></a><span class='ecrm-0500'>131</span><span class='ectt-0800'> </span><span id='textcolor3563'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *buffer, </span><span id='textcolor3564'><span class='ectt-0800'>/* buffer to fill with data */</span></span>
|
|
<a id='x1-66293r132'></a><span class='ecrm-0500'>132</span><span class='ectt-0800'> </span><span id='textcolor3565'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'> length, </span><span id='textcolor3566'><span class='ectt-0800'>/* length of the buffer */</span></span>
|
|
<a id='x1-66295r133'></a><span class='ecrm-0500'>133</span><span class='ectt-0800'> loff_t *offset)</span>
|
|
<a id='x1-66297r134'></a><span class='ecrm-0500'>134</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-66299r135'></a><span class='ecrm-0500'>135</span><span class='ectt-0800'> </span><span id='textcolor3567'><span class='ectt-0800'>/* Number of the bytes actually written to the buffer */</span></span>
|
|
<a id='x1-66301r136'></a><span class='ecrm-0500'>136</span><span class='ectt-0800'> </span><span id='textcolor3568'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> bytes_read = 0;</span>
|
|
<a id='x1-66303r137'></a><span class='ecrm-0500'>137</span><span class='ectt-0800'> </span><span id='textcolor3569'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor3570'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *msg_ptr = msg;</span>
|
|
<a id='x1-66305r138'></a><span class='ecrm-0500'>138</span>
|
|
<a id='x1-66307r139'></a><span class='ecrm-0500'>139</span><span class='ectt-0800'> </span><span id='textcolor3571'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (!*(msg_ptr + *offset)) { </span><span id='textcolor3572'><span class='ectt-0800'>/* We are at the end of the message */</span></span>
|
|
<a id='x1-66309r140'></a><span class='ecrm-0500'>140</span><span class='ectt-0800'> *offset = 0; </span><span id='textcolor3573'><span class='ectt-0800'>/* reset the offset */</span></span>
|
|
<a id='x1-66311r141'></a><span class='ecrm-0500'>141</span><span class='ectt-0800'> </span><span id='textcolor3574'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0; </span><span id='textcolor3575'><span class='ectt-0800'>/* signify end of file */</span></span>
|
|
<a id='x1-66313r142'></a><span class='ecrm-0500'>142</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-66315r143'></a><span class='ecrm-0500'>143</span>
|
|
<a id='x1-66317r144'></a><span class='ecrm-0500'>144</span><span class='ectt-0800'> msg_ptr += *offset;</span>
|
|
<a id='x1-66319r145'></a><span class='ecrm-0500'>145</span>
|
|
<a id='x1-66321r146'></a><span class='ecrm-0500'>146</span><span class='ectt-0800'> </span><span id='textcolor3576'><span class='ectt-0800'>/* Actually put the data into the buffer */</span></span>
|
|
<a id='x1-66323r147'></a><span class='ecrm-0500'>147</span><span class='ectt-0800'> </span><span id='textcolor3577'><span class='ectt-0800'>while</span></span><span class='ectt-0800'> (length && *msg_ptr) {</span>
|
|
<a id='x1-66325r148'></a><span class='ecrm-0500'>148</span><span class='ectt-0800'> </span><span id='textcolor3578'><span class='ectt-0800'>/**</span></span>
|
|
<a id='x1-66327r149'></a><span class='ecrm-0500'>149</span><span id='textcolor3579'><span class='ectt-0800'> * The buffer is in the user data segment, not the kernel</span></span>
|
|
<a id='x1-66329r150'></a><span class='ecrm-0500'>150</span><span id='textcolor3580'><span class='ectt-0800'> * segment so "*" assignment won</span><span class='tctt-0800'>'</span><span class='ectt-0800'>t work. We have to use</span></span>
|
|
<a id='x1-66331r151'></a><span class='ecrm-0500'>151</span><span id='textcolor3581'><span class='ectt-0800'> * put_user which copies data from the kernel data segment to</span></span>
|
|
<a id='x1-66333r152'></a><span class='ecrm-0500'>152</span><span id='textcolor3582'><span class='ectt-0800'> * the user data segment.</span></span>
|
|
<a id='x1-66335r153'></a><span class='ecrm-0500'>153</span><span id='textcolor3583'><span class='ectt-0800'> */</span></span>
|
|
<a id='x1-66337r154'></a><span class='ecrm-0500'>154</span><span class='ectt-0800'> put_user(*(msg_ptr++), buffer++);</span>
|
|
<a id='x1-66339r155'></a><span class='ecrm-0500'>155</span><span class='ectt-0800'> length--;</span>
|
|
<a id='x1-66341r156'></a><span class='ecrm-0500'>156</span><span class='ectt-0800'> bytes_read++;</span>
|
|
<a id='x1-66343r157'></a><span class='ecrm-0500'>157</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-66345r158'></a><span class='ecrm-0500'>158</span>
|
|
<a id='x1-66347r159'></a><span class='ecrm-0500'>159</span><span class='ectt-0800'> *offset += bytes_read;</span>
|
|
<a id='x1-66349r160'></a><span class='ecrm-0500'>160</span>
|
|
<a id='x1-66351r161'></a><span class='ecrm-0500'>161</span><span class='ectt-0800'> </span><span id='textcolor3584'><span class='ectt-0800'>/* Most read functions return the number of bytes put into the buffer. */</span></span>
|
|
<a id='x1-66353r162'></a><span class='ecrm-0500'>162</span><span class='ectt-0800'> </span><span id='textcolor3585'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> bytes_read;</span>
|
|
<a id='x1-66355r163'></a><span class='ecrm-0500'>163</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-66357r164'></a><span class='ecrm-0500'>164</span>
|
|
<a id='x1-66359r165'></a><span class='ecrm-0500'>165</span><span id='textcolor3586'><span class='ectt-0800'>/* Called when a process writes to dev file; echo "enable" > /dev/key_state */</span></span>
|
|
<a id='x1-66361r166'></a><span class='ecrm-0500'>166</span><span id='textcolor3587'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3588'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> device_write(</span><span id='textcolor3589'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *filp, </span><span id='textcolor3590'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor3591'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *buffer,</span>
|
|
<a id='x1-66363r167'></a><span class='ecrm-0500'>167</span><span class='ectt-0800'> </span><span id='textcolor3592'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'> length, loff_t *offset)</span>
|
|
<a id='x1-66365r168'></a><span class='ecrm-0500'>168</span><span class='ectt-0800'>{</span>
|
|
<a id='x1-66367r169'></a><span class='ecrm-0500'>169</span><span class='ectt-0800'> </span><span id='textcolor3593'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> command[10];</span>
|
|
<a id='x1-66369r170'></a><span class='ecrm-0500'>170</span>
|
|
<a id='x1-66371r171'></a><span class='ecrm-0500'>171</span><span class='ectt-0800'> </span><span id='textcolor3594'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (length > 10) {</span>
|
|
<a id='x1-66373r172'></a><span class='ecrm-0500'>172</span><span class='ectt-0800'> pr_err(</span><span id='textcolor3595'><span class='ectt-0800'>"command exceeded 10 char</span></span><span id='textcolor3596'><span class='ectt-0800'>\n</span></span><span id='textcolor3597'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span>
|
|
<a id='x1-66375r173'></a><span class='ecrm-0500'>173</span><span class='ectt-0800'> </span><span id='textcolor3598'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -EINVAL;</span>
|
|
<a id='x1-66377r174'></a><span class='ecrm-0500'>174</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-66379r175'></a><span class='ecrm-0500'>175</span>
|
|
<a id='x1-66381r176'></a><span class='ecrm-0500'>176</span><span class='ectt-0800'> </span><span id='textcolor3599'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (copy_from_user(command, buffer, length))</span>
|
|
<a id='x1-66383r177'></a><span class='ecrm-0500'>177</span><span class='ectt-0800'> </span><span id='textcolor3600'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -EFAULT;</span>
|
|
<a id='x1-66385r178'></a><span class='ecrm-0500'>178</span>
|
|
<a id='x1-66387r179'></a><span class='ecrm-0500'>179</span><span class='ectt-0800'> </span><span id='textcolor3601'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (strncmp(command, </span><span id='textcolor3602'><span class='ectt-0800'>"enable"</span></span><span class='ectt-0800'>, strlen(</span><span id='textcolor3603'><span class='ectt-0800'>"enable"</span></span><span class='ectt-0800'>)) == 0)</span>
|
|
<a id='x1-66389r180'></a><span class='ecrm-0500'>180</span><span class='ectt-0800'> static_branch_enable(&fkey);</span>
|
|
<a id='x1-66391r181'></a><span class='ecrm-0500'>181</span><span class='ectt-0800'> </span><span id='textcolor3604'><span class='ectt-0800'>else</span></span><span class='ectt-0800'> </span><span id='textcolor3605'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (strncmp(command, </span><span id='textcolor3606'><span class='ectt-0800'>"disable"</span></span><span class='ectt-0800'>, strlen(</span><span id='textcolor3607'><span class='ectt-0800'>"disable"</span></span><span class='ectt-0800'>)) == 0)</span>
|
|
<a id='x1-66393r182'></a><span class='ecrm-0500'>182</span><span class='ectt-0800'> static_branch_disable(&fkey);</span>
|
|
<a id='x1-66395r183'></a><span class='ecrm-0500'>183</span><span class='ectt-0800'> </span><span id='textcolor3608'><span class='ectt-0800'>else</span></span><span class='ectt-0800'> {</span>
|
|
<a id='x1-66397r184'></a><span class='ecrm-0500'>184</span><span class='ectt-0800'> pr_err(</span><span id='textcolor3609'><span class='ectt-0800'>"Invalid command: %s</span></span><span id='textcolor3610'><span class='ectt-0800'>\n</span></span><span id='textcolor3611'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, command);</span>
|
|
<a id='x1-66399r185'></a><span class='ecrm-0500'>185</span><span class='ectt-0800'> </span><span id='textcolor3612'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -EINVAL;</span>
|
|
<a id='x1-66401r186'></a><span class='ecrm-0500'>186</span><span class='ectt-0800'> }</span>
|
|
<a id='x1-66403r187'></a><span class='ecrm-0500'>187</span>
|
|
<a id='x1-66405r188'></a><span class='ecrm-0500'>188</span><span class='ectt-0800'> </span><span id='textcolor3613'><span class='ectt-0800'>/* Again, return the number of input characters used. */</span></span>
|
|
<a id='x1-66407r189'></a><span class='ecrm-0500'>189</span><span class='ectt-0800'> </span><span id='textcolor3614'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> length;</span>
|
|
<a id='x1-66409r190'></a><span class='ecrm-0500'>190</span><span class='ectt-0800'>}</span>
|
|
<a id='x1-66411r191'></a><span class='ecrm-0500'>191</span>
|
|
<a id='x1-66413r192'></a><span class='ecrm-0500'>192</span><span class='ectt-0800'>module_init(chardev_init);</span>
|
|
<a id='x1-66415r193'></a><span class='ecrm-0500'>193</span><span class='ectt-0800'>module_exit(chardev_exit);</span>
|
|
<a id='x1-66417r194'></a><span class='ecrm-0500'>194</span>
|
|
<a id='x1-66419r195'></a><span class='ecrm-0500'>195</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor3615'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span></pre>
|
|
<!-- l. 2129 --><p class='indent'> To check the state of the static key, we can use the <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/dev/key_state</span></span></span>
|
|
interface.
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb100'><a id='x1-66422r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>cat /dev/key_state</span></pre>
|
|
<!-- l. 2135 --><p class='indent'> This will display the current state of the key, which is disabled by default.
|
|
</p><!-- l. 2137 --><p class='indent'> To change the state of the static key, we can perform a write operation on the
|
|
file:
|
|
</p><!-- l. 1 --><p class='indent'>
|
|
</p>
|
|
<pre class='fancyvrb' id='fancyvrb101'><a id='x1-66425r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>echo enable > /dev/key_state</span></pre>
|
|
<!-- l. 2143 --><p class='indent'> This will enable the static key, causing the code path to switch from the fastpath
|
|
to the slowpath.
|
|
</p><!-- l. 2145 --><p class='indent'> In some cases, the key is enabled or disabled at initialization and never changed,
|
|
we can declare a static key as read-only, which means that it can only be toggled in
|
|
the module init function. To declare a read-only static key, we can use the
|
|
<code> <span class='ectt-1000'>DEFINE_STATIC_KEY_FALSE_RO</span>
|
|
</code> or <code> <span class='ectt-1000'>DEFINE_STATIC_KEY_TRUE_RO</span>
|
|
</code> macro instead. Attempts to change the key at runtime will result in a page fault. For
|
|
more information, see <a href='https://www.kernel.org/doc/Documentation/static-keys.txt'>Static keys</a>
|
|
</p><!-- l. 2148 --><p class='noindent'>
|
|
</p>
|
|
<h3 class='sectionHead' id='common-pitfalls'><span class='titlemark'>19 </span> <a id='x1-6700019'></a>Common Pitfalls</h3>
|
|
<!-- l. 2151 --><p class='noindent'>
|
|
</p>
|
|
|
|
|
|
|
|
<h4 class='subsectionHead' id='using-standard-libraries'><span class='titlemark'>19.1 </span> <a id='x1-6800019.1'></a>Using standard libraries</h4>
|
|
<!-- l. 2153 --><p class='noindent'>You can not do that. In a kernel module, you can only use kernel functions which are
|
|
the functions you can see in <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc/kallsyms</span></span></span>.
|
|
</p><!-- l. 2156 --><p class='noindent'>
|
|
</p>
|
|
<h4 class='subsectionHead' id='disabling-interrupts'><span class='titlemark'>19.2 </span> <a id='x1-6900019.2'></a>Disabling interrupts</h4>
|
|
<!-- l. 2158 --><p class='noindent'>You might need to do this for a short time and that is OK, but if you do not enable
|
|
them afterwards, your system will be stuck and you will have to power it
|
|
off.
|
|
</p><!-- l. 2160 --><p class='noindent'>
|
|
</p>
|
|
<h3 class='sectionHead' id='where-to-go-from-here'><span class='titlemark'>20 </span> <a id='x1-7000020'></a>Where To Go From Here?</h3>
|
|
<!-- l. 2162 --><p class='noindent'>For those deeply interested in kernel programming, <a href='https://kernelnewbies.org'>kernelnewbies.org</a> and the
|
|
<a href='https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/Documentation'>Documentation</a> subdirectory within the kernel source code are highly recommended.
|
|
Although the latter may not always be straightforward, it serves as a valuable initial
|
|
step for further exploration. Echoing Linus Torvalds’ perspective, the most effective
|
|
method to understand the kernel is through personal examination of the source
|
|
code.
|
|
</p><!-- l. 2167 --><p class='indent'> Contributions to this guide are welcome, especially if there are any significant
|
|
inaccuracies identified. To contribute or report an issue, please initiate an
|
|
issue at <a class='url' href='https://github.com/sysprog21/lkmpg'><span class='ectt-1000'>https://github.com/sysprog21/lkmpg</span></a>. Pull requests are greatly
|
|
appreciated.
|
|
</p><!-- l. 2171 --><p class='indent'> Happy hacking!
|
|
</p>
|
|
<div class='footnotes'><!-- l. 1846 --><p class='indent'> <span class='footnote-mark'><a href='#fn1x0-bk' id='fn1x0'><sup class='textsuperscript'>1</sup></a></span><span class='ecrm-0800'>The goal of threaded interrupts is to push more of the work to separate threads, so that the
|
|
</span><span class='ecrm-0800'>minimum needed for acknowledging an interrupt is reduced, and therefore the time spent handling
|
|
</span><span class='ecrm-0800'>the interrupt (where it can’t handle any other interrupts at the same time) is reduced. See</span>
|
|
<a class='url' href='https://lwn.net/Articles/302043/'><span class='ectt-0800'>https://lwn.net/Articles/302043/</span></a><span class='ecrm-0800'>.</span></p> </div>
|
|
|
|
</body>
|
|
</html> |